From eae3eb58a2ef39d22f8f701ce39a355c0fb9104e Mon Sep 17 00:00:00 2001 From: Baris Aydinoglu Date: Wed, 5 Feb 2014 19:33:52 +0200 Subject: [PATCH 001/321] detectizr library added Detectizr is a Modernizr extension to detect - device - device model - device orientation - screen size - operating system - operating system version - operating system version full - browser - browser version - browser engine - browser plugins --- public/js/editors/libraries.js | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/public/js/editors/libraries.js b/public/js/editors/libraries.js index e0535f29..e449b0c3 100644 --- a/public/js/editors/libraries.js +++ b/public/js/editors/libraries.js @@ -61,7 +61,6 @@ var libraries = [ 'http://code.jquery.com/mobile/git/jquery.mobile-git.css', 'http://code.jquery.com/jquery-1.10.2.min.js', 'http://code.jquery.com/mobile/git/jquery.mobile-git.js' - ], 'label': 'jQuery Mobile WIP (via git)', 'group': 'jQuery Mobile' }, @@ -366,6 +365,13 @@ var libraries = [ 'url': 'http://cdnjs.cloudflare.com/ajax/libs/modernizr/2.6.2/modernizr.min.js', 'label': 'Modernizr 2.6.2' }, + { + 'url': [ + 'http://cdnjs.cloudflare.com/ajax/libs/modernizr/2.6.2/modernizr.min.js', + 'http://cdnjs.cloudflare.com/ajax/libs/detectizr/1.5.0/detectizr.min.js' + ], + 'label': 'Detectizr 1.5.0' + }, { 'url': 'http://cdnjs.cloudflare.com/ajax/libs/prefixfree/1.0.7/prefixfree.min.js', 'label': 'Prefixfree 1.0.7' From 78d7c7f4ca036b75d28ec5dfc74dc1955e3f6aaf Mon Sep 17 00:00:00 2001 From: Baris Aydinoglu Date: Wed, 5 Feb 2014 19:36:37 +0200 Subject: [PATCH 002/321] Update libraries.js --- public/js/editors/libraries.js | 1 + 1 file changed, 1 insertion(+) diff --git a/public/js/editors/libraries.js b/public/js/editors/libraries.js index e449b0c3..b9d10647 100644 --- a/public/js/editors/libraries.js +++ b/public/js/editors/libraries.js @@ -61,6 +61,7 @@ var libraries = [ 'http://code.jquery.com/mobile/git/jquery.mobile-git.css', 'http://code.jquery.com/jquery-1.10.2.min.js', 'http://code.jquery.com/mobile/git/jquery.mobile-git.js' + ], 'label': 'jQuery Mobile WIP (via git)', 'group': 'jQuery Mobile' }, From fd07004202ac41465a59514751f6e5824df23320 Mon Sep 17 00:00:00 2001 From: prabirshrestha Date: Tue, 25 Feb 2014 22:44:52 -0500 Subject: [PATCH 003/321] added Highcharts latest --- public/js/editors/libraries.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/public/js/editors/libraries.js b/public/js/editors/libraries.js index e7b1ce0e..f5797a42 100644 --- a/public/js/editors/libraries.js +++ b/public/js/editors/libraries.js @@ -388,6 +388,10 @@ var libraries = [ 'url': 'http://d3js.org/d3.v3.min.js', 'label': 'D3 3.x' }, + { + 'url': '//code.highcharts.com/highcharts.js', + 'label': 'Highcharts latest' + }, { 'url': 'http://cdnjs.cloudflare.com/ajax/libs/raphael/2.1.0/raphael-min.js', 'label': 'Raphaël 2.1.0' From b9cc5aee25129e67dba21e9c291fbec06b225cc2 Mon Sep 17 00:00:00 2001 From: electricg Date: Thu, 10 Apr 2014 23:24:42 +0100 Subject: [PATCH 004/321] #1403 Enabled in Tern renaming in scope --- public/js/editors/tern.js | 1 + 1 file changed, 1 insertion(+) diff --git a/public/js/editors/tern.js b/public/js/editors/tern.js index cbac223c..c0c42d29 100644 --- a/public/js/editors/tern.js +++ b/public/js/editors/tern.js @@ -8,6 +8,7 @@ var initTern = function(editor, defs){ var keyMap = { + 'Ctrl-Q': function(cm) { ternServer.selectName(cm); }, 'Ctrl-I': function(cm) { ternServer.showType(cm); }, 'Ctrl-Space': function(cm) { ternServer.complete(cm); } }; From cb33e0a5418cc5c535176b8b847f0c1279b3a8c1 Mon Sep 17 00:00:00 2001 From: Fabien O'Carroll Date: Wed, 30 Apr 2014 10:41:03 +0100 Subject: [PATCH 005/321] Add route handler for /upgrade --- lib/routes.js | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/lib/routes.js b/lib/routes.js index 0e2add99..6526749e 100644 --- a/lib/routes.js +++ b/lib/routes.js @@ -160,6 +160,23 @@ module.exports = function (app) { app.post('/api/save', binHandler.apiCreateBin); app.post('/api/:bin/save', binHandler.apiCreateRevision); + app.get('/upgrade', function (req, res) { + + var featureList = JSON.stringify(require('./data/features.json').list); + var root = sandbox.helpers.url('', true, req.secure); + var static = sandbox.helpers.urlForStatic('', req.secure); + var referrer = req.get('referer'); + + res.render('upgrade', { + layout: 'sub/layout', + root: root, + static: static, + referrer: referrer, + featureList: featureList + }); + + }); + // Account settings var renderAccountSettings = (function(){ var pages = ['editor', 'profile', 'delete', 'preferences']; From e9bead2b534754a536e91bca1e937726113d2c0e Mon Sep 17 00:00:00 2001 From: Fabien O'Carroll Date: Wed, 30 Apr 2014 11:40:56 +0100 Subject: [PATCH 006/321] Add initial upgrade page and data --- lib/data/features.json | 20 +++++++ views/upgrade.html | 125 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 145 insertions(+) create mode 100644 lib/data/features.json create mode 100644 views/upgrade.html diff --git a/lib/data/features.json b/lib/data/features.json new file mode 100644 index 00000000..2e2d56ba --- /dev/null +++ b/lib/data/features.json @@ -0,0 +1,20 @@ +{ + "list": [ + { + "name": "Private Bins", + "user": 2 + }, + { + "name": "Dropbox Sync", + "user": 2 + }, + { + "name": "Save bins to Gist", + "user": 1 + }, + { + "name": "Codecasting (Professor mode)", + "user": 0 + } + ] +} diff --git a/views/upgrade.html b/views/upgrade.html new file mode 100644 index 00000000..96f28855 --- /dev/null +++ b/views/upgrade.html @@ -0,0 +1,125 @@ +

Upgrade

+ + + + + + + + + + + + + + + + + +
Anon Free Pro
+
+ +
+
+ + + + + From c0c45014dbfe376a24e3901a6be440e27a45b47e Mon Sep 17 00:00:00 2001 From: Fabien O'Carroll Date: Wed, 30 Apr 2014 12:35:49 +0100 Subject: [PATCH 007/321] Move upgrade page js into seperate file --- public/js/account/upgrade-page.js | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 public/js/account/upgrade-page.js diff --git a/public/js/account/upgrade-page.js b/public/js/account/upgrade-page.js new file mode 100644 index 00000000..6c5e79c1 --- /dev/null +++ b/public/js/account/upgrade-page.js @@ -0,0 +1,29 @@ +'use strict'; +/* globals $, features */ + +var $table = $('table'); + +features.sort(function (a, b) { + return a.user - b.user; +}); + +features.forEach(function (feature) { + var $row = $(''); + $row.append( + $('').html(feature.name).addClass('feature') + ); + + for (var i = 0; i < 3; i++) { + var $td = $(''); + // use this if we reverse order of columns + if (i > feature.user - 1) { + //if ((2 - i) >= feature.user) { + $td.html('✔').addClass(); + } else { + $td.html(' ').addClass(); + } + $row.append($td); + } + + $table.append($row); +}); From 1c44b44ef44c053504c06ae1f68cffae55480a0d Mon Sep 17 00:00:00 2001 From: Fabien O'Carroll Date: Wed, 30 Apr 2014 12:39:22 +0100 Subject: [PATCH 008/321] Remove upgrade-page code froms scrip tag --- views/upgrade.html | 30 +----------------------------- 1 file changed, 1 insertion(+), 29 deletions(-) diff --git a/views/upgrade.html b/views/upgrade.html index 96f28855..02f23e60 100644 --- a/views/upgrade.html +++ b/views/upgrade.html @@ -31,35 +31,7 @@ From cf63330a8e305097f95fcc53e8be135e6d4c6068 Mon Sep 17 00:00:00 2001 From: Fabien O'Carroll Date: Wed, 30 Apr 2014 14:16:00 +0100 Subject: [PATCH 011/321] Put the upgrade page behind a feature flag --- lib/routes.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/routes.js b/lib/routes.js index 6526749e..e12e8506 100644 --- a/lib/routes.js +++ b/lib/routes.js @@ -160,7 +160,7 @@ module.exports = function (app) { app.post('/api/save', binHandler.apiCreateBin); app.post('/api/:bin/save', binHandler.apiCreateRevision); - app.get('/upgrade', function (req, res) { + app.get('/upgrade', features.route('stripe'), function (req, res) { var featureList = JSON.stringify(require('./data/features.json').list); var root = sandbox.helpers.url('', true, req.secure); From e717ef6231f6a9908ee390e445f4e93d1c88f576 Mon Sep 17 00:00:00 2001 From: Fabien O'Carroll Date: Wed, 30 Apr 2014 15:51:10 +0100 Subject: [PATCH 012/321] Use width auto for the left most 's --- public/css/upgrade.css | 1 + 1 file changed, 1 insertion(+) diff --git a/public/css/upgrade.css b/public/css/upgrade.css index 48d9b9ba..3d299d68 100644 --- a/public/css/upgrade.css +++ b/public/css/upgrade.css @@ -32,6 +32,7 @@ td { td.feature { text-align:left; + width:auto; } /* button.stripe-button-el { From c326f9e98fdf407cee2c5076ac1be84ed26afdd2 Mon Sep 17 00:00:00 2001 From: Fabien O'Carroll Date: Wed, 30 Apr 2014 15:52:03 +0100 Subject: [PATCH 013/321] Add script and link tags for uprgade page externals --- views/upgrade.html | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/views/upgrade.html b/views/upgrade.html index 0b4b4939..aa3b3ef6 100644 --- a/views/upgrade.html +++ b/views/upgrade.html @@ -1,3 +1,4 @@ +

Upgrade

@@ -29,7 +30,8 @@
- + + From ca0b63631dbb5972fc09555b4488898e8cd48072 Mon Sep 17 00:00:00 2001 From: Fabien O'Carroll Date: Thu, 1 May 2014 11:47:54 +0100 Subject: [PATCH 014/321] Use !== rather than > in condition This is more aligned to the actual logic we're implementing although there is no difference in flow. --- lib/middleware.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/middleware.js b/lib/middleware.js index 79803ad2..50e94e35 100644 --- a/lib/middleware.js +++ b/lib/middleware.js @@ -284,7 +284,7 @@ module.exports = { } } else { if (!req.secure) { - if (config.url.ssl.paths.indexOf(pathname) > -1) { + if (config.url.ssl.paths.indexOf(pathname) !== -1) { return res.redirect('https://' + req.headers.host.replace(/:.*/, '') + req.url); } } else { From 99678eba235d8b3b238d746a345469e1e2734e32 Mon Sep 17 00:00:00 2001 From: Fabien O'Carroll Date: Thu, 1 May 2014 11:23:57 +0100 Subject: [PATCH 015/321] Add more features --- lib/data/features.json | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/lib/data/features.json b/lib/data/features.json index 2e2d56ba..e5625198 100644 --- a/lib/data/features.json +++ b/lib/data/features.json @@ -15,6 +15,30 @@ { "name": "Codecasting (Professor mode)", "user": 0 + }, + { + "name": "Custom CNAME", + "user": 2 + }, + { + "name": "Custom starting template", + "user": 0 + }, + { + "name": "Multiple external resources", + "user": 0 + }, + { + "name": "Asset hosting", + "user": 2 + }, + { + "name": "Custom libraries", + "user": 0 + }, + { + "name": "Remote rendering", + "user": 0 } ] } From b334d3295c0a2f2fd64316bb2db6e52f332c5acf Mon Sep 17 00:00:00 2001 From: Fabien O'Carroll Date: Thu, 1 May 2014 14:09:44 +0100 Subject: [PATCH 016/321] Add pathIsSSL predicate --- lib/middleware.js | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/lib/middleware.js b/lib/middleware.js index 50e94e35..9df01d18 100644 --- a/lib/middleware.js +++ b/lib/middleware.js @@ -333,3 +333,12 @@ module.exports = { }; }, }; + +function pathIsSSL (route) { + return config.url.ssl.paths.reduce(function (bool, path) { + if (route.indexOf(path) === 0) { + bool = true; + } + return bool; + }, false); +} From c839dea558ff7bf2f60c7a494c5d0dc8c340d36a Mon Sep 17 00:00:00 2001 From: Fabien O'Carroll Date: Thu, 1 May 2014 14:10:49 +0100 Subject: [PATCH 017/321] Use pathIsSSL for protocalCheck conditions --- lib/middleware.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/middleware.js b/lib/middleware.js index 9df01d18..c7af1826 100644 --- a/lib/middleware.js +++ b/lib/middleware.js @@ -284,11 +284,11 @@ module.exports = { } } else { if (!req.secure) { - if (config.url.ssl.paths.indexOf(pathname) !== -1) { + if (pathIsSSL(pathname)) { return res.redirect('https://' + req.headers.host.replace(/:.*/, '') + req.url); } } else { - if (config.url.ssl.paths.indexOf(pathname) === -1) { + if (!pathIsSSL(pathname)) { return res.redirect('http://' + req.headers.host.replace(/:.*/, '') + req.url); } } From 633cb7786ba1133385027672aea3162e735e0464 Mon Sep 17 00:00:00 2001 From: Fabien O'Carroll Date: Fri, 2 May 2014 11:20:34 +0100 Subject: [PATCH 018/321] Add education text --- views/upgrade.html | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/views/upgrade.html b/views/upgrade.html index aa3b3ef6..90c69118 100644 --- a/views/upgrade.html +++ b/views/upgrade.html @@ -30,6 +30,23 @@ +

Keep JS Bin 100% free for education

+

+ Aside from the features listed above, your pro account will help keep + JS Bin 100% free for educational uses (schools, universities and community + training). those good people will be able to get free training accounts + so they can continue to help young students and new-comers with JS Bin in + their tool belt +

+ +

+ Education is dear to my heart, and pro accounts allows us to keep developing + JS Bin with feature i want to see land, and to help fix and issues that cause + problems for noth general users and those students stuck working with limited + access to tech (like the version of JS Bin that works without a web connection + and entirely from a usb stick with zero install). +

+ From 3ad0606b1572c31a081cfb64de4d270af80d9f57 Mon Sep 17 00:00:00 2001 From: Fabien O'Carroll Date: Fri, 2 May 2014 15:47:47 +0100 Subject: [PATCH 023/321] add backers markup --- views/upgrade.html | 3 +++ views/upgrade.html.orig | 58 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 61 insertions(+) create mode 100644 views/upgrade.html.orig diff --git a/views/upgrade.html b/views/upgrade.html index 9508c5e0..3c1d3e1f 100644 --- a/views/upgrade.html +++ b/views/upgrade.html @@ -47,6 +47,9 @@ and entirely from a usb stick with zero install).

+

Backers

+
+ + + + + + + +<<<<<<< HEAD + +======= +

Keep JS Bin 100% free for education

+

+ Aside from the features listed above, your pro account will help keep + JS Bin 100% free for educational uses (schools, universities and community + training). those good people will be able to get free training accounts + so they can continue to help young students and new-comers with JS Bin in + their tool belt +

+ +

+ Education is dear to my heart, and pro accounts allows us to keep developing + JS Bin with feature i want to see land, and to help fix and issues that cause + problems for noth general users and those students stuck working with limited + access to tech (like the version of JS Bin that works without a web connection + and entirely from a usb stick with zero install). +

+ + +>>>>>>> 83add53... Add education text + + From c702193a3315751e3f329723c5580cb709b95dd8 Mon Sep 17 00:00:00 2001 From: Fabien O'Carroll Date: Fri, 2 May 2014 15:48:14 +0100 Subject: [PATCH 024/321] create and add markup for each backer --- public/js/account/upgrade-page.js | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/public/js/account/upgrade-page.js b/public/js/account/upgrade-page.js index 6c5e79c1..b045ded5 100644 --- a/public/js/account/upgrade-page.js +++ b/public/js/account/upgrade-page.js @@ -27,3 +27,14 @@ features.forEach(function (feature) { $table.append($row); }); + +var $backers = $('.backers'); + +backers.forEach(function (backer) { + var $a = $(''); + $a.attr('href', backer.url); + var $img = $(''); + $img.attr('src', backer.image); + $a.html($img); + $backers.append($a); +}); From 052aa5efd85283c39603c7c0bb14b56fe27da4f3 Mon Sep 17 00:00:00 2001 From: Fabien O'Carroll Date: Fri, 2 May 2014 16:16:38 +0100 Subject: [PATCH 025/321] Begin css for backers section --- public/css/upgrade.css | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/public/css/upgrade.css b/public/css/upgrade.css index a28acef3..2accb19b 100644 --- a/public/css/upgrade.css +++ b/public/css/upgrade.css @@ -34,6 +34,16 @@ td.feature { text-align:left; width:auto; } + +.backers { +} +.backers a { + +} +.backers img { + width:33%; + float:left; +} /* button.stripe-button-el { font-size: 1.4em; From 3c4f3b0713516a8c67d912ce1ab4dcebacf8a125 Mon Sep 17 00:00:00 2001 From: Fabien O'Carroll Date: Fri, 2 May 2014 16:26:37 +0100 Subject: [PATCH 026/321] set width of backers container to 100% --- public/css/upgrade.css | 1 + 1 file changed, 1 insertion(+) diff --git a/public/css/upgrade.css b/public/css/upgrade.css index 2accb19b..ee80cec5 100644 --- a/public/css/upgrade.css +++ b/public/css/upgrade.css @@ -36,6 +36,7 @@ td.feature { } .backers { + width:100%; } .backers a { From d2ca3411fdb866d5b879f7958f37f644035db4bf Mon Sep 17 00:00:00 2001 From: Fabien O'Carroll Date: Fri, 2 May 2014 16:36:21 +0100 Subject: [PATCH 027/321] give backer image a class to overwite styles --- public/js/account/upgrade-page.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/js/account/upgrade-page.js b/public/js/account/upgrade-page.js index b045ded5..3fbd66e2 100644 --- a/public/js/account/upgrade-page.js +++ b/public/js/account/upgrade-page.js @@ -34,7 +34,7 @@ backers.forEach(function (backer) { var $a = $(''); $a.attr('href', backer.url); var $img = $(''); - $img.attr('src', backer.image); + $img.attr('src', backer.image).addClass('backer-img'); $a.html($img); $backers.append($a); }); From 350b8e4fe4685e1e43d62fc728942835950ac82f Mon Sep 17 00:00:00 2001 From: Fabien O'Carroll Date: Fri, 2 May 2014 16:44:37 +0100 Subject: [PATCH 028/321] use class over tag name --- public/css/upgrade.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/css/upgrade.css b/public/css/upgrade.css index ee80cec5..11625970 100644 --- a/public/css/upgrade.css +++ b/public/css/upgrade.css @@ -41,7 +41,7 @@ td.feature { .backers a { } -.backers img { +.backers .backer-img { width:33%; float:left; } From 2c0b2bdaca74171ce026d0535a4dec141d45c237 Mon Sep 17 00:00:00 2001 From: Fabien O'Carroll Date: Fri, 2 May 2014 16:49:47 +0100 Subject: [PATCH 029/321] prefix selector with #body --- public/css/upgrade.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/css/upgrade.css b/public/css/upgrade.css index 11625970..e931cb98 100644 --- a/public/css/upgrade.css +++ b/public/css/upgrade.css @@ -41,7 +41,7 @@ td.feature { .backers a { } -.backers .backer-img { +#body .backers .backer-img { width:33%; float:left; } From ef429287203a5683d4c8c3e88dd024628d3c0b65 Mon Sep 17 00:00:00 2001 From: Fabien O'Carroll Date: Fri, 2 May 2014 16:51:41 +0100 Subject: [PATCH 030/321] Update backer img styles, center container and use fixed widths --- public/css/upgrade.css | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/public/css/upgrade.css b/public/css/upgrade.css index e931cb98..d8bba86e 100644 --- a/public/css/upgrade.css +++ b/public/css/upgrade.css @@ -36,14 +36,17 @@ td.feature { } .backers { - width:100%; + width:720px; + margin:0 auto; } .backers a { } #body .backers .backer-img { - width:33%; + width:200px; + margin:20px; float:left; + border:none; } /* button.stripe-button-el { From 97dee063bb2cc3264169c8240cff63f7f13d2c78 Mon Sep 17 00:00:00 2001 From: Fabien O'Carroll Date: Fri, 2 May 2014 16:54:48 +0100 Subject: [PATCH 031/321] Move h1/h2 dont weights to their own selectors, embolden h2 slightly --- public/css/upgrade.css | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/public/css/upgrade.css b/public/css/upgrade.css index d8bba86e..35f42b37 100644 --- a/public/css/upgrade.css +++ b/public/css/upgrade.css @@ -4,10 +4,17 @@ body { } h1, h2 { - font-weight:300; text-align:center; } +h1 { + font-weight:300; +} + +h2 { + font-weight:400; +} + table { width:100%; margin:0 auto; From 408406716e0e9688eaa925789f64558fb552cead Mon Sep 17 00:00:00 2001 From: Fabien O'Carroll Date: Fri, 2 May 2014 17:08:31 +0100 Subject: [PATCH 032/321] stupid mistake --- views/upgrade.html.orig | 58 ----------------------------------------- 1 file changed, 58 deletions(-) delete mode 100644 views/upgrade.html.orig diff --git a/views/upgrade.html.orig b/views/upgrade.html.orig deleted file mode 100644 index 2f9cae10..00000000 --- a/views/upgrade.html.orig +++ /dev/null @@ -1,58 +0,0 @@ - -

Upgrade

- - - - - - - - - - - - - - - - - -
Anon Free Pro
-
- -
-
- -<<<<<<< HEAD - -======= -

Keep JS Bin 100% free for education

-

- Aside from the features listed above, your pro account will help keep - JS Bin 100% free for educational uses (schools, universities and community - training). those good people will be able to get free training accounts - so they can continue to help young students and new-comers with JS Bin in - their tool belt -

- -

- Education is dear to my heart, and pro accounts allows us to keep developing - JS Bin with feature i want to see land, and to help fix and issues that cause - problems for noth general users and those students stuck working with limited - access to tech (like the version of JS Bin that works without a web connection - and entirely from a usb stick with zero install). -

- - ->>>>>>> 83add53... Add education text - - From dcb160c79c4aeb9e7e796ed5c7c234c048f2a3f2 Mon Sep 17 00:00:00 2001 From: Fabien O'Carroll Date: Fri, 2 May 2014 11:20:34 +0100 Subject: [PATCH 033/321] Add education text --- views/upgrade.html | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/views/upgrade.html b/views/upgrade.html index aa3b3ef6..90c69118 100644 --- a/views/upgrade.html +++ b/views/upgrade.html @@ -30,6 +30,23 @@ +

Keep JS Bin 100% free for education

+

+ Aside from the features listed above, your pro account will help keep + JS Bin 100% free for educational uses (schools, universities and community + training). those good people will be able to get free training accounts + so they can continue to help young students and new-comers with JS Bin in + their tool belt +

+ +

+ Education is dear to my heart, and pro accounts allows us to keep developing + JS Bin with feature i want to see land, and to help fix and issues that cause + problems for noth general users and those students stuck working with limited + access to tech (like the version of JS Bin that works without a web connection + and entirely from a usb stick with zero install). +

+ From 9c1ebc32d1040a9ffaa7024ee4bb55a38565b525 Mon Sep 17 00:00:00 2001 From: Fabien O'Carroll Date: Fri, 2 May 2014 15:47:47 +0100 Subject: [PATCH 038/321] add backers markup --- views/upgrade.html | 3 +++ views/upgrade.html.orig | 58 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 61 insertions(+) create mode 100644 views/upgrade.html.orig diff --git a/views/upgrade.html b/views/upgrade.html index 9508c5e0..3c1d3e1f 100644 --- a/views/upgrade.html +++ b/views/upgrade.html @@ -47,6 +47,9 @@ and entirely from a usb stick with zero install).

+

Backers

+
+ + + + + + + +<<<<<<< HEAD + +======= +

Keep JS Bin 100% free for education

+

+ Aside from the features listed above, your pro account will help keep + JS Bin 100% free for educational uses (schools, universities and community + training). those good people will be able to get free training accounts + so they can continue to help young students and new-comers with JS Bin in + their tool belt +

+ +

+ Education is dear to my heart, and pro accounts allows us to keep developing + JS Bin with feature i want to see land, and to help fix and issues that cause + problems for noth general users and those students stuck working with limited + access to tech (like the version of JS Bin that works without a web connection + and entirely from a usb stick with zero install). +

+ + +>>>>>>> 83add53... Add education text + + From 2262a6de51d0dff502d59ebda949bc6c6b014853 Mon Sep 17 00:00:00 2001 From: Fabien O'Carroll Date: Fri, 2 May 2014 15:48:14 +0100 Subject: [PATCH 039/321] create and add markup for each backer --- public/js/account/upgrade-page.js | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/public/js/account/upgrade-page.js b/public/js/account/upgrade-page.js index 6c5e79c1..b045ded5 100644 --- a/public/js/account/upgrade-page.js +++ b/public/js/account/upgrade-page.js @@ -27,3 +27,14 @@ features.forEach(function (feature) { $table.append($row); }); + +var $backers = $('.backers'); + +backers.forEach(function (backer) { + var $a = $('
'); + $a.attr('href', backer.url); + var $img = $(''); + $img.attr('src', backer.image); + $a.html($img); + $backers.append($a); +}); From b51774c1f241a74cd2f2681f51ce68d294dcbcea Mon Sep 17 00:00:00 2001 From: Fabien O'Carroll Date: Fri, 2 May 2014 16:16:38 +0100 Subject: [PATCH 040/321] Begin css for backers section --- public/css/upgrade.css | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/public/css/upgrade.css b/public/css/upgrade.css index a28acef3..2accb19b 100644 --- a/public/css/upgrade.css +++ b/public/css/upgrade.css @@ -34,6 +34,16 @@ td.feature { text-align:left; width:auto; } + +.backers { +} +.backers a { + +} +.backers img { + width:33%; + float:left; +} /* button.stripe-button-el { font-size: 1.4em; From 1dcd4b9f7f86d5dc1b829c3b2411dc859fa7439e Mon Sep 17 00:00:00 2001 From: Fabien O'Carroll Date: Fri, 2 May 2014 16:26:37 +0100 Subject: [PATCH 041/321] set width of backers container to 100% --- public/css/upgrade.css | 1 + 1 file changed, 1 insertion(+) diff --git a/public/css/upgrade.css b/public/css/upgrade.css index 2accb19b..ee80cec5 100644 --- a/public/css/upgrade.css +++ b/public/css/upgrade.css @@ -36,6 +36,7 @@ td.feature { } .backers { + width:100%; } .backers a { From aaa19078a5d17decdd0d9e720f00ab586818aaa8 Mon Sep 17 00:00:00 2001 From: Fabien O'Carroll Date: Fri, 2 May 2014 16:36:21 +0100 Subject: [PATCH 042/321] give backer image a class to overwite styles --- public/js/account/upgrade-page.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/js/account/upgrade-page.js b/public/js/account/upgrade-page.js index b045ded5..3fbd66e2 100644 --- a/public/js/account/upgrade-page.js +++ b/public/js/account/upgrade-page.js @@ -34,7 +34,7 @@ backers.forEach(function (backer) { var $a = $(''); $a.attr('href', backer.url); var $img = $(''); - $img.attr('src', backer.image); + $img.attr('src', backer.image).addClass('backer-img'); $a.html($img); $backers.append($a); }); From 19c484565bd290e04248f7c213bcb53f4d0a96f1 Mon Sep 17 00:00:00 2001 From: Fabien O'Carroll Date: Fri, 2 May 2014 16:44:37 +0100 Subject: [PATCH 043/321] use class over tag name --- public/css/upgrade.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/css/upgrade.css b/public/css/upgrade.css index ee80cec5..11625970 100644 --- a/public/css/upgrade.css +++ b/public/css/upgrade.css @@ -41,7 +41,7 @@ td.feature { .backers a { } -.backers img { +.backers .backer-img { width:33%; float:left; } From 6aec4bfe54ccd72ac8d200e67ca855ef61a07609 Mon Sep 17 00:00:00 2001 From: Fabien O'Carroll Date: Fri, 2 May 2014 16:49:47 +0100 Subject: [PATCH 044/321] prefix selector with #body --- public/css/upgrade.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/css/upgrade.css b/public/css/upgrade.css index 11625970..e931cb98 100644 --- a/public/css/upgrade.css +++ b/public/css/upgrade.css @@ -41,7 +41,7 @@ td.feature { .backers a { } -.backers .backer-img { +#body .backers .backer-img { width:33%; float:left; } From 7b5b640f2c3625aeda06847adde94aca0d795284 Mon Sep 17 00:00:00 2001 From: Fabien O'Carroll Date: Fri, 2 May 2014 16:51:41 +0100 Subject: [PATCH 045/321] Update backer img styles, center container and use fixed widths --- public/css/upgrade.css | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/public/css/upgrade.css b/public/css/upgrade.css index e931cb98..d8bba86e 100644 --- a/public/css/upgrade.css +++ b/public/css/upgrade.css @@ -36,14 +36,17 @@ td.feature { } .backers { - width:100%; + width:720px; + margin:0 auto; } .backers a { } #body .backers .backer-img { - width:33%; + width:200px; + margin:20px; float:left; + border:none; } /* button.stripe-button-el { From c08de59c8bb7ec918aede302cf40a73f13fa23e1 Mon Sep 17 00:00:00 2001 From: Fabien O'Carroll Date: Fri, 2 May 2014 16:54:48 +0100 Subject: [PATCH 046/321] Move h1/h2 dont weights to their own selectors, embolden h2 slightly --- public/css/upgrade.css | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/public/css/upgrade.css b/public/css/upgrade.css index d8bba86e..35f42b37 100644 --- a/public/css/upgrade.css +++ b/public/css/upgrade.css @@ -4,10 +4,17 @@ body { } h1, h2 { - font-weight:300; text-align:center; } +h1 { + font-weight:300; +} + +h2 { + font-weight:400; +} + table { width:100%; margin:0 auto; From 8a3172d943876462170fe60da2035334a9a0dc7d Mon Sep 17 00:00:00 2001 From: Fabien O'Carroll Date: Fri, 2 May 2014 17:08:31 +0100 Subject: [PATCH 047/321] stupid mistake --- views/upgrade.html.orig | 58 ----------------------------------------- 1 file changed, 58 deletions(-) delete mode 100644 views/upgrade.html.orig diff --git a/views/upgrade.html.orig b/views/upgrade.html.orig deleted file mode 100644 index 2f9cae10..00000000 --- a/views/upgrade.html.orig +++ /dev/null @@ -1,58 +0,0 @@ - -

Upgrade

- - - - - - - - - - - - - - - - - -
Anon Free Pro
-
- -
-
- -<<<<<<< HEAD - -======= -

Keep JS Bin 100% free for education

-

- Aside from the features listed above, your pro account will help keep - JS Bin 100% free for educational uses (schools, universities and community - training). those good people will be able to get free training accounts - so they can continue to help young students and new-comers with JS Bin in - their tool belt -

- -

- Education is dear to my heart, and pro accounts allows us to keep developing - JS Bin with feature i want to see land, and to help fix and issues that cause - problems for noth general users and those students stuck working with limited - access to tech (like the version of JS Bin that works without a web connection - and entirely from a usb stick with zero install). -

- - ->>>>>>> 83add53... Add education text - - From 38c5569f0448c0f197f05ddd3fa4fe94bf455c65 Mon Sep 17 00:00:00 2001 From: Fabien O'Carroll Date: Wed, 7 May 2014 15:16:58 +0100 Subject: [PATCH 048/321] pass stripe key to upgrade view --- lib/routes.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/routes.js b/lib/routes.js index 2e6b07f5..a78db634 100644 --- a/lib/routes.js +++ b/lib/routes.js @@ -9,6 +9,7 @@ var express = require('express'), metrics = require('./metrics'), scripts = require('../scripts.json'), Promise = require('rsvp').Promise, + config = require('./config'); reBin = null; // created when the module is imported function tag(label) { @@ -167,6 +168,7 @@ module.exports = function (app) { var root = sandbox.helpers.url('', true, req.secure); var static = sandbox.helpers.urlForStatic('', req.secure); var referrer = req.get('referer'); + var stripeKey = config.payment.stripe.public; res.render('upgrade', { layout: 'sub/layout', @@ -174,7 +176,8 @@ module.exports = function (app) { static: static, referrer: referrer, featureList: featureList, - backersList: backersList + backersList: backersList, + stripeKey: stripeKey }); }); From 846c6a48ae3cce5723ca8eaa5d3ab7571006c698 Mon Sep 17 00:00:00 2001 From: Fabien O'Carroll Date: Wed, 7 May 2014 15:17:15 +0100 Subject: [PATCH 049/321] update view to use stripeKey --- views/upgrade.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/views/upgrade.html b/views/upgrade.html index 3c1d3e1f..10fbd51a 100644 --- a/views/upgrade.html +++ b/views/upgrade.html @@ -18,7 +18,7 @@
diff --git a/views/partials/account_sidebar.html b/views/partials/account_sidebar.html index 89311e93..b3528da8 100644 --- a/views/partials/account_sidebar.html +++ b/views/partials/account_sidebar.html @@ -4,11 +4,7 @@ Profile Editor settings Preferences - {{#feature request "github"}} - Link your Github account - {{/feature}} - Link with Dropbox {{#unless user.pro}} Upgrade From 5c5e818ff45976db223687facbf494b9affafe0d Mon Sep 17 00:00:00 2001 From: Fabien O'Carroll Date: Mon, 12 May 2014 15:13:17 +0100 Subject: [PATCH 054/321] Add redirect to refer for dropbox auth --- lib/handlers/session.js | 12 +++++++++--- views/account/profile.html | 8 ++++++-- views/partials/account_sidebar.html | 4 ---- 3 files changed, 15 insertions(+), 9 deletions(-) diff --git a/lib/handlers/session.js b/lib/handlers/session.js index 4bb61169..49ac20df 100644 --- a/lib/handlers/session.js +++ b/lib/handlers/session.js @@ -385,18 +385,24 @@ module.exports = Observable.extend({ * DropBox Auth */ - dropboxAuth: passport.authenticate('dropbox-oauth2'), + dropboxAuth: [ + function (req, res, next) { + req.session.referer = req.headers.referer; + next(); + }, + passport.authenticate('dropbox-oauth2') + ], dropboxPassportCallback: passport.authenticate('dropbox-oauth2', { failureRedirect: '/' }), - dropboxCallback: function (req, res, next) { + dropboxCallback: function (req, res) { if (req.session.user) { req.session.user.dropbox_token = req.user.accessToken; } res.flash(req.flash.NOTIFICATION, 'Your dropbox account has been linked to JS Bin, all future bins will now be saved to dropbox'); - res.redirect('/'); + res.redirect(req.session.referer || '/'); }, /** diff --git a/views/account/profile.html b/views/account/profile.html index 04aa6c5b..9ee36a89 100644 --- a/views/account/profile.html +++ b/views/account/profile.html @@ -2,7 +2,7 @@

Your personal details

-
+

@@ -25,7 +25,11 @@ + Link with Dropbox + {{#feature request "github"}} + Link your Github account + {{/feature}}
- \ No newline at end of file + diff --git a/views/partials/account_sidebar.html b/views/partials/account_sidebar.html index 89311e93..b3528da8 100644 --- a/views/partials/account_sidebar.html +++ b/views/partials/account_sidebar.html @@ -4,11 +4,7 @@ Profile Editor settings Preferences - {{#feature request "github"}} - Link your Github account - {{/feature}} - Link with Dropbox {{#unless user.pro}} Upgrade From d63c522e9f53d312394c9e2aa9f45aea3e62486a Mon Sep 17 00:00:00 2001 From: Fabien O'Carroll Date: Tue, 13 May 2014 12:41:56 +0100 Subject: [PATCH 055/321] wrap links in p tag for spacing --- views/account/profile.html | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/views/account/profile.html b/views/account/profile.html index 9ee36a89..33289427 100644 --- a/views/account/profile.html +++ b/views/account/profile.html @@ -25,10 +25,14 @@ - Link with Dropbox - {{#feature request "github"}} - Link your Github account - {{/feature}} + +
From d0388094d6587e955c36b9cf29a856e32a37473c Mon Sep 17 00:00:00 2001 From: Fabien O'Carroll Date: Tue, 13 May 2014 12:42:10 +0100 Subject: [PATCH 056/321] link to external stylesheet --- views/account/profile.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/views/account/profile.html b/views/account/profile.html index 33289427..a44abf7e 100644 --- a/views/account/profile.html +++ b/views/account/profile.html @@ -34,6 +34,6 @@ {{/feature}}

- + From e0207f83d96bba816d1d13ea0f38ae2158414923 Mon Sep 17 00:00:00 2001 From: Fabien O'Carroll Date: Tue, 13 May 2014 12:42:36 +0100 Subject: [PATCH 057/321] Add basic styling for "link to" buttons --- public/css/account-profile.css | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 public/css/account-profile.css diff --git a/public/css/account-profile.css b/public/css/account-profile.css new file mode 100644 index 00000000..90dc5f2d --- /dev/null +++ b/public/css/account-profile.css @@ -0,0 +1,24 @@ +a.link-btn { + font-size: 0.9em; + font-weight: 200; + background: #f0f0f0; + background: linear-gradient(0deg, #f0f0f0, #fefefe); + box-shadow: 0px 1px 1px #eee; + border: 1px solid #aaa; + border-radius: 2px; + padding: 10px 12px; + cursor: pointer; + display: block; + -moz-box-sizing: border-box; + box-sizing: border-box; + text-align: center; + text-decoration: none; + border-bottom: 2px solid #aaa; + color:#232323; + width:276px; + margin-left:104px; +} +a.link-btn:hover { + background: linear-gradient(0deg, #e8e8e8, #f8f8f8); +} + From 1d57f99ea4009c17360aef7144f867f396d805bd Mon Sep 17 00:00:00 2001 From: Remy Sharp Date: Wed, 14 May 2014 16:17:29 +0100 Subject: [PATCH 058/321] Fixed #1447 Removed second logout link --- views/partials/account_sidebar.html | 1 - 1 file changed, 1 deletion(-) diff --git a/views/partials/account_sidebar.html b/views/partials/account_sidebar.html index b3528da8..0e10a4bf 100644 --- a/views/partials/account_sidebar.html +++ b/views/partials/account_sidebar.html @@ -9,7 +9,6 @@ {{#unless user.pro}} Upgrade {{/unless}} - Logout diff --git a/views/sub/layout.html b/views/sub/layout.html index b1bdfa63..13e4fabd 100644 --- a/views/sub/layout.html +++ b/views/sub/layout.html @@ -20,6 +20,7 @@
Back to JS Bin
From 53d7e33ea1785c1a11f454f10e2f2ed7b6044a1c Mon Sep 17 00:00:00 2001 From: Remy Sharp Date: Wed, 21 May 2014 22:16:34 +0100 Subject: [PATCH 073/321] Fixed archive running when not logged in --- public/js/chrome/archive.js | 18 ++++++++++++------ public/js/jsbin.js | 2 +- 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/public/js/chrome/archive.js b/public/js/chrome/archive.js index 3e347d39..ec945d46 100644 --- a/public/js/chrome/archive.js +++ b/public/js/chrome/archive.js @@ -1,30 +1,36 @@ function archive(unarchive) { - /*global jsbin, $, $document*/ + /*global jsbin, $, $document, analytics*/ 'use strict'; var type = unarchive === false ? 'unarchive' : 'archive'; - - if (jsbin.owner()) { + var text = unarchive === false ? 'restore from archive' : 'archiving'; + analytics[type](jsbin.getURL()); + if (!jsbin.user.name) { + $document.trigger('tip', { + type: 'notication', + content: 'You must be logged in and the owner of the bin to archive.' + }); + } else if (jsbin.owner()) { $.ajax({ type: 'POST', url: jsbin.getURL() + '/' + type, error: function () { $document.trigger('tip', { type: 'error', - content: 'The ' + type + ' action failed. If this continues, please can you file an issue?' + content: 'The ' + text + ' failed. If this continues, please can you file an issue?' }); }, success: function () { $document.trigger('tip', { type: 'notication', autohide: 5000, - content: 'This bin is now ' + type + 'd' + content: 'This bin is now ' + (unarchive === false ? 'restored from the archive.' : 'archived.') }); } }); } else { $document.trigger('tip', { type: 'notication', - content: 'The ' + type + ' action failed. You can only own' + content: 'The ' + text + ' failed. You can only archive bins that you own.' }); } } diff --git a/public/js/jsbin.js b/public/js/jsbin.js index 483f9e78..de4d71d6 100644 --- a/public/js/jsbin.js +++ b/public/js/jsbin.js @@ -121,7 +121,7 @@ jQuery.ajaxPrefilter(function (options, original, xhr) { }); jsbin.owner = function () { - return jsbin.user && jsbin.state.metadata && jsbin.state.metadata.name === jsbin.user.name; + return jsbin.user && jsbin.user.name && jsbin.state.metadata && jsbin.state.metadata.name === jsbin.user.name; }; jsbin.getURL = function (withoutRoot, share) { From ed61e2e8f7b96a1ed82b5de0bcba8a7608792f24 Mon Sep 17 00:00:00 2001 From: Remy Sharp Date: Thu, 22 May 2014 15:16:48 +0100 Subject: [PATCH 074/321] Styling --- public/css/style.css | 3 ++- views/partials/top-panel.html | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/public/css/style.css b/public/css/style.css index 7080942f..43b22158 100644 --- a/public/css/style.css +++ b/public/css/style.css @@ -4712,7 +4712,7 @@ html * { #toppanel { height: 250px; - background: #0074D9; + background: #ecf2fa; position: relative; z-index: 100000; margin-top: -250px; @@ -4721,6 +4721,7 @@ html * { -o-transition: margin-top ease-out 100ms; transition: margin-top ease-out 100ms; + border-bottom: rgb(191, 191, 191) solid 1px; } .toppanel #toppanel { diff --git a/views/partials/top-panel.html b/views/partials/top-panel.html index 383abd83..0c77f129 100644 --- a/views/partials/top-panel.html +++ b/views/partials/top-panel.html @@ -1,5 +1,5 @@
-

Hello world

+
+ + Pro @ $15/month + From c56535cf047d1cfa6a69e7289923599b202167af Mon Sep 17 00:00:00 2001 From: Fabien O'Carroll Date: Fri, 23 May 2014 15:58:03 +0100 Subject: [PATCH 086/321] dont send feature list down to client --- views/upgrade.html | 1 - 1 file changed, 1 deletion(-) diff --git a/views/upgrade.html b/views/upgrade.html index 5cabf45f..e3e89e24 100644 --- a/views/upgrade.html +++ b/views/upgrade.html @@ -62,7 +62,6 @@ From 21a2bfa88a3d9ca6f31a1a5b8746b3662544f46b Mon Sep 17 00:00:00 2001 From: Fabien O'Carroll Date: Fri, 23 May 2014 15:58:28 +0100 Subject: [PATCH 087/321] render feature list server side --- views/upgrade.html | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/views/upgrade.html b/views/upgrade.html index e3e89e24..b3f63d20 100644 --- a/views/upgrade.html +++ b/views/upgrade.html @@ -40,6 +40,18 @@ + + {{#each featureList}} + + + {{name}} + + + + + + {{/each}} +

Your Pro accounts keep JS Bin 100% free for education

From 7cacaa73bb40f6bebb2c4ce34485d6cfe2eb4632 Mon Sep 17 00:00:00 2001 From: Fabien O'Carroll Date: Fri, 23 May 2014 15:58:49 +0100 Subject: [PATCH 088/321] style ticks with :after --- public/css/upgrade.css | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/public/css/upgrade.css b/public/css/upgrade.css index 3c7854a6..759d65ee 100644 --- a/public/css/upgrade.css +++ b/public/css/upgrade.css @@ -83,4 +83,14 @@ button.stripe-button-el:hover { th small { color: rgb(165, 164, 164); font-weight: normal; -} \ No newline at end of file +} + +tr.anon td.anon:after, tr.anon td.free:after, tr.anon td.pro:after { + content: "\2713"; +} +tr.free td.free:after, tr.free td.pro:after { + content: "\2713"; +} +tr.pro td.pro:after { + content: "\2713"; +} From 03e07e5eb539d618fb0a3e32c80eec80318e57be Mon Sep 17 00:00:00 2001 From: Fabien O'Carroll Date: Fri, 23 May 2014 15:59:28 +0100 Subject: [PATCH 089/321] remove client side feature rendering --- public/js/account/upgrade-page.js | 29 +---------------------------- 1 file changed, 1 insertion(+), 28 deletions(-) diff --git a/public/js/account/upgrade-page.js b/public/js/account/upgrade-page.js index 3fbd66e2..6a78c2ce 100644 --- a/public/js/account/upgrade-page.js +++ b/public/js/account/upgrade-page.js @@ -1,32 +1,5 @@ 'use strict'; -/* globals $, features */ - -var $table = $('table'); - -features.sort(function (a, b) { - return a.user - b.user; -}); - -features.forEach(function (feature) { - var $row = $(''); - $row.append( - $('').html(feature.name).addClass('feature') - ); - - for (var i = 0; i < 3; i++) { - var $td = $(''); - // use this if we reverse order of columns - if (i > feature.user - 1) { - //if ((2 - i) >= feature.user) { - $td.html('✔').addClass(); - } else { - $td.html(' ').addClass(); - } - $row.append($td); - } - - $table.append($row); -}); +/* globals $, backers */ var $backers = $('.backers'); From b5470846aa6463dc1b3079324b1c09b1fd97d47d Mon Sep 17 00:00:00 2001 From: Fabien O'Carroll Date: Fri, 23 May 2014 16:52:56 +0100 Subject: [PATCH 090/321] bring table inline with h1 --- public/css/upgrade.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/css/upgrade.css b/public/css/upgrade.css index 759d65ee..b2725958 100644 --- a/public/css/upgrade.css +++ b/public/css/upgrade.css @@ -19,7 +19,7 @@ table { border: 1; width: 80%; border-collapse: collapse; - margin: 0 auto; + margin: -45px auto 0; } tbody tr { From df7f4bff79b3c7fdbb6e29117563c5f4fd49ef9d Mon Sep 17 00:00:00 2001 From: Fabien O'Carroll Date: Fri, 23 May 2014 17:09:24 +0100 Subject: [PATCH 091/321] typo --- lib/data/features.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/data/features.json b/lib/data/features.json index 559f5308..a27eb2cb 100644 --- a/lib/data/features.json +++ b/lib/data/features.json @@ -16,7 +16,7 @@ "user": "pro" }, { - "name": "Asset hosting (Coming soon)", + "name": "Asset hosting (coming soon)", "user": "pro" }, { From ba326aeda18fb11927353bd7675d61fdfd08173a Mon Sep 17 00:00:00 2001 From: Fabien O'Carroll Date: Fri, 23 May 2014 17:12:04 +0100 Subject: [PATCH 092/321] Backers -> Supporters --- views/upgrade.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/views/upgrade.html b/views/upgrade.html index b3f63d20..84b7bc82 100644 --- a/views/upgrade.html +++ b/views/upgrade.html @@ -69,7 +69,7 @@ access to tech (like the version of JS Bin that works without a web connection and entirely from a usb stick with zero install).

-

Backers

+

Supporters

From 94fbbdaa5c220482e0b7f47e0bca8ec7fd14e018 Mon Sep 17 00:00:00 2001 From: Fabien O'Carroll Date: Fri, 23 May 2014 17:15:56 +0100 Subject: [PATCH 093/321] remove microsoft and google from backers --- lib/data/backers.json | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/lib/data/backers.json b/lib/data/backers.json index 766a89be..6379b51d 100644 --- a/lib/data/backers.json +++ b/lib/data/backers.json @@ -4,16 +4,6 @@ "name": "Librato", "url": "http://metrics.librato.com", "image": "http://data.bigdatastartups.netdna-cdn.com/wp-content/uploads/2013/08/Librato-logo.jpg" - }, - { - "name": "Google", - "url": "http://google.com", - "image": "https://www.google.co.uk/images/srpr/logo11w.png" - }, - { - "name": "Microsoft", - "url": "http://microsoft.com", - "image": "http://c.s-microsoft.com/en-us/CMSImages/mslogo.png?version=856673f8-e6be-0476-6669-d5bf2300391d" } ] } From 6cf8ae299bfec8987e048ddddb54a21165e7c2ce Mon Sep 17 00:00:00 2001 From: Fabien O'Carroll Date: Fri, 23 May 2014 17:16:10 +0100 Subject: [PATCH 094/321] center librato image --- public/css/upgrade.css | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/public/css/upgrade.css b/public/css/upgrade.css index b2725958..9b59bbbf 100644 --- a/public/css/upgrade.css +++ b/public/css/upgrade.css @@ -53,8 +53,7 @@ td.feature { } #body .backers .backer-img { width:200px; - margin:20px; - float:left; + margin:20px auto; border:none; } /* From 388ba0fe7b61f2e6498e21f3e3db406f9c1e0818 Mon Sep 17 00:00:00 2001 From: Fabien O'Carroll Date: Fri, 23 May 2014 17:25:03 +0100 Subject: [PATCH 095/321] cachebust resources --- views/upgrade.html | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/views/upgrade.html b/views/upgrade.html index 84b7bc82..3a351b7a 100644 --- a/views/upgrade.html +++ b/views/upgrade.html @@ -1,4 +1,4 @@ - +

Upgrade

@@ -72,8 +72,8 @@

Supporters

- + - + From 043e9c447ce1608ef15e7b80d52600b877148298 Mon Sep 17 00:00:00 2001 From: Fabien O'Carroll Date: Fri, 23 May 2014 17:26:19 +0100 Subject: [PATCH 096/321] add cachebust to view context --- lib/routes.js | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/routes.js b/lib/routes.js index 488f75d0..590cee02 100644 --- a/lib/routes.js +++ b/lib/routes.js @@ -177,6 +177,7 @@ module.exports = function (app) { referrer: referrer, featureList: featureList, backersList: backersList, + cachebust: app.set('is_production') ? '?' + app.set('version') : '', stripeKey: stripeKey }); From 80f990b993cd2447a1b0958ce19236b48a45bdb2 Mon Sep 17 00:00:00 2001 From: Remy Sharp Date: Tue, 27 May 2014 10:20:38 +0100 Subject: [PATCH 097/321] Fixed detatched console.logging --- public/js/runner/proxy-console.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/public/js/runner/proxy-console.js b/public/js/runner/proxy-console.js index 15bc8adb..8ec9cddc 100644 --- a/public/js/runner/proxy-console.js +++ b/public/js/runner/proxy-console.js @@ -13,7 +13,7 @@ var proxyConsole = (function () { /** * Stringify all of the console objects from an array for proxying */ - proxyConsole.prototype.stringifyArgs = function (args) { + var stringifyArgs = function (args) { var newArgs = []; // TODO this was forEach but when the array is [undefined] it wouldn't // iterate over them @@ -42,7 +42,7 @@ var proxyConsole = (function () { proxyConsole.prototype[method] = function () { // Replace args that can't be sent through postMessage var originalArgs = [].slice.call(arguments), - args = this.stringifyArgs(originalArgs); + args = stringifyArgs(originalArgs); // Post up with method and the arguments runner.postMessage('console', { From 018ac537bb20ee12915fb066789a5d939e227142 Mon Sep 17 00:00:00 2001 From: Remy Sharp Date: Tue, 27 May 2014 14:14:06 +0100 Subject: [PATCH 098/321] Account pages live for all --- lib/features.js | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/lib/features.js b/lib/features.js index 05289f2c..a5be24d1 100644 --- a/lib/features.js +++ b/lib/features.js @@ -92,9 +92,7 @@ var flags = { }, // seperate account management pages - accountPages: function (req) { - return alpha(req) || percentage(40, req); - }, + accountPages: true, // live 2014-05-27 // use SSL for sign in sslLogin: true, @@ -127,9 +125,7 @@ var flags = { return team(req); }, - fileMenuTest: function (req) { - return team(req) || percentage(50, req); - }, + fileMenuTest: true, // live 2014-05-27 - #1414 upgrade: function (req) { return team(req); // return !pro(req); From dcc017df1720d71cdf5470e43a99d75291f506dd Mon Sep 17 00:00:00 2001 From: Remy Sharp Date: Tue, 27 May 2014 14:14:40 +0100 Subject: [PATCH 099/321] 3.13.29 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 459aae60..726ce340 100644 --- a/package.json +++ b/package.json @@ -9,7 +9,7 @@ "name": "jsbin", "description": "Collaborative JavaScript Debugging App", "main": "./lib/app", - "version": "3.13.28", + "version": "3.13.29", "preferGlobal": "true", "homepage": "http://jsbin.com", "bin": "./bin/jsbin", From 13feaa905996557a6a11b486149c6375937f67a4 Mon Sep 17 00:00:00 2001 From: Giulia Alfonsi Date: Wed, 28 May 2014 11:33:44 +0100 Subject: [PATCH 100/321] Fixed the bug where flash messages where not showed anymore --- lib/app.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/app.js b/lib/app.js index 9a11b9cf..f6d72071 100644 --- a/lib/app.js +++ b/lib/app.js @@ -218,7 +218,7 @@ app.connect = function (callback) { app.emit('before:cookies', { app: app }); app.use(express.cookieParser(app.get('session secret') || generateSessionSecret())); - app.use(filteredCookieSession(['user.settings', 'passport', 'user.email', 'user.github_id', 'user.github_token', 'user.bincount', 'user.api_key', 'flashCache', ])); + app.use(filteredCookieSession(['user.settings', 'passport', 'user.email', 'user.github_id', 'user.github_token', 'user.bincount', 'user.api_key'])); app.use(express.cookieSession({ key: 'jsbin', cookie: { From 459c276b0f4128f77f9e4af285ec09d987b77c39 Mon Sep 17 00:00:00 2001 From: Giulia Alfonsi Date: Wed, 28 May 2014 11:34:14 +0100 Subject: [PATCH 101/321] Updated error message when github username conflicts with jsbin username --- lib/handlers/session.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/handlers/session.js b/lib/handlers/session.js index 49ac20df..c1824b81 100644 --- a/lib/handlers/session.js +++ b/lib/handlers/session.js @@ -523,7 +523,7 @@ module.exports = Observable.extend({ // Was a name matching user found if (jsbinUserFromGithubName) { // Uh oh, that user exists already - res.flash(res.flash.ERROR, 'Your GitHub username is already used in JS Bin. If this is you, please sign into JS Bin and "link your GitHub account" otherwise, register, then link your account.'); + res.flash(res.flash.ERROR, 'Your GitHub username is taken on JS Bin. If this is you, please register with JS Bin and link your GitHub account. Read this for more help.'); return res.redirect(redirect); } // No matching user was found, create an account! From fc04dec001af1b0413f38c209906f25080ddeeff Mon Sep 17 00:00:00 2001 From: Giulia Alfonsi Date: Wed, 28 May 2014 12:01:05 +0100 Subject: [PATCH 102/321] Added tips flash messages to account pages --- lib/routes.js | 12 ++++++ public/css/help.css | 96 +++++++++++++++++++++++++++++++++++++++++++ views/sub/layout.html | 12 +++++- 3 files changed, 119 insertions(+), 1 deletion(-) diff --git a/lib/routes.js b/lib/routes.js index 59d0c532..2fa43dbe 100644 --- a/lib/routes.js +++ b/lib/routes.js @@ -180,6 +180,16 @@ module.exports = function (app) { } } + var info = req.flash(req.flash.INFO), + error = req.flash(req.flash.ERROR), + notification = req.flash(req.flash.NOTIFICATION); + + var flash = error || notification || info; + var flashType = ''; + if (info) {flashType = 'info';} + if (notification) {flashType = 'notification';} + if (error) {flashType = 'error';} + if (!page) { return res.redirect('back'); } @@ -188,6 +198,8 @@ module.exports = function (app) { } res.render('account/' + page, { + flash_tip: flash, + flash_tip_type: flashType, token: req.session._csrf, layout: 'sub/layout.html', referrer: referrer, diff --git a/public/css/help.css b/public/css/help.css index f9b2a793..62437374 100644 --- a/public/css/help.css +++ b/public/css/help.css @@ -735,4 +735,100 @@ span.status { span.status.show { opacity: 1; +} + +/* Tip flash messages */ +/* Slightly changed from the one in style.css */ +#tip { + -webkit-user-select: none; + -khtml-user-select: none; + -moz-user-select: -moz-none; /* if this is "none" you can't copy text */ + -ms-user-select: none; + user-select: none; +} +#tip { + color: #000; + z-index: 100; + display: none; + border-top: 1px solid #ccc; + position: absolute; + bottom: 0; + font-size: 14px; + line-height: 22px; + background: #fdfece; + left: 0; + right: 0; + padding: 2px 10px 2px 10px; + -webkit-animation: tip-flash 100ms linear 4 alternate; + -moz-animation: tip-flash 100ms linear 4 alternate; + -ms-animation: tip-flash 100ms linear 4 alternate; + -o-animation: tip-flash 100ms linear 4 alternate; + animation: tip-flash 100ms linear 4 alternate; + + -webkit-transition: bottom 100ms linear; + transition: bottom 100ms linear; +} + +@-webkit-keyframes tip-flash { + to { + background: white; + } +} +@-moz-keyframes tip-flash { + to { + background: white; + } +} +@-ms-keyframes tip-flash { + to { + background: white; + } +} +@-o-keyframes tip-flash { + to { + background: white; + } +} +@keyframes tip-flash { + to { + background: white; + } +} + +#tip.error { + background: #FF4136; + color: #fff; +} + +.error a { + color: #fff; + text-shadow: none; +} + +#tip.notification, +#tip.error { + bottom: auto; + top: 60px; + line-height: 28px; + box-shadow: 0 2px 4px rgba(0,0,0,.2); +} + +#tip p { + margin: 5px 25px 5px 0; + padding: 0 65px 0 0; + line-height: 1.3; +} + +#tip a.dismiss { + line-height: 28px; + position: absolute; + right: 20px; + top: 2px; + text-decoration: none; + text-shadow: none; + color: inherit; +} + +.showtip #tip { + display: block; } \ No newline at end of file diff --git a/views/sub/layout.html b/views/sub/layout.html index f037bd4d..859c5f5c 100644 --- a/views/sub/layout.html +++ b/views/sub/layout.html @@ -1,5 +1,5 @@ - + Account Management @@ -27,6 +27,12 @@ +
+

+ {{#if flash_tip}}{{{flash_tip}}}{{/if}} +

+ Dismiss x +
{{{body}}}
@@ -52,6 +58,10 @@ + + From 6aa967b929453c10e4de9539dfa1dba5b07bfa11 Mon Sep 17 00:00:00 2001 From: Keith Cirkel Date: Thu, 29 May 2014 11:32:28 +0100 Subject: [PATCH 103/321] Update Polymer 0.2.4 -> 0.3.0 --- public/js/editors/libraries.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/public/js/editors/libraries.js b/public/js/editors/libraries.js index 5698373a..6c1be0eb 100644 --- a/public/js/editors/libraries.js +++ b/public/js/editors/libraries.js @@ -450,8 +450,8 @@ var libraries = [ }, { 'url': [ - '//cdnjs.cloudflare.com/ajax/libs/polymer/0.2.4/platform.js', - '//cdnjs.cloudflare.com/ajax/libs/polymer/0.2.4/polymer.js' + '//cdnjs.cloudflare.com/ajax/libs/polymer/0.3.0/platform.js', + '//cdnjs.cloudflare.com/ajax/libs/polymer/0.3.0/polymer.js' ], 'label': 'Polymer 0.2.3' }, From 45dafd31eba09ecdaad0f90112b151084a29bc7c Mon Sep 17 00:00:00 2001 From: Giulia Alfonsi Date: Thu, 29 May 2014 13:33:08 +0100 Subject: [PATCH 104/321] Some layout --- public/css/style.css | 18 ++++++++++++++ views/partials/top-panel.html | 44 ++++++++++++++++++++++++++++++++++- 2 files changed, 61 insertions(+), 1 deletion(-) diff --git a/public/css/style.css b/public/css/style.css index 43b22158..c6b23c46 100644 --- a/public/css/style.css +++ b/public/css/style.css @@ -4742,3 +4742,21 @@ html * { body.ready.toppanel { background: white; } + +/* top panel */ +.toppanel-wrapper { + +} +.toppanel-title { + font-size: inherit; +} +.toppanel-list { + list-style: none; + margin: 0; + padding: 0; +} +.toppanel-wrapper a { + color: #007FFF; + display: block; + text-decoration: none; +} diff --git a/views/partials/top-panel.html b/views/partials/top-panel.html index 0c77f129..279ac413 100644 --- a/views/partials/top-panel.html +++ b/views/partials/top-panel.html @@ -1,5 +1,47 @@ -
+ {{/if}} +{{#feature request "topPanel"}} + +{{/feature}} diff --git a/views/partials/top-panel.html b/views/partials/top-panel.html index 279ac413..2fb2893e 100644 --- a/views/partials/top-panel.html +++ b/views/partials/top-panel.html @@ -1,12 +1,15 @@
- +
@@ -40,7 +43,35 @@
- + +
+

Help

+ +
+ +
+ +
+
+
“Everyone should learn how to program a computer because it teaches you how to think” — Steve Jobs
+
+
\ No newline at end of file From 6d8a201a159ad5f85d63c78407e7fe6ec7577ba2 Mon Sep 17 00:00:00 2001 From: Giulia Alfonsi Date: Wed, 4 Jun 2014 08:53:37 +0100 Subject: [PATCH 145/321] Cleaned code --- public/js/account/preferences-settings.js | 1 - public/js/chrome/errors.js | 3 +++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/public/js/account/preferences-settings.js b/public/js/account/preferences-settings.js index ffeabf81..43067667 100644 --- a/public/js/account/preferences-settings.js +++ b/public/js/account/preferences-settings.js @@ -115,7 +115,6 @@ try { localStorageSettings[ hints[m] + 'hintOptions' ] = JSON.parse($hintsOptions[ hints[m] ].val() || '{}'); } catch (e) { - // console.log('no no no... ' + e); $hintsOptError[ hints[m] ].html(e).addClass('show'); } } diff --git a/public/js/chrome/errors.js b/public/js/chrome/errors.js index a7cb8e0e..251724c1 100644 --- a/public/js/chrome/errors.js +++ b/public/js/chrome/errors.js @@ -2,9 +2,12 @@ var jshint = function () { var source = editors.javascript.editor.getCode(); + + // default jshint options var options = { 'eqnull': true }; + $.extend(options, jsbin.settings.jshintOptions || {}); var ok = JSHINT(source, options); From 3636c6df604451bed8efb0feca79c9a0abc5d37d Mon Sep 17 00:00:00 2001 From: electricg Date: Wed, 4 Jun 2014 15:42:50 +0100 Subject: [PATCH 146/321] Changed esc action --- public/js/chrome/esc.js | 2 -- public/js/chrome/toppanel.js | 8 ++++++++ 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/public/js/chrome/esc.js b/public/js/chrome/esc.js index 4d1fd80e..fb6c4d34 100644 --- a/public/js/chrome/esc.js +++ b/public/js/chrome/esc.js @@ -26,8 +26,6 @@ function hideOpen() { $('#login').hide(); analytics.closeMenu('login'); loginVisible = false; - } else if ($body.hasClass('toppanel')) { - $body.removeClass('toppanel'); } } diff --git a/public/js/chrome/toppanel.js b/public/js/chrome/toppanel.js index 7a6f7d53..92d35e1b 100644 --- a/public/js/chrome/toppanel.js +++ b/public/js/chrome/toppanel.js @@ -38,5 +38,13 @@ jsbin.settings.gui.toppanel = true; showToppanel(); }); + $document.keydown(function (event) { + if (event.which == 27) { + if ($body.hasClass('toppanel')) { + jsbin.settings.gui.toppanel = false; + removeToppanel(); + } + } + }); }()); \ No newline at end of file From f54140ec4ebaa3aa11e9353f1f0fbc4c2fa827ec Mon Sep 17 00:00:00 2001 From: electricg Date: Wed, 4 Jun 2014 19:27:08 +0100 Subject: [PATCH 147/321] Columns --- public/css/style.css | 28 ++++++++++++++++++++++++++-- views/partials/top-panel.html | 2 +- 2 files changed, 27 insertions(+), 3 deletions(-) diff --git a/public/css/style.css b/public/css/style.css index 09a5f87a..04b84249 100644 --- a/public/css/style.css +++ b/public/css/style.css @@ -4770,6 +4770,7 @@ body.ready.toppanel { .toppanel-wrapper { color: #232323; font-size: 0; + white-space: nowrap; padding: 13px; -webkit-box-sizing: border-box; -moz-box-sizing: border-box; @@ -4781,10 +4782,33 @@ body.ready.toppanel { padding: 0 4px; vertical-align: top; width: 20%; + min-width: 196px; + max-width: 250px; + white-space: normal; + height: 220px; + overflow: hidden; -webkit-box-sizing: border-box; -moz-box-sizing: border-box; box-sizing: border-box; } +.toppanel-column-first { + overflow: visible; +} +@media (max-width: 590px) { + .toppanel-column:nth-child(n+3) { + visibility: hidden; + } +} +@media (max-width: 789px) { + .toppanel-column:nth-child(n+4) { + visibility: hidden; + } +} +@media (max-width: 990px) { + .toppanel-column:nth-child(n+5) { + visibility: hidden; + } +} .toppanel-section + .toppanel-section { margin-top: 13px; } @@ -4866,8 +4890,8 @@ body.ready.toppanel { } a.toppanel-hide { position: absolute; - left: 3%; - top: 5%; + left: 20px; + top: 15px; padding: 0 5px 7px; font-size: 35px; line-height: 0.7; diff --git a/views/partials/top-panel.html b/views/partials/top-panel.html index 630f794a..bc3fdaf3 100644 --- a/views/partials/top-panel.html +++ b/views/partials/top-panel.html @@ -1,5 +1,5 @@
-
+
×
×
From 2b3aab0c49fde1cec1d2e3b7756286e06eefee86 Mon Sep 17 00:00:00 2001 From: electricg Date: Thu, 5 Jun 2014 07:07:37 +0100 Subject: [PATCH 149/321] Animation --- public/css/style.css | 30 ++++++++++++++++-------------- public/js/chrome/toppanel.js | 2 +- views/partials/top-panel.html | 5 ++--- 3 files changed, 19 insertions(+), 18 deletions(-) diff --git a/public/css/style.css b/public/css/style.css index 04b84249..27cace61 100644 --- a/public/css/style.css +++ b/public/css/style.css @@ -4906,8 +4906,10 @@ a.toppanel-logo { text-align: center; position: relative; z-index: 1; - -webkit-transform: translate(-55px, 198px) scale(0.25); - transform: translate(-55px, 198px) scale(0.25); + -webkit-transform: translate(-95px, 155px) scale(0.25); + transform: translate(-95px, 155px) scale(0.25); + -webkit-transform-origin: 100% 100%; + transform-origin: 100% 100%; } a.toppanel-logo:hover { /*background: rgba(0, 0, 0, 0.04); @@ -4930,22 +4932,22 @@ a.toppanel-logo:hover { /* toppanel animation */ #bin { - -webkit-transition: top ease-in-out 300ms; - -moz-transition: top ease-in-out 300ms; - -o-transition: top ease-in-out 300ms; - transition: top ease-in-out 300ms; + -webkit-transition: top ease-in-out 100ms; + -moz-transition: top ease-in-out 100ms; + -o-transition: top ease-in-out 100ms; + transition: top ease-in-out 100ms; } #toppanel { - -webkit-transition: margin-top ease-in-out 300ms; - -moz-transition: margin-top ease-in-out 300ms; - -o-transition: margin-top ease-in-out 300ms; - transition: margin-top ease-in-out 300ms; + -webkit-transition: margin-top ease-in-out 100ms; + -moz-transition: margin-top ease-in-out 100ms; + -o-transition: margin-top ease-in-out 100ms; + transition: margin-top ease-in-out 100ms; } a.toppanel-logo { - -webkit-transition: -webkit-transform linear 300ms; - -moz-transition: transform linear 300ms; - -o-transition: transform linear 300ms; - transition: transform linear 300ms; + -webkit-transition: -webkit-transform linear 120ms 120ms; + -moz-transition: transform linear 120ms 120ms; + -o-transition: transform linear 120ms 120ms; + transition: transform linear 120ms 120ms; } .toppanel-slow #bin, diff --git a/public/js/chrome/toppanel.js b/public/js/chrome/toppanel.js index 92d35e1b..cfe77e2a 100644 --- a/public/js/chrome/toppanel.js +++ b/public/js/chrome/toppanel.js @@ -9,7 +9,7 @@ jsbin.settings.gui.toppanel = true; } - $body.toggleClass('toppanel', jsbin.settings.gui.toppanel); + // $body.toggleClass('toppanel', jsbin.settings.gui.toppanel); var removeToppanel = function() { $body.removeClass('toppanel'); diff --git a/views/partials/top-panel.html b/views/partials/top-panel.html index 1bf6143d..0dbdef92 100644 --- a/views/partials/top-panel.html +++ b/views/partials/top-panel.html @@ -73,12 +73,11 @@
\ No newline at end of file From 35dcde620c5bc57a2cb98b6d3415ca9f00b54794 Mon Sep 17 00:00:00 2001 From: Remy Sharp Date: Thu, 5 Jun 2014 08:47:43 +0100 Subject: [PATCH 150/321] Update full-db-v3.mysql.sql --- build/full-db-v3.mysql.sql | 80 +++++++++++++++++++++++++++++--------- 1 file changed, 62 insertions(+), 18 deletions(-) diff --git a/build/full-db-v3.mysql.sql b/build/full-db-v3.mysql.sql index d52b6e3f..9ab7ca49 100644 --- a/build/full-db-v3.mysql.sql +++ b/build/full-db-v3.mysql.sql @@ -1,8 +1,8 @@ --- MySQL dump 10.13 Distrib 5.5.9, for osx10.6 (i386) +-- MySQL dump 10.13 Distrib 5.5.29, for debian-linux-gnu (x86_64) -- -- Host: localhost Database: jsbin -- ------------------------------------------------------ --- Server version 5.5.9 +-- Server version 5.5.29-0ubuntu0.12.04.1 /*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; /*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; @@ -15,11 +15,31 @@ /*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; /*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; +-- +-- Table structure for table `customers` +-- + +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `customers` ( + `stripe_id` char(255) NOT NULL, + `id` int(11) NOT NULL AUTO_INCREMENT, + `user_id` int(11) DEFAULT NULL, + `name` char(255) NOT NULL, + `expiry` datetime DEFAULT NULL, + `active` tinyint(1) DEFAULT '1', + PRIMARY KEY (`id`), + KEY `stripe_id` (`stripe_id`), + KEY `name` (`name`), + KEY `user_id` (`user_id`), + KEY `expired` (`expiry`,`active`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + -- -- Table structure for table `forgot_tokens` -- -DROP TABLE IF EXISTS `forgot_tokens`; /*!40101 SET @saved_cs_client = @@character_set_client */; /*!40101 SET character_set_client = utf8 */; CREATE TABLE `forgot_tokens` ( @@ -32,16 +52,34 @@ CREATE TABLE `forgot_tokens` ( ) ENGINE=MyISAM DEFAULT CHARSET=utf8; /*!40101 SET character_set_client = @saved_cs_client */; +-- +-- Table structure for table `owner_bookmarks` +-- + +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `owner_bookmarks` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `name` char(255) NOT NULL, + `url` char(255) NOT NULL, + `revision` int(11) NOT NULL, + `type` char(50) NOT NULL, + `created` datetime NOT NULL, + PRIMARY KEY (`id`), + KEY `name` (`name`,`type`,`created`), + KEY `revision` (`url`(191),`revision`) +) ENGINE=InnoDB CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + -- -- Table structure for table `owners` -- -DROP TABLE IF EXISTS `owners`; /*!40101 SET @saved_cs_client = @@character_set_client */; /*!40101 SET character_set_client = utf8 */; CREATE TABLE `owners` ( `id` int(11) NOT NULL AUTO_INCREMENT, - `name` char(255) NOT NULL, + `name` char(75) NOT NULL, `url` char(255) NOT NULL, `revision` int(11) DEFAULT '1', `last_updated` datetime NOT NULL, @@ -50,41 +88,47 @@ CREATE TABLE `owners` ( `css` tinyint(1) NOT NULL DEFAULT '0', `javascript` tinyint(1) NOT NULL DEFAULT '0', `archive` tinyint(1) NOT NULL DEFAULT '0', - `visibility` ENUM('public', 'unlisted', 'private') DEFAULT 'public' NOT NULL, + `visibility` enum('public','unlisted','private') NOT NULL DEFAULT 'public', PRIMARY KEY (`id`), KEY `name_url` (`name`,`url`,`revision`), - KEY `last_updated` (`name`,`last_updated`) -) ENGINE=InnoDB AUTO_INCREMENT=289 DEFAULT CHARSET=utf8; + KEY `last_updated` (`name`,`last_updated`), + KEY `url` (`url`,`revision`) +) ENGINE=InnoDB CHARSET=utf8; /*!40101 SET character_set_client = @saved_cs_client */; -- -- Table structure for table `ownership` -- -DROP TABLE IF EXISTS `ownership`; /*!40101 SET @saved_cs_client = @@character_set_client */; /*!40101 SET character_set_client = utf8 */; CREATE TABLE `ownership` ( - `name` char(255) NOT NULL, + `name` char(75) NOT NULL, `key` char(255) NOT NULL, `email` varchar(255) NOT NULL DEFAULT '', - `api_key` VARCHAR(255) NULL, - `github_token` VARCHAR(255), - `github_id` int(11), `last_login` datetime NOT NULL, `created` datetime NOT NULL, `updated` datetime NOT NULL, - PRIMARY KEY (`name`), + `api_key` varchar(255) DEFAULT NULL, + `github_token` varchar(255) DEFAULT NULL, + `github_id` int(11) DEFAULT NULL, + `verified` tinyint(1) NOT NULL DEFAULT '0', + `pro` tinyint(1) NOT NULL DEFAULT '0', + `id` int(11) NOT NULL AUTO_INCREMENT, + `settings` text, + `dropbox_token` varchar(255) DEFAULT NULL, + PRIMARY KEY (`id`), + UNIQUE KEY `name` (`name`), KEY `name_key` (`name`,`key`), + KEY `created` (`created`), KEY `ownership_api_key` (`api_key`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8; +) ENGINE=InnoDB CHARSET=utf8; /*!40101 SET character_set_client = @saved_cs_client */; -- -- Table structure for table `sandbox` -- -DROP TABLE IF EXISTS `sandbox`; /*!40101 SET @saved_cs_client = @@character_set_client */; /*!40101 SET character_set_client = utf8 */; CREATE TABLE `sandbox` ( @@ -110,7 +154,7 @@ CREATE TABLE `sandbox` ( KEY `streaming_key` (`streaming_key`), KEY `spam` (`created`,`last_viewed`), KEY `revision` (`url`(191),`revision`) -) ENGINE=InnoDB AUTO_INCREMENT=1585463 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; +) ENGINE=InnoDB CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; /*!40101 SET character_set_client = @saved_cs_client */; /*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */; @@ -122,4 +166,4 @@ CREATE TABLE `sandbox` ( /*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; /*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; --- Dump completed on 2013-01-11 9:26:38 \ No newline at end of file +-- Dump completed on 2014-06-05 7:45:41 From 39772d57dd6181c0296703f27d0409f53904c96f Mon Sep 17 00:00:00 2001 From: Remy Sharp Date: Thu, 5 Jun 2014 09:23:43 +0100 Subject: [PATCH 151/321] Refactored blacklist code. Blacklisting now live. Rather than only applied on save. --- lib/blacklist.js | 25 +++++++++++++------------ lib/models/bin.js | 6 ++++++ 2 files changed, 19 insertions(+), 12 deletions(-) diff --git a/lib/blacklist.js b/lib/blacklist.js index 2f8c26b9..a401967b 100644 --- a/lib/blacklist.js +++ b/lib/blacklist.js @@ -1,19 +1,20 @@ +'use strict'; var blacklist = require('./config').blacklist || {}; module.exports.validate = function (bin) { - var type, keywords, content, index, length; + var okay = true; - for (type in blacklist) { - if (blacklist.hasOwnProperty(type)) { - content = bin[type] || ''; - keywords = blacklist[type] || []; + Object.keys(blacklist).forEach(function (type) { + var content = bin[type] || ''; + var keywords = blacklist[type] || []; - for (index = 0, length = keywords.length; index < length; index += 1) { - if (content.indexOf(keywords[index]) > -1) { - return false; - } - } + if (okay) { // then keep checking + okay = keywords.filter(function (keyword) { + // return if found + return content.indexOf(keyword) !== -1; + }).length === 0; } - } - return true; + }); + + return okay; }; diff --git a/lib/models/bin.js b/lib/models/bin.js index d2f463ea..e9dc26f0 100644 --- a/lib/models/bin.js +++ b/lib/models/bin.js @@ -6,6 +6,7 @@ var Observable = require('../utils').Observable, crypto = require('crypto'), dropbox = require('../dropbox'), processors = require('../processors'), + blacklist = require('../blacklist'), readFileSync = require('fs').readFileSync, compileTemplate = require('handlebars').compile, binFileTemplate = compileTemplate(readFileSync(__dirname + '/../dropbox/bin-template.hbs').toString()), @@ -24,6 +25,11 @@ var model = { return fn(err); } + // this syntax sucks hard...but none the less + if (blacklist.validate(bin) === false) { + return fn(418); + } + this.getBinMetadata(bin, function loadBinMetadata(err, metadata) { if (err) { return fn(err); From d0694d95e1cd6fcd966794cddf4ba8f43bda7d0c Mon Sep 17 00:00:00 2001 From: Remy Sharp Date: Thu, 5 Jun 2014 09:28:35 +0100 Subject: [PATCH 152/321] 3.13.33 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 9b04f2fc..f0eecfb5 100644 --- a/package.json +++ b/package.json @@ -9,7 +9,7 @@ "name": "jsbin", "description": "Collaborative JavaScript Debugging App", "main": "./lib/app", - "version": "3.13.32", + "version": "3.13.33", "preferGlobal": "true", "homepage": "http://jsbin.com", "bin": "./bin/jsbin", From f0ad317b879d7aef15fc25749394ad90064a4d33 Mon Sep 17 00:00:00 2001 From: Giulia Alfonsi Date: Thu, 5 Jun 2014 11:23:07 +0100 Subject: [PATCH 153/321] Hiding top panel until css kicks in --- public/css/style.css | 1 + views/partials/top-panel.html | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/public/css/style.css b/public/css/style.css index 27cace61..7deb8fdb 100644 --- a/public/css/style.css +++ b/public/css/style.css @@ -4768,6 +4768,7 @@ body.ready.toppanel { /* top panel */ .toppanel-wrapper { + display: block !important; color: #232323; font-size: 0; white-space: nowrap; diff --git a/views/partials/top-panel.html b/views/partials/top-panel.html index 0dbdef92..4ac9d1b7 100644 --- a/views/partials/top-panel.html +++ b/views/partials/top-panel.html @@ -1,4 +1,4 @@ -
+ From fe5c50ed160db2f1aa2161109feda3bac3a9d5a9 Mon Sep 17 00:00:00 2001 From: Fabien O'Carroll Date: Mon, 9 Jun 2014 12:03:00 +0100 Subject: [PATCH 177/321] fix merge and use array as top level data structure --- lib/data/backers.json | 29 +++++++---------------------- 1 file changed, 7 insertions(+), 22 deletions(-) diff --git a/lib/data/backers.json b/lib/data/backers.json index 3caefd8c..f078bc7f 100644 --- a/lib/data/backers.json +++ b/lib/data/backers.json @@ -1,22 +1,7 @@ -{ - "backers": [ - { - "name": "Librato", - "url": "http://metrics.librato.com", - "image": "http://data.bigdatastartups.netdna-cdn.com/wp-content/uploads/2013/08/Librato-logo.jpg" -<<<<<<< HEAD - }, - { - "name": "Google", - "url": "http://google.com", - "image": "https://www.google.co.uk/images/srpr/logo11w.png" - }, - { - "name": "Microsoft", - "url": "http://microsoft.com", - "image": "http://c.s-microsoft.com/en-us/CMSImages/mslogo.png?version=856673f8-e6be-0476-6669-d5bf2300391d" -======= ->>>>>>> 043e9c447ce1608ef15e7b80d52600b877148298 - } - ] -} +[ + { + "name": "Librato", + "url": "http://metrics.librato.com", + "image": "http://data.bigdatastartups.netdna-cdn.com/wp-content/uploads/2013/08/Librato-logo.jpg" + } +] From a60887963b402edf3b5a6afebb03eb2599ee17e0 Mon Sep 17 00:00:00 2001 From: Fabien O'Carroll Date: Mon, 9 Jun 2014 12:05:07 +0100 Subject: [PATCH 178/321] safely get the stripekey --- lib/routes.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/routes.js b/lib/routes.js index 590cee02..6b2d5287 100644 --- a/lib/routes.js +++ b/lib/routes.js @@ -8,6 +8,7 @@ var express = require('express'), features = require('./features'), metrics = require('./metrics'), scripts = require('../scripts.json'), + undefsafe = require('undefsafe'), Promise = require('rsvp').Promise, config = require('./config'); reBin = null; // created when the module is imported @@ -168,7 +169,7 @@ module.exports = function (app) { var root = sandbox.helpers.url('', true, req.secure); var static = sandbox.helpers.urlForStatic('', req.secure); var referrer = req.get('referer'); - var stripeKey = config.payment.stripe.public; + var stripeKey = undefsafe(config, 'payment.stripe.public'); res.render('upgrade', { layout: 'sub/layout', From 72b129635be0400708f00fa6bfb81f1339e10eb1 Mon Sep 17 00:00:00 2001 From: Fabien O'Carroll Date: Mon, 9 Jun 2014 12:05:27 +0100 Subject: [PATCH 179/321] send object to template rather than string --- lib/routes.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/routes.js b/lib/routes.js index 6b2d5287..663d9bbf 100644 --- a/lib/routes.js +++ b/lib/routes.js @@ -165,7 +165,7 @@ module.exports = function (app) { app.get('/upgrade', features.route('stripe'), function (req, res) { var featureList = require('./data/features.json'); - var backersList = JSON.stringify(require('./data/backers.json').backers); + var backersList = require('./data/backers.json'); var root = sandbox.helpers.url('', true, req.secure); var static = sandbox.helpers.urlForStatic('', req.secure); var referrer = req.get('referer'); From 7c50a81a369c8917f92096adb600070baf693c55 Mon Sep 17 00:00:00 2001 From: Fabien O'Carroll Date: Mon, 9 Jun 2014 12:31:01 +0100 Subject: [PATCH 180/321] add upgrade feature currently defaults to teamjsbin --- lib/features.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/features.js b/lib/features.js index a673b6c5..dfb16d90 100644 --- a/lib/features.js +++ b/lib/features.js @@ -83,6 +83,8 @@ var flags = { return alpha(req); }, + upgrade: team, + // use SSL for sign in sslLogin: true, From bc4b4303badecba7c0335d460b71fcd4f9fabd5c Mon Sep 17 00:00:00 2001 From: Fabien O'Carroll Date: Mon, 9 Jun 2014 12:31:21 +0100 Subject: [PATCH 181/321] put the upgrade button behind upgrade feature flag --- views/partials/account_sidebar.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/views/partials/account_sidebar.html b/views/partials/account_sidebar.html index 0e10a4bf..b09025b5 100644 --- a/views/partials/account_sidebar.html +++ b/views/partials/account_sidebar.html @@ -6,9 +6,9 @@ Preferences
- {{#unless user.pro}} + {{#feature upgrade}} Upgrade - {{/unless}} + {{/feature}}
\ No newline at end of file From 5a8ebb20c4929dcfc69656a8962da25ed8578dad Mon Sep 17 00:00:00 2001 From: Giulia Alfonsi Date: Wed, 11 Jun 2014 17:02:59 +0100 Subject: [PATCH 187/321] Fixed missing css for Firefox --- views/upgrade.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/views/upgrade.html b/views/upgrade.html index 6648fab9..1370eb54 100644 --- a/views/upgrade.html +++ b/views/upgrade.html @@ -1,4 +1,4 @@ - +

Upgrade

From 321256c4c0bf7ff06feb9549a4ebd7bfe8c7d8c6 Mon Sep 17 00:00:00 2001 From: Giulia Alfonsi Date: Wed, 11 Jun 2014 17:03:46 +0100 Subject: [PATCH 188/321] Fixed nav header for all browsers --- public/css/help.css | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/public/css/help.css b/public/css/help.css index 62437374..a8034953 100644 --- a/public/css/help.css +++ b/public/css/help.css @@ -200,13 +200,14 @@ header nav a { header nav a.selected:before { position: absolute; - top: 42px; + top: 45px; /* 42px */ left: 35%; /* border-left: solid 1px #ccc; */ /* border-top: solid 1px #ccc; */ width: 1.1em; height: 1.1em; -webkit-transform: rotate(45deg); + transform: rotate(45deg); background: #fff; content: ''; } @@ -253,6 +254,8 @@ article p { nav { float: right; + width: 50%; + text-align: right; } .button.action { From 73e5d794cc7e5e0bd949917c33ae6c29d095925f Mon Sep 17 00:00:00 2001 From: Giulia Alfonsi Date: Wed, 11 Jun 2014 17:04:25 +0100 Subject: [PATCH 189/321] Fixed content of feature table to be in html not css --- lib/hbs.js | 11 +++++++++++ public/css/upgrade.css | 4 ++-- views/upgrade.html | 15 ++++++++++++--- 3 files changed, 25 insertions(+), 5 deletions(-) diff --git a/lib/hbs.js b/lib/hbs.js index 77d7a498..9252e8f4 100644 --- a/lib/hbs.js +++ b/lib/hbs.js @@ -13,6 +13,17 @@ hbs.registerHelper('feature', function(request, flag, options) { } }); +hbs.registerHelper('equal', function(lvalue, rvalue, options) { + if (arguments.length < 3) { + return false; + } + if (lvalue !== rvalue) { + return options.inverse(this); + } else { + return options.fn(this); + } +}); + hbs.registerHelper('dump', function(obj) { return JSON.stringify(obj, null, 2); }); diff --git a/public/css/upgrade.css b/public/css/upgrade.css index 9b59bbbf..bbfecdd3 100644 --- a/public/css/upgrade.css +++ b/public/css/upgrade.css @@ -84,7 +84,7 @@ th small { font-weight: normal; } -tr.anon td.anon:after, tr.anon td.free:after, tr.anon td.pro:after { +/*tr.anon td.anon:after, tr.anon td.free:after, tr.anon td.pro:after { content: "\2713"; } tr.free td.free:after, tr.free td.pro:after { @@ -92,4 +92,4 @@ tr.free td.free:after, tr.free td.pro:after { } tr.pro td.pro:after { content: "\2713"; -} +}*/ diff --git a/views/upgrade.html b/views/upgrade.html index 1370eb54..efca412c 100644 --- a/views/upgrade.html +++ b/views/upgrade.html @@ -46,9 +46,18 @@ - - - + + + {{/each}} From 32db74028c48f10d2fe2e359e131e67062d32fbd Mon Sep 17 00:00:00 2001 From: Remy Sharp Date: Thu, 12 Jun 2014 10:19:24 +0100 Subject: [PATCH 190/321] Fixed new user seeing welcome panel --- lib/features.js | 4 +++- views/partials/top-panel.html | 4 ++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/lib/features.js b/lib/features.js index 672e14ac..816acda1 100644 --- a/lib/features.js +++ b/lib/features.js @@ -48,7 +48,7 @@ function team(req) { } function pro(req) { - return flags.alpha(req) || undefsafe(req, 'session.user.pro'); + return undefsafe(req, 'session.user.pro'); } /* End: user types */ @@ -69,6 +69,8 @@ var flags = { /* Begin: actual features */ admin: team, + pro: pro, + github: function () { return options.github && options.github.id; }, diff --git a/views/partials/top-panel.html b/views/partials/top-panel.html index f769281b..a514c2a6 100644 --- a/views/partials/top-panel.html +++ b/views/partials/top-panel.html @@ -108,10 +108,10 @@ \ No newline at end of file From 27f2bdad3c1c85a7db36903a60463ce171d9bd82 Mon Sep 17 00:00:00 2001 From: Giulia Alfonsi Date: Thu, 12 Jun 2014 12:48:49 +0100 Subject: [PATCH 191/321] Renamed files --- lib/features.js | 2 +- lib/hbs.js | 2 +- public/js/chrome/{toppanel.js => welcome-panel.js} | 0 views/index.html | 8 ++++---- views/partials/{top-panel.html => welcome-panel.html} | 0 5 files changed, 6 insertions(+), 6 deletions(-) rename public/js/chrome/{toppanel.js => welcome-panel.js} (100%) rename views/partials/{top-panel.html => welcome-panel.html} (100%) diff --git a/lib/features.js b/lib/features.js index 816acda1..97db9fc3 100644 --- a/lib/features.js +++ b/lib/features.js @@ -134,7 +134,7 @@ var flags = { }, // top introduction view with help and features of JS Bin - topPanel: function (req) { + welcomePanel: function (req) { return team(req); }, }; diff --git a/lib/hbs.js b/lib/hbs.js index 52b3c11b..0ccac9d8 100644 --- a/lib/hbs.js +++ b/lib/hbs.js @@ -17,6 +17,6 @@ hbs.registerHelper('dump', function(obj) { return JSON.stringify(obj, null, 2); }); -hbs.registerPartial('top_panel', __dirname + '/../views/partials/top-panel.html'); +hbs.registerPartial('welcome_panel', __dirname + '/../views/partials/welcome-panel.html'); module.exports = hbs; \ No newline at end of file diff --git a/public/js/chrome/toppanel.js b/public/js/chrome/welcome-panel.js similarity index 100% rename from public/js/chrome/toppanel.js rename to public/js/chrome/welcome-panel.js diff --git a/views/index.html b/views/index.html index 237878ab..729779a1 100644 --- a/views/index.html +++ b/views/index.html @@ -16,8 +16,8 @@ -{{#feature request "topPanel"}} - {{> top_panel}} +{{#feature request "welcomePanel"}} + {{> welcome_panel}} {{/feature}}
@@ -578,8 +578,8 @@ Include alerts, prompts & confirm boxes">Run with JS {{/if}} -{{#feature request "topPanel"}} - +{{#feature request "welcomePanel"}} + {{/feature}} diff --git a/views/partials/top-panel.html b/views/partials/welcome-panel.html similarity index 100% rename from views/partials/top-panel.html rename to views/partials/welcome-panel.html From 2e6f8985d84d2729be5d3cc7ebf8d0e74030bd20 Mon Sep 17 00:00:00 2001 From: Giulia Alfonsi Date: Thu, 12 Jun 2014 12:50:01 +0100 Subject: [PATCH 192/321] Remove return statement when there is no user on the cookie This is so we can check if they are logged in on the "way out" and update memcached accordingly --- lib/addons/memcached/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/addons/memcached/index.js b/lib/addons/memcached/index.js index 86a75d3a..a529b00e 100644 --- a/lib/addons/memcached/index.js +++ b/lib/addons/memcached/index.js @@ -75,7 +75,7 @@ module.exports = function(app, connection) { next(); }); } else { - return next(); + next(); } // We're basically yaking the same idea that connects cookieSessions use From b1d0994554ec646b5bc23f20ec9e9211ece88a7c Mon Sep 17 00:00:00 2001 From: Giulia Alfonsi Date: Thu, 12 Jun 2014 12:50:57 +0100 Subject: [PATCH 193/321] Check for req._userJSONCopy as well as oldSessionUser This is because when logging in, the oldSessionUSer will exist but the userJSONCopy not, this is how we can tell if this request is a login. --- lib/addons/memcached/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/addons/memcached/index.js b/lib/addons/memcached/index.js index a529b00e..08bdb475 100644 --- a/lib/addons/memcached/index.js +++ b/lib/addons/memcached/index.js @@ -82,7 +82,7 @@ module.exports = function(app, connection) { // from here: http://www.senchalabs.org/connect/cookieSession.html res.on('header', function () { var oldSessionUser = undefsafe(req, '_sessionBeforeBlacklist.user'); - if (oldSessionUser) { + if (oldSessionUser && req._userJSONCopy) { // FIXME - this is hacky if (JSON.stringify(oldSessionUser) !== req._userJSONCopy) { memcached.set(oldSessionUser.name, oldSessionUser); From 038a121daa8637d97f9a65f290db24996d54ec89 Mon Sep 17 00:00:00 2001 From: Giulia Alfonsi Date: Thu, 12 Jun 2014 12:53:11 +0100 Subject: [PATCH 194/321] Check for lack of original username and presence of a user objetc on the session We use the sessionBeforeBlack list to avoid missing values from our blacklisted cookies which happen high in the stack. If there was no original username, and there is a req.session.user now, we know that the user has just logged in, so we set them to memcached, knowing that the data just came from mysql --- lib/addons/memcached/index.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/lib/addons/memcached/index.js b/lib/addons/memcached/index.js index 08bdb475..6a9c97bf 100644 --- a/lib/addons/memcached/index.js +++ b/lib/addons/memcached/index.js @@ -87,6 +87,12 @@ module.exports = function(app, connection) { if (JSON.stringify(oldSessionUser) !== req._userJSONCopy) { memcached.set(oldSessionUser.name, oldSessionUser); } + } else + if (!username) { + var user = undefsafe(req, '_sessionBeforeBlacklist.user'); + if (user) { + memcached.set(user.name, user); + } } }); }); From c02dfff5d20c3c87803f8c795a1f817bdf0f91da Mon Sep 17 00:00:00 2001 From: Giulia Alfonsi Date: Thu, 12 Jun 2014 12:55:32 +0100 Subject: [PATCH 195/321] Reformat else if indentation --- lib/addons/memcached/index.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/addons/memcached/index.js b/lib/addons/memcached/index.js index 6a9c97bf..423c9025 100644 --- a/lib/addons/memcached/index.js +++ b/lib/addons/memcached/index.js @@ -87,8 +87,7 @@ module.exports = function(app, connection) { if (JSON.stringify(oldSessionUser) !== req._userJSONCopy) { memcached.set(oldSessionUser.name, oldSessionUser); } - } else - if (!username) { + } else if (!username) { var user = undefsafe(req, '_sessionBeforeBlacklist.user'); if (user) { memcached.set(user.name, user); From 4e664ef92ec852ee0ec32c43fe6bd8a50cd0eb15 Mon Sep 17 00:00:00 2001 From: Fabien O'Carroll Date: Thu, 12 Jun 2014 13:09:35 +0100 Subject: [PATCH 196/321] Refactor the logic for setting to memcached. First we've renamed the oldSessionUser variable to sessionUser, as that is most accurate in what we're actually doing. The logic implemented is as follows: - If there's no user on the session - don't save! - If there *is* a user on the session, and the data is the same as what we have in memcache already - don't save! - For everything else - save it. --- lib/addons/memcached/index.js | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/lib/addons/memcached/index.js b/lib/addons/memcached/index.js index 423c9025..3fb25004 100644 --- a/lib/addons/memcached/index.js +++ b/lib/addons/memcached/index.js @@ -81,18 +81,21 @@ module.exports = function(app, connection) { // We're basically yaking the same idea that connects cookieSessions use // from here: http://www.senchalabs.org/connect/cookieSession.html res.on('header', function () { - var oldSessionUser = undefsafe(req, '_sessionBeforeBlacklist.user'); - if (oldSessionUser && req._userJSONCopy) { - // FIXME - this is hacky - if (JSON.stringify(oldSessionUser) !== req._userJSONCopy) { - memcached.set(oldSessionUser.name, oldSessionUser); - } - } else if (!username) { - var user = undefsafe(req, '_sessionBeforeBlacklist.user'); - if (user) { - memcached.set(user.name, user); + var sessionUser = undefsafe(req, '_sessionBeforeBlacklist.user'); + // If there's no user on the session, there's nothing to save + if (!sessionUser) { + return; + } + // If we have a copy of the user on the "way in" and it's the + // same as the user on the session now, there's no need to save + if (req._userJSONCopy) { + // FIXME - this is hacky (use a compare/equals function?) + if (JSON.stringify(sessionUser) === req._userJSONCopy) { + return; } } + // For everything else, we save them to memcache + memcached.set(sessionUser.name, sessionUser); }); }); From 300057d23a10272f9f7b6a0e9e3f41c4542eb86c Mon Sep 17 00:00:00 2001 From: Giulia Alfonsi Date: Thu, 12 Jun 2014 13:57:18 +0100 Subject: [PATCH 197/321] Fixed pro variable --- views/partials/welcome-panel.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/views/partials/welcome-panel.html b/views/partials/welcome-panel.html index a514c2a6..c3936efa 100644 --- a/views/partials/welcome-panel.html +++ b/views/partials/welcome-panel.html @@ -32,7 +32,7 @@ {{#pro-features}}
-

{{title}}{{#unless user.pro}} (£10/month){{/unless}}

+

{{title}}{{#unless ../../user.pro}} (£10/month){{/unless}}

{{#data}}
    {{#.}} From 4647c6a26eec27d12eb06917b35073cdd7e379ed Mon Sep 17 00:00:00 2001 From: Giulia Alfonsi Date: Thu, 12 Jun 2014 16:02:56 +0100 Subject: [PATCH 198/321] Changed panel height to 200px --- lib/data/welcome-panel.json | 16 ------------- public/css/style.css | 38 +++++++++++++++---------------- views/partials/welcome-panel.html | 3 +++ 3 files changed, 22 insertions(+), 35 deletions(-) diff --git a/lib/data/welcome-panel.json b/lib/data/welcome-panel.json index f1e00406..c13e05f0 100644 --- a/lib/data/welcome-panel.json +++ b/lib/data/welcome-panel.json @@ -18,14 +18,6 @@ { "title": "Exporting/importing gist", "link": "http://jsbin.com/help/export-gist" - }, - { - "title": "Codecasting", - "link": "http://remysharp.com/2013/11/14/what-is-codecasting/" - }, - { - "title": "Tutorial videos", - "link": "http://www.youtube.com/playlist?list=PLXmT1r4krsTooRDWOrIu23P3SEZ3luIUq" } ] }, @@ -48,14 +40,6 @@ { "title": "Direct support (rather that via GitHub)", "link": "http://jsbin.com/help/features" - }, - { - "title": "Asset hosting", - "link": "http://jsbin.com/help/features" - }, - { - "title": "Access experiments", - "link": "http://jsbin.com/help/features" } ] }, diff --git a/public/css/style.css b/public/css/style.css index 9e597de7..dc3ca739 100644 --- a/public/css/style.css +++ b/public/css/style.css @@ -4712,12 +4712,12 @@ html * { /* toppanel status */ #toppanel { - height: 250px; + height: 200px; background: #ecf2fa; position: relative; z-index: 100000; border-bottom: rgb(191, 191, 191) solid 1px; - margin-top: -250px; + margin-top: -200px; } .toppanel #toppanel { margin-top: 0; @@ -4726,7 +4726,7 @@ html * { .toppanel #bin, .toppanel #history, .toppanel #history .preview { - top: 286px; + top: 236px; } #toppanel ~ #control .brand { @@ -4748,7 +4748,7 @@ body.ready.toppanel { display: block !important; color: #232323; font-size: 0; - padding: 13px; + padding: 10px; -webkit-box-sizing: border-box; -moz-box-sizing: border-box; box-sizing: border-box; @@ -4759,7 +4759,7 @@ body.ready.toppanel { padding: 0 4px; vertical-align: top; width: 200px; - height: 220px; + height: 179px; overflow: hidden; -webkit-box-sizing: border-box; -moz-box-sizing: border-box; @@ -4794,6 +4794,7 @@ body.ready.toppanel { } .toppanel-actions { position: relative; + top: -12px; z-index: 0; } .toppanel-title { @@ -4841,7 +4842,7 @@ div:first-child > .toppanel-button { } .toppanel-button { border: 1px solid #6293D3; - line-height: 30px; + line-height: 25px; margin: 0 auto; text-align: center; width: 150px; @@ -4867,8 +4868,8 @@ div:first-child > .toppanel-button { } a.toppanel-hide { position: absolute; - left: 20px; - top: 15px; + left: 5px; + top: 5px; padding: 0 5px 7px; font-size: 35px; line-height: 0.7; @@ -4884,11 +4885,11 @@ a.toppanel-logo { text-align: center; position: relative; z-index: 1; - -webkit-transform: translate(-95px, 155px) scale(0.25); - -moz-transform: translate(-95px, 155px) scale(0.25); - -ms-transform: translate(-95px, 155px) scale(0.25); - -o-transform: translate(-95px, 155px) scale(0.25); - transform: translate(-95px, 155px) scale(0.25); + -webkit-transform: translate(-94px, 112px) scale(0.25); + -moz-transform: translate(-94px, 112px) scale(0.25); + -ms-transform: translate(-94px, 112px) scale(0.25); + -o-transform: translate(-94px, 112px) scale(0.25); + transform: translate(-94px, 112px) scale(0.25); -webkit-transform-origin: 100% 100%; -moz-transform-origin: 100% 100%; -ms-transform-origin: 100% 100%; @@ -4901,16 +4902,15 @@ a.toppanel-logo:hover { } .toppanel-logo img { border: 0 none; - margin-top: 4px; width: 100%; } .toppanel .toppanel-logo { cursor: default; - -webkit-transform: translate(70px, 0) scale(1); - -moz-transform: translate(70px, 0) scale(1); - -ms-transform: translate(70px, 0) scale(1); - -o-transform: translate(70px, 0) scale(1); - transform: translate(70px, 0) scale(1); + -webkit-transform: translate(41px, -8px) scale(1); + -moz-transform: translate(41px, -8px) scale(1); + -ms-transform: translate(41px, -8px) scale(1); + -o-transform: translate(41px, -8px) scale(1); + transform: translate(41px, -8px) scale(1); } /* toppanel animation */ diff --git a/views/partials/welcome-panel.html b/views/partials/welcome-panel.html index c3936efa..d107d957 100644 --- a/views/partials/welcome-panel.html +++ b/views/partials/welcome-panel.html @@ -70,6 +70,9 @@ {{/data}}
{{/help}} +
+ +
{{#twitter}}
From 0966d49f5b2b2ce34d47fd7be2729f07e9ca33a4 Mon Sep 17 00:00:00 2001 From: Giulia Alfonsi Date: Thu, 12 Jun 2014 16:03:25 +0100 Subject: [PATCH 199/321] Changed column width to be more flexible --- public/css/style.css | 29 +++++++++++++++++++++++------ 1 file changed, 23 insertions(+), 6 deletions(-) diff --git a/public/css/style.css b/public/css/style.css index dc3ca739..85981a52 100644 --- a/public/css/style.css +++ b/public/css/style.css @@ -4765,30 +4765,47 @@ body.ready.toppanel { -moz-box-sizing: border-box; box-sizing: border-box; } -.toppanel-column-first { - overflow: visible; - width: 197px; +@media (max-width: 1223px) { /* 5 */ + .toppanel-column { + width: calc((100% - 217px) / 4); + } + .toppanel-column:nth-child(n+6) { + display: none; + } } @media (max-width: 1023px) { /* 4 */ + .toppanel-column { + width: calc((100% - 217px) / 3); + } .toppanel-column:nth-child(n+5) { display: none; } } -@media (max-width: 823px) { /* 3 */ +@media (max-width: 816px) { /* 3 */ + .toppanel-column { + width: calc((100% - 217px) / 2); + } .toppanel-column:nth-child(n+4) { display: none; } } -@media (max-width: 623px) { /* 2 */ +@media (max-width: 616px) { /* 2 */ + .toppanel-column { + width: calc(100% - 217px); + } .toppanel-column:nth-child(n+3) { display: none; } } -@media (max-width: 423px) { /* 1 */ +@media (max-width: 416px) { /* 1 */ .toppanel-column:nth-child(n+2) { display: none; } } +.toppanel-column-first { + overflow: visible; + width: 197px; +} .toppanel-section + .toppanel-section { margin-top: 13px; } From f41b8bf780e65347b98f764a7e6093084ad06cf3 Mon Sep 17 00:00:00 2001 From: Giulia Alfonsi Date: Thu, 12 Jun 2014 16:09:04 +0100 Subject: [PATCH 200/321] Added GitHub button --- public/css/style.css | 9 +++++++++ views/partials/welcome-panel.html | 33 +++++++++++++++++++------------ 2 files changed, 29 insertions(+), 13 deletions(-) diff --git a/public/css/style.css b/public/css/style.css index 85981a52..10dc8d6e 100644 --- a/public/css/style.css +++ b/public/css/style.css @@ -4894,6 +4894,15 @@ a.toppanel-hide { color: rgba(98, 147, 211, 0.5); font-weight: 200; } +.toppanel-actions .btn-github { + font-size: 70%; + width: 163px; + margin: 0 auto; + color: #232323; +} +.toppanel-actions .btn-github:hover { + background: linear-gradient(0deg, #e8e8e8, #f8f8f8); +} a.toppanel-logo { display: inline-block; diff --git a/views/partials/welcome-panel.html b/views/partials/welcome-panel.html index d107d957..aef3efeb 100644 --- a/views/partials/welcome-panel.html +++ b/views/partials/welcome-panel.html @@ -9,7 +9,14 @@ New bin
+ {{#if home}} Open bin... + {{else}} + + + Login or Register via GitHub + + {{/if}}
@@ -73,19 +80,19 @@
- {{#twitter}} - -
-

{{title}}

- {{#data}} - - {{/data}} -
- {{/twitter}} + {{#twitter}} + +
+

{{title}}

+ {{#data}} + + {{/data}} +
+ {{/twitter}}
From 4522261a5ead8de2b6a2bc08d939353ececc2bdd Mon Sep 17 00:00:00 2001 From: Giulia Alfonsi Date: Thu, 12 Jun 2014 16:09:32 +0100 Subject: [PATCH 201/321] Removed GitHub button --- views/partials/welcome-panel.html | 5 ----- 1 file changed, 5 deletions(-) diff --git a/views/partials/welcome-panel.html b/views/partials/welcome-panel.html index aef3efeb..86e8da28 100644 --- a/views/partials/welcome-panel.html +++ b/views/partials/welcome-panel.html @@ -11,11 +11,6 @@
{{#if home}} Open bin... - {{else}} - - - Login or Register via GitHub - {{/if}}
From be2d16948fb116fb61d69150b5e5e4a516d8e80e Mon Sep 17 00:00:00 2001 From: Giulia Alfonsi Date: Thu, 12 Jun 2014 16:18:57 +0100 Subject: [PATCH 202/321] Added svg Dave --- public/images/dave.svg | 43 +++++++++++++++++++++++++++++++ views/partials/welcome-panel.html | 2 +- 2 files changed, 44 insertions(+), 1 deletion(-) create mode 100644 public/images/dave.svg diff --git a/public/images/dave.svg b/public/images/dave.svg new file mode 100644 index 00000000..ddc4f821 --- /dev/null +++ b/public/images/dave.svg @@ -0,0 +1,43 @@ + + + Layer 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/views/partials/welcome-panel.html b/views/partials/welcome-panel.html index 86e8da28..862de82c 100644 --- a/views/partials/welcome-panel.html +++ b/views/partials/welcome-panel.html @@ -2,7 +2,7 @@
×
From 5508b0cd2a7af8036df4cf75c85309bdc5cf3c1a Mon Sep 17 00:00:00 2001 From: Giulia Alfonsi Date: Thu, 12 Jun 2014 16:33:53 +0100 Subject: [PATCH 203/321] Tip positioning fixed --- public/css/style.css | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/public/css/style.css b/public/css/style.css index 10dc8d6e..bb24652c 100644 --- a/public/css/style.css +++ b/public/css/style.css @@ -4743,6 +4743,11 @@ body.ready.toppanel { background: white; } +.toppanel #tip.notification, +.toppanel #tip.error { + top: 234px; +} + /* toppanel */ .toppanel-wrapper { display: block !important; From 66742397ddf1535f98bf60d2ac28c45bbef4a034 Mon Sep 17 00:00:00 2001 From: Giulia Alfonsi Date: Thu, 12 Jun 2014 16:43:49 +0100 Subject: [PATCH 204/321] Moved new bin button down if it's the only one --- public/css/style.css | 3 +++ views/partials/welcome-panel.html | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/public/css/style.css b/public/css/style.css index bb24652c..3d530f56 100644 --- a/public/css/style.css +++ b/public/css/style.css @@ -4819,6 +4819,9 @@ body.ready.toppanel { top: -12px; z-index: 0; } +.toppanel-actions-alone { + top: 0; +} .toppanel-title { font-size: 14px; font-weight: 600; diff --git a/views/partials/welcome-panel.html b/views/partials/welcome-panel.html index 862de82c..f405731d 100644 --- a/views/partials/welcome-panel.html +++ b/views/partials/welcome-panel.html @@ -4,7 +4,7 @@ -
+
From 21a38dc4985e9c813d776256ad59781ce0764de2 Mon Sep 17 00:00:00 2001 From: Giulia Alfonsi Date: Thu, 12 Jun 2014 16:52:55 +0100 Subject: [PATCH 205/321] Increased column width --- public/css/style.css | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/public/css/style.css b/public/css/style.css index 3d530f56..8e3f04d5 100644 --- a/public/css/style.css +++ b/public/css/style.css @@ -4763,7 +4763,8 @@ body.ready.toppanel { display: inline-block; padding: 0 4px; vertical-align: top; - width: 200px; + max-width: 220px; + width: 16.66%; height: 179px; overflow: hidden; -webkit-box-sizing: border-box; @@ -4773,6 +4774,7 @@ body.ready.toppanel { @media (max-width: 1223px) { /* 5 */ .toppanel-column { width: calc((100% - 217px) / 4); + max-width: 100%; } .toppanel-column:nth-child(n+6) { display: none; From b5b0c7ac56af5d4866d9d245414cbdbd9ed400bf Mon Sep 17 00:00:00 2001 From: Giulia Alfonsi Date: Thu, 12 Jun 2014 16:56:36 +0100 Subject: [PATCH 206/321] Improved font stack --- public/css/upgrade.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/css/upgrade.css b/public/css/upgrade.css index bbfecdd3..537838c4 100644 --- a/public/css/upgrade.css +++ b/public/css/upgrade.css @@ -1,5 +1,5 @@ body { - font-family: helvetica neue; + font-family: 'helvetica neue', sans-serif; font-weight:200!important; } From 985b93bee8ed702add1b8dd0b3f9eabb30d92748 Mon Sep 17 00:00:00 2001 From: Peter Blazejewicz Date: Thu, 12 Jun 2014 18:51:44 +0200 Subject: [PATCH 207/321] Use BootstrapCDN in libraries configuration. Closes #1564 --- public/js/editors/libraries.js | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/public/js/editors/libraries.js b/public/js/editors/libraries.js index 6c465973..19f15d1e 100644 --- a/public/js/editors/libraries.js +++ b/public/js/editors/libraries.js @@ -99,8 +99,8 @@ var libraries = [ { 'url': [ 'http://code.jquery.com/jquery.min.js', - 'http://getbootstrap.com/dist/css/bootstrap.css', - 'http://getbootstrap.com/dist/js/bootstrap.js' + 'http://maxcdn.bootstrapcdn.com/bootstrap/3.1.1/css/bootstrap.min.css', + 'http://maxcdn.bootstrapcdn.com/bootstrap/3.1.1/js/bootstrap.min.js' ], 'label': 'Bootstrap Latest', 'group': 'Bootstrap' @@ -108,9 +108,8 @@ var libraries = [ { 'url': [ 'http://code.jquery.com/jquery.min.js', - 'http://getbootstrap.com/2.3.2/assets/css/bootstrap.css', - 'http://getbootstrap.com/2.3.2/assets/css/bootstrap-responsive.css', - 'http://getbootstrap.com/2.3.2/assets/js/bootstrap.js' + 'http://netdna.bootstrapcdn.com/twitter-bootstrap/2.3.2/css/bootstrap-combined.min.css', + 'http://netdna.bootstrapcdn.com/twitter-bootstrap/2.3.2/js/bootstrap.min.js' ], 'label': 'Bootstrap 2.3.2', 'group': 'Bootstrap' From c5b21a3c0649d0359d1460d14b813d9aa3ec8668 Mon Sep 17 00:00:00 2001 From: Remy Sharp Date: Thu, 12 Jun 2014 22:39:50 +0100 Subject: [PATCH 208/321] Fixed #1565 Set a flag saying the content came from a POST, and then prefer the posted content over the user defined template. --- lib/handlers/bin.js | 6 ++++++ public/js/editors/panel.js | 4 ++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/lib/handlers/bin.js b/lib/handlers/bin.js index d0fc9afd..f64d2093 100644 --- a/lib/handlers/bin.js +++ b/lib/handlers/bin.js @@ -76,6 +76,8 @@ module.exports = Observable.extend({ data.settings.processors = processorSettings; } + data.post = true; + this.render(req, res, data); }, getCustom: function (req, res, next) { @@ -1064,6 +1066,10 @@ module.exports = Observable.extend({ template[panel] = utils.cleanForRender(template[panel] || ''); }); + if (bin.post) { + template.post = bin.post; + } + template.url = this.helpers.jsbinURL(bin); //.permalink; return template; }, diff --git a/public/js/editors/panel.js b/public/js/editors/panel.js index 9fdbeae1..4db3db63 100644 --- a/public/js/editors/panel.js +++ b/public/js/editors/panel.js @@ -119,7 +119,7 @@ var Panel = function (name, settings) { // Bind events using CM3 syntax panel.editor.on('change', function codeChange(cm, changeObj) { if (jsbin.saveDisabled) { - $document.trigger('codeChange.live', [{ panelId: panel.id, revert: true, origin: changeObj.origin }]); + $document.trigger('codeChange.live', [{ panelId: panel.id, revert: true, origin: changeObj.origin }]); } else { $document.trigger('codeChange', [{ panelId: panel.id, revert: true, origin: changeObj.origin }]); } @@ -532,7 +532,7 @@ function populateEditor(editor, panel) { // tell the document that it's currently being edited, but check that it doesn't match the saved template // because sessionStorage gets set on a reload changed = cached != saved && cached != template[panel]; - } else if (saved !== null && !/edit/.test(window.location) && !window.location.search) { // then their saved preference + } else if (!template.post && saved !== null && !/edit/.test(window.location) && !window.location.search) { // then their saved preference editor.setCode(saved); } else { // otherwise fall back on the JS Bin default editor.setCode(template[panel]); From ff66865c55bcd60074fdfdd1bb575f9088aeeb48 Mon Sep 17 00:00:00 2001 From: Giulia Alfonsi Date: Fri, 13 Jun 2014 12:03:07 +0100 Subject: [PATCH 209/321] #1571 setting indentUnit and fixing problems of it with Tern --- public/js/account/editor-settings.js | 1 + public/js/editors/tern.js | 5 ++++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/public/js/account/editor-settings.js b/public/js/account/editor-settings.js index 4ae36880..9ac6abd5 100644 --- a/public/js/account/editor-settings.js +++ b/public/js/account/editor-settings.js @@ -138,6 +138,7 @@ editor.setOption('lineNumbers', $lineNumbers.prop('checked')); editor.setOption('indentWithTabs', $indentWithTabs.prop('checked')); editor.setOption('tabSize', $tabSize.val()); + editor.setOption('indentUnit', $tabSize.val()); editor.setOption('theme', $theme.val()); $CodeMirror.css('font-size', $fontsize.val()+'px'); editor.refresh(); diff --git a/public/js/editors/tern.js b/public/js/editors/tern.js index cbac223c..db2c269e 100644 --- a/public/js/editors/tern.js +++ b/public/js/editors/tern.js @@ -2,6 +2,9 @@ 'use strict'; /*globals $, jsbin, CodeMirror, template, ternDefinitions, ternBasicDefs */ + if (!jsbin.settings.addons.tern) { + return; + } var ternServer; var ternLoaded = {}; @@ -90,7 +93,7 @@ if (cm.options.indentWithTabs) { indent = '\t'; } else { - indent = new Array(cm.options.indentUnit + 1).join(' '); + indent = new Array(cm.options.indentUnit * 1 + 1).join(' '); } if (tok.string === ';') { From 364bf5f5b9f055dc5e91107120d139d2f65cfef8 Mon Sep 17 00:00:00 2001 From: Giulia Alfonsi Date: Fri, 13 Jun 2014 12:24:42 +0100 Subject: [PATCH 210/321] #1573 Added the script to show the "Settings saved" message in editor preferences page --- public/js/account/editor-settings.js | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/public/js/account/editor-settings.js b/public/js/account/editor-settings.js index 4ae36880..1d614660 100644 --- a/public/js/account/editor-settings.js +++ b/public/js/account/editor-settings.js @@ -78,6 +78,9 @@ ]; var $addons = {}; + var $saveStatus = $('span.status'); + var saveTimer = null; + // setup variables; var $textarea = $('textarea'); @@ -179,6 +182,9 @@ } reloadAddons(tempAddonsKeys); + clearTimeout(saveTimer); + $saveStatus.addClass('show'); + // Save on server $.ajax({ type: 'POST', @@ -196,6 +202,11 @@ if (console && console.log) { console.log('Error: ' + status); } + }, + complete: function () { + saveTimer = setTimeout(function () { + $saveStatus.removeClass('show'); + }, 1000); } }); From aac06eb8f9ccfd0b888bf3c036136f184cbab6d6 Mon Sep 17 00:00:00 2001 From: Giulia Alfonsi Date: Fri, 13 Jun 2014 15:16:44 +0100 Subject: [PATCH 211/321] Added analytics --- public/js/chrome/analytics.js | 10 ++++++++++ public/js/chrome/welcome-panel.js | 9 ++++++++- views/partials/welcome-panel.html | 20 ++++++++++---------- 3 files changed, 28 insertions(+), 11 deletions(-) diff --git a/public/js/chrome/analytics.js b/public/js/chrome/analytics.js index 19a66d96..87df080f 100644 --- a/public/js/chrome/analytics.js +++ b/public/js/chrome/analytics.js @@ -119,6 +119,16 @@ var analytics = { }, runconsole: function (from) { analytics.track(from || 'button', 'run console'); + }, + welcomePanelState: function (state) { + var s = 'close'; + if (state) { + s = 'open'; + } + analytics.track('state', 'welcome-panel', s); + }, + welcomePanelLink: function (url) { + analytics.track('welcome-panel-link', url); } }; diff --git a/public/js/chrome/welcome-panel.js b/public/js/chrome/welcome-panel.js index 88293e22..d6bc4a8f 100644 --- a/public/js/chrome/welcome-panel.js +++ b/public/js/chrome/welcome-panel.js @@ -1,5 +1,5 @@ (function () { - /*global jsbin, $, $body, $document*/ + /*global jsbin, $, $body, $document, analytics*/ 'use strict'; if (jsbin.settings.gui === undefined) { @@ -10,6 +10,8 @@ localStorage.setItem('settings', JSON.stringify(jsbin.settings)); } + analytics.welcomePanelState($body.hasClass('toppanel')); + var removeToppanel = function() { jsbin.settings.gui.toppanel = false; localStorage.setItem('settings', JSON.stringify(jsbin.settings)); @@ -50,4 +52,9 @@ } }); + // analytics for links + $('#toppanel').find('.toppanel-link').mousedown(function() { + analytics.welcomePanelLink(this.href); + }); + }()); \ No newline at end of file diff --git a/views/partials/welcome-panel.html b/views/partials/welcome-panel.html index f405731d..256036b0 100644 --- a/views/partials/welcome-panel.html +++ b/views/partials/welcome-panel.html @@ -20,11 +20,11 @@ {{#features}}
-

{{title}}

+

{{title}}

{{#data}} {{/data}} @@ -34,11 +34,11 @@ {{#pro-features}}
-

{{title}}{{#unless ../../user.pro}} (£10/month){{/unless}}

+

{{title}}{{#unless ../../user.pro}} (£10/month){{/unless}}

{{#data}} {{/data}} @@ -49,11 +49,11 @@ {{#blog}}
-

{{title}}

+

{{title}}

{{#data}} {{/data}} @@ -62,11 +62,11 @@ {{#help}}
-

{{title}}

+

{{title}}

{{#data}} {{/data}} @@ -78,11 +78,11 @@ {{#twitter}}
-

{{title}}

+

{{title}}

{{#data}} {{/data}} From c87211aa9a0bf1fdeebb18f7dc28fd86bd066bcb Mon Sep 17 00:00:00 2001 From: Giulia Alfonsi Date: Fri, 13 Jun 2014 16:14:52 +0100 Subject: [PATCH 212/321] Created settings object --- public/js/chrome/settings.js | 27 +++++++++++++++++++++++++++ scripts.json | 1 + 2 files changed, 28 insertions(+) create mode 100644 public/js/chrome/settings.js diff --git a/public/js/chrome/settings.js b/public/js/chrome/settings.js new file mode 100644 index 00000000..0eaa6b75 --- /dev/null +++ b/public/js/chrome/settings.js @@ -0,0 +1,27 @@ +/*global jsbin, $*/ + +var settings = { + save: function () { + localStorage.setItem('settings', JSON.stringify(jsbin.settings)); + + $.ajax({ + url: '/account/editor', + type: 'POST', + dataType: 'json', + data: { + settings: localStorage.settings, + _csrf: jsbin.state.token + }, + success: function() { + if (console && console.log) { + console.log('Success on saving settings'); + } + }, + error: function(xhr, status) { + if (console && console.log) { + console.log('Error: ' + status); + } + } + }); + } +}; \ No newline at end of file diff --git a/scripts.json b/scripts.json index be7cd5dc..26391d51 100644 --- a/scripts.json +++ b/scripts.json @@ -25,6 +25,7 @@ "/js/editors/mobileCodeMirror.js", "/js/chrome/splitter.js", "/js/chrome/analytics.js", + "/js/chrome/settings.js", "/js/chrome/font.js", "/js/render/render.js", "/js/render/live.js", From de9fb70b1a11adbe1dd12a278ee8854aa720e075 Mon Sep 17 00:00:00 2001 From: Giulia Alfonsi Date: Fri, 13 Jun 2014 16:15:14 +0100 Subject: [PATCH 213/321] Saving settings and panel state to db --- public/js/chrome/welcome-panel.js | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/public/js/chrome/welcome-panel.js b/public/js/chrome/welcome-panel.js index d6bc4a8f..c0ad9af5 100644 --- a/public/js/chrome/welcome-panel.js +++ b/public/js/chrome/welcome-panel.js @@ -1,5 +1,5 @@ (function () { - /*global jsbin, $, $body, $document, analytics*/ + /*global jsbin, $, $body, $document, analytics, settings*/ 'use strict'; if (jsbin.settings.gui === undefined) { @@ -10,18 +10,24 @@ localStorage.setItem('settings', JSON.stringify(jsbin.settings)); } - analytics.welcomePanelState($body.hasClass('toppanel')); + if ($body.hasClass('toppanel') && jsbin.settings.gui.toppanel === false) { + $body.addClass('toppanel-close'); + $body.removeClass('toppanel'); + } + + // analytics for panel state + analytics.welcomePanelState(jsbin.settings.gui.toppanel); var removeToppanel = function() { jsbin.settings.gui.toppanel = false; - localStorage.setItem('settings', JSON.stringify(jsbin.settings)); + settings.save(); $body.addClass('toppanel-close'); $body.removeClass('toppanel'); }; var showToppanel = function() { jsbin.settings.gui.toppanel = true; - localStorage.setItem('settings', JSON.stringify(jsbin.settings)); + settings.save(); $body.removeClass('toppanel-close'); $body.addClass('toppanel'); }; From 8f2b7a88dff9f5bfe70290c29144a6b44cd18758 Mon Sep 17 00:00:00 2001 From: Giulia Alfonsi Date: Fri, 13 Jun 2014 16:23:39 +0100 Subject: [PATCH 214/321] Changed first column paddings and close button alt text --- public/css/style.css | 11 ++++++----- views/partials/welcome-panel.html | 2 +- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/public/css/style.css b/public/css/style.css index 8e3f04d5..27667577 100644 --- a/public/css/style.css +++ b/public/css/style.css @@ -4810,6 +4810,7 @@ body.ready.toppanel { } } .toppanel-column-first { + padding-right: 10px; overflow: visible; width: 197px; } @@ -4942,11 +4943,11 @@ a.toppanel-logo:hover { } .toppanel .toppanel-logo { cursor: default; - -webkit-transform: translate(41px, -8px) scale(1); - -moz-transform: translate(41px, -8px) scale(1); - -ms-transform: translate(41px, -8px) scale(1); - -o-transform: translate(41px, -8px) scale(1); - transform: translate(41px, -8px) scale(1); + -webkit-transform: translate(35px, -8px) scale(1); + -moz-transform: translate(35px, -8px) scale(1); + -ms-transform: translate(35px, -8px) scale(1); + -o-transform: translate(35px, -8px) scale(1); + transform: translate(35px, -8px) scale(1); } /* toppanel animation */ diff --git a/views/partials/welcome-panel.html b/views/partials/welcome-panel.html index 256036b0..1bf9e6c8 100644 --- a/views/partials/welcome-panel.html +++ b/views/partials/welcome-panel.html @@ -1,6 +1,6 @@ From f56bf625e5c56f61c0c170770172911f6dfda4f0 Mon Sep 17 00:00:00 2001 From: Fabien O'Carroll Date: Fri, 13 Jun 2014 17:15:31 +0100 Subject: [PATCH 219/321] add coupon input to upgrade page --- views/upgrade.html | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/views/upgrade.html b/views/upgrade.html index efca412c..17ecd161 100644 --- a/views/upgrade.html +++ b/views/upgrade.html @@ -7,7 +7,7 @@
@@ -27,7 +27,7 @@ @@ -63,6 +65,7 @@
{{name}} + {{#equal user 'anon'}}✓{{/equal}} + + {{#equal user 'anon'}}✓{{/equal}} + {{#equal user 'free'}}✓{{/equal}} + + {{#equal user 'anon'}}✓{{/equal}} + {{#equal user 'free'}}✓{{/equal}} + {{#equal user 'pro'}}✓{{/equal}} +
Anonymous Free -
+ Pro @ $15/month
    - + + Click here if you have a code +
+

Your Pro accounts keep JS Bin 100% free for education

Aside from the features listed above, your pro account will help keep @@ -86,4 +89,5 @@ {{/each}} - \ No newline at end of file + + From 25b56d13bfd4d029ee88d3e22e5915a92021b5d1 Mon Sep 17 00:00:00 2001 From: Fabien O'Carroll Date: Fri, 13 Jun 2014 17:16:15 +0100 Subject: [PATCH 220/321] Add coupon to customer if it exists --- lib/stripe/handlers/index.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/stripe/handlers/index.js b/lib/stripe/handlers/index.js index 0e601de7..1278c644 100644 --- a/lib/stripe/handlers/index.js +++ b/lib/stripe/handlers/index.js @@ -65,6 +65,10 @@ module.exports = function (config) { plan: req.params.plan, card: req.body.stripeToken }; + var couponCode = req.url.indexOf('?') !== -1 ? req.url.split('?').pop() : null; + if (couponCode) { + customerOptions.coupon = couponCode; + } if (!user) { res.flash('error', 'Please login before attempting to signup'); From 9bad132a27c72febd6e95cf80ae2121a1b9a422b Mon Sep 17 00:00:00 2001 From: Fabien O'Carroll Date: Fri, 13 Jun 2014 17:16:29 +0100 Subject: [PATCH 221/321] add javascript for upgrade page --- public/js/account/upgrade.js | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 public/js/account/upgrade.js diff --git a/public/js/account/upgrade.js b/public/js/account/upgrade.js new file mode 100644 index 00000000..a8d85b6d --- /dev/null +++ b/public/js/account/upgrade.js @@ -0,0 +1,19 @@ +/* globals $ */ +(function () { + + var $input = $('#coupon_code'); + var $form = $('#stripe_pro_month'); + var originalAction = $form.attr('action'); + + $input.on('change', function () { + 'use strict'; + $form.attr('action', originalAction + '?' + $input.val()); + }); + + var $couponBtn = $('.coupon-btn'); + $couponBtn.on('click', function (event) { + event.preventDefault(); + $input.css('visibility', 'visible'); + }); + +}()); From 686a10f9697d9c47e14594031c0b8566819da3a1 Mon Sep 17 00:00:00 2001 From: Fabien O'Carroll Date: Fri, 13 Jun 2014 17:16:42 +0100 Subject: [PATCH 222/321] restyle upgrade page table --- public/css/upgrade.css | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/public/css/upgrade.css b/public/css/upgrade.css index 537838c4..7d2027e4 100644 --- a/public/css/upgrade.css +++ b/public/css/upgrade.css @@ -19,7 +19,7 @@ table { border: 1; width: 80%; border-collapse: collapse; - margin: -45px auto 0; + margin-left:10%; } tbody tr { @@ -36,7 +36,7 @@ td { line-height:30px; font-size:16px; font-weight:300; - width:100px; + width:160px; } td.feature { @@ -44,6 +44,15 @@ td.feature { width:auto; } +.coupon-btn { + font-size:14px; +} + +#coupon_code { + visibility:hidden; + font-size:14px; +} + .backers { width:720px; margin:0 auto; From 00277eb7f345d67dcfdada80cb1d1b536f55a010 Mon Sep 17 00:00:00 2001 From: Fabien O'Carroll Date: Fri, 13 Jun 2014 17:56:30 +0100 Subject: [PATCH 223/321] Read url from config --- lib/routes.js | 4 +++- views/upgrade.html | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/routes.js b/lib/routes.js index 275e7e16..395cf87b 100644 --- a/lib/routes.js +++ b/lib/routes.js @@ -170,6 +170,7 @@ module.exports = function (app) { var static = sandbox.helpers.urlForStatic('', req.secure); var referrer = req.get('referer'); var stripeKey = undefsafe(config, 'payment.stripe.public'); + var stripeProMonthURL = undefsafe(config, 'payment.stripe.urls.month'); res.render('upgrade', { layout: 'sub/layout', @@ -179,7 +180,8 @@ module.exports = function (app) { featureList: featureList, backersList: backersList, cachebust: app.set('is_production') ? '?' + app.set('version') : '', - stripeKey: stripeKey + stripeKey: stripeKey, + stripeProMonthURL: stripeProMonthURL }); }); diff --git a/views/upgrade.html b/views/upgrade.html index 17ecd161..e0d79d6d 100644 --- a/views/upgrade.html +++ b/views/upgrade.html @@ -27,7 +27,7 @@     -

+ -
diff --git a/views/upgrade.html b/views/upgrade.html index e0d79d6d..fa218f0c 100644 --- a/views/upgrade.html +++ b/views/upgrade.html @@ -7,17 +7,7 @@ Anonymous Free - - Pro @ $15/month + Pro @ $12/month @@ -29,11 +19,11 @@
From 2e29c300e6d6a8894a7f71346903928006ae9ca7 Mon Sep 17 00:00:00 2001 From: Remy Sharp Date: Mon, 16 Jun 2014 17:53:58 +0100 Subject: [PATCH 229/321] Ensure /upgrade is in account urls --- config.default.json | 1 + lib/features.js | 2 +- lib/routes.js | 2 +- views/partials/account_sidebar.html | 2 +- 4 files changed, 4 insertions(+), 3 deletions(-) diff --git a/config.default.json b/config.default.json index 6961d66e..06292932 100644 --- a/config.default.json +++ b/config.default.json @@ -152,6 +152,7 @@ "translate", "trends", "unarchive", + "upgrade", "user", "users", "widgets", diff --git a/lib/features.js b/lib/features.js index ef389998..0bf52129 100644 --- a/lib/features.js +++ b/lib/features.js @@ -48,7 +48,7 @@ function team(req) { } function pro(req) { - return flags.alpha(req) || undefsafe(req, 'session.user.pro'); + return alpha(req) || undefsafe(req, 'session.user.pro'); } /* End: user types */ diff --git a/lib/routes.js b/lib/routes.js index f6b2a5e2..75c03220 100644 --- a/lib/routes.js +++ b/lib/routes.js @@ -162,7 +162,7 @@ module.exports = function (app) { app.post('/api/save', binHandler.apiCreateBin); app.post('/api/:bin/save', binHandler.apiCreateRevision); - app.get('/upgrade', features.route('uprade'), function (req, res) { + app.get('/account/upgrade', features.route('upgrade'), function (req, res) { var featureList = require('./data/features.json'); var backersList = require('./data/backers.json'); var root = sandbox.helpers.url('', true, req.secure); diff --git a/views/partials/account_sidebar.html b/views/partials/account_sidebar.html index 6704a221..93e06cb6 100644 --- a/views/partials/account_sidebar.html +++ b/views/partials/account_sidebar.html @@ -7,7 +7,7 @@ {{#feature request "upgrade"}} - Upgrade + Upgrade {{/feature}} + {{#if isProduction}} From c057a8dea854685f42064ac9ec20b3c2109ef439 Mon Sep 17 00:00:00 2001 From: Remy Sharp Date: Fri, 20 Jun 2014 14:19:01 +0100 Subject: [PATCH 237/321] Now supports line highlighting --- public/css/style.css | 6 +- public/js/editors/editors.js | 46 ++++- public/js/editors/panel.js | 30 +-- .../js/vendor/cm_addons/cm-highlight-line.js | 172 ++++++++++++++++++ scripts.json | 1 + 5 files changed, 228 insertions(+), 27 deletions(-) create mode 100644 public/js/vendor/cm_addons/cm-highlight-line.js diff --git a/public/css/style.css b/public/css/style.css index d7084cc6..8146e80a 100644 --- a/public/css/style.css +++ b/public/css/style.css @@ -4718,7 +4718,11 @@ html * { margin-right: 10px; } -.line-highlight {background: rgb(255, 255, 204);} +.CodeMirror-highlight-line, +.CodeMirror-highlight-line .CodeMirror-linenumber, +.CodeMirror-highlight-line-background { + background: rgba(255, 255, 204, 0.6); +} /* toppanel status */ #toppanel { diff --git a/public/js/editors/editors.js b/public/js/editors/editors.js index e289714a..88b65a35 100644 --- a/public/js/editors/editors.js +++ b/public/js/editors/editors.js @@ -110,10 +110,11 @@ panels.restore = function () { width = $window.width(), deferredCodeInsert = '', focused = !!sessionStorage.getItem('panel'), - validPanels = 'live javascript html css console'.split(' '); + validPanels = 'live javascript html css console'.split(' '), + cachedHash = ''; if (history.replaceState && (location.pathname.indexOf('/edit') !== -1) || ((location.origin + location.pathname) === jsbin.getURL() + '/')) { - history.replaceState(null, '', jsbin.getURL() + (jsbin.getURL() === jsbin.root ? '' : '/edit')); + history.replaceState(null, '', jsbin.getURL() + (jsbin.getURL() === jsbin.root ? '' : '/edit') + (hash ? '#' + hash : '')); } if (search || hash) { @@ -305,6 +306,28 @@ panels.savecontent = function () { } }; +panels.highlightLines = function (cm, lines, string) { + 'use strict'; + var hash = []; + var lines = ''; + var panel; + for (name in panels.panels) { + panel = panels.panels[name]; + if (panel.editor) { + lines = panel.editor.highlightLines().string; + if (lines) { + hash.push(name.substr(0, 1).toUpperCase() + ':L' + lines); + } + } + + if (hash.length) { + window.location.hash = hash.join(','); + } else { + window.location.hash = ''; + } + } +}; + panels.focus = function (panel) { this.focused = panel; if (panel) { @@ -578,16 +601,31 @@ var editorsReady = setInterval(function () { var ready = true, resizeTimer = null, panel, - panelId; + panelId, + hash = window.location.hash.substring(1); + for (panelId in panels.panels) { panel = panels.panels[panelId]; - if (panel.visible && !panel.ready) ready = false; + if (panel.visible && !panel.ready) { + ready = false; + break; + } } panels.ready = ready; if (ready) { + panels.allEditors(function (panel) { + var key = panel.id.substr(0, 1).toUpperCase() + ':L'; + if (hash.indexOf(key) !== -1) { + var lines = hash.match(new RegExp(key + '(\\d+(?:-\\d+)?)')); + if (lines !== null) { + panel.editor.highlightLines(lines[1]); + } + } + }); + clearInterval(editorsReady); // panels.ready = true; // if (typeof editors.onReady == 'function') editors.onReady(); diff --git a/public/js/editors/panel.js b/public/js/editors/panel.js index 1dbd7a82..bf90f123 100644 --- a/public/js/editors/panel.js +++ b/public/js/editors/panel.js @@ -42,6 +42,7 @@ CodeMirror.commands.snippets = function (cm) { }; var Panel = function (name, settings) { + 'use strict'; var panel = this, showPanelButton = true, $panel = null, @@ -93,8 +94,9 @@ var Panel = function (name, settings) { dragDrop: false, // we handle it ourselves mode: editorModes[panelLanguage], lineWrapping: true, - gutters: ['line-highlight'], - theme: jsbin.settings.theme || 'jsbin' + // gutters: ['line-highlight'], + theme: jsbin.settings.theme || 'jsbin', + highlighLine: true }; $.extend(cmSettings, jsbin.settings.editor || {}); @@ -117,6 +119,10 @@ var Panel = function (name, settings) { panel.editor = CodeMirror.fromTextArea(panel.el, cmSettings); + panel.editor.on('highlightLines', function () { + panels.highlightLines.apply(this, arguments); + }); + // Bind events using CM3 syntax panel.editor.on('change', function codeChange(cm, changeObj) { if (jsbin.saveDisabled) { @@ -127,26 +133,6 @@ var Panel = function (name, settings) { return true; }); - panel.editor.on('gutterClick', function(cm, n, event) { - if (event.shiftKey) { // find other selected lines and highlight to here - console.log('shiftKey'); - } else { - cm.clearGutter('line-highlight'); - } - - // TODO - // 1. Keep track of marked lines, and individually remove them - // using clearGutter won't work, because we're manually setting classes - // 2. Use #html:L30-L20 - var info = cm.lineInfo(n); - cm.setGutterMarker(n, 'line-highlight', info.gutterMarkers ? null : document.createElement('div')); - if (info.gutterMarkers) { - cm.removeLineClass(n, 'wrap', 'line-highlight'); - } else { - cm.addLineClass(n, 'wrap', 'line-highlight'); - } - }); - panel.editor.on('focus', function () { panel.focus(); }); diff --git a/public/js/vendor/cm_addons/cm-highlight-line.js b/public/js/vendor/cm_addons/cm-highlight-line.js new file mode 100644 index 00000000..6fe62bc9 --- /dev/null +++ b/public/js/vendor/cm_addons/cm-highlight-line.js @@ -0,0 +1,172 @@ +// Remy Sharp / MIT +// +// Because sometimes you want line numbers to be highlighted +// +// Adds an option 'highlightedLine' which, when enabled, gives the +// active line's wrapping
the CSS class 'CodeMirror-highlight-line', +// and gives its background
the class 'CodeMirror-highlight-line-background'. +// *and* emits an event called "highlight-lines" against the CM instance with +// the first argument being the line numbers now highlighted. + +(function(mod) { + /* globals define, CodeMirror */ + 'use strict'; + if (typeof exports === 'object' && typeof module === 'object') { // CommonJS + mod(require('../../lib/codemirror')); + } else if (typeof define === 'function' && define.amd) { // AMD + define(['../../lib/codemirror'], mod); + } else { // Plain browser env + mod(CodeMirror); + } +})(function(CodeMirror) { + 'use strict'; + var WRAP_CLASS = 'CodeMirror-highlight-line'; + var BACK_CLASS = 'CodeMirror-highlight-line-background'; + + CodeMirror.defineOption('highlighLine', false, function(cm, val, old) { + var prev = old && old !== CodeMirror.Init; + if (val && !prev) { + cm.state.highlightedLines = []; + if (typeof val !== 'boolean') { + updateHighlightedLines(cm, parseLinesToArray(val)); + } + cm.on('gutterClick', gutterClick); + } else if (!val && prev) { + cm.off('gutterClick', gutterClick); + clearHighlightedLines(cm); + delete cm.state.highlightedLines; + } + }); + + CodeMirror.defineExtension('highlightLines', function (lines) { + if (lines) { + clearHighlightedLines(this); + updateHighlightedLines(this, parseLinesToArray(lines)); + } else { + var active = [].slice.call(this.state.highlightedLines); + return { + lines: active, + string: parseArrayToString(active) + }; + } + }); + + function parseLinesToArray(str) { + var active = []; + + if (({}).toString.call(str) === '[object Array]') { + // wat...oh you gave me an array + return str; + } + + if (str.indexOf('-') !== -1) { + // range + var range = str.split('-'); + var i = parseInt(range[0], 10); + var length = parseInt(range[1], 10); + for (; i <= length; i++) { + active.push(i-1); + } + } else { + active = [parseInt(str, 10) - 1]; + } + + return active; + } + + function parseArrayToString(active) { + if (active.length === 1) { + return (active[0] + 1) + ''; + } else if (active.length === 0) { + return ''; + } else { + return (active[0] + 1) + '-' + (active.slice(-1)[0] + 1); + } + } + + function clearHighlightedLines(cm) { + for (var i = 0; i < cm.state.highlightedLines.length; i++) { + cm.removeLineClass(cm.state.highlightedLines[i], 'wrap', WRAP_CLASS); + cm.removeLineClass(cm.state.highlightedLines[i], 'background', BACK_CLASS); + } + cm.state.highlightedLines = []; + } + + function sameArray(a, b) { + if (a.length !== b.length) { + return false; + } + for (var i = 0; i < a.length; i++) { + if (a[i] !== b[i]) { + return false; + } + } + return true; + } + + function highlightLines(cm, lineNumber, event) { + // copy the array (to avoid creating a reference) + var active = [].slice.call(cm.state.highlightedLines, 0); + + // shiftKey down gives multi-line highlight support + if (active.length && event.shiftKey) { + var i = active[0]; + active = []; + + // then highlight *to* this line + if (lineNumber < i) { + // highlight *up* to this new number + // reduce highlight to this point + for (; i >= lineNumber; i--) { + active.push(i); + } + } else { + // reduce highlight to this point + for (; i <= lineNumber; i++) { + active.push(i); + } + } + } else if (active.indexOf(lineNumber) === -1) { + active = [lineNumber]; // only select one line + } + + // sort the line numbers so when the user gets them in the event, it's vaguely sane. + active = active.sort(function (a, b) { + return a - b; + }); + + if (sameArray(cm.state.highlightedLines, active)) { + clearHighlightedLines(cm); + if (event) { + // only signal if it came from a user action + signal(cm, active); + } + return; + } + + updateHighlightedLines(cm, active, event); + } + + function updateHighlightedLines(cm, active, event) { + cm.operation(function() { + clearHighlightedLines(cm); + for (var i = 0; i < active.length; i++) { + cm.addLineClass(active[i], 'wrap', WRAP_CLASS); + cm.addLineClass(active[i], 'background', BACK_CLASS); + } + cm.state.highlightedLines = active; + if (event) { + // only signal if it came from a user action + signal(cm, active); + } + }); + } + + function signal(cm, active) { + CodeMirror.signal(cm, 'highlightLines', cm, active, parseArrayToString(active)); + } + + function gutterClick(cm, lineNumber, gutter, event) { + highlightLines(cm, lineNumber, event); + } +}); \ No newline at end of file diff --git a/scripts.json b/scripts.json index 0e7f6a91..43a72655 100644 --- a/scripts.json +++ b/scripts.json @@ -17,6 +17,7 @@ "/js/vendor/codemirror4/addon/edit/matchbrackets.js", "/js/vendor/codemirror4/addon/comment/comment.js", "/js/vendor/lz-string-1.3.3.js", + "/js/vendor/cm_addons/cm-highlight-line.js", "/js/editors/snippets.cm.js", "/js/vendor/json2.js", "/js/vendor/prettyprint.js", From fda7637f4d5929fd761e86fec030e314a30a2b5f Mon Sep 17 00:00:00 2001 From: Remy Sharp Date: Fri, 20 Jun 2014 15:53:15 +0100 Subject: [PATCH 238/321] Add line highlight to share --- public/js/chrome/save.js | 16 ++++++++++++++-- public/js/editors/editors.js | 9 ++------- public/js/editors/panel.js | 2 +- 3 files changed, 17 insertions(+), 10 deletions(-) diff --git a/public/js/chrome/save.js b/public/js/chrome/save.js index 8d7201fe..91e0fa90 100644 --- a/public/js/chrome/save.js +++ b/public/js/chrome/save.js @@ -51,6 +51,7 @@ var $shareLinks = $('#share .link'); $panelCheckboxes = $('#sharemenu #sharepanels input'); function updateSavedState() { + 'use strict'; var mapping = { live: 'output', javascript: 'js', @@ -65,12 +66,21 @@ function updateSavedState() { var path = this.getAttribute('data-path'); var url = jsbin.getURL(false, path === '/') + path + (query && this.id !== 'livepreview' ? '?' + query : ''), nodeName = this.nodeName; + var hash = panels.getHighlightLines(); + + if (hash) { + hash = '#' + hash; + } + if (nodeName === 'A') { this.href = url; } else if (nodeName === 'INPUT') { this.value = url; + if (path === '/edit') { + this.value += hash; + } } else if (nodeName === 'TEXTAREA') { - this.value = ('' + documentTitle + '<' + 'script src="' + jsbin.static + '/js/embed.js"><' + '/script>').replace(/<>"&/g, function (m) { + this.value = ('' + documentTitle + '<' + 'script src="' + jsbin.static + '/js/embed.js"><' + '/script>').replace(/<>"&/g, function (m) { return { '<': '<', '>': '>', @@ -377,7 +387,9 @@ function saveCode(method, ajax, ajaxCallback) { if (window.history && window.history.pushState) { // updateURL(edit); - window.history.pushState(null, '', jsbin.getURL() + '/edit'); + var hash = panels.getHighlightLines(); + if (hash) hash = '#' + hash; + window.history.pushState(null, '', jsbin.getURL() + '/edit' + hash); sessionStorage.setItem('url', jsbin.getURL()); } else { window.location.hash = data.edit; diff --git a/public/js/editors/editors.js b/public/js/editors/editors.js index 88b65a35..b652d958 100644 --- a/public/js/editors/editors.js +++ b/public/js/editors/editors.js @@ -306,7 +306,7 @@ panels.savecontent = function () { } }; -panels.highlightLines = function (cm, lines, string) { +panels.getHighlightLines = function () { 'use strict'; var hash = []; var lines = ''; @@ -319,13 +319,8 @@ panels.highlightLines = function (cm, lines, string) { hash.push(name.substr(0, 1).toUpperCase() + ':L' + lines); } } - - if (hash.length) { - window.location.hash = hash.join(','); - } else { - window.location.hash = ''; - } } + return hash.join(','); }; panels.focus = function (panel) { diff --git a/public/js/editors/panel.js b/public/js/editors/panel.js index bf90f123..670a2c3b 100644 --- a/public/js/editors/panel.js +++ b/public/js/editors/panel.js @@ -120,7 +120,7 @@ var Panel = function (name, settings) { panel.editor = CodeMirror.fromTextArea(panel.el, cmSettings); panel.editor.on('highlightLines', function () { - panels.highlightLines.apply(this, arguments); + window.location.hash = panels.getHighlightLines(); }); // Bind events using CM3 syntax From 1ce9c1a227e67094a4ebe71ac0881da8f19e6b2a Mon Sep 17 00:00:00 2001 From: Giulia Alfonsi Date: Fri, 20 Jun 2014 15:55:43 +0100 Subject: [PATCH 239/321] Show coupon input only if requested on query string --- lib/routes.js | 7 ++++++- views/upgrade.html | 6 ++++-- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/lib/routes.js b/lib/routes.js index 75c03220..423c8a25 100644 --- a/lib/routes.js +++ b/lib/routes.js @@ -170,6 +170,10 @@ module.exports = function (app) { var referrer = req.get('referer'); var stripeKey = undefsafe(config, 'payment.stripe.public'); var stripeProMonthURL = undefsafe(config, 'payment.stripe.urls.month'); + var showCoupon = false; + if (req.query.coupon === 'true') { + showCoupon = true; + } res.render('upgrade', { layout: 'sub/layout', @@ -180,7 +184,8 @@ module.exports = function (app) { backersList: backersList, cachebust: app.set('is_production') ? '?' + app.set('version') : '', stripeKey: stripeKey, - stripeProMonthURL: stripeProMonthURL + stripeProMonthURL: stripeProMonthURL, + showCoupon: showCoupon }); }); diff --git a/views/upgrade.html b/views/upgrade.html index fa218f0c..1e1cb2f2 100644 --- a/views/upgrade.html +++ b/views/upgrade.html @@ -27,8 +27,10 @@ data-label="Upgrade"> - Click here if you have a code - + {{#if showCoupon}} + Click here if you have a code + + {{/if}} From da39f2b6b6082c305b356b2f709555757af9b357 Mon Sep 17 00:00:00 2001 From: Remy Sharp Date: Tue, 17 Jun 2014 21:42:40 +0100 Subject: [PATCH 240/321] Tweaks --- lib/data/features.json | 18 +++++++++++------- public/css/upgrade.css | 3 ++- views/upgrade.html | 4 ++-- 3 files changed, 15 insertions(+), 10 deletions(-) diff --git a/lib/data/features.json b/lib/data/features.json index a27eb2cb..2d2db869 100644 --- a/lib/data/features.json +++ b/lib/data/features.json @@ -11,6 +11,10 @@ "name": "Dropbox Sync", "user": "pro" }, + { + "name": "Read & write API access", + "user": "pro" + }, { "name": "Direct support", "user": "pro" @@ -24,23 +28,23 @@ "user": "free" }, { - "name": "Codecasting", + "name": "Codecasting (unlimited connections)", "user": "anon" }, { - "name": "Custom starting template", + "name": "Live reload (unlimited connections)", "user": "anon" }, { - "name": "Multiple external resources", + "name": "Custom starting code", + "user": "anon" + }, + { + "name": "Unlimited external resources", "user": "anon" }, { "name": "Custom libraries", "user": "anon" - }, - { - "name": "Remote rendering", - "user": "anon" } ] diff --git a/public/css/upgrade.css b/public/css/upgrade.css index 7d2027e4..bac40c33 100644 --- a/public/css/upgrade.css +++ b/public/css/upgrade.css @@ -41,7 +41,8 @@ td { td.feature { text-align:left; - width:auto; + width: auto; + min-width:230px; } .coupon-btn { diff --git a/views/upgrade.html b/views/upgrade.html index 1e1cb2f2..4f2d38fa 100644 --- a/views/upgrade.html +++ b/views/upgrade.html @@ -73,7 +73,7 @@ access to tech (like the version of JS Bin that works without a web connection and entirely from a usb stick with zero install).

-

Supporters

+ From ba868c93f786831a31240347d501d2cf8010d0b4 Mon Sep 17 00:00:00 2001 From: Giulia Alfonsi Date: Fri, 20 Jun 2014 16:01:13 +0100 Subject: [PATCH 241/321] Removed link for click to show coupon input --- public/css/upgrade.css | 1 - public/js/account/upgrade.js | 6 ------ views/upgrade.html | 1 - 3 files changed, 8 deletions(-) diff --git a/public/css/upgrade.css b/public/css/upgrade.css index 7d2027e4..5549a699 100644 --- a/public/css/upgrade.css +++ b/public/css/upgrade.css @@ -49,7 +49,6 @@ td.feature { } #coupon_code { - visibility:hidden; font-size:14px; } diff --git a/public/js/account/upgrade.js b/public/js/account/upgrade.js index a8d85b6d..8fa879bf 100644 --- a/public/js/account/upgrade.js +++ b/public/js/account/upgrade.js @@ -10,10 +10,4 @@ $form.attr('action', originalAction + '?' + $input.val()); }); - var $couponBtn = $('.coupon-btn'); - $couponBtn.on('click', function (event) { - event.preventDefault(); - $input.css('visibility', 'visible'); - }); - }()); diff --git a/views/upgrade.html b/views/upgrade.html index 1e1cb2f2..fe2a7d86 100644 --- a/views/upgrade.html +++ b/views/upgrade.html @@ -28,7 +28,6 @@ {{#if showCoupon}} - Click here if you have a code {{/if}} From 791cdbe9e80fbbc056f2685445a7c924b741e0ff Mon Sep 17 00:00:00 2001 From: Remy Sharp Date: Fri, 20 Jun 2014 16:08:31 +0100 Subject: [PATCH 242/321] Update feature flags --- lib/features.js | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/lib/features.js b/lib/features.js index 0bf52129..11e7837d 100644 --- a/lib/features.js +++ b/lib/features.js @@ -98,13 +98,9 @@ var flags = { vanity: pro, // live June 16, 2014-05-27 - dropbox: function (req) { - return alpha(req); - }, + dropbox: pro, // live June 20, 2014 - assets: function (req) { - return alpha(req); - }, + assets: false, // disabled June 20, 2014 revisionless: function (req) { return team(req); From 318feaefb106bc5a3233ce04aec57968c41e4a9d Mon Sep 17 00:00:00 2001 From: Remy Sharp Date: Fri, 20 Jun 2014 16:11:28 +0100 Subject: [PATCH 243/321] 3.14.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 73e13fff..6b9fb0b2 100644 --- a/package.json +++ b/package.json @@ -9,7 +9,7 @@ "name": "jsbin", "description": "Collaborative JavaScript Debugging App", "main": "./lib/app", - "version": "3.13.35", + "version": "3.14.0", "preferGlobal": "true", "homepage": "http://jsbin.com", "bin": "./bin/jsbin", From 1374d6e4cdfb28eb946ec9c9e7942c0663a60a69 Mon Sep 17 00:00:00 2001 From: Remy Sharp Date: Fri, 20 Jun 2014 16:51:51 +0100 Subject: [PATCH 244/321] Fixed default jshint --- lib/data/welcome-panel.json | 20 ++++++++++++-------- public/js/account/preferences-settings.js | 4 +++- public/js/chrome/last-bin.js | 2 +- views/partials/welcome-panel.html | 2 +- views/upgrade.html | 6 +++--- 5 files changed, 20 insertions(+), 14 deletions(-) diff --git a/lib/data/welcome-panel.json b/lib/data/welcome-panel.json index cff438bd..9fa3aa84 100644 --- a/lib/data/welcome-panel.json +++ b/lib/data/welcome-panel.json @@ -1,11 +1,11 @@ { "features": { - "title": "JS BIN features", + "title": "JS Bin features", "link": "http://jsbin.com/help/features", "data": [ { "title": "Getting started with JS Bin", - "link": "http://jsbin.com" + "link": "http://jsbin.com/help/getting-started" }, { "title": "Keyboard Shortcuts", @@ -34,11 +34,11 @@ "link": "http://jsbin.com/help/features" }, { - "title": "Your own subdomain", + "title": "Vanity URLs", "link": "http://jsbin.com/help/features" }, { - "title": "Direct support (rather that via GitHub)", + "title": "Read & write API", "link": "http://jsbin.com/help/features" } ] @@ -48,8 +48,8 @@ "link": "http://jsbin.com/blog", "data": [ { - "title": "SVG support and settings live", - "link": "http://jsbin.com/blog/twdtw-8-svg-settings" + "title": "JSHint, line highlighting and more", + "link": "http://jsbin.com/blog/twdtw-10-jshint-highlighting-pro" } ] }, @@ -57,6 +57,10 @@ "title": "Help", "link": "http://jsbin.com/help", "data": [ + { + "title": "Versions: processors & more", + "link": "http://jsbin.com/help/versions" + }, { "title": "Delete a bin", "link": "http://jsbin.com/help/delete-a-bin" @@ -68,8 +72,8 @@ "link": "http://twitter.com/js_bin", "data": [ { - "title": "…and account settings is live for all now", - "link": "https://twitter.com/js_bin/status/471279979305918464" + "title": "We’re expecting to hit our 10 __millionth__ bin in around a week’s time. Wow.", + "link": "https://twitter.com/js_bin/status/479668198384865281" } ] }, diff --git a/public/js/account/preferences-settings.js b/public/js/account/preferences-settings.js index 095a774f..8b84b4e7 100644 --- a/public/js/account/preferences-settings.js +++ b/public/js/account/preferences-settings.js @@ -75,8 +75,10 @@ .on('click', { el: $hintsOptWrapper[hints[m]] }, function(event) { event.data.el.toggle(this.checked); }); + hintsOptionsVal[hints[m]] = JSON.stringify(currentSettings[ hints[m] + 'hintOptions'], undefined, 2); - if (hintsOptionsVal[hints[m]] === '{}') { + + if (hintsOptionsVal[hints[m]] === '{}' || !currentSettings[ hints[m] + 'hintOptions']) { hintsOptionsVal[hints[m]] = ''; } $hintsOptions[hints[m]] = $('#' + hints[m] + 'hintOptions') diff --git a/public/js/chrome/last-bin.js b/public/js/chrome/last-bin.js index c6a5232e..8a2099f3 100644 --- a/public/js/chrome/last-bin.js +++ b/public/js/chrome/last-bin.js @@ -34,7 +34,7 @@ var el = document.getElementById('back'); var back = readCookie('last'); - if (el && back !== null) { + if (el && back !== null && back !== '%2Fedit') { el.href = decodeURIComponent(back); } } diff --git a/views/partials/welcome-panel.html b/views/partials/welcome-panel.html index f697b5b7..a6b731e3 100644 --- a/views/partials/welcome-panel.html +++ b/views/partials/welcome-panel.html @@ -34,7 +34,7 @@ {{#pro-features}}
-

{{title}}{{#unless ../../user.pro}} (£10/month){{/unless}}

+

{{title}}{{#unless ../../user.pro}} ($15/month){{/unless}}

    {{#data}} {{#.}} diff --git a/views/upgrade.html b/views/upgrade.html index f952faff..b3faf0ca 100644 --- a/views/upgrade.html +++ b/views/upgrade.html @@ -7,7 +7,7 @@ Anonymous Free - Pro @ $12/month + Pro @ $15/month @@ -22,8 +22,8 @@ src="https://checkout.stripe.com/checkout.js" class="stripe-button" data-key="{{stripeKey}}" data-name="JB Bin Pro!" - data-description="Pro Account - $12 p/m" - data-amount="1200" + data-description="Pro Account - $15 p/m" + data-amount="1500" data-label="Upgrade"> From 9e1c8bbe67f47419a9485f39fccbc3bea900f1b1 Mon Sep 17 00:00:00 2001 From: Remy Sharp Date: Fri, 20 Jun 2014 16:52:03 +0100 Subject: [PATCH 245/321] 3.14.1 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 6b9fb0b2..902da6d0 100644 --- a/package.json +++ b/package.json @@ -9,7 +9,7 @@ "name": "jsbin", "description": "Collaborative JavaScript Debugging App", "main": "./lib/app", - "version": "3.14.0", + "version": "3.14.1", "preferGlobal": "true", "homepage": "http://jsbin.com", "bin": "./bin/jsbin", From 2002b1ed887fd84eecdf01d46200aa3190ad07b6 Mon Sep 17 00:00:00 2001 From: Mordy Tikotzky Date: Sun, 22 Jun 2014 17:02:46 -0400 Subject: [PATCH 246/321] add clear console button --- public/js/chrome/navigation.js | 5 +++++ views/index.html | 1 + 2 files changed, 6 insertions(+) diff --git a/public/js/chrome/navigation.js b/public/js/chrome/navigation.js index fe4ec334..7098546d 100644 --- a/public/js/chrome/navigation.js +++ b/public/js/chrome/navigation.js @@ -221,6 +221,11 @@ $('#runconsole').click(function () { return false; }); +$('#clearconsole').click(function () { + jsconsole.clear(); + return false; +}); + $('#showhelp').click(function () { $body.toggleClass('keyboardHelp'); keyboardHelpVisible = $body.is('.keyboardHelp'); diff --git a/views/index.html b/views/index.html index 4d980ab5..a8daf392 100644 --- a/views/index.html +++ b/views/index.html @@ -345,6 +345,7 @@ Console +
    From 93891048ca7c49a6492c42378f2b1a43e0b498f0 Mon Sep 17 00:00:00 2001 From: Peter Blazejewicz Date: Fri, 27 Jun 2014 00:14:48 +0200 Subject: [PATCH 247/321] Update Bootstrap to version 3.2. Closes #1604 New version of Bootstrap has been released. This commit updates version used by JSBin libraries. --- public/js/editors/libraries.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/public/js/editors/libraries.js b/public/js/editors/libraries.js index a180d8d2..c90bcea5 100644 --- a/public/js/editors/libraries.js +++ b/public/js/editors/libraries.js @@ -99,8 +99,8 @@ var libraries = [ { 'url': [ 'http://code.jquery.com/jquery.min.js', - 'http://maxcdn.bootstrapcdn.com/bootstrap/3.1.1/css/bootstrap.min.css', - 'http://maxcdn.bootstrapcdn.com/bootstrap/3.1.1/js/bootstrap.min.js' + 'http://maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css', + 'http://maxcdn.bootstrapcdn.com/bootstrap/3.2.0/js/bootstrap.min.js' ], 'label': 'Bootstrap Latest', 'group': 'Bootstrap' From 4ec61816ded34091d60cd4360c4053d01370eac1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=CC=88rn=20Zaefferer?= Date: Fri, 27 Jun 2014 11:25:56 +0200 Subject: [PATCH 248/321] Add jQuery UI 1.11.0 --- public/js/editors/libraries.js | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/public/js/editors/libraries.js b/public/js/editors/libraries.js index a180d8d2..390b3eb4 100644 --- a/public/js/editors/libraries.js +++ b/public/js/editors/libraries.js @@ -33,6 +33,15 @@ var libraries = [ 'label': 'jQuery UI WIP (via git)', 'group': 'jQuery UI' }, + { + 'url': [ + 'http://code.jquery.com/ui/1.11.0/themes/smoothness/jquery-ui.min.css', + 'http://code.jquery.com/jquery-1.11.0.min.js', + 'http://code.jquery.com/ui/1.11.0/jquery-ui.min.js' + ], + 'label': 'jQuery UI 1.11.0', + 'group': 'jQuery UI' + }, { 'url': [ 'http://code.jquery.com/ui/1.10.4/themes/smoothness/jquery-ui.min.css', From 2ef36f220f72f38dcfd39eb16a75648ccbba0bb6 Mon Sep 17 00:00:00 2001 From: Tomek Wytrebowicz Date: Fri, 27 Jun 2014 17:10:52 +0200 Subject: [PATCH 249/321] Update Polymer 0.3.0 -> 0.3.3 --- public/js/editors/libraries.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/public/js/editors/libraries.js b/public/js/editors/libraries.js index a180d8d2..d2878c7d 100644 --- a/public/js/editors/libraries.js +++ b/public/js/editors/libraries.js @@ -464,10 +464,10 @@ var libraries = [ }, { 'url': [ - '//cdnjs.cloudflare.com/ajax/libs/polymer/0.3.0/platform.js', - '//cdnjs.cloudflare.com/ajax/libs/polymer/0.3.0/polymer.js' + '//cdnjs.cloudflare.com/ajax/libs/polymer/0.3.3/platform.js', + '//cdnjs.cloudflare.com/ajax/libs/polymer/0.3.3/polymer.js' ], - 'label': 'Polymer 0.3.0' + 'label': 'Polymer 0.3.3' }, { 'url': '//netdna.bootstrapcdn.com/font-awesome/4.0.3/css/font-awesome.min.css', From 42d7581aff9cc12bb061c3cce0050f44258393c4 Mon Sep 17 00:00:00 2001 From: Mmis1000 Date: Sat, 28 Jun 2014 14:09:40 +0800 Subject: [PATCH 250/321] update Less.js to 1.7.3 --- package.json | 2 +- public/js/processors/processor.js | 2 +- public/js/vendor/less-1.4.2.min.js | 11 ----------- public/js/vendor/less-1.7.3.min.js | 16 ++++++++++++++++ 4 files changed, 18 insertions(+), 13 deletions(-) delete mode 100644 public/js/vendor/less-1.4.2.min.js create mode 100644 public/js/vendor/less-1.7.3.min.js diff --git a/package.json b/package.json index 902da6d0..a37ace6f 100644 --- a/package.json +++ b/package.json @@ -29,7 +29,7 @@ "sqlite3": "~2.2.0", "nodemailer": "0.3.20", "commander": "1.0.0", - "less": "~1.4.2", + "less": "~1.7.3", "jade": "0.26.3", "stylus": "0.28.2", "flatten.js": "0.1.0", diff --git a/public/js/processors/processor.js b/public/js/processors/processor.js index bbc8e346..2e546036 100644 --- a/public/js/processors/processor.js +++ b/public/js/processors/processor.js @@ -277,7 +277,7 @@ var processors = jsbin.processors = (function () { id: 'less', target: 'css', extensions: ['less'], - url: jsbin.static + '/js/vendor/less-1.4.2.min.js', + url: jsbin.static + '/js/vendor/less-1.7.3.min.js', init: function (ready) { // In CodeMirror 4, less is now included in the css mode, so no files to load ready(); diff --git a/public/js/vendor/less-1.4.2.min.js b/public/js/vendor/less-1.4.2.min.js deleted file mode 100644 index e4a34ff2..00000000 --- a/public/js/vendor/less-1.4.2.min.js +++ /dev/null @@ -1,11 +0,0 @@ -/* - * LESS - Leaner CSS v1.4.2 - * http://lesscss.org - * - * Copyright (c) 2009-2013, Alexis Sellier - * Licensed under the Apache 2.0 License. - * - * @licence - */(function(e,t){function n(t){return e.less[t.split("/")[1]]}function f(){r.env==="development"?(r.optimization=0,r.watchTimer=setInterval(function(){r.watchMode&&g(function(e,t,n,i,s){e?k(e,i.href):t&&S(t.toCSS(r),i,s.lastModified)})},r.poll)):r.optimization=3}function m(){var e=document.getElementsByTagName("style");for(var t=0;t0&&(s.splice(o-1,2),o-=2)}return i.hostPart=r[1],i.directories=s,i.path=r[1]+s.join("/"),i.fileUrl=i.path+(r[4]||""),i.url=i.fileUrl+(r[5]||""),i}function w(t,n,i,s){var o=b(t.href,e.location.href),u=o.url,a=l&&l.getItem(u),f=l&&l.getItem(u+":timestamp"),c={css:a,timestamp:f},h,p={relativeUrls:r.relativeUrls,currentDirectory:o.path,filename:u};t instanceof r.tree.parseEnv?(h=new r.tree.parseEnv(t),p.entryPath=h.currentFileInfo.entryPath,p.rootpath=h.currentFileInfo.rootpath,p.rootFilename=h.currentFileInfo.rootFilename):(h=new r.tree.parseEnv(r),h.mime=t.type,p.entryPath=o.path,p.rootpath=r.rootpath||o.path,p.rootFilename=u),h.relativeUrls&&(r.rootpath?p.rootpath=b(r.rootpath+y(o.path,p.entryPath)).path:p.rootpath=o.path),x(u,t.type,function(e,a){v+=e.replace(/@import .+?;/ig,"");if(!i&&c&&a&&(new Date(a)).valueOf()===(new Date(c.timestamp)).valueOf())S(c.css,t),n(null,null,e,t,{local:!0,remaining:s},u);else try{h.contents[u]=e,h.paths=[o.path],h.currentFileInfo=p,(new r.Parser(h)).parse(e,function(r,i){if(r)return n(r,null,null,t);try{n(r,i,e,t,{local:!1,lastModified:a,remaining:s},u),h.currentFileInfo.rootFilename===u&&N(document.getElementById("less-error-message:"+E(u)))}catch(r){n(r,null,null,t)}})}catch(f){n(f,null,null,t)}},function(e,r){n({type:"File",message:"'"+r+"' wasn't found ("+e+")"},null,null,t)})}function E(e){return e.replace(/^[a-z-]+:\/+?[^\/]+/,"").replace(/^\//,"").replace(/\.[a-zA-Z]+$/,"").replace(/[^\.\w-]+/g,"-").replace(/\./g,":")}function S(e,t,n){var r=t.href||"",i="less:"+(t.title||E(r)),s=document.getElementById(i),o=!1,u=document.createElement("style");u.setAttribute("type","text/css"),t.media&&u.setAttribute("media",t.media),u.id=i;if(u.styleSheet)try{u.styleSheet.cssText=e}catch(a){throw new Error("Couldn't reassign styleSheet.cssText.")}else u.appendChild(document.createTextNode(e)),o=s!==null&&s.childNodes.length>0&&u.childNodes.length>0&&s.firstChild.nodeValue===u.firstChild.nodeValue;var f=document.getElementsByTagName("head")[0];if(s==null||o===!1){var c=t&&t.nextSibling||null;(c||document.getElementsByTagName("head")[0]).parentNode.insertBefore(u,c)}s&&o===!1&&f.removeChild(s);if(n&&l){C("saving "+r+" to cache.");try{l.setItem(r,e),l.setItem(r+":timestamp",n)}catch(a){C("failed to save")}}}function x(e,t,n,i){function a(t,n,r){t.status>=200&&t.status<300?n(t.responseText,t.getResponseHeader("Last-Modified")):typeof r=="function"&&r(t.status,e)}var s=T(),u=o?r.fileAsync:r.async;typeof s.overrideMimeType=="function"&&s.overrideMimeType("text/css"),s.open("GET",e,u),s.setRequestHeader("Accept",t||"text/x-less, text/css; q=0.9, */*; q=0.5"),s.send(null),o&&!r.fileAsync?s.status===0||s.status>=200&&s.status<300?n(s.responseText):i(s.status,e):u?s.onreadystatechange=function(){s.readyState==4&&a(s,n,i)}:a(s,n,i)}function T(){if(e.XMLHttpRequest)return new XMLHttpRequest;try{return new ActiveXObject("MSXML2.XMLHTTP.3.0")}catch(t){return C("browser doesn't support AJAX."),null}}function N(e){return e&&e.parentNode.removeChild(e)}function C(e){r.env=="development"&&typeof console!="undefined"&&console.log("less: "+e)}function k(e,n){var i="less-error-message:"+E(n||""),s='
  • {content}
  • ',o=document.createElement("div"),u,a,f=[],l=e.filename||n,c=l.match(/([^\/]+(\?.*)?)$/)[1];o.id=i,o.className="less-error-message",a="

    "+(e.type||"Syntax")+"Error: "+(e.message||"There is an error in your .less file")+"

    "+'

    in '+c+" ";var h=function(e,n,r){e.extract[n]!=t&&f.push(s.replace(/\{line\}/,(parseInt(e.line)||0)+(n-1)).replace(/\{class\}/,r).replace(/\{content\}/,e.extract[n]))};e.extract?(h(e,0,""),h(e,1,"line"),h(e,2,""),a+="on line "+e.line+", column "+(e.column+1)+":

    "+"
      "+f.join("")+"
    "):e.stack&&(a+="
    "+e.stack.split("\n").slice(1).join("
    ")),o.innerHTML=a,S([".less-error-message ul, .less-error-message li {","list-style-type: none;","margin-right: 15px;","padding: 4px 0;","margin: 0;","}",".less-error-message label {","font-size: 12px;","margin-right: 15px;","padding: 4px 0;","color: #cc7777;","}",".less-error-message pre {","color: #dd6666;","padding: 4px 0;","margin: 0;","display: inline-block;","}",".less-error-message pre.line {","color: #ff0000;","}",".less-error-message h3 {","font-size: 20px;","font-weight: bold;","padding: 15px 0 5px 0;","margin: 0;","}",".less-error-message a {","color: #10a","}",".less-error-message .error {","color: red;","font-weight: bold;","padding-bottom: 2px;","border-bottom: 1px dashed red;","}"].join("\n"),{title:"error-message"}),o.style.cssText=["font-family: Arial, sans-serif","border: 1px solid #e00","background-color: #eee","border-radius: 5px","-webkit-border-radius: 5px","-moz-border-radius: 5px","color: #e00","padding: 15px","margin-bottom: 15px"].join(";"),r.env=="development"&&(u=setInterval(function(){document.body&&(document.getElementById(i)?document.body.replaceChild(o,document.getElementById(i)):document.body.insertBefore(o,document.body.firstChild),clearInterval(u))},10))}var r,i,s;typeof environment=="object"&&{}.toString.call(environment)==="[object Environment]"?(typeof e=="undefined"?r={}:r=e.less={},i=r.tree={},r.mode="rhino"):typeof e=="undefined"?(r=exports,i=n("./tree"),r.mode="node"):(typeof e.less=="undefined"&&(e.less={}),r=e.less,i=e.less.tree={},r.mode="browser"),r.Parser=function(t){function m(){a=c[u],f=o,h=o}function g(){c[u]=a,o=f,h=o}function y(){o>h&&(c[u]=c[u].slice(o-h),h=o)}function b(e){var t=e.charCodeAt(0);return t===32||t===10||t===9}function w(e){var t,n,r,i,a;if(e instanceof Function)return e.call(p.parsers);if(typeof e=="string")t=s.charAt(o)===e?e:null,r=1,y();else{y();if(!(t=e.exec(c[u])))return null;r=t[0].length}if(t)return E(r),typeof t=="string"?t:t.length===1?t[0]:t}function E(e){var t=o,n=u,r=o+c[u].length,i=o+=e;while(o=0&&t.charAt(n)!=="\n";n--)r++;return{line:typeof e=="number"?(t.slice(0,e).match(/\n/g)||"").length:null,column:r}}function k(e,t,i){var s=i.currentFileInfo.filename;return r.mode!=="browser"&&r.mode!=="rhino"&&(s=n("path").resolve(s)),{lineNumber:C(e,t).line+1,fileName:s}}function L(e,t){var n=N(e,t),r=C(e.index,n),i=r.line,s=r.column,o=n.split("\n");this.type=e.type||"Syntax",this.message=e.message,this.filename=e.filename||t.currentFileInfo.filename,this.index=e.index,this.line=typeof i=="number"?i+1:null,this.callLine=e.call&&C(e.call,n).line+1,this.callExtract=o[C(e.call,n).line],this.stack=e.stack,this.column=s,this.extract=[o[i-1],o[i],o[i+1]]}var s,o,u,a,f,l,c,h,p,d=this;t instanceof i.parseEnv||(t=new i.parseEnv(t));var v=this.imports={paths:t.paths||[],queue:[],files:t.files,contents:t.contents,mime:t.mime,error:null,push:function(e,n,i){var s=this;this.queue.push(e),r.Parser.importer(e,n,function(t,n,r){s.queue.splice(s.queue.indexOf(e),1);var o=r in s.files;s.files[r]=n,t&&!s.error&&(s.error=t),i(t,n,o)},t)}};return L.prototype=new Error,L.prototype.constructor=L,this.env=t=t||{},this.optimization="optimization"in this.env?this.env.optimization:1,p={imports:v,parse:function(e,a){var f,d,v,m,g,y,b=[],E,S=null;o=u=h=l=0,s=e.replace(/\r\n/g,"\n"),s=s.replace(/^\uFEFF/,""),c=function(e){var n=0,r=/(?:@\{[\w-]+\}|[^"'`\{\}\/\(\)\\])+/g,i=/\/\*(?:[^*]|\*+[^\/*])*\*+\/|\/\/.*/g,o=/"((?:[^"\\\r\n]|\\.)*)"|'((?:[^'\\\r\n]|\\.)*)'|`((?:[^`]|\\.)*)`/g,u=0,a,f=e[0],l;for(var c=0,h,p;c0?"missing closing `}`":"missing opening `{`",filename:t.currentFileInfo.filename},t)),e.map(function(e){return e.join("")})}([[]]);if(S)return a(new L(S,t));try{f=new i.Ruleset([],w(this.parsers.primary)),f.root=!0,f.firstRoot=!0}catch(x){return a(new L(x,t))}f.toCSS=function(e){var s,o,u;return function(s,o){s=s||{};var u,a=new i.evalEnv(s);typeof o=="object"&&!Array.isArray(o)&&(o=Object.keys(o).map(function(e){var t=o[e];return t instanceof i.Value||(t instanceof i.Expression||(t=new i.Expression([t])),t=new i.Value([t])),new i.Rule("@"+e,t,!1,0)}),a.frames=[new i.Ruleset(null,o)]);try{var f=e.call(this,a);(new i.joinSelectorVisitor).run(f),(new i.processExtendsVisitor).run(f);var l=f.toCSS({compress:Boolean(s.compress),dumpLineNumbers:t.dumpLineNumbers,strictUnits:Boolean(s.strictUnits)})}catch(c){throw new L(c,t)}return s.yuicompress&&r.mode==="node"?n("ycssmin").cssmin(l,s.maxLineLen):s.compress?l.replace(/(\s)+/g,"$1"):l}}(f.eval);if(o=0&&s.charAt(T)!=="\n";T--)N++;S={type:"Parse",message:"Unrecognised input",index:o,filename:t.currentFileInfo.filename,line:g,column:N,extract:[y[g-2],y[g-1],y[g]]}}var C=function(e){e=S||e||p.imports.error,e?(e instanceof L||(e=new L(e,t)),a(e)):a(null,f)};t.processImports!==!1?(new i.importVisitor(this.imports,C)).run(f):C()},parsers:{primary:function(){var e,t=[];while((e=w(this.extendRule)||w(this.mixin.definition)||w(this.rule)||w(this.ruleset)||w(this.mixin.call)||w(this.comment)||w(this.directive))||w(/^[\s\n]+/)||w(/^;+/))e&&t.push(e);return t},comment:function(){var e;if(s.charAt(o)!=="/")return;if(s.charAt(o+1)==="/")return new i.Comment(w(/^\/\/.*/),!0);if(e=w(/^\/\*(?:[^*]|\*+[^\/*])*\*+\/\n?/))return new i.Comment(e)},entities:{quoted:function(){var e,n=o,r,u=o;s.charAt(n)==="~"&&(n++,r=!0);if(s.charAt(n)!=='"'&&s.charAt(n)!=="'")return;r&&w("~");if(e=w(/^"((?:[^"\\\r\n]|\\.)*)"|'((?:[^'\\\r\n]|\\.)*)'/))return new i.Quoted(e[0],e[1]||e[2],r,u,t.currentFileInfo)},keyword:function(){var e;if(e=w(/^[_A-Za-z-][_A-Za-z0-9-]*/))return i.colors.hasOwnProperty(e)?new i.Color(i.colors[e].slice(1)):new i.Keyword(e)},call:function(){var e,n,r,s,a=o;if(!(e=/^([\w-]+|%|progid:[\w\.]+)\(/.exec(c[u])))return;e=e[1],n=e.toLowerCase();if(n==="url")return null;o+=e.length;if(n==="alpha"){s=w(this.alpha);if(typeof s!="undefined")return s}w("("),r=w(this.entities.arguments);if(!w(")"))return;if(e)return new i.Call(e,r,a,t.currentFileInfo)},arguments:function(){var e=[],t;while(t=w(this.entities.assignment)||w(this.expression)){e.push(t);if(!w(","))break}return e},literal:function(){return w(this.entities.dimension)||w(this.entities.color)||w(this.entities.quoted)||w(this.entities.unicodeDescriptor)},assignment:function(){var e,t;if((e=w(/^\w+(?=\s?=)/i))&&w("=")&&(t=w(this.entity)))return new i.Assignment(e,t)},url:function(){var e;if(s.charAt(o)!=="u"||!w(/^url\(/))return;return e=w(this.entities.quoted)||w(this.entities.variable)||w(/^(?:(?:\\[\(\)'"])|[^\(\)'"])+/)||"",S(")"),new i.URL(e.value!=null||e instanceof i.Variable?e:new i.Anonymous(e),t.currentFileInfo)},variable:function(){var e,n=o;if(s.charAt(o)==="@"&&(e=w(/^@@?[\w-]+/)))return new i.Variable(e,n,t.currentFileInfo)},variableCurly:function(){var e,n,r=o;if(s.charAt(o)==="@"&&(n=w(/^@\{([\w-]+)\}/)))return new i.Variable("@"+n[1],r,t.currentFileInfo)},color:function(){var e;if(s.charAt(o)==="#"&&(e=w(/^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})/)))return new i.Color(e[1])},dimension:function(){var e,t=s.charCodeAt(o);if(t>57||t<43||t===47||t==44)return;if(e=w(/^([+-]?\d*\.?\d+)(%|[a-z]+)?/))return new i.Dimension(e[1],e[2])},unicodeDescriptor:function(){var e;if(e=w(/^U\+[0-9a-fA-F?]+(\-[0-9a-fA-F?]+)?/))return new i.UnicodeDescriptor(e[0])},javascript:function(){var e,t=o,n;s.charAt(t)==="~"&&(t++,n=!0);if(s.charAt(t)!=="`")return;n&&w("~");if(e=w(/^`([^`]*)`/))return new i.JavaScript(e[1],o,n)}},variable:function(){var e;if(s.charAt(o)==="@"&&(e=w(/^(@[\w-]+)\s*:/)))return e[1]},extend:function(e){var t,n,r=o,s,u=[];if(!w(e?/^&:extend\(/:/^:extend\(/))return;do{s=null,t=[];for(;;){s=w(/^(all)(?=\s*(\)|,))/);if(s)break;n=w(this.element);if(!n)break;t.push(n)}s=s&&s[1],u.push(new i.Extend(new i.Selector(t),s,r))}while(w(","));return S(/^\)/),e&&S(/^;/),u},extendRule:function(){return this.extend(!0)},mixin:{call:function(){var e=[],n,r,u,a,f,l=o,c=s.charAt(o),h=!1;if(c!=="."&&c!=="#")return;m();while(n=w(/^[#.](?:[\w-]|\\(?:[A-Fa-f0-9]{1,6} ?|[^A-Fa-f0-9]))+/))e.push(new i.Element(r,n,o)),r=w(">");w("(")&&(u=this.mixin.args.call(this,!0).args,S(")")),u=u||[],w(this.important)&&(h=!0);if(e.length>0&&(w(";")||T("}")))return new i.mixin.Call(e,u,l,t.currentFileInfo,h);g()},args:function(e){var t=[],n=[],r,u=[],a,f,l,c,h,p={args:null,variadic:!1};for(;;){if(e)h=w(this.expression);else{w(this.comment);if(s.charAt(o)==="."&&w(/^\.{3}/)){p.variadic=!0,w(";")&&!r&&(r=!0),(r?n:u).push({variadic:!0});break}h=w(this.entities.variable)||w(this.entities.literal)||w(this.entities.keyword)}if(!h)break;l=null,h.throwAwayComments&&h.throwAwayComments(),c=h;var d=null;if(e){if(h.value.length==1)var d=h.value[0]}else d=h;if(d&&d instanceof i.Variable)if(w(":"))t.length>0&&(r&&x("Cannot mix ; and , as delimiter types"),a=!0),c=S(this.expression),l=f=d.name;else{if(!e&&w(/^\.{3}/)){p.variadic=!0,w(";")&&!r&&(r=!0),(r?n:u).push({name:h.name,variadic:!0});break}e||(f=l=d.name,c=null)}c&&t.push(c),u.push({name:l,value:c});if(w(","))continue;if(w(";")||r)a&&x("Cannot mix ; and , as delimiter types"),r=!0,t.length>1&&(c=new i.Value(t)),n.push({name:f,value:c}),f=null,t=[],a=!1}return p.args=r?n:u,p},definition:function(){var e,t=[],n,r,u,a,f,c=!1;if(s.charAt(o)!=="."&&s.charAt(o)!=="#"||T(/^[^{]*\}/))return;m();if(n=w(/^([#.](?:[\w-]|\\(?:[A-Fa-f0-9]{1,6} ?|[^A-Fa-f0-9]))+)\s*\(/)){e=n[1];var h=this.mixin.args.call(this,!1);t=h.args,c=h.variadic,w(")")||(l=o,g()),w(this.comment),w(/^when/)&&(f=S(this.conditions,"expected condition")),r=w(this.block);if(r)return new i.mixin.Definition(e,t,r,f,c);g()}}},entity:function(){return w(this.entities.literal)||w(this.entities.variable)||w(this.entities.url)||w(this.entities.call)||w(this.entities.keyword)||w(this.entities.javascript)||w(this.comment)},end:function(){return w(";")||T("}")},alpha:function(){var e;if(!w(/^\(opacity=/i))return;if(e=w(/^\d+/)||w(this.entities.variable))return S(")"),new i.Alpha(e)},element:function(){var e,t,n,r;n=w(this.combinator),e=w(/^(?:\d+\.\d+|\d+)%/)||w(/^(?:[.#]?|:*)(?:[\w-]|[^\x00-\x9f]|\\(?:[A-Fa-f0-9]{1,6} ?|[^A-Fa-f0-9]))+/)||w("*")||w("&")||w(this.attribute)||w(/^\([^()@]+\)/)||w(/^[\.#](?=@)/)||w(this.entities.variableCurly),e||w("(")&&(r=w(this.selector))&&w(")")&&(e=new i.Paren(r));if(e)return new i.Element(n,e,o)},combinator:function(){var e=s.charAt(o);if(e===">"||e==="+"||e==="~"||e==="|"){o++;while(s.charAt(o).match(/\s/))o++;return new i.Combinator(e)}return s.charAt(o-1).match(/\s/)?new i.Combinator(" "):new i.Combinator(null)},selector:function(){var e,t,n=[],r,u,a=[];while((u=w(this.extend))||(t=w(this.element))){u?a.push.apply(a,u):(a.length&&x("Extend can only be used at the end of selector"),r=s.charAt(o),n.push(t),t=null);if(r==="{"||r==="}"||r===";"||r===","||r===")")break}if(n.length>0)return new i.Selector(n,a);a.length&&x("Extend must be used to extend a selector, it cannot be used on its own")},attribute:function(){var e="",t,n,r;if(!w("["))return;(t=w(this.entities.variableCurly))||(t=S(/^(?:[_A-Za-z0-9-\*]*\|)?(?:[_A-Za-z0-9-]|\\.)+/));if(r=w(/^[|~*$^]?=/))n=w(this.entities.quoted)||w(/^[\w-]+/)||w(this.entities.variableCurly);return S("]"),new i.Attribute(t,r,n)},block:function(){var e;if(w("{")&&(e=w(this.primary))&&w("}"))return e},ruleset:function(){var e=[],n,r,u;m(),t.dumpLineNumbers&&(u=k(o,s,t));while(n=w(this.selector)){e.push(n),w(this.comment);if(!w(","))break;w(this.comment)}if(e.length>0&&(r=w(this.block))){var a=new i.Ruleset(e,r,t.strictImports);return t.dumpLineNumbers&&(a.debugInfo=u),a}l=o,g()},rule:function(e){var n,r,u=s.charAt(o),a;m();if(u==="."||u==="#"||u==="&")return;if(n=w(this.variable)||w(this.property)){r=!e&&(t.compress||n.charAt(0)==="@")?w(this.value)||w(this.anonymousValue):w(this.anonymousValue)||w(this.value),a=w(this.important);if(r&&w(this.end))return new i.Rule(n,r,a,f,t.currentFileInfo);l=o,g();if(r&&!e)return this.rule(!0)}},anonymousValue:function(){var e;if(e=/^([^@+\/'"*`(;{}-]*);/.exec(c[u]))return o+=e[0].length-1,new i.Anonymous(e[1])},"import":function(){var e,n,r=o;m();var s=w(/^@import?\s+/),u=(s?w(this.importOptions):null)||{};if(s&&(e=w(this.entities.quoted)||w(this.entities.url))){n=w(this.mediaFeatures);if(w(";"))return n=n&&new i.Value(n),new i.Import(e,n,u,r,t.currentFileInfo)}g()},importOptions:function(){var e,t={},n,r;if(!w("("))return null;do if(e=w(this.importOption)){n=e,r=!0;switch(n){case"css":n="less",r=!1;break;case"once":n="multiple",r=!1}t[n]=r;if(!w(","))break}while(e);return S(")"),t},importOption:function(){var e=w(/^(less|css|multiple|once)/);if(e)return e[1]},mediaFeature:function(){var e,n,r=[];do if(e=w(this.entities.keyword))r.push(e);else if(w("(")){n=w(this.property),e=w(this.value);if(!w(")"))return null;if(n&&e)r.push(new i.Paren(new i.Rule(n,e,null,o,t.currentFileInfo,!0)));else{if(!e)return null;r.push(new i.Paren(e))}}while(e);if(r.length>0)return new i.Expression(r)},mediaFeatures:function(){var e,t=[];do if(e=w(this.mediaFeature)){t.push(e);if(!w(","))break}else if(e=w(this.entities.variable)){t.push(e);if(!w(","))break}while(e);return t.length>0?t:null},media:function(){var e,n,r,u;t.dumpLineNumbers&&(u=k(o,s,t));if(w(/^@media/)){e=w(this.mediaFeatures);if(n=w(this.block))return r=new i.Media(n,e),t.dumpLineNumbers&&(r.debugInfo=u),r}},directive:function(){var e,n,r,u,a,f,l,c,h,p;if(s.charAt(o)!=="@")return;if(n=w(this["import"])||w(this.media))return n;m(),e=w(/^@[a-z-]+/);if(!e)return;l=e,e.charAt(1)=="-"&&e.indexOf("-",2)>0&&(l="@"+e.slice(e.indexOf("-",2)+1));switch(l){case"@font-face":c=!0;break;case"@viewport":case"@top-left":case"@top-left-corner":case"@top-center":case"@top-right":case"@top-right-corner":case"@bottom-left":case"@bottom-left-corner":case"@bottom-center":case"@bottom-right":case"@bottom-right-corner":case"@left-top":case"@left-middle":case"@left-bottom":case"@right-top":case"@right-middle":case"@right-bottom":c=!0;break;case"@page":case"@document":case"@supports":case"@keyframes":c=!0,h=!0;break;case"@namespace":p=!0}h&&(e+=" "+(w(/^[^{]+/)||"").trim());if(c){if(r=w(this.block))return new i.Directive(e,r)}else if((n=p?w(this.expression):w(this.entity))&&w(";")){var d=new i.Directive(e,n);return t.dumpLineNumbers&&(d.debugInfo=k(o,s,t)),d}g()},value:function(){var e,t=[],n;while(e=w(this.expression)){t.push(e);if(!w(","))break}if(t.length>0)return new i.Value(t)},important:function(){if(s.charAt(o)==="!")return w(/^! *important/)},sub:function(){var e,t;if(w("("))if(e=w(this.addition))return t=new i.Expression([e]),S(")"),t.parens=!0,t},multiplication:function(){var e,t,n,r,u,a=[];if(e=w(this.operand)){u=b(s.charAt(o-1));while(!T(/^\/[*\/]/)&&(n=w("/")||w("*"))){if(!(t=w(this.operand)))break;e.parensInOp=!0,t.parensInOp=!0,r=new i.Operation(n,[r||e,t],u),u=b(s.charAt(o-1))}return r||e}},addition:function(){var e,t,n,r,u;if(e=w(this.multiplication)){u=b(s.charAt(o-1));while((n=w(/^[-+]\s+/)||!u&&(w("+")||w("-")))&&(t=w(this.multiplication)))e.parensInOp=!0,t.parensInOp=!0,r=new i.Operation(n,[r||e,t],u),u=b(s.charAt(o-1));return r||e}},conditions:function(){var e,t,n=o,r;if(e=w(this.condition)){while(w(",")&&(t=w(this.condition)))r=new i.Condition("or",r||e,t,n);return r||e}},condition:function(){var e,t,n,r,s=o,u=!1;w(/^not/)&&(u=!0),S("(");if(e=w(this.addition)||w(this.entities.keyword)||w(this.entities.quoted))return(r=w(/^(?:>=|=<|[<=>])/))?(t=w(this.addition)||w(this.entities.keyword)||w(this.entities.quoted))?n=new i.Condition(r,e,t,s,u):x("expected expression"):n=new i.Condition("=",e,new i.Keyword("true"),s,u),S(")"),w(/^and/)?new i.Condition("and",n,w(this.condition)):n},operand:function(){var e,t=s.charAt(o+1);s.charAt(o)==="-"&&(t==="@"||t==="(")&&(e=w("-"));var n=w(this.sub)||w(this.entities.dimension)||w(this.entities.color)||w(this.entities.variable)||w(this.entities.call);return e&&(n.parensInOp=!0,n=new i.Negative(n)),n},expression:function(){var e,t,n=[],r;while(e=w(this.addition)||w(this.entity))n.push(e),!T(/^\/[\/*]/)&&(t=w("/"))&&n.push(new i.Anonymous(t));if(n.length>0)return new i.Expression(n)},property:function(){var e;if(e=w(/^(\*?-?[_a-zA-Z0-9-]+)\s*:/))return e[1]}}}};if(r.mode==="browser"||r.mode==="rhino")r.Parser.importer=function(e,t,n,r){!/^([a-z-]+:)?\//.test(e)&&t.currentDirectory&&(e=t.currentDirectory+e);var i=r.toSheet(e);i.processImports=!1,i.currentFileInfo=t,w(i,function(e,t,r,i,s,o){n.call(null,e,t,o)},!0)};(function(r){function u(e){return r.functions.hsla(e.h,e.s,e.l,e.a)}function a(e,t){return e instanceof r.Dimension&&e.unit.is("%")?parseFloat(e.value*t/100):f(e)}function f(e){if(e instanceof r.Dimension)return parseFloat(e.unit.is("%")?e.value/100:e.value);if(typeof e=="number")return e;throw{error:"RuntimeError",message:"color functions take numbers as parameters"}}function l(e){return Math.min(1,Math.max(0,e))}r.functions={rgb:function(e,t,n){return this.rgba(e,t,n,1)},rgba:function(e,t,n,i){var s=[e,t,n].map(function(e){return a(e,256)});return i=f(i),new r.Color(s,i)},hsl:function(e,t,n){return this.hsla(e,t,n,1)},hsla:function(e,t,n,r){function o(e){return e=e<0?e+1:e>1?e-1:e,e*6<1?s+(i-s)*e*6:e*2<1?i:e*3<2?s+(i-s)*(2/3-e)*6:s}e=f(e)%360/360,t=l(f(t)),n=l(f(n)),r=l(f(r));var i=n<=.5?n*(t+1):n+t-n*t,s=n*2-i;return this.rgba(o(e+1/3)*255,o(e)*255,o(e-1/3)*255,r)},hsv:function(e,t,n){return this.hsva(e,t,n,1)},hsva:function(e,t,n,r){e=f(e)%360/360*360,t=f(t),n=f(n),r=f(r);var i,s;i=Math.floor(e/60%6),s=e/60-i;var o=[n,n*(1-t),n*(1-s*t),n*(1-(1-s)*t)],u=[[0,3,1],[2,0,1],[1,0,3],[1,2,0],[3,1,0],[0,1,2]];return this.rgba(o[u[i][0]]*255,o[u[i][1]]*255,o[u[i][2]]*255,r)},hue:function(e){return new r.Dimension(Math.round(e.toHSL().h))},saturation:function(e){return new r.Dimension(Math.round(e.toHSL().s*100),"%")},lightness:function(e){return new r.Dimension(Math.round(e.toHSL().l*100),"%")},hsvhue:function(e){return new r.Dimension(Math.round(e.toHSV().h))},hsvsaturation:function(e){return new r.Dimension(Math.round(e.toHSV().s*100),"%")},hsvvalue:function(e){return new r.Dimension(Math.round(e.toHSV().v*100),"%")},red:function(e){return new r.Dimension(e.rgb[0])},green:function(e){return new r.Dimension(e.rgb[1])},blue:function(e){return new r.Dimension(e.rgb[2])},alpha:function(e){return new r.Dimension(e.toHSL().a)},luma:function(e){return new r.Dimension(Math.round(e.luma()*e.alpha*100),"%")},saturate:function(e,t){var n=e.toHSL();return n.s+=t.value/100,n.s=l(n.s),u(n)},desaturate:function(e,t){var n=e.toHSL();return n.s-=t.value/100,n.s=l(n.s),u(n)},lighten:function(e,t){var n=e.toHSL();return n.l+=t.value/100,n.l=l(n.l),u(n)},darken:function(e,t){var n=e.toHSL();return n.l-=t.value/100,n.l=l(n.l),u(n)},fadein:function(e,t){var n=e.toHSL();return n.a+=t.value/100,n.a=l(n.a),u(n)},fadeout:function(e,t){var n=e.toHSL();return n.a-=t.value/100,n.a=l(n.a),u(n)},fade:function(e,t){var n=e.toHSL();return n.a=t.value/100,n.a=l(n.a),u(n)},spin:function(e,t){var n=e.toHSL(),r=(n.h+t.value)%360;return n.h=r<0?360+r:r,u(n)},mix:function(e,t,n){n||(n=new r.Dimension(50));var i=n.value/100,s=i*2-1,o=e.toHSL().a-t.toHSL().a,u=((s*o==-1?s:(s+o)/(1+s*o))+1)/2,a=1-u,f=[e.rgb[0]*u+t.rgb[0]*a,e.rgb[1]*u+t.rgb[1]*a,e.rgb[2]*u+t.rgb[2]*a],l=e.alpha*i+t.alpha*(1-i);return new r.Color(f,l)},greyscale:function(e){return this.desaturate(e,new r.Dimension(100))},contrast:function(e,t,n,r){if(!e.rgb)return null;typeof n=="undefined"&&(n=this.rgba(255,255,255,1)),typeof t=="undefined"&&(t=this.rgba(0,0,0,1));if(t.luma()>n.luma()){var i=n;n=t,t=i}return typeof r=="undefined"?r=.43:r=f(r),e.luma()*e.alpha=d){if(this.env.ieCompat!==!1)return this.env.silent||console.warn("Skipped data-uri embedding of %s because its size (%dKB) exceeds IE8-safe %dKB!",o,v,d),(new r.URL(i||t,this.currentFileInfo)).eval(this.env);this.env.silent||console.warn("WARNING: Embedding %s (%dKB) exceeds IE8's data-uri size limit of %dKB!",o,v,d)}p=f?p.toString("base64"):encodeURIComponent(p);var m="'data:"+s+","+p+"'";return new r.URL(new r.Anonymous(m))}},r._mime={_types:{".htm":"text/html",".html":"text/html",".gif":"image/gif",".jpg":"image/jpeg",".jpeg":"image/jpeg",".png":"image/png"},lookup:function(e){var i=n("path").extname(e),s=r._mime._types[i];if(s===t)throw new Error('Optional dependency "mime" is required for '+i);return s},charsets:{lookup:function(e){return e&&/^text\//.test(e)?"UTF-8":""}}};var i=[{name:"ceil"},{name:"floor"},{name:"sqrt"},{name:"abs"},{name:"tan",unit:""},{name:"sin",unit:""},{name:"cos",unit:""},{name:"atan",unit:"rad"},{name:"asin",unit:"rad"},{name:"acos",unit:"rad"}],s=function(e,t){return function(n){return t!=null&&(n=n.unify()),this._math(Math[e],t,n)}};for(var o=0;o255?255:e<0?0:e).toString(16),e.length===1?"0"+e:e}).join("");return n&&(r=r.split(""),r[0]==r[1]&&r[2]==r[3]&&r[4]==r[5]?r=r[0]+r[2]+r[4]:r=r.join("")),"#"+r},operate:function(t,n,r){var i=[];r instanceof e.Color||(r=r.toColor());for(var s=0;s<3;s++)i[s]=e.operate(t,n,this.rgb[s],r.rgb[s]);return new e.Color(i,this.alpha+r.alpha)},toHSL:function(){var e=this.rgb[0]/255,t=this.rgb[1]/255,n=this.rgb[2]/255,r=this.alpha,i=Math.max(e,t,n),s=Math.min(e,t,n),o,u,a=(i+s)/2,f=i-s;if(i===s)o=u=0;else{u=a>.5?f/(2-i-s):f/(i+s);switch(i){case e:o=(t-n)/f+(t255?255:e<0?0:e).toString(16),e.length===1?"0"+e:e}).join("")},compare:function(e){return e.rgb?e.rgb[0]===this.rgb[0]&&e.rgb[1]===this.rgb[1]&&e.rgb[2]===this.rgb[2]&&e.alpha===this.alpha?0:-1:-1}}}(n("../tree")),function(e){e.Comment=function(e,t){this.value=e,this.silent=!!t},e.Comment.prototype={type:"Comment",toCSS:function(e){return e.compress?"":this.value},eval:function(){return this}}}(n("../tree")),function(e){e.Condition=function(e,t,n,r,i){this.op=e.trim(),this.lvalue=t,this.rvalue=n,this.index=r,this.negate=i},e.Condition.prototype={type:"Condition",accept:function(e){this.lvalue=e.visit(this.lvalue),this.rvalue=e.visit(this.rvalue)},eval:function(e){var t=this.lvalue.eval(e),n=this.rvalue.eval(e),r=this.index,i,i=function(e){switch(e){case"and":return t&&n;case"or":return t||n;default:if(t.compare)i=t.compare(n);else{if(!n.compare)throw{type:"Type",message:"Unable to perform comparison",index:r};i=n.compare(t)}switch(i){case-1:return e==="<"||e==="=<";case 0:return e==="="||e===">="||e==="=<";case 1:return e===">"||e===">="}}}(this.op);return this.negate?!i:i}}}(n("../tree")),function(e){e.Dimension=function(n,r){this.value=parseFloat(n),this.unit=r&&r instanceof e.Unit?r:new e.Unit(r?[r]:t)},e.Dimension.prototype={type:"Dimension",accept:function(e){this.unit=e.visit(this.unit)},eval:function(e){return this},toColor:function(){return new e.Color([this.value,this.value,this.value])},toCSS:function(e){if(e&&e.strictUnits&&!this.unit.isSingular())throw new Error("Multiple units in dimension. Correct the units or use the unit function. Bad unit: "+this.unit.toString());var t=this.value,n=String(t);t!==0&&t<1e-6&&t>-0.000001&&(n=t.toFixed(20).replace(/0+$/,""));if(e&&e.compress){if(t===0&&!this.unit.isAngle())return n;t>0&&t<1&&(n=n.substr(1))}return n+this.unit.toCSS(e)},operate:function(t,n,r){var i=e.operate(t,n,this.value,r.value),s=this.unit.clone();if(n==="+"||n==="-"){if(s.numerator.length===0&&s.denominator.length===0)s.numerator=r.unit.numerator.slice(0),s.denominator=r.unit.denominator.slice(0);else if(r.unit.numerator.length!=0||s.denominator.length!=0){r=r.convertTo(this.unit.usedUnits());if(t.strictUnits&&r.unit.toString()!==s.toString())throw new Error("Incompatible units. Change the units or use the unit function. Bad units: '"+s.toString()+"' and '"+r.unit.toString()+"'.");i=e.operate(t,n,this.value,r.value)}}else n==="*"?(s.numerator=s.numerator.concat(r.unit.numerator).sort(),s.denominator=s.denominator.concat(r.unit.denominator).sort(),s.cancel()):n==="/"&&(s.numerator=s.numerator.concat(r.unit.denominator).sort(),s.denominator=s.denominator.concat(r.unit.numerator).sort(),s.cancel());return new e.Dimension(i,s)},compare:function(t){if(t instanceof e.Dimension){var n=this.unify(),r=t.unify(),i=n.value,s=r.value;return s>i?-1:s=1?this.numerator[0]:this.denominator.length>=1?this.denominator[0]:(!e||!e.strictUnits)&&this.backupUnit?this.backupUnit:""},toString:function(){var e,t=this.numerator.join("*");for(e=0;e0)for(n=0;n":e.compress?">":" > ","|":e.compress?"|":" | "}[this.value]}}}(n("../tree")),function(e){e.Expression=function(e){this.value=e},e.Expression.prototype={type:"Expression",accept:function(e){this.value=e.visit(this.value)},eval:function(t){var n,r=this.parens&&!this.parensInOp,i=!1;return r&&t.inParenthesis(),this.value.length>1?n=new e.Expression(this.value.map(function(e){return e.eval(t)})):this.value.length===1?(this.value[0].parens&&!this.value[0].parensInOp&&(i=!0),n=this.value[0].eval(t)):n=this,r&&t.outOfParenthesis(),this.parens&&this.parensInOp&&!t.isMathOn()&&!i&&(n=new e.Paren(n)),n},toCSS:function(e){return this.value.map(function(t){return t.toCSS?t.toCSS(e):""}).join(" ")},throwAwayComments:function(){this.value=this.value.filter(function(t){return!(t instanceof e.Comment)})}}}(n("../tree")),function(e){e.Extend=function(t,n,r){this.selector=t,this.option=n,this.index=r;switch(n){case"all":this.allowBefore=!0,this.allowAfter=!0;break;default:this.allowBefore=!1,this.allowAfter=!1}},e.Extend.prototype={type:"Extend",accept:function(e){this.selector=e.visit(this.selector)},eval:function(t){return new e.Extend(this.selector.eval(t),this.option,this.index)},clone:function(t){return new e.Extend(this.selector,this.option,this.index)},findSelfSelectors:function(e){var t=[],n;for(n=0;n1){var r=this.emptySelectors();n=new e.Ruleset(r,t.mediaBlocks),n.multiMedia=!0}return delete t.mediaBlocks,delete t.mediaPath,n},evalNested:function(t){var n,r,i=t.mediaPath.concat([this]);for(n=0;n0;n--)t.splice(n,0,new e.Anonymous("and"));return new e.Expression(t)})),new e.Ruleset([],[])},permute:function(e){if(e.length===0)return[];if(e.length===1)return e[0];var t=[],n=this.permute(e.slice(1));for(var r=0;r0){c=!0;for(a=0;athis.params.length)return!1;if(this.required>0&&n>this.params.length)return!1}r=Math.min(n,this.arity);for(var s=0;si.selectors[o].elements.length?Array.prototype.push.apply(r,i.find(new e.Selector(t.elements.slice(1)),n)):r.push(i);break}}),this._lookups[o]=r)},toCSS:function(t){var n=[],r=[],i=[],s=[],o,u,a;for(var f=0;f0){u=e.debugInfo(t,this),o=this.paths.map(function(e){return e.map(function(e){return e.toCSS(t)}).join("").trim()}).join(t.compress?",":",\n");for(var f=r.length-1;f>=0;f--)(r[f].slice(0,2)==="/*"||i.indexOf(r[f])===-1)&&i.unshift(r[f]);r=i,n.push(u+o+(t.compress?"{":" {\n ")+r.join(t.compress?"":"\n ")+(t.compress?"}":"\n}\n"))}return n.push(s),n.join("")+(t.compress?"\n":"")},joinSelectors:function(e,t,n){for(var r=0;r0)for(i=0;i0&&this.mergeElementsOnToSelectors(g,a);for(s=0;s0&&(l[0].elements=l[0].elements.slice(0),l[0].elements.push(new e.Element(f.combinator,"",0))),y.push(l);else for(o=0;o0?(h=l.slice(0),m=h.pop(),d=new e.Selector(m.elements.slice(0),r.extendList),v=!1):d=new e.Selector([],r.extendList),c.length>1&&(p=p.concat(c.slice(1))),c.length>0&&(v=!1,d.elements.push(new e.Element(f.combinator,c[0].elements[0].value,0)),d.elements=d.elements.concat(c[0].elements.slice(1))),v||h.push(d),h=h.concat(p),y.push(h)}a=y,g=[]}}g.length>0&&this.mergeElementsOnToSelectors(g,a);for(i=0;i0&&t.push(a[i])},mergeElementsOnToSelectors:function(t,n){var r,i,s;if(n.length==0){n.push([new e.Selector(t)]);return}for(r=0;r0?i[i.length-1]=new e.Selector(i[i.length-1].elements.concat(t),i[i.length-1].extendList):i.push(new e.Selector(t))}}}(n("../tree")),function(e){e.Selector=function(e,t){this.elements=e,this.extendList=t||[]},e.Selector.prototype={type:"Selector",accept:function(e){this.elements=e.visit(this.elements),this.extendList=e.visit(this.extendList)},match:function(e){var t=this.elements,n=t.length,r,i,s,o;r=e.elements.slice(e.elements.length&&e.elements[0].value==="&"?1:0),i=r.length,s=Math.min(n,i);if(i===0||n1?"["+e.value.map(function(e){return e.toCSS(!1)}).join(", ")+"]":e.toCSS(!1)}}(n("./tree")),function(e){var t=["paths","optimization","files","contents","relativeUrls","strictImports","dumpLineNumbers","compress","processImports","syncImport","mime","currentFileInfo"];e.parseEnv=function(e){r(e,this,t),this.contents||(this.contents={}),this.files||(this.files={});if(!this.currentFileInfo){var n=e&&e.filename||"input",i=n.replace(/[^\/\\]*$/,"");e&&(e.filename=null),this.currentFileInfo={filename:n,relativeUrls:this.relativeUrls,rootpath:e&&e.rootpath||"",currentDirectory:i,entryPath:i,rootFilename:n}}},e.parseEnv.prototype.toSheet=function(t){var n=new e.parseEnv(this);return n.href=t,n.type=this.mime,n};var n=["silent","verbose","compress","yuicompress","ieCompat","strictMath","strictUnits"];e.evalEnv=function(e,t){r(e,this,n),this.frames=t||[]},e.evalEnv.prototype.inParenthesis=function(){this.parensStack||(this.parensStack=[]),this.parensStack.push(!0)},e.evalEnv.prototype.outOfParenthesis=function(){this.parensStack.pop()},e.evalEnv.prototype.isMathOn=function(){return this.strictMath?this.parensStack&&this.parensStack.length:!0},e.evalEnv.prototype.isPathRelative=function(e){return!/^(?:[a-z-]+:|\/)/.test(e)};var r=function(e,t,n){if(!e)return;for(var r=0;r100){var d="{unable to calculate}",v="{unable to calculate}";try{d=u[0].selfSelectors[0].toCSS(),v=u[0].selector.toCSS()}catch(m){}throw{message:"extend circular reference detected. One of the circular extends is currently:"+d+":extend("+v+")"}}return u.concat(f.doExtendChaining(u,n,r+1))}return u},inInheritanceChain:function(e,t){if(e===t)return!0;if(t.parents){if(this.inInheritanceChain(e,t.parents[0]))return!0;if(this.inInheritanceChain(e,t.parents[1]))return!0}return!1},visitRule:function(e,t){t.visitDeeper=!1},visitMixinDefinition:function(e,t){t.visitDeeper=!1},visitSelector:function(e,t){t.visitDeeper=!1},visitRuleset:function(e,t){if(e.root)return;var n,r,i,s=this.allExtendsStack[this.allExtendsStack.length-1],o=[],u=this,a;for(i=0;i0&&f[c.matched].combinator.value!==o?c=null:c.matched++,c&&(c.finished=c.matched===f.length,c.finished&&!e.allowAfter&&(i+1i&&s>0&&(o[o.length-1].elements=o[o.length-1].elements.concat(n[i].elements.slice(s)),s=0,i++),o=o.concat(n.slice(i,l.pathIndex)),o.push(new e.Selector(a.elements.slice(s,l.index).concat([f]).concat(r.elements.slice(1)))),i=l.endPathIndex,s=l.endPathElementIndex,s>=a.elements.length&&(s=0,i++);return i0&&(o[o.length-1].elements=o[o.length-1].elements.concat(n[i].elements.slice(s)),s=0,i++),o=o.concat(n.slice(i,n.length)),o},visitRulesetOut:function(e){},visitMedia:function(e,t){var n=e.allExtends.concat(this.allExtendsStack[this.allExtendsStack.length-1]);n=n.concat(this.doExtendChaining(n,e.allExtends)),this.allExtendsStack.push(n)},visitMediaOut:function(e){this.allExtendsStack.length=this.allExtendsStack.length-1},visitDirective:function(e,t){var n=e.allExtends.concat(this.allExtendsStack[this.allExtendsStack.length-1]);n=n.concat(this.doExtendChaining(n,e.allExtends)),this.allExtendsStack.push(n)},visitDirectiveOut:function(e){this.allExtendsStack.length=this.allExtendsStack.length-1}}}(n("./tree"));var o=/^(file|chrome(-extension)?|resource|qrc|app):/.test(location.protocol);r.env=r.env||(location.hostname=="127.0.0.1"||location.hostname=="0.0.0.0"||location.hostname=="localhost"||location.port.length>0||o?"development":"production"),r.async=r.async||!1,r.fileAsync=r.fileAsync||!1,r.poll=r.poll||(o?1e3:1500);if(r.functions)for(var u in r.functions)r.tree.functions[u]=r.functions[u];var a=/!dumpLineNumbers:(comments|mediaquery|all)/.exec(location.hash);a&&(r.dumpLineNumbers=a[1]),r.watch=function(){return r.watchMode||(r.env="development",f()),this.watchMode=!0},r.unwatch=function(){return clearInterval(r.watchTimer),this.watchMode=!1},/!watch/.test(location.hash)&&r.watch();var l=null;if(r.env!="development")try{l=typeof e.localStorage=="undefined"?null:e.localStorage}catch(c){}var h=document.getElementsByTagName("link"),p=/^text\/(x-)?less$/;r.sheets=[];for(var d=0;d + * Licensed under the Apache v2 License. + * + */ + + /** * @license Apache v2 + */ + +!function(a,b){function c(b){return a.less[b.split("/")[1]]}function d(a,b){"undefined"!=typeof console&&w.logLevel>=b&&console.log("less: "+a)}function e(a){return a.replace(/^[a-z-]+:\/+?[^\/]+/,"").replace(/^\//,"").replace(/\.[a-zA-Z]+$/,"").replace(/[^\.\w-]+/g,"-").replace(/\./g,":")}function f(a,c){var e="{line} {content}",f=a.filename||c,g=[],h=(a.type||"Syntax")+"Error: "+(a.message||"There is an error in your .less file")+" in "+f+" ",i=function(a,c,d){a.extract[c]!==b&&g.push(e.replace(/\{line\}/,(parseInt(a.line,10)||0)+(c-1)).replace(/\{class\}/,d).replace(/\{content\}/,a.extract[c]))};a.extract?(i(a,0,""),i(a,1,"line"),i(a,2,""),h+="on line "+a.line+", column "+(a.column+1)+":\n"+g.join("\n")):a.stack&&(h+=a.stack),d(h,z.errors)}function g(a,b,c){var f=b.href||"",g="less:"+(b.title||e(f)),h=document.getElementById(g),i=!1,j=document.createElement("style");j.setAttribute("type","text/css"),b.media&&j.setAttribute("media",b.media),j.id=g,j.styleSheet||(j.appendChild(document.createTextNode(a)),i=null!==h&&h.childNodes.length>0&&j.childNodes.length>0&&h.firstChild.nodeValue===j.firstChild.nodeValue);var k=document.getElementsByTagName("head")[0];if(null===h||i===!1){var l=b&&b.nextSibling||null;l?l.parentNode.insertBefore(j,l):k.appendChild(j)}if(h&&i===!1&&h.parentNode.removeChild(h),j.styleSheet)try{j.styleSheet.cssText=a}catch(m){throw new Error("Couldn't reassign styleSheet.cssText.")}if(c&&D){d("saving "+f+" to cache.",z.info);try{D.setItem(f,a),D.setItem(f+":timestamp",c)}catch(m){d("failed to save",z.errors)}}}function h(a){return w.postProcessor&&"function"==typeof w.postProcessor&&(a=w.postProcessor.call(a,a)||a),a}function i(a,c){var d,f,h="less-error-message:"+e(c||""),i='
  • {content}
  • ',j=document.createElement("div"),k=[],l=a.filename||c,m=l.match(/([^\/]+(\?.*)?)$/)[1];j.id=h,j.className="less-error-message",f="

    "+(a.type||"Syntax")+"Error: "+(a.message||"There is an error in your .less file")+'

    in '+m+" ";var n=function(a,c,d){a.extract[c]!==b&&k.push(i.replace(/\{line\}/,(parseInt(a.line,10)||0)+(c-1)).replace(/\{class\}/,d).replace(/\{content\}/,a.extract[c]))};a.extract?(n(a,0,""),n(a,1,"line"),n(a,2,""),f+="on line "+a.line+", column "+(a.column+1)+":

      "+k.join("")+"
    "):a.stack&&(f+="
    "+a.stack.split("\n").slice(1).join("
    ")),j.innerHTML=f,g([".less-error-message ul, .less-error-message li {","list-style-type: none;","margin-right: 15px;","padding: 4px 0;","margin: 0;","}",".less-error-message label {","font-size: 12px;","margin-right: 15px;","padding: 4px 0;","color: #cc7777;","}",".less-error-message pre {","color: #dd6666;","padding: 4px 0;","margin: 0;","display: inline-block;","}",".less-error-message pre.line {","color: #ff0000;","}",".less-error-message h3 {","font-size: 20px;","font-weight: bold;","padding: 15px 0 5px 0;","margin: 0;","}",".less-error-message a {","color: #10a","}",".less-error-message .error {","color: red;","font-weight: bold;","padding-bottom: 2px;","border-bottom: 1px dashed red;","}"].join("\n"),{title:"error-message"}),j.style.cssText=["font-family: Arial, sans-serif","border: 1px solid #e00","background-color: #eee","border-radius: 5px","-webkit-border-radius: 5px","-moz-border-radius: 5px","color: #e00","padding: 15px","margin-bottom: 15px"].join(";"),"development"==w.env&&(d=setInterval(function(){document.body&&(document.getElementById(h)?document.body.replaceChild(j,document.getElementById(h)):document.body.insertBefore(j,document.body.firstChild),clearInterval(d))},10))}function j(a,b){w.errorReporting&&"html"!==w.errorReporting?"console"===w.errorReporting?f(a,b):"function"==typeof w.errorReporting&&w.errorReporting("add",a,b):i(a,b)}function k(a){var b=document.getElementById("less-error-message:"+e(a));b&&b.parentNode.removeChild(b)}function l(){}function m(a){w.errorReporting&&"html"!==w.errorReporting?"console"===w.errorReporting?l(a):"function"==typeof w.errorReporting&&w.errorReporting("remove",a):k(a)}function n(a){for(var b,c=document.getElementsByTagName("style"),d=0;d0&&(h.splice(c-1,2),c-=2)}return g.hostPart=f[1],g.directories=h,g.path=f[1]+h.join("/"),g.fileUrl=g.path+(f[4]||""),g.url=g.fileUrl+(f[5]||""),g}function p(a,b){var c,d,e,f,g=o(a),h=o(b),i="";if(g.hostPart!==h.hostPart)return"";for(d=Math.max(h.directories.length,g.directories.length),c=0;d>c&&h.directories[c]===g.directories[c];c++);for(f=h.directories.slice(c),e=g.directories.slice(c),c=0;c=200&&b.status<300?c(b.responseText,b.getResponseHeader("Last-Modified")):"function"==typeof d&&d(b.status,a)}var g=q(),h=y?w.fileAsync:w.async;"function"==typeof g.overrideMimeType&&g.overrideMimeType("text/css"),d("XHR: Getting '"+a+"'",z.debug),g.open("GET",a,h),g.setRequestHeader("Accept",b||"text/x-less, text/css; q=0.9, */*; q=0.5"),g.send(null),y&&!w.fileAsync?0===g.status||g.status>=200&&g.status<300?c(g.responseText):e(g.status,a):h?g.onreadystatechange=function(){4==g.readyState&&f(g,c,e)}:f(g,c,e)}function s(b,c,d,e){c&&c.currentDirectory&&!/^([a-z-]+:)?\//.test(b)&&(b=c.currentDirectory+b);var f=o(b,a.location.href),g=f.url,h={currentDirectory:f.path,filename:g};if(c?(h.entryPath=c.entryPath,h.rootpath=c.rootpath,h.rootFilename=c.rootFilename,h.relativeUrls=c.relativeUrls):(h.entryPath=f.path,h.rootpath=w.rootpath||f.path,h.rootFilename=g,h.relativeUrls=e.relativeUrls),h.relativeUrls&&(h.rootpath=e.rootpath?o(e.rootpath+p(f.path,h.entryPath)).path:f.path),e.useFileCache&&E[g])try{var i=E[g];d(null,i,g,h,{lastModified:new Date})}catch(j){d(j,null,g)}else r(g,e.mime,function(a,b){E[g]=a;try{d(null,a,g,h,{lastModified:b})}catch(c){d(c,null,g)}},function(a,b){d({type:"File",message:"'"+b+"' wasn't found ("+a+")"},null,g)})}function t(a,b,c,d,e){var f=new w.tree.parseEnv(w);f.mime=a.type,(e||w.globalVars)&&(f.useFileCache=!0),s(a.href,null,function(h,i,j,k,l){if(l){l.remaining=d;var n=D&&D.getItem(j),o=D&&D.getItem(j+":timestamp");if(!c&&o&&l.lastModified&&new Date(l.lastModified).valueOf()===new Date(o).valueOf())return g(n,a),l.local=!0,void b(null,null,i,a,l,j)}m(j),i?(f.currentFileInfo=k,new w.Parser(f).parse(i,function(c,d){if(c)return b(c,null,null,a);try{b(c,d,i,a,l,j)}catch(c){b(c,null,null,a)}},{modifyVars:e,globalVars:w.globalVars})):b(h,null,null,a,l,j)},f,e)}function u(a,b,c){for(var d=0;dD&&(C=C.slice(y-D),D=y)}function h(a,b){var c=a.charCodeAt(0|b);return 32>=c&&(32===c||10===c||9===c)}function i(a){var b,c,d=typeof a;return"string"===d?v.charAt(y)!==a?null:(l(1),a):(g(),(b=a.exec(C))?(c=b[0].length,l(c),"string"==typeof b?b:1===b.length?b[0]:b):null)}function j(a){y>D&&(C=C.slice(y-D),D=y);var b=a.exec(C);return b?(l(b[0].length),"string"==typeof b?b:1===b.length?b[0]:b):null}function k(a){return v.charAt(y)!==a?null:(l(1),a)}function l(a){for(var b,c=y,d=z,e=y-D,f=y+C.length-e,g=y+=a,h=v;f>y&&(b=h.charCodeAt(y),!(b>32))&&(32===b||10===b||9===b||13===b);y++);return C=C.slice(a+y-g+e),D=y,!C.length&&z=0&&"\n"!==b.charAt(c);)e++;return"number"==typeof a&&(d=(b.slice(0,a).match(/\n/g)||"").length),{line:d,column:e}}function t(a,b,d){var e=d.currentFileInfo.filename;return"browser"!==w.mode&&"rhino"!==w.mode&&(e=c("path").resolve(e)),{lineNumber:s(a,b).line+1,fileName:e}}function u(a,b){var c=r(a,b),d=s(a.index,c),e=d.line,f=d.column,g=a.call&&s(a.call,c).line,h=c.split("\n");this.type=a.type||"Syntax",this.message=a.message,this.filename=a.filename||b.currentFileInfo.filename,this.index=a.index,this.line="number"==typeof e?e+1:null,this.callLine=g+1,this.callExtract=h[g],this.stack=a.stack,this.column=f,this.extract=[h[e-1],h[e],h[e+1]]}var v,y,z,A,B,C,D,E,F,G=[],H=a&&a.filename;a instanceof x.parseEnv||(a=new x.parseEnv(a));var I=this.imports={paths:a.paths||[],queue:[],files:a.files,contents:a.contents,contentsIgnoredChars:a.contentsIgnoredChars,mime:a.mime,error:null,push:function(b,c,d,e){var f=this;this.queue.push(b);var g=function(a,c,d){f.queue.splice(f.queue.indexOf(b),1);var g=d===H;f.files[d]=c,a&&!f.error&&(f.error=a),e(a,c,g,d)};w.Parser.importer?w.Parser.importer(b,c,g,a):w.Parser.fileLoader(b,c,function(b,e,f,h){if(b)return void g(b);var i=new x.parseEnv(a);i.currentFileInfo=h,i.processImports=!1,i.contents[f]=e,(c.reference||d.reference)&&(h.reference=!0),d.inline?g(null,e,f):new w.Parser(i).parse(e,function(a,b){g(a,b,f)})},a)}},J=j;return u.prototype=new Error,u.prototype.constructor=u,this.env=a=a||{},this.optimization="optimization"in this.env?this.env.optimization:1,E={imports:I,parse:function(d,e,f){var g,h,i,j,k,l=null,m="";if(y=z=D=A=0,j=f&&f.globalVars?w.Parser.serializeVars(f.globalVars)+"\n":"",k=f&&f.modifyVars?"\n"+w.Parser.serializeVars(f.modifyVars):"",(j||f&&f.banner)&&(m=(f&&f.banner?f.banner:"")+j,E.imports.contentsIgnoredChars[a.currentFileInfo.filename]=m.length),d=d.replace(/\r\n/g,"\n"),v=d=m+d.replace(/^\uFEFF/,"")+k,E.imports.contents[a.currentFileInfo.filename]=d,B=function(b){function c(b,c){l=new u({index:c||i,type:"Parse",message:b,filename:a.currentFileInfo.filename},a)}function d(a){var c=i-s;512>c&&!a||!c||(r.push(b.slice(s,i+1)),s=i+1)}var e,f,g,h,i,j,k,m,n,o=b.length,p=0,q=0,r=[],s=0;for(i=0;o>i;i++)if(k=b.charCodeAt(i),!(k>=97&&122>=k||34>k))switch(k){case 40:q++,f=i;continue;case 41:if(--q<0)return c("missing opening `(`");continue;case 59:q||d();continue;case 123:p++,e=i;continue;case 125:if(--p<0)return c("missing opening `{`");p||q||d();continue;case 92:if(o-1>i){i++;continue}return c("unescaped `\\`");case 34:case 39:case 96:for(n=0,j=i,i+=1;o>i;i++)if(m=b.charCodeAt(i),!(m>96)){if(m==k){n=1;break}if(92==m){if(i==o-1)return c("unescaped `\\`");i++}}if(n)continue;return c("unmatched `"+String.fromCharCode(k)+"`",j);case 47:if(q||i==o-1)continue;if(m=b.charCodeAt(i+1),47==m)for(i+=2;o>i&&(m=b.charCodeAt(i),!(13>=m)||10!=m&&13!=m);i++);else if(42==m){for(g=j=i,i+=2;o-1>i&&(m=b.charCodeAt(i),125==m&&(h=i),42!=m||47!=b.charCodeAt(i+1));i++);if(i==o-1)return c("missing closing `*/`",j);i++}continue;case 42:if(o-1>i&&47==b.charCodeAt(i+1))return c("unmatched `/*`");continue}return 0!==p?g>e&&h>g?c("missing closing `}` or `*/`",e):c("missing closing `}`",e):0!==q?c("missing closing `)`",f):(d(!0),r)}(d),l)return e(new u(l,a));C=B[0];try{g=new x.Ruleset(null,this.parsers.primary()),g.root=!0,g.firstRoot=!0}catch(n){return e(new u(n,a))}if(g.toCSS=function(d){return function(e,f){e=e||{};var g,h,i=new x.evalEnv(e);"object"!=typeof f||Array.isArray(f)||(f=Object.keys(f).map(function(a){var b=f[a];return b instanceof x.Value||(b instanceof x.Expression||(b=new x.Expression([b])),b=new x.Value([b])),new x.Rule("@"+a,b,!1,null,0)}),i.frames=[new x.Ruleset(null,f)]);try{var j,k=[],l=[new x.joinSelectorVisitor,new x.processExtendsVisitor,new x.toCSSVisitor({compress:Boolean(e.compress)})],m=this;if(e.plugins)for(j=0;j57||43>b||47===b||44==b))return a=j(/^([+-]?\d*\.?\d+)(%|[a-z]+)?/),a?new x.Dimension(a[1],a[2]):void 0},unicodeDescriptor:function(){var a;return a=j(/^U\+[0-9a-fA-F?]+(\-[0-9a-fA-F?]+)?/),a?new x.UnicodeDescriptor(a[0]):void 0},javascript:function(){var c,d,e=y;return"~"===v.charAt(e)&&(e++,d=!0),"`"===v.charAt(e)?(a.javascriptEnabled===b||a.javascriptEnabled||o("You are using JavaScript, which has been disabled."),d&&k("~"),c=j(/^`([^`]*)`/),c?new x.JavaScript(c[1],y,d):void 0):void 0}},variable:function(){var a;return"@"===v.charAt(y)&&(a=j(/^(@[\w-]+)\s*:/))?a[1]:void 0},rulesetCall:function(){var a;return"@"===v.charAt(y)&&(a=j(/^(@[\w-]+)\s*\(\s*\)\s*;/))?new x.RulesetCall(a[1]):void 0},extend:function(a){var b,c,d,e,f,g=y;if(j(a?/^&:extend\(/:/^:extend\(/)){do{for(d=null,b=null;!(d=j(/^(all)(?=\s*(\)|,))/))&&(c=this.element());)b?b.push(c):b=[c];d=d&&d[1],f=new x.Extend(new x.Selector(b),d,g),e?e.push(f):e=[f]}while(k(","));return m(/^\)/),a&&m(/^;/),e}},extendRule:function(){return this.extend(!0)},mixin:{call:function(){var b,c,g,h,i,l,m=v.charAt(y),o=!1,p=y;if("."===m||"#"===m){for(d();;){if(b=y,h=j(/^[#.](?:[\w-]|\\(?:[A-Fa-f0-9]{1,6} ?|[^A-Fa-f0-9]))+/),!h)break;g=new x.Element(i,h,b,a.currentFileInfo),c?c.push(g):c=[g],i=k(">")}return c&&(k("(")&&(l=this.args(!0).args,n(")")),F.important()&&(o=!0),F.end())?(f(),new x.mixin.Call(c,l,p,a.currentFileInfo,o)):void e()}},args:function(a){var b,c,g,h,i,l,m=E.parsers,n=m.entities,p={args:null,variadic:!1},q=[],r=[],s=[];for(d();;){if(a)l=m.detachedRuleset()||m.expression();else{if(m.comments(),"."===v.charAt(y)&&j(/^\.{3}/)){p.variadic=!0,k(";")&&!b&&(b=!0),(b?r:s).push({variadic:!0});break}l=n.variable()||n.literal()||n.keyword()}if(!l)break;h=null,l.throwAwayComments&&l.throwAwayComments(),i=l;var t=null;if(a?l.value&&1==l.value.length&&(t=l.value[0]):t=l,t&&t instanceof x.Variable)if(k(":")){if(q.length>0&&(b&&o("Cannot mix ; and , as delimiter types"),c=!0),i=a&&m.detachedRuleset()||m.expression(),!i){if(!a)return e(),p.args=[],p;o("could not understand value for named argument")}h=g=t.name}else{if(!a&&j(/^\.{3}/)){p.variadic=!0,k(";")&&!b&&(b=!0),(b?r:s).push({name:l.name,variadic:!0});break}a||(g=h=t.name,i=null)}i&&q.push(i),s.push({name:h,value:i}),k(",")||(k(";")||b)&&(c&&o("Cannot mix ; and , as delimiter types"),b=!0,q.length>1&&(i=new x.Value(q)),r.push({name:g,value:i}),g=null,q=[],c=!1)}return f(),p.args=b?r:s,p},definition:function(){var a,b,c,g,h=[],i=!1;if(!("."!==v.charAt(y)&&"#"!==v.charAt(y)||p(/^[^{]*\}/)))if(d(),b=j(/^([#.](?:[\w-]|\\(?:[A-Fa-f0-9]{1,6} ?|[^A-Fa-f0-9]))+)\s*\(/)){a=b[1];var l=this.args(!1);if(h=l.args,i=l.variadic,!k(")"))return A=y,void e();if(F.comments(),j(/^when/)&&(g=m(F.conditions,"expected condition")),c=F.block())return f(),new x.mixin.Definition(a,h,c,g,i);e()}else f()}},entity:function(){var a=this.entities;return a.literal()||a.variable()||a.url()||a.call()||a.keyword()||a.javascript()||this.comment()},end:function(){return k(";")||q("}")},alpha:function(){var a;if(j(/^\(opacity=/i))return a=j(/^\d+/)||this.entities.variable(),a?(n(")"),new x.Alpha(a)):void 0},element:function(){var b,c,g,h=y;return c=this.combinator(),b=j(/^(?:\d+\.\d+|\d+)%/)||j(/^(?:[.#]?|:*)(?:[\w-]|[^\x00-\x9f]|\\(?:[A-Fa-f0-9]{1,6} ?|[^A-Fa-f0-9]))+/)||k("*")||k("&")||this.attribute()||j(/^\([^()@]+\)/)||j(/^[\.#](?=@)/)||this.entities.variableCurly(),b||(d(),k("(")?(g=this.selector())&&k(")")?(b=new x.Paren(g),f()):e():f()),b?new x.Element(c,b,h,a.currentFileInfo):void 0},combinator:function(){var a=v.charAt(y);if(">"===a||"+"===a||"~"===a||"|"===a||"^"===a){for(y++,"^"===v.charAt(y)&&(a="^^",y++);h(v,y);)y++;return new x.Combinator(a)}return new x.Combinator(h(v,y-1)?" ":null)},lessSelector:function(){return this.selector(!0)},selector:function(b){for(var c,d,e,f,g,h,i,j=y,k=J;(b&&(g=this.extend())||b&&(h=k(/^when/))||(f=this.element()))&&(h?i=m(this.conditions,"expected condition"):i?o("CSS guard can only be used at the end of selector"):g?d?d.push(g):d=[g]:(d&&o("Extend can only be used at the end of selector"),e=v.charAt(y),c?c.push(f):c=[f],f=null),"{"!==e&&"}"!==e&&";"!==e&&","!==e&&")"!==e););return c?new x.Selector(c,d,i,j,a.currentFileInfo):void(d&&o("Extend must be used to extend a selector, it cannot be used on its own"))},attribute:function(){if(k("[")){var a,b,c,d=this.entities;return(a=d.variableCurly())||(a=m(/^(?:[_A-Za-z0-9-\*]*\|)?(?:[_A-Za-z0-9-]|\\.)+/)),c=j(/^[|~*$^]?=/),c&&(b=d.quoted()||j(/^[0-9]+%/)||j(/^[\w-]+/)||d.variableCurly()),n("]"),new x.Attribute(a,c,b)}},block:function(){var a;return k("{")&&(a=this.primary())&&k("}")?a:void 0},blockRuleset:function(){var a=this.block();return a&&(a=new x.Ruleset(null,a)),a},detachedRuleset:function(){var a=this.blockRuleset();return a?new x.DetachedRuleset(a):void 0},ruleset:function(){var b,c,g,h;for(d(),a.dumpLineNumbers&&(h=t(y,v,a));;){if(c=this.lessSelector(),!c)break;if(b?b.push(c):b=[c],this.comments(),c.condition&&b.length>1&&o("Guards are only currently allowed on a single selector."),!k(","))break;c.condition&&o("Guards are only currently allowed on a single selector."),this.comments()}if(b&&(g=this.block())){f();var i=new x.Ruleset(b,g,a.strictImports);return a.dumpLineNumbers&&(i.debugInfo=h),i}A=y,e()},rule:function(b){var c,g,h,i,j,k=y,l=v.charAt(k);if("."!==l&&"#"!==l&&"&"!==l)if(d(),c=this.variable()||this.ruleProperty()){if(j="string"==typeof c,j&&(g=this.detachedRuleset()),g||(g=b||!a.compress&&!j?this.anonymousValue()||this.value():this.value()||this.anonymousValue(),h=this.important(),i=!j&&c.pop().value),g&&this.end())return f(),new x.Rule(c,g,h,i,k,a.currentFileInfo);if(A=y,e(),g&&!b)return this.rule(!0)}else f()},anonymousValue:function(){var a;return a=/^([^@+\/'"*`(;{}-]*);/.exec(C),a?(y+=a[0].length-1,new x.Anonymous(a[1])):void 0},"import":function(){var b,c,g=y;d();var h=j(/^@import?\s+/),i=(h?this.importOptions():null)||{};return h&&(b=this.entities.quoted()||this.entities.url())&&(c=this.mediaFeatures(),k(";"))?(f(),c=c&&new x.Value(c),new x.Import(b,c,i,g,a.currentFileInfo)):void e()},importOptions:function(){var a,b,c,d={};if(!k("("))return null;do if(a=this.importOption()){switch(b=a,c=!0,b){case"css":b="less",c=!1;break;case"once":b="multiple",c=!1}if(d[b]=c,!k(","))break}while(a);return n(")"),d},importOption:function(){var a=j(/^(less|css|multiple|once|inline|reference)/);return a?a[1]:void 0},mediaFeature:function(){var b,c,d=this.entities,e=[];do if(b=d.keyword()||d.variable())e.push(b);else if(k("(")){if(c=this.property(),b=this.value(),!k(")"))return null;if(c&&b)e.push(new x.Paren(new x.Rule(c,b,null,null,y,a.currentFileInfo,!0)));else{if(!b)return null;e.push(new x.Paren(b))}}while(b);return e.length>0?new x.Expression(e):void 0},mediaFeatures:function(){var a,b=this.entities,c=[];do if(a=this.mediaFeature()){if(c.push(a),!k(","))break}else if(a=b.variable(),a&&(c.push(a),!k(",")))break;while(a);return c.length>0?c:null},media:function(){var b,c,d,e;return a.dumpLineNumbers&&(e=t(y,v,a)),j(/^@media/)&&(b=this.mediaFeatures(),c=this.block())?(d=new x.Media(c,b,y,a.currentFileInfo),a.dumpLineNumbers&&(d.debugInfo=e),d):void 0},directive:function(){var b,c,g,h,i,l,m,n=y,p=!0;if("@"===v.charAt(y)){if(c=this["import"]()||this.media())return c;if(d(),b=j(/^@[a-z-]+/)){switch(h=b,"-"==b.charAt(1)&&b.indexOf("-",2)>0&&(h="@"+b.slice(b.indexOf("-",2)+1)),h){case"@charset":i=!0,p=!1;break;case"@namespace":l=!0,p=!1;break;case"@keyframes":i=!0;break;case"@host":case"@page":case"@document":case"@supports":m=!0}return i?(c=this.entity(),c||o("expected "+b+" identifier")):l?(c=this.expression(),c||o("expected "+b+" expression")):m&&(c=(j(/^[^{;]+/)||"").trim(),c&&(c=new x.Anonymous(c))),p&&(g=this.blockRuleset()),g||!p&&c&&k(";")?(f(),new x.Directive(b,c,g,n,a.currentFileInfo,a.dumpLineNumbers?t(n,v,a):null)):void e()}}},value:function(){var a,b=[];do if(a=this.expression(),a&&(b.push(a),!k(",")))break;while(a);return b.length>0?new x.Value(b):void 0},important:function(){return"!"===v.charAt(y)?j(/^! *important/):void 0},sub:function(){var a,b;return k("(")&&(a=this.addition())?(b=new x.Expression([a]),n(")"),b.parens=!0,b):void 0},multiplication:function(){var a,b,c,g,i;if(a=this.operand()){for(i=h(v,y-1);;){if(p(/^\/[*\/]/))break;if(d(),c=k("/")||k("*"),!c){f();break}if(b=this.operand(),!b){e();break}f(),a.parensInOp=!0,b.parensInOp=!0,g=new x.Operation(c,[g||a,b],i),i=h(v,y-1)}return g||a}},addition:function(){var a,b,c,d,e;if(a=this.multiplication()){for(e=h(v,y-1);;){if(c=j(/^[-+]\s+/)||!e&&(k("+")||k("-")),!c)break;if(b=this.multiplication(),!b)break;a.parensInOp=!0,b.parensInOp=!0,d=new x.Operation(c,[d||a,b],e),e=h(v,y-1)}return d||a}},conditions:function(){var a,b,c,d=y;if(a=this.condition()){for(;;){if(!p(/^,\s*(not\s*)?\(/)||!k(","))break;if(b=this.condition(),!b)break;c=new x.Condition("or",c||a,b,d)}return c||a}},condition:function(){var a,b,c,d,e=this.entities,f=y,g=!1;return j(/^not/)&&(g=!0),n("("),a=this.addition()||e.keyword()||e.quoted(),a?(d=j(/^(?:>=|<=|=<|[<=>])/),d?(b=this.addition()||e.keyword()||e.quoted(),b?c=new x.Condition(d,a,b,f,g):o("expected expression")):c=new x.Condition("=",a,new x.Keyword("true"),f,g),n(")"),j(/^and/)?new x.Condition("and",c,this.condition()):c):void 0},operand:function(){var a,b=this.entities,c=v.charAt(y+1);"-"!==v.charAt(y)||"@"!==c&&"("!==c||(a=k("-"));var d=this.sub()||b.dimension()||b.color()||b.variable()||b.call();return a&&(d.parensInOp=!0,d=new x.Negative(d)),d},expression:function(){var a,b,c=[];do a=this.addition()||this.entity(),a&&(c.push(a),p(/^\/[\/*]/)||(b=k("/"),b&&c.push(new x.Anonymous(b))));while(a);return c.length>0?new x.Expression(c):void 0},property:function(){var a=j(/^(\*?-?[_a-zA-Z0-9-]+)\s*:/);return a?a[1]:void 0},ruleProperty:function(){function b(a){var b=a.exec(e);return b?(g.push(y+h),h+=b[0].length,e=e.slice(b[1].length),f.push(b[1])):void 0}var c,d,e=C,f=[],g=[],h=0;for(b(/^(\*?)/);b(/^((?:[\w-]+)|(?:@\{[\w-]+\}))/););if(f.length>1&&b(/^\s*((?:\+_|\+)?)\s*:/)){for(l(h),""===f[0]&&(f.shift(),g.shift()),d=0;dl;l++)e=b.rgb[l]/255,f=c.rgb[l]/255,h=a(e,f),g&&(h=(j*f+i*(e-j*(e+f-h)))/g),k[l]=255*h;return new d.Color(k,g)}function g(){var a,b=d.functions;for(a in l)l.hasOwnProperty(a)&&(b[a]=e.bind(null,Math[a],l[a]));for(a in m)m.hasOwnProperty(a)&&(b[a]=f.bind(null,m[a]));a=d.defaultFunc,b["default"]=a.eval.bind(a)}function h(a){return d.functions.hsla(a.h,a.s,a.l,a.a)}function i(a,b){return a instanceof d.Dimension&&a.unit.is("%")?parseFloat(a.value*b/100):j(a)}function j(a){if(a instanceof d.Dimension)return parseFloat(a.unit.is("%")?a.value/100:a.value);if("number"==typeof a)return a;throw{error:"RuntimeError",message:"color functions take numbers as parameters"}}function k(a){return Math.min(1,Math.max(0,a))}d.functions={rgb:function(a,b,c){return this.rgba(a,b,c,1)},rgba:function(a,b,c,e){var f=[a,b,c].map(function(a){return i(a,255)});return e=j(e),new d.Color(f,e)},hsl:function(a,b,c){return this.hsla(a,b,c,1)},hsla:function(a,b,c,d){function e(a){return a=0>a?a+1:a>1?a-1:a,1>6*a?g+(f-g)*a*6:1>2*a?f:2>3*a?g+(f-g)*(2/3-a)*6:g}a=j(a)%360/360,b=k(j(b)),c=k(j(c)),d=k(j(d));var f=.5>=c?c*(b+1):c+b-c*b,g=2*c-f;return this.rgba(255*e(a+1/3),255*e(a),255*e(a-1/3),d)},hsv:function(a,b,c){return this.hsva(a,b,c,1)},hsva:function(a,b,c,d){a=j(a)%360/360*360,b=j(b),c=j(c),d=j(d);var e,f;e=Math.floor(a/60%6),f=a/60-e;var g=[c,c*(1-b),c*(1-f*b),c*(1-(1-f)*b)],h=[[0,3,1],[2,0,1],[1,0,3],[1,2,0],[3,1,0],[0,1,2]];return this.rgba(255*g[h[e][0]],255*g[h[e][1]],255*g[h[e][2]],d)},hue:function(a){return new d.Dimension(a.toHSL().h)},saturation:function(a){return new d.Dimension(100*a.toHSL().s,"%")},lightness:function(a){return new d.Dimension(100*a.toHSL().l,"%")},hsvhue:function(a){return new d.Dimension(a.toHSV().h)},hsvsaturation:function(a){return new d.Dimension(100*a.toHSV().s,"%")},hsvvalue:function(a){return new d.Dimension(100*a.toHSV().v,"%")},red:function(a){return new d.Dimension(a.rgb[0])},green:function(a){return new d.Dimension(a.rgb[1])},blue:function(a){return new d.Dimension(a.rgb[2])},alpha:function(a){return new d.Dimension(a.toHSL().a)},luma:function(a){return new d.Dimension(a.luma()*a.alpha*100,"%")},luminance:function(a){var b=.2126*a.rgb[0]/255+.7152*a.rgb[1]/255+.0722*a.rgb[2]/255;return new d.Dimension(b*a.alpha*100,"%")},saturate:function(a,b){if(!a.rgb)return null;var c=a.toHSL();return c.s+=b.value/100,c.s=k(c.s),h(c)},desaturate:function(a,b){var c=a.toHSL();return c.s-=b.value/100,c.s=k(c.s),h(c)},lighten:function(a,b){var c=a.toHSL();return c.l+=b.value/100,c.l=k(c.l),h(c)},darken:function(a,b){var c=a.toHSL();return c.l-=b.value/100,c.l=k(c.l),h(c)},fadein:function(a,b){var c=a.toHSL();return c.a+=b.value/100,c.a=k(c.a),h(c)},fadeout:function(a,b){var c=a.toHSL();return c.a-=b.value/100,c.a=k(c.a),h(c)},fade:function(a,b){var c=a.toHSL();return c.a=b.value/100,c.a=k(c.a),h(c)},spin:function(a,b){var c=a.toHSL(),d=(c.h+b.value)%360;return c.h=0>d?360+d:d,h(c)},mix:function(a,b,c){c||(c=new d.Dimension(50));var e=c.value/100,f=2*e-1,g=a.toHSL().a-b.toHSL().a,h=((f*g==-1?f:(f+g)/(1+f*g))+1)/2,i=1-h,j=[a.rgb[0]*h+b.rgb[0]*i,a.rgb[1]*h+b.rgb[1]*i,a.rgb[2]*h+b.rgb[2]*i],k=a.alpha*e+b.alpha*(1-e);return new d.Color(j,k)},greyscale:function(a){return this.desaturate(a,new d.Dimension(100))},contrast:function(a,b,c,d){if(!a.rgb)return null;if("undefined"==typeof c&&(c=this.rgba(255,255,255,1)),"undefined"==typeof b&&(b=this.rgba(0,0,0,1)),b.luma()>c.luma()){var e=c;c=b,b=e}return d="undefined"==typeof d?.43:j(d),a.luma()i.value)&&(m[f]=g);else{if(k!==b&&j!==k)throw{type:"Argument",message:"incompatible types"};n[j]=m.length,m.push(g)}else Array.isArray(c[e].value)&&Array.prototype.push.apply(c,Array.prototype.slice.call(c[e].value));return 1==m.length?m[0]:(c=m.map(function(a){return a.toCSS(this.env)}).join(this.env.compress?",":", "),new d.Anonymous((a?"min":"max")+"("+c+")"))},min:function(){return this._minmax(!0,arguments)},max:function(){return this._minmax(!1,arguments)},"get-unit":function(a){return new d.Anonymous(a.unit)},argb:function(a){return new d.Anonymous(a.toARGB())},percentage:function(a){return new d.Dimension(100*a.value,"%")},color:function(a){if(a instanceof d.Quoted){var b,c=a.value;if(b=d.Color.fromKeyword(c))return b;if(/^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})/.test(c))return new d.Color(c.slice(1));throw{type:"Argument",message:"argument must be a color keyword or 3/6 digit hex e.g. #FFF"}}throw{type:"Argument",message:"argument must be a string"}},iscolor:function(a){return this._isa(a,d.Color)},isnumber:function(a){return this._isa(a,d.Dimension)},isstring:function(a){return this._isa(a,d.Quoted)},iskeyword:function(a){return this._isa(a,d.Keyword)},isurl:function(a){return this._isa(a,d.URL)},ispixel:function(a){return this.isunit(a,"px")},ispercentage:function(a){return this.isunit(a,"%")},isem:function(a){return this.isunit(a,"em")},isunit:function(a,b){return a instanceof d.Dimension&&a.unit.is(b.value||b)?d.True:d.False},_isa:function(a,b){return a instanceof b?d.True:d.False},tint:function(a,b){return this.mix(this.rgb(255,255,255),a,b)},shade:function(a,b){return this.mix(this.rgb(0,0,0),a,b)},extract:function(a,b){return b=b.value-1,Array.isArray(a.value)?a.value[b]:Array(a)[b]},length:function(a){var b=Array.isArray(a.value)?a.value.length:1;return new d.Dimension(b)},"data-uri":function(b,e){if("undefined"!=typeof a)return new d.URL(e||b,this.currentFileInfo).eval(this.env);var f=b.value,g=e&&e.value,h=c("./fs"),i=c("path"),j=!1;if(arguments.length<2&&(g=f),this.env.isPathRelative(g)&&(g=this.currentFileInfo.relativeUrls?i.join(this.currentFileInfo.currentDirectory,g):i.join(this.currentFileInfo.entryPath,g)),arguments.length<2){var k;try{k=c("mime")}catch(l){k=d._mime}f=k.lookup(g);var m=k.charsets.lookup(f);j=["US-ASCII","UTF-8"].indexOf(m)<0,j&&(f+=";base64")}else j=/;base64$/.test(f);var n=h.readFileSync(g),o=32,p=parseInt(n.length/1024,10);if(p>=o&&this.env.ieCompat!==!1)return this.env.silent||console.warn("Skipped data-uri embedding of %s because its size (%dKB) exceeds IE8-safe %dKB!",g,p,o),new d.URL(e||b,this.currentFileInfo).eval(this.env);n=j?n.toString("base64"):encodeURIComponent(n);var q='"data:'+f+","+n+'"';return new d.URL(new d.Anonymous(q))},"svg-gradient":function(a){function e(){throw{type:"Argument",message:"svg-gradient expects direction, start_color [start_position], [color position,]..., end_color [end_position]"}}arguments.length<3&&e();var f,g,h,i,j,k,l,m=Array.prototype.slice.call(arguments,1),n="linear",o='x="0" y="0" width="1" height="1"',p=!0,q={compress:!1},r=a.toCSS(q);switch(r){case"to bottom":f='x1="0%" y1="0%" x2="0%" y2="100%"';break;case"to right":f='x1="0%" y1="0%" x2="100%" y2="0%"';break;case"to bottom right":f='x1="0%" y1="0%" x2="100%" y2="100%"';break;case"to top right":f='x1="0%" y1="100%" x2="100%" y2="0%"';break;case"ellipse":case"ellipse at center":n="radial",f='cx="50%" cy="50%" r="75%"',o='x="-50" y="-50" width="101" height="101"';break;default:throw{type:"Argument",message:"svg-gradient direction must be 'to bottom', 'to right', 'to bottom right', 'to top right' or 'ellipse at center'"}}for(g='<'+n+'Gradient id="gradient" gradientUnits="userSpaceOnUse" '+f+">",h=0;hl?' stop-opacity="'+l+'"':"")+"/>";if(g+="',p)try{g=c("./encoder").encodeBase64(g)}catch(s){p=!1}return g="'data:image/svg+xml"+(p?";base64":"")+","+g+"'",new d.URL(new d.Anonymous(g))}},d._mime={_types:{".htm":"text/html",".html":"text/html",".gif":"image/gif",".jpg":"image/jpeg",".jpeg":"image/jpeg",".png":"image/png"},lookup:function(a){var e=c("path").extname(a),f=d._mime._types[e];if(f===b)throw new Error('Optional dependency "mime" is required for '+e);return f},charsets:{lookup:function(a){return a&&/^text\//.test(a)?"UTF-8":""}}};var l={ceil:null,floor:null,sqrt:null,abs:null,tan:"",sin:"",cos:"",atan:"rad",asin:"rad",acos:"rad"},m={multiply:function(a,b){return a*b},screen:function(a,b){return a+b-a*b},overlay:function(a,b){return a*=2,1>=a?m.multiply(a,b):m.screen(a-1,b)},softlight:function(a,b){var c=1,d=a;return b>.5&&(d=1,c=a>.25?Math.sqrt(a):((16*a-12)*a+4)*a),a-(1-2*b)*d*(c-a)},hardlight:function(a,b){return m.overlay(b,a)},difference:function(a,b){return Math.abs(a-b)},exclusion:function(a,b){return a+b-2*a*b},average:function(a,b){return(a+b)/2},negation:function(a,b){return 1-Math.abs(a+b-1)}};d.defaultFunc={eval:function(){var a=this.value_,b=this.error_;if(b)throw b;return null!=a?a?d.True:d.False:void 0},value:function(a){this.value_=a},error:function(a){this.error_=a},reset:function(){this.value_=this.error_=null}},g(),d.fround=function(a,b){var c=a&&a.numPrecision;return null==c?b:Number((b+2e-16).toFixed(c))},d.functionCall=function(a,b){this.env=a,this.currentFileInfo=b},d.functionCall.prototype=d.functions}(c("./tree")),function(a){a.colors={aliceblue:"#f0f8ff",antiquewhite:"#faebd7",aqua:"#00ffff",aquamarine:"#7fffd4",azure:"#f0ffff",beige:"#f5f5dc",bisque:"#ffe4c4",black:"#000000",blanchedalmond:"#ffebcd",blue:"#0000ff",blueviolet:"#8a2be2",brown:"#a52a2a",burlywood:"#deb887",cadetblue:"#5f9ea0",chartreuse:"#7fff00",chocolate:"#d2691e",coral:"#ff7f50",cornflowerblue:"#6495ed",cornsilk:"#fff8dc",crimson:"#dc143c",cyan:"#00ffff",darkblue:"#00008b",darkcyan:"#008b8b",darkgoldenrod:"#b8860b",darkgray:"#a9a9a9",darkgrey:"#a9a9a9",darkgreen:"#006400",darkkhaki:"#bdb76b",darkmagenta:"#8b008b",darkolivegreen:"#556b2f",darkorange:"#ff8c00",darkorchid:"#9932cc",darkred:"#8b0000",darksalmon:"#e9967a",darkseagreen:"#8fbc8f",darkslateblue:"#483d8b",darkslategray:"#2f4f4f",darkslategrey:"#2f4f4f",darkturquoise:"#00ced1",darkviolet:"#9400d3",deeppink:"#ff1493",deepskyblue:"#00bfff",dimgray:"#696969",dimgrey:"#696969",dodgerblue:"#1e90ff",firebrick:"#b22222",floralwhite:"#fffaf0",forestgreen:"#228b22",fuchsia:"#ff00ff",gainsboro:"#dcdcdc",ghostwhite:"#f8f8ff",gold:"#ffd700",goldenrod:"#daa520",gray:"#808080",grey:"#808080",green:"#008000",greenyellow:"#adff2f",honeydew:"#f0fff0",hotpink:"#ff69b4",indianred:"#cd5c5c",indigo:"#4b0082",ivory:"#fffff0",khaki:"#f0e68c",lavender:"#e6e6fa",lavenderblush:"#fff0f5",lawngreen:"#7cfc00",lemonchiffon:"#fffacd",lightblue:"#add8e6",lightcoral:"#f08080",lightcyan:"#e0ffff",lightgoldenrodyellow:"#fafad2",lightgray:"#d3d3d3",lightgrey:"#d3d3d3",lightgreen:"#90ee90",lightpink:"#ffb6c1",lightsalmon:"#ffa07a",lightseagreen:"#20b2aa",lightskyblue:"#87cefa",lightslategray:"#778899",lightslategrey:"#778899",lightsteelblue:"#b0c4de",lightyellow:"#ffffe0",lime:"#00ff00",limegreen:"#32cd32",linen:"#faf0e6",magenta:"#ff00ff",maroon:"#800000",mediumaquamarine:"#66cdaa",mediumblue:"#0000cd",mediumorchid:"#ba55d3",mediumpurple:"#9370d8",mediumseagreen:"#3cb371",mediumslateblue:"#7b68ee",mediumspringgreen:"#00fa9a",mediumturquoise:"#48d1cc",mediumvioletred:"#c71585",midnightblue:"#191970",mintcream:"#f5fffa",mistyrose:"#ffe4e1",moccasin:"#ffe4b5",navajowhite:"#ffdead",navy:"#000080",oldlace:"#fdf5e6",olive:"#808000",olivedrab:"#6b8e23",orange:"#ffa500",orangered:"#ff4500",orchid:"#da70d6",palegoldenrod:"#eee8aa",palegreen:"#98fb98",paleturquoise:"#afeeee",palevioletred:"#d87093",papayawhip:"#ffefd5",peachpuff:"#ffdab9",peru:"#cd853f",pink:"#ffc0cb",plum:"#dda0dd",powderblue:"#b0e0e6",purple:"#800080",red:"#ff0000",rosybrown:"#bc8f8f",royalblue:"#4169e1",saddlebrown:"#8b4513",salmon:"#fa8072",sandybrown:"#f4a460",seagreen:"#2e8b57",seashell:"#fff5ee",sienna:"#a0522d",silver:"#c0c0c0",skyblue:"#87ceeb",slateblue:"#6a5acd",slategray:"#708090",slategrey:"#708090",snow:"#fffafa",springgreen:"#00ff7f",steelblue:"#4682b4",tan:"#d2b48c",teal:"#008080",thistle:"#d8bfd8",tomato:"#ff6347",turquoise:"#40e0d0",violet:"#ee82ee",wheat:"#f5deb3",white:"#ffffff",whitesmoke:"#f5f5f5",yellow:"#ffff00",yellowgreen:"#9acd32"}}(c("./tree")),function(a){a.debugInfo=function(b,c,d){var e="";if(b.dumpLineNumbers&&!b.compress)switch(b.dumpLineNumbers){case"comments":e=a.debugInfo.asComment(c);break;case"mediaquery":e=a.debugInfo.asMediaQuery(c);break;case"all":e=a.debugInfo.asComment(c)+(d||"")+a.debugInfo.asMediaQuery(c)}return e},a.debugInfo.asComment=function(a){return"/* line "+a.debugInfo.lineNumber+", "+a.debugInfo.fileName+" */\n"},a.debugInfo.asMediaQuery=function(a){return"@media -sass-debug-info{filename{font-family:"+("file://"+a.debugInfo.fileName).replace(/([.:\/\\])/g,function(a){return"\\"==a&&(a="/"),"\\"+a})+"}line{font-family:\\00003"+a.debugInfo.lineNumber+"}}\n"},a.find=function(a,b){for(var c,d=0;d1?"["+a.value.map(function(a){return a.toCSS()}).join(", ")+"]":a.toCSS()},a.toCSS=function(a){var b=[];return this.genCSS(a,{add:function(a){b.push(a)},isEmpty:function(){return 0===b.length}}),b.join("")},a.outputRuleset=function(a,b,c){var d,e=c.length;if(a.tabLevel=(0|a.tabLevel)+1,a.compress){for(b.add("{"),d=0;e>d;d++)c[d].genCSS(a,b);return b.add("}"),void a.tabLevel--}var f="\n"+Array(a.tabLevel).join(" "),g=f+" ";if(e){for(b.add(" {"+g),c[0].genCSS(a,b),d=1;e>d;d++)b.add(g),c[d].genCSS(a,b);b.add(f+"}")}else b.add(" {"+f+"}");a.tabLevel--}}(c("./tree")),function(a){a.Alpha=function(a){this.value=a},a.Alpha.prototype={type:"Alpha",accept:function(a){this.value=a.visit(this.value)},eval:function(b){return this.value.eval?new a.Alpha(this.value.eval(b)):this},genCSS:function(a,b){b.add("alpha(opacity="),this.value.genCSS?this.value.genCSS(a,b):b.add(this.value),b.add(")")},toCSS:a.toCSS}}(c("../tree")),function(a){a.Anonymous=function(a,b,c,d){this.value=a,this.index=b,this.mapLines=d,this.currentFileInfo=c},a.Anonymous.prototype={type:"Anonymous",eval:function(){return new a.Anonymous(this.value,this.index,this.currentFileInfo,this.mapLines)},compare:function(a){if(!a.toCSS)return-1;var b=this.toCSS(),c=a.toCSS();return b===c?0:c>b?-1:1},genCSS:function(a,b){b.add(this.value,this.currentFileInfo,this.index,this.mapLines)},toCSS:a.toCSS}}(c("../tree")),function(a){a.Assignment=function(a,b){this.key=a,this.value=b},a.Assignment.prototype={type:"Assignment",accept:function(a){this.value=a.visit(this.value)},eval:function(b){return this.value.eval?new a.Assignment(this.key,this.value.eval(b)):this},genCSS:function(a,b){b.add(this.key+"="),this.value.genCSS?this.value.genCSS(a,b):b.add(this.value)},toCSS:a.toCSS}}(c("../tree")),function(a){a.Call=function(a,b,c,d){this.name=a,this.args=b,this.index=c,this.currentFileInfo=d},a.Call.prototype={type:"Call",accept:function(a){this.args&&(this.args=a.visitArray(this.args))},eval:function(b){var c,d,e=this.args.map(function(a){return a.eval(b)}),f=this.name.toLowerCase();if(f in a.functions)try{if(d=new a.functionCall(b,this.currentFileInfo),c=d[f].apply(d,e),null!=c)return c}catch(g){throw{type:g.type||"Runtime",message:"error evaluating function `"+this.name+"`"+(g.message?": "+g.message:""),index:this.index,filename:this.currentFileInfo.filename}}return new a.Call(this.name,e,this.index,this.currentFileInfo)},genCSS:function(a,b){b.add(this.name+"(",this.currentFileInfo,this.index);for(var c=0;ca?"0":"")+a.toString(16)}).join("")}function c(a,b){return Math.min(Math.max(a,0),b)}a.Color=function(a,b){this.rgb=Array.isArray(a)?a:6==a.length?a.match(/.{2}/g).map(function(a){return parseInt(a,16)}):a.split("").map(function(a){return parseInt(a+a,16)}),this.alpha="number"==typeof b?b:1};var d="transparent";a.Color.prototype={type:"Color",eval:function(){return this},luma:function(){var a=this.rgb[0]/255,b=this.rgb[1]/255,c=this.rgb[2]/255;return a=.03928>=a?a/12.92:Math.pow((a+.055)/1.055,2.4),b=.03928>=b?b/12.92:Math.pow((b+.055)/1.055,2.4),c=.03928>=c?c/12.92:Math.pow((c+.055)/1.055,2.4),.2126*a+.7152*b+.0722*c},genCSS:function(a,b){b.add(this.toCSS(a))},toCSS:function(b,e){var f=b&&b.compress&&!e,g=a.fround(b,this.alpha);if(1>g)return 0===g&&this.isTransparentKeyword?d:"rgba("+this.rgb.map(function(a){return c(Math.round(a),255)}).concat(c(g,1)).join(","+(f?"":" "))+")";var h=this.toRGB();if(f){var i=h.split("");i[1]===i[2]&&i[3]===i[4]&&i[5]===i[6]&&(h="#"+i[1]+i[3]+i[5])}return h},operate:function(b,c,d){for(var e=[],f=this.alpha*(1-d.alpha)+d.alpha,g=0;3>g;g++)e[g]=a.operate(b,c,this.rgb[g],d.rgb[g]);return new a.Color(e,f)},toRGB:function(){return b(this.rgb)},toHSL:function(){var a,b,c=this.rgb[0]/255,d=this.rgb[1]/255,e=this.rgb[2]/255,f=this.alpha,g=Math.max(c,d,e),h=Math.min(c,d,e),i=(g+h)/2,j=g-h;if(g===h)a=b=0;else{switch(b=i>.5?j/(2-g-h):j/(g+h),g){case c:a=(d-e)/j+(e>d?6:0);break;case d:a=(e-c)/j+2;break;case e:a=(c-d)/j+4}a/=6}return{h:360*a,s:b,l:i,a:f}},toHSV:function(){var a,b,c=this.rgb[0]/255,d=this.rgb[1]/255,e=this.rgb[2]/255,f=this.alpha,g=Math.max(c,d,e),h=Math.min(c,d,e),i=g,j=g-h;if(b=0===g?0:j/g,g===h)a=0;else{switch(g){case c:a=(d-e)/j+(e>d?6:0);break;case d:a=(e-c)/j+2;break;case e:a=(c-d)/j+4}a/=6}return{h:360*a,s:b,v:i,a:f}},toARGB:function(){return b([255*this.alpha].concat(this.rgb))},compare:function(a){return a.rgb&&a.rgb[0]===this.rgb[0]&&a.rgb[1]===this.rgb[1]&&a.rgb[2]===this.rgb[2]&&a.alpha===this.alpha?0:-1}},a.Color.fromKeyword=function(b){if(b=b.toLowerCase(),a.colors.hasOwnProperty(b))return new a.Color(a.colors[b].slice(1));if(b===d){var c=new a.Color([0,0,0],0);return c.isTransparentKeyword=!0,c}}}(c("../tree")),function(a){a.Comment=function(a,b,c,d){this.value=a,this.silent=!!b,this.currentFileInfo=d},a.Comment.prototype={type:"Comment",genCSS:function(b,c){this.debugInfo&&c.add(a.debugInfo(b,this),this.currentFileInfo,this.index),c.add(this.value.trim())},toCSS:a.toCSS,isSilent:function(a){var b=this.currentFileInfo&&this.currentFileInfo.reference&&!this.isReferenced,c=a.compress&&!this.value.match(/^\/\*!/);return this.silent||b||c},eval:function(){return this},markReferenced:function(){this.isReferenced=!0}}}(c("../tree")),function(a){a.Condition=function(a,b,c,d,e){this.op=a.trim(),this.lvalue=b,this.rvalue=c,this.index=d,this.negate=e},a.Condition.prototype={type:"Condition",accept:function(a){this.lvalue=a.visit(this.lvalue),this.rvalue=a.visit(this.rvalue)},eval:function(a){var b,c=this.lvalue.eval(a),d=this.rvalue.eval(a),e=this.index;return b=function(a){switch(a){case"and":return c&&d;case"or":return c||d;default:if(c.compare)b=c.compare(d);else{if(!d.compare)throw{type:"Type",message:"Unable to perform comparison",index:e};b=d.compare(c)}switch(b){case-1:return"<"===a||"=<"===a||"<="===a;case 0:return"="===a||">="===a||"=<"===a||"<="===a;case 1:return">"===a||">="===a}}}(this.op),this.negate?!b:b}}}(c("../tree")),function(a){a.DetachedRuleset=function(a,b){this.ruleset=a,this.frames=b},a.DetachedRuleset.prototype={type:"DetachedRuleset",accept:function(a){this.ruleset=a.visit(this.ruleset)},eval:function(b){var c=this.frames||b.frames.slice(0);return new a.DetachedRuleset(this.ruleset,c)},callEval:function(b){return this.ruleset.eval(this.frames?new a.evalEnv(b,this.frames.concat(b.frames)):b)}}}(c("../tree")),function(a){a.Dimension=function(c,d){this.value=parseFloat(c),this.unit=d&&d instanceof a.Unit?d:new a.Unit(d?[d]:b)},a.Dimension.prototype={type:"Dimension",accept:function(a){this.unit=a.visit(this.unit)},eval:function(){return this},toColor:function(){return new a.Color([this.value,this.value,this.value])},genCSS:function(b,c){if(b&&b.strictUnits&&!this.unit.isSingular())throw new Error("Multiple units in dimension. Correct the units or use the unit function. Bad unit: "+this.unit.toString());var d=a.fround(b,this.value),e=String(d);if(0!==d&&1e-6>d&&d>-1e-6&&(e=d.toFixed(20).replace(/0+$/,"")),b&&b.compress){if(0===d&&this.unit.isLength())return void c.add(e);d>0&&1>d&&(e=e.substr(1))}c.add(e),this.unit.genCSS(b,c)},toCSS:a.toCSS,operate:function(b,c,d){var e=a.operate(b,c,this.value,d.value),f=this.unit.clone();if("+"===c||"-"===c)if(0===f.numerator.length&&0===f.denominator.length)f.numerator=d.unit.numerator.slice(0),f.denominator=d.unit.denominator.slice(0);else if(0===d.unit.numerator.length&&0===f.denominator.length);else{if(d=d.convertTo(this.unit.usedUnits()),b.strictUnits&&d.unit.toString()!==f.toString())throw new Error("Incompatible units. Change the units or use the unit function. Bad units: '"+f.toString()+"' and '"+d.unit.toString()+"'.");e=a.operate(b,c,this.value,d.value)}else"*"===c?(f.numerator=f.numerator.concat(d.unit.numerator).sort(),f.denominator=f.denominator.concat(d.unit.denominator).sort(),f.cancel()):"/"===c&&(f.numerator=f.numerator.concat(d.unit.denominator).sort(),f.denominator=f.denominator.concat(d.unit.numerator).sort(),f.cancel());return new a.Dimension(e,f)},compare:function(b){if(b instanceof a.Dimension){var c,d,e,f;if(this.unit.isEmpty()||b.unit.isEmpty())c=this,d=b;else if(c=this.unify(),d=b.unify(),0!==c.unit.compare(d.unit))return-1;return e=c.value,f=d.value,f>e?-1:e>f?1:0}return-1},unify:function(){return this.convertTo({length:"px",duration:"s",angle:"rad"})},convertTo:function(b){var c,d,e,f,g,h=this.value,i=this.unit.clone(),j={};if("string"==typeof b){for(c in a.UnitConversions)a.UnitConversions[c].hasOwnProperty(b)&&(j={},j[c]=b);b=j}g=function(a,b){return e.hasOwnProperty(a)?(b?h/=e[a]/e[f]:h*=e[a]/e[f],f):a};for(d in b)b.hasOwnProperty(d)&&(f=b[d],e=a.UnitConversions[d],i.map(g));return i.cancel(),new a.Dimension(h,i)}},a.UnitConversions={length:{m:1,cm:.01,mm:.001,"in":.0254,px:.0254/96,pt:.0254/72,pc:.0254/72*12},duration:{s:1,ms:.001},angle:{rad:1/(2*Math.PI),deg:1/360,grad:.0025,turn:1}},a.Unit=function(a,b,c){this.numerator=a?a.slice(0).sort():[],this.denominator=b?b.slice(0).sort():[],this.backupUnit=c},a.Unit.prototype={type:"Unit",clone:function(){return new a.Unit(this.numerator.slice(0),this.denominator.slice(0),this.backupUnit)},genCSS:function(a,b){this.numerator.length>=1?b.add(this.numerator[0]):this.denominator.length>=1?b.add(this.denominator[0]):a&&a.strictUnits||!this.backupUnit||b.add(this.backupUnit)},toCSS:a.toCSS,toString:function(){var a,b=this.numerator.join("*");for(a=0;a0)for(b=0;e>b;b++)this.numerator.push(a);else if(0>e)for(b=0;-e>b;b++)this.denominator.push(a)}0===this.numerator.length&&0===this.denominator.length&&c&&(this.backupUnit=c),this.numerator.sort(),this.denominator.sort()}}}(c("../tree")),function(a){a.Directive=function(a,b,c,d,e,f){this.name=a,this.value=b,c&&(this.rules=c,this.rules.allowImports=!0),this.index=d,this.currentFileInfo=e,this.debugInfo=f},a.Directive.prototype={type:"Directive",accept:function(a){var b=this.value,c=this.rules;c&&(c=a.visit(c)),b&&(b=a.visit(b))},genCSS:function(b,c){var d=this.value,e=this.rules;c.add(this.name,this.currentFileInfo,this.index),d&&(c.add(" "),d.genCSS(b,c)),e?a.outputRuleset(b,c,[e]):c.add(";")},toCSS:a.toCSS,eval:function(b){var c=this.value,d=this.rules;return c&&(c=c.eval(b)),d&&(d=d.eval(b),d.root=!0),new a.Directive(this.name,c,d,this.index,this.currentFileInfo,this.debugInfo)},variable:function(b){return this.rules?a.Ruleset.prototype.variable.call(this.rules,b):void 0},find:function(){return this.rules?a.Ruleset.prototype.find.apply(this.rules,arguments):void 0},rulesets:function(){return this.rules?a.Ruleset.prototype.rulesets.apply(this.rules):void 0},markReferenced:function(){var a,b;if(this.isReferenced=!0,this.rules)for(b=this.rules.rules,a=0;a":" > ","|":"|","^":" ^ ","^^":" ^^ "},_outputMapCompressed:{"":""," ":" ",":":" :","+":"+","~":"~",">":">","|":"|","^":"^","^^":"^^"},genCSS:function(a,b){b.add((a.compress?this._outputMapCompressed:this._outputMap)[this.value])},toCSS:a.toCSS}}(c("../tree")),function(a){a.Expression=function(a){this.value=a},a.Expression.prototype={type:"Expression",accept:function(a){this.value&&(this.value=a.visitArray(this.value))},eval:function(b){var c,d=this.parens&&!this.parensInOp,e=!1;return d&&b.inParenthesis(),this.value.length>1?c=new a.Expression(this.value.map(function(a){return a.eval(b)})):1===this.value.length?(this.value[0].parens&&!this.value[0].parensInOp&&(e=!0),c=this.value[0].eval(b)):c=this,d&&b.outOfParenthesis(),this.parens&&this.parensInOp&&!b.isMathOn()&&!e&&(c=new a.Paren(c)),c},genCSS:function(a,b){for(var c=0;c0&&c.length&&""===c[0].combinator.value&&(c[0].combinator.value=" "),d=d.concat(a[b].elements);this.selfSelectors=[{elements:d}]}}}(c("../tree")),function(a){a.Import=function(a,c,d,e,f){if(this.options=d,this.index=e,this.path=a,this.features=c,this.currentFileInfo=f,this.options.less!==b||this.options.inline)this.css=!this.options.less||this.options.inline;else{var g=this.getPath();g&&/css([\?;].*)?$/.test(g)&&(this.css=!0)}},a.Import.prototype={type:"Import",accept:function(a){this.features&&(this.features=a.visit(this.features)),this.path=a.visit(this.path),!this.options.inline&&this.root&&(this.root=a.visit(this.root))},genCSS:function(a,b){this.css&&(b.add("@import ",this.currentFileInfo,this.index),this.path.genCSS(a,b),this.features&&(b.add(" "),this.features.genCSS(a,b)),b.add(";"))},toCSS:a.toCSS,getPath:function(){if(this.path instanceof a.Quoted){var c=this.path.value;return this.css!==b||/(\.[a-z]*$)|([\?;].*)$/.test(c)?c:c+".less"}return this.path instanceof a.URL?this.path.value.value:null},evalForImport:function(b){return new a.Import(this.path.eval(b),this.features,this.options,this.index,this.currentFileInfo)},evalPath:function(b){var c=this.path.eval(b),d=this.currentFileInfo&&this.currentFileInfo.rootpath;if(!(c instanceof a.URL)){if(d){var e=c.value;e&&b.isPathRelative(e)&&(c.value=d+e)}c.value=b.normalizePath(c.value)}return c},eval:function(b){var c,d=this.features&&this.features.eval(b);if(this.skip&&("function"==typeof this.skip&&(this.skip=this.skip()),this.skip))return[];if(this.options.inline){var e=new a.Anonymous(this.root,0,{filename:this.importedFilename},!0);return this.features?new a.Media([e],this.features.value):[e]}if(this.css){var f=new a.Import(this.evalPath(b),d,this.options,this.index);if(!f.css&&this.error)throw this.error;return f}return c=new a.Ruleset(null,this.root.rules.slice(0)),c.evalImports(b),this.features?new a.Media(c.rules,this.features.value):c.rules}}}(c("../tree")),function(a){a.JavaScript=function(a,b,c){this.escaped=c,this.expression=a,this.index=b},a.JavaScript.prototype={type:"JavaScript",eval:function(b){var c,d=this,e={},f=this.expression.replace(/@\{([\w-]+)\}/g,function(c,e){return a.jsify(new a.Variable("@"+e,d.index).eval(b))});try{f=new Function("return ("+f+")")}catch(g){throw{message:"JavaScript evaluation error: "+g.message+" from `"+f+"`",index:this.index}}var h=b.frames[0].variables();for(var i in h)h.hasOwnProperty(i)&&(e[i.slice(1)]={value:h[i].value,toJS:function(){return this.value.eval(b).toCSS()}});try{c=f.call(e)}catch(g){throw{message:"JavaScript evaluation error: '"+g.name+": "+g.message.replace(/["]/g,"'")+"'",index:this.index}}return"number"==typeof c?new a.Dimension(c):"string"==typeof c?new a.Quoted('"'+c+'"',c,this.escaped,this.index):new a.Anonymous(Array.isArray(c)?c.join(", "):c)}}}(c("../tree")),function(a){a.Keyword=function(a){this.value=a},a.Keyword.prototype={type:"Keyword",eval:function(){return this},genCSS:function(a,b){if("%"===this.value)throw{type:"Syntax",message:"Invalid % without number"};b.add(this.value)},toCSS:a.toCSS,compare:function(b){return b instanceof a.Keyword?b.value===this.value?0:1:-1}},a.True=new a.Keyword("true"),a.False=new a.Keyword("false")}(c("../tree")),function(a){a.Media=function(b,c,d,e){this.index=d,this.currentFileInfo=e;var f=this.emptySelectors();this.features=new a.Value(c),this.rules=[new a.Ruleset(f,b)],this.rules[0].allowImports=!0},a.Media.prototype={type:"Media",accept:function(a){this.features&&(this.features=a.visit(this.features)),this.rules&&(this.rules=a.visitArray(this.rules))},genCSS:function(b,c){c.add("@media ",this.currentFileInfo,this.index),this.features.genCSS(b,c),a.outputRuleset(b,c,this.rules)},toCSS:a.toCSS,eval:function(b){b.mediaBlocks||(b.mediaBlocks=[],b.mediaPath=[]);var c=new a.Media(null,[],this.index,this.currentFileInfo);this.debugInfo&&(this.rules[0].debugInfo=this.debugInfo,c.debugInfo=this.debugInfo);var d=!1;b.strictMath||(d=!0,b.strictMath=!0);try{c.features=this.features.eval(b)}finally{d&&(b.strictMath=!1)}return b.mediaPath.push(c),b.mediaBlocks.push(c),b.frames.unshift(this.rules[0]),c.rules=[this.rules[0].eval(b)],b.frames.shift(),b.mediaPath.pop(),0===b.mediaPath.length?c.evalTop(b):c.evalNested(b)},variable:function(b){return a.Ruleset.prototype.variable.call(this.rules[0],b)},find:function(){return a.Ruleset.prototype.find.apply(this.rules[0],arguments)},rulesets:function(){return a.Ruleset.prototype.rulesets.apply(this.rules[0])},emptySelectors:function(){var b=new a.Element("","&",this.index,this.currentFileInfo),c=[new a.Selector([b],null,null,this.index,this.currentFileInfo)];return c[0].mediaEmpty=!0,c},markReferenced:function(){var a,b=this.rules[0].rules;for(this.rules[0].markReferenced(),this.isReferenced=!0,a=0;a1){var d=this.emptySelectors();c=new a.Ruleset(d,b.mediaBlocks),c.multiMedia=!0}return delete b.mediaBlocks,delete b.mediaPath,c},evalNested:function(b){var c,d,e=b.mediaPath.concat([this]);for(c=0;c0;c--)b.splice(c,0,new a.Anonymous("and"));return new a.Expression(b)})),new a.Ruleset([],[])},permute:function(a){if(0===a.length)return[];if(1===a.length)return a[0];for(var b=[],c=this.permute(a.slice(1)),d=0;d0){for(j=!0,g=0;gh;h++)t.value(h),s[h]=d.matchCondition(e,b);(s[0]||s[1])&&(s[0]!=s[1]&&(l.group=s[1]?v:w),r.push(l))}else r.push(l);q=!0}}for(t.reset(),n=[0,0,0],g=0;g0)m=w;else if(m=v,n[v]+n[w]>1)throw{type:"Runtime",message:"Ambiguous use of `default()` found when matching for `"+this.format(e)+"`",index:this.index,filename:this.currentFileInfo.filename};for(g=0;gh;h++)if(g=d[h],k=g&&g.name){for(l=!1,i=0;ii;i++)f.push(d[i].value.eval(b));n.prependRule(new a.Rule(k,new a.Expression(f).eval(b)))}else{if(j=g&&g.value)j=j.eval(b);else{if(!o[h].value)throw{type:"Runtime",message:"wrong number of arguments for "+this.name+" ("+p+" for "+this.arity+")"};j=o[h].value.eval(c),n.resetCache()}n.prependRule(new a.Rule(k,j)),e[h]=j}if(o[h].variadic&&d)for(i=m;p>i;i++)e[i]=d[i].value.eval(b);m++}return n},eval:function(b){return new a.mixin.Definition(this.name,this.params,this.rules,this.condition,this.variadic,this.frames||b.frames.slice(0))},evalCall:function(b,c,d){var e,f,g=[],h=this.frames?this.frames.concat(b.frames):b.frames,i=this.evalParams(b,new a.evalEnv(b,h),c,g);return i.prependRule(new a.Rule("@arguments",new a.Expression(g).eval(b))),e=this.rules.slice(0),f=new a.Ruleset(null,e),f.originalRuleset=this,f=f.eval(new a.evalEnv(b,[this,i].concat(h))),d&&(f=this.parent.makeImportant.apply(f)),f},matchCondition:function(b,c){return this.condition&&!this.condition.eval(new a.evalEnv(c,[this.evalParams(c,new a.evalEnv(c,this.frames?this.frames.concat(c.frames):c.frames),b,[])].concat(this.frames).concat(c.frames)))?!1:!0},matchArgs:function(a,b){var c,d=a&&a.length||0;if(this.variadic){if(dthis.params.length)return!1}c=Math.min(d,this.arity);for(var e=0;c>e;e++)if(!this.params[e].name&&!this.params[e].variadic&&a[e].value.eval(b).toCSS()!=this.params[e].value.eval(b).toCSS())return!1;return!0}}}(c("../tree")),function(a){a.Negative=function(a){this.value=a},a.Negative.prototype={type:"Negative",accept:function(a){this.value=a.visit(this.value)},genCSS:function(a,b){b.add("-"),this.value.genCSS(a,b)},toCSS:a.toCSS,eval:function(b){return b.isMathOn()?new a.Operation("*",[new a.Dimension(-1),this.value]).eval(b):new a.Negative(this.value.eval(b))}}}(c("../tree")),function(a){a.Operation=function(a,b,c){this.op=a.trim(),this.operands=b,this.isSpaced=c},a.Operation.prototype={type:"Operation",accept:function(a){this.operands=a.visit(this.operands)},eval:function(b){var c=this.operands[0].eval(b),d=this.operands[1].eval(b);if(b.isMathOn()){if(c instanceof a.Dimension&&d instanceof a.Color&&(c=c.toColor()),d instanceof a.Dimension&&c instanceof a.Color&&(d=d.toColor()),!c.operate)throw{type:"Operation",message:"Operation on an invalid type"};return c.operate(b,this.op,d)}return new a.Operation(this.op,[c,d],this.isSpaced)},genCSS:function(a,b){this.operands[0].genCSS(a,b),this.isSpaced&&b.add(" "),b.add(this.op),this.isSpaced&&b.add(" "),this.operands[1].genCSS(a,b)},toCSS:a.toCSS},a.operate=function(a,b,c,d){switch(b){case"+":return c+d;case"-":return c-d;case"*":return c*d;case"/":return c/d}}}(c("../tree")),function(a){a.Paren=function(a){this.value=a},a.Paren.prototype={type:"Paren",accept:function(a){this.value=a.visit(this.value)},genCSS:function(a,b){b.add("("),this.value.genCSS(a,b),b.add(")")},toCSS:a.toCSS,eval:function(b){return new a.Paren(this.value.eval(b))}}}(c("../tree")),function(a){a.Quoted=function(a,b,c,d,e){this.escaped=c,this.value=b||"",this.quote=a.charAt(0),this.index=d,this.currentFileInfo=e},a.Quoted.prototype={type:"Quoted",genCSS:function(a,b){this.escaped||b.add(this.quote,this.currentFileInfo,this.index),b.add(this.value),this.escaped||b.add(this.quote)},toCSS:a.toCSS,eval:function(b){var c=this,d=this.value.replace(/`([^`]+)`/g,function(d,e){return new a.JavaScript(e,c.index,!0).eval(b).value}).replace(/@\{([\w-]+)\}/g,function(d,e){var f=new a.Variable("@"+e,c.index,c.currentFileInfo).eval(b,!0);return f instanceof a.Quoted?f.value:f.toCSS()});return new a.Quoted(this.quote+d+this.quote,d,this.escaped,this.index,this.currentFileInfo)},compare:function(a){if(!a.toCSS)return-1;var b,c;return"Quoted"!==a.type||this.escaped||a.escaped?(b=this.toCSS(),c=a.toCSS()):(b=a.value,c=this.value),b===c?0:c>b?-1:1}}}(c("../tree")),function(a){function b(a,b){var c,d="",e=b.length,f={add:function(a){d+=a}};for(c=0;e>c;c++)b[c].eval(a).genCSS(a,f);return d}a.Rule=function(b,c,d,e,f,g,h){this.name=b,this.value=c instanceof a.Value||c instanceof a.Ruleset?c:new a.Value([c]),this.important=d?" "+d.trim():"",this.merge=e,this.index=f,this.currentFileInfo=g,this.inline=h||!1,this.variable=b.charAt&&"@"===b.charAt(0)},a.Rule.prototype={type:"Rule",accept:function(a){this.value=a.visit(this.value)},genCSS:function(a,b){b.add(this.name+(a.compress?":":": "),this.currentFileInfo,this.index);try{this.value.genCSS(a,b)}catch(c){throw c.index=this.index,c.filename=this.currentFileInfo.filename,c}b.add(this.important+(this.inline||a.lastRule&&a.compress?"":";"),this.currentFileInfo,this.index)},toCSS:a.toCSS,eval:function(c){var d,e=!1,f=this.name;"string"!=typeof f&&(f=1===f.length&&f[0]instanceof a.Keyword?f[0].value:b(c,f)),"font"!==f||c.strictMath||(e=!0,c.strictMath=!0);try{if(d=this.value.eval(c),!this.variable&&"DetachedRuleset"===d.type)throw{message:"Rulesets cannot be evaluated on a property.",index:this.index,filename:this.currentFileInfo.filename};return new a.Rule(f,d,this.important,this.merge,this.index,this.currentFileInfo,this.inline)}catch(g){throw"number"!=typeof g.index&&(g.index=this.index,g.filename=this.currentFileInfo.filename),g}finally{e&&(c.strictMath=!1)}},makeImportant:function(){return new a.Rule(this.name,this.value,"!important",this.merge,this.index,this.currentFileInfo,this.inline)}}}(c("../tree")),function(a){a.RulesetCall=function(a){this.variable=a},a.RulesetCall.prototype={type:"RulesetCall",accept:function(){},eval:function(b){var c=new a.Variable(this.variable).eval(b);return c.callEval(b)}}}(c("../tree")),function(a){a.Ruleset=function(a,b,c){this.selectors=a,this.rules=b,this._lookups={},this.strictImports=c},a.Ruleset.prototype={type:"Ruleset",accept:function(a){this.paths?a.visitArray(this.paths,!0):this.selectors&&(this.selectors=a.visitArray(this.selectors)),this.rules&&this.rules.length&&(this.rules=a.visitArray(this.rules))},eval:function(b){var c,d,e,f,g=this.selectors,h=a.defaultFunc,i=!1;if(g&&(d=g.length)){for(c=[],h.error({type:"Syntax",message:"it is currently only allowed in parametric mixin guards,"}),f=0;d>f;f++)e=g[f].eval(b),c.push(e),e.evaldCondition&&(i=!0);h.reset()}else i=!0;var j,k,l=this.rules?this.rules.slice(0):null,m=new a.Ruleset(c,l,this.strictImports);m.originalRuleset=this,m.root=this.root,m.firstRoot=this.firstRoot,m.allowImports=this.allowImports,this.debugInfo&&(m.debugInfo=this.debugInfo),i||(l.length=0);var n=b.frames;n.unshift(m);var o=b.selectors;o||(b.selectors=o=[]),o.unshift(this.selectors),(m.root||m.allowImports||!m.strictImports)&&m.evalImports(b);var p=m.rules,q=p?p.length:0;for(f=0;q>f;f++)(p[f]instanceof a.mixin.Definition||p[f]instanceof a.DetachedRuleset)&&(p[f]=p[f].eval(b));var r=b.mediaBlocks&&b.mediaBlocks.length||0;for(f=0;q>f;f++)p[f]instanceof a.mixin.Call?(l=p[f].eval(b).filter(function(b){return b instanceof a.Rule&&b.variable?!m.variable(b.name):!0}),p.splice.apply(p,[f,1].concat(l)),q+=l.length-1,f+=l.length-1,m.resetCache()):p[f]instanceof a.RulesetCall&&(l=p[f].eval(b).rules.filter(function(b){return b instanceof a.Rule&&b.variable?!1:!0}),p.splice.apply(p,[f,1].concat(l)),q+=l.length-1,f+=l.length-1,m.resetCache());for(f=0;fb;b++)c=g[b],(c instanceof d||c instanceof e)&&f.push(c);return f},prependRule:function(a){var b=this.rules;b?b.unshift(a):this.rules=[a]},find:function(b,c){c=c||this;var d,e=[],f=b.toCSS();return f in this._lookups?this._lookups[f]:(this.rulesets().forEach(function(f){if(f!==c)for(var g=0;gd?Array.prototype.push.apply(e,f.find(new a.Selector(b.elements.slice(d)),c)):e.push(f);break}}),this._lookups[f]=e,e)},genCSS:function(b,c){var d,e,f,g,h,i,j=[],k=[];b.tabLevel=b.tabLevel||0,this.root||b.tabLevel++;var l,m=b.compress?"":Array(b.tabLevel+1).join(" "),n=b.compress?"":Array(b.tabLevel).join(" ");for(d=0;dd;d++)if(i=p[d],o=i.length)for(d>0&&c.add(l),b.firstSelector=!0,i[0].genCSS(b,c),b.firstSelector=!1,e=1;o>e;e++)i[e].genCSS(b,c);c.add((b.compress?"{":" {\n")+m)}for(d=0;dd;d++)l&&c.add(l),k[d].genCSS(b,c);c.isEmpty()||b.compress||!this.firstRoot||c.add("\n")},toCSS:a.toCSS,markReferenced:function(){if(this.selectors)for(var a=0;a0&&this.mergeElementsOnToSelectors(r,i),f=0;f0&&(k[0].elements=k[0].elements.slice(0),k[0].elements.push(new a.Element(j.combinator,"",j.index,j.currentFileInfo))),s.push(k);else for(g=0;g0?(m=k.slice(0),q=m.pop(),o=d.createDerived(q.elements.slice(0)),p=!1):o=d.createDerived([]),l.length>1&&(n=n.concat(l.slice(1))),l.length>0&&(p=!1,o.elements.push(new a.Element(j.combinator,l[0].elements[0].value,j.index,j.currentFileInfo)),o.elements=o.elements.concat(l[0].elements.slice(1))),p||m.push(o),m=m.concat(n),s.push(m);i=s,r=[]}for(r.length>0&&this.mergeElementsOnToSelectors(r,i),e=0;e0&&b.push(i[e])}else if(c.length>0)for(e=0;e0?e[e.length-1]=e[e.length-1].createDerived(e[e.length-1].elements.concat(b)):e.push(new a.Selector(b))}}}(c("../tree")),function(a){a.Selector=function(a,b,c,d,e,f){this.elements=a,this.extendList=b,this.condition=c,this.currentFileInfo=e||{},this.isReferenced=f,c||(this.evaldCondition=!0)},a.Selector.prototype={type:"Selector",accept:function(a){this.elements&&(this.elements=a.visitArray(this.elements)),this.extendList&&(this.extendList=a.visitArray(this.extendList)),this.condition&&(this.condition=a.visit(this.condition))},createDerived:function(b,c,d){d=null!=d?d:this.evaldCondition;var e=new a.Selector(b,c||this.extendList,null,this.index,this.currentFileInfo,this.isReferenced);return e.evaldCondition=d,e.mediaEmpty=this.mediaEmpty,e},match:function(a){var b,c,d=this.elements,e=d.length;if(a.CacheElements(),b=a._elements.length,0===b||b>e)return 0;for(c=0;b>c;c++)if(d[c].value!==a._elements[c])return 0;return b},CacheElements:function(){var a,b,c,d="";if(!this._elements){for(a=this.elements.length,c=0;a>c;c++)if(b=this.elements[c],d+=b.combinator.value,b.value.value){if("string"!=typeof b.value.value){d="";break}d+=b.value.value}else d+=b.value;this._elements=d.match(/[,&#\.\w-]([\w-]|(\\.))*/g),this._elements?"&"===this._elements[0]&&this._elements.shift():this._elements=[]}},isJustParentSelector:function(){return!this.mediaEmpty&&1===this.elements.length&&"&"===this.elements[0].value&&(" "===this.elements[0].combinator.value||""===this.elements[0].combinator.value)},eval:function(a){var b=this.condition&&this.condition.eval(a),c=this.elements,d=this.extendList;return c=c&&c.map(function(b){return b.eval(a)}),d=d&&d.map(function(b){return b.eval(a)}),this.createDerived(c,d,b)},genCSS:function(a,b){var c,d;if(a&&a.firstSelector||""!==this.elements[0].combinator.value||b.add(" ",this.currentFileInfo,this.index),!this._css)for(c=0;cc;c++)this.visit(a[c]);return a}var e=[];for(c=0;d>c;c++){var f=this.visit(a[c]);f.splice?f.length&&this.flatten(f,e):e.push(f)}return e},flatten:function(a,b){b||(b=[]);var c,d,e,f,g,h;for(d=0,c=a.length;c>d;d++)if(e=a[d],e.splice)for(g=0,f=e.length;f>g;g++)h=e[g],h.splice?h.length&&this.flatten(h,b):b.push(h);else b.push(e);return b}}}(c("./tree")),function(a){a.importVisitor=function(b,c,d,e,f){if(this._visitor=new a.visitor(this),this._importer=b,this._finish=c,this.env=d||new a.evalEnv,this.importCount=0,this.onceFileDetectionMap=e||{},this.recursionDetector={},f)for(var g in f)f.hasOwnProperty(g)&&(this.recursionDetector[g]=!0)},a.importVisitor.prototype={isReplacing:!0,run:function(a){var b;try{this._visitor.visit(a)}catch(c){b=c}this.isFinished=!0,0===this.importCount&&this._finish(b)},visitImport:function(b,c){var d,e=this,f=b.options.inline;if(!b.css||f){try{d=b.evalForImport(this.env)}catch(g){g.filename||(g.index=b.index,g.filename=b.currentFileInfo.filename),b.css=!0,b.error=g}if(d&&(!d.css||f)){b=d,this.importCount++;var h=new a.evalEnv(this.env,this.env.frames.slice(0));b.options.multiple&&(h.importMultiple=!0),this._importer.push(b.getPath(),b.currentFileInfo,b.options,function(c,d,g,i){c&&!c.filename&&(c.index=b.index,c.filename=b.currentFileInfo.filename),h.importMultiple||(b.skip=g?!0:function(){return i in e.onceFileDetectionMap?!0:(e.onceFileDetectionMap[i]=!0,!1)});var j=function(a){e.importCount--,0===e.importCount&&e.isFinished&&e._finish(a)};if(d){b.root=d,b.importedFilename=i;var k=g||i in e.recursionDetector;if(!f&&(h.importMultiple||!k))return e.recursionDetector[i]=!0,void new a.importVisitor(e._importer,j,h,e.onceFileDetectionMap,e.recursionDetector).run(d)}j()})}}return c.visitDeeper=!1,b},visitRule:function(a,b){return b.visitDeeper=!1,a},visitDirective:function(a){return this.env.frames.unshift(a),a},visitDirectiveOut:function(){this.env.frames.shift()},visitMixinDefinition:function(a){return this.env.frames.unshift(a),a},visitMixinDefinitionOut:function(){this.env.frames.shift()},visitRuleset:function(a){return this.env.frames.unshift(a),a},visitRulesetOut:function(){this.env.frames.shift()},visitMedia:function(a){return this.env.frames.unshift(a.ruleset),a},visitMediaOut:function(){this.env.frames.shift()}}}(c("./tree")),function(a){a.joinSelectorVisitor=function(){this.contexts=[[]],this._visitor=new a.visitor(this)},a.joinSelectorVisitor.prototype={run:function(a){return this._visitor.visit(a)},visitRule:function(a,b){b.visitDeeper=!1},visitMixinDefinition:function(a,b){b.visitDeeper=!1},visitRuleset:function(a){var b,c=this.contexts[this.contexts.length-1],d=[];this.contexts.push(d),a.root||(b=a.selectors,b&&(b=b.filter(function(a){return a.getIsOutput()}),a.selectors=b.length?b:b=null,b&&a.joinSelectors(d,c,b)),b||(a.rules=null),a.paths=d)},visitRulesetOut:function(){this.contexts.length=this.contexts.length-1},visitMedia:function(a){var b=this.contexts[this.contexts.length-1];a.rules[0].root=0===b.length||b[0].multiMedia}}}(c("./tree")),function(a){a.toCSSVisitor=function(b){this._visitor=new a.visitor(this),this._env=b},a.toCSSVisitor.prototype={isReplacing:!0,run:function(a){return this._visitor.visit(a)},visitRule:function(a){return a.variable?[]:a},visitMixinDefinition:function(a){return a.frames=[],[]},visitExtend:function(){return[]},visitComment:function(a){return a.isSilent(this._env)?[]:a},visitMedia:function(a,b){return a.accept(this._visitor),b.visitDeeper=!1,a.rules.length?a:[]},visitDirective:function(b){if(b.currentFileInfo.reference&&!b.isReferenced)return[];if("@charset"===b.name){if(this.charset){if(b.debugInfo){var c=new a.Comment("/* "+b.toCSS(this._env).replace(/\n/g,"")+" */\n");return c.debugInfo=b.debugInfo,this._visitor.visit(c)}return[]}this.charset=!0}return b},checkPropertiesInRoot:function(b){for(var c,d=0;d0)&&e.splice(0,0,b);else{b.paths&&(b.paths=b.paths.filter(function(b){var c;for(" "===b[0].elements[0].combinator.value&&(b[0].elements[0].combinator=new a.Combinator("")),c=0;ch;)d=f[h],d&&d.rules?(e.push(this._visitor.visit(d)),f.splice(h,1),g--):h++;g>0?b.accept(this._visitor):b.rules=null,c.visitDeeper=!1,f=b.rules,f&&(this._mergeRules(f),f=b.rules),f&&(this._removeDuplicateRules(f),f=b.rules),f&&f.length>0&&b.paths.length>0&&e.splice(0,0,b)}return 1===e.length?e[0]:e},_removeDuplicateRules:function(b){if(b){var c,d,e,f={};for(e=b.length-1;e>=0;e--)if(d=b[e],d instanceof a.Rule)if(f[d.name]){c=f[d.name],c instanceof a.Rule&&(c=f[d.name]=[f[d.name].toCSS(this._env)]);var g=d.toCSS(this._env);-1!==c.indexOf(g)?b.splice(e,1):c.push(g)}else f[d.name]=d}},_mergeRules:function(b){if(b){for(var c,d,e,f={},g=0;g1){d=c[0];var h=[],i=[];c.map(function(a){"+"===a.merge&&(i.length>0&&h.push(e(i)),i=[]),i.push(a)}),h.push(e(i)),d.value=g(h)}})}}}}(c("./tree")),function(a){a.extendFinderVisitor=function(){this._visitor=new a.visitor(this),this.contexts=[],this.allExtendsStack=[[]]},a.extendFinderVisitor.prototype={run:function(a){return a=this._visitor.visit(a),a.allExtends=this.allExtendsStack[0],a},visitRule:function(a,b){b.visitDeeper=!1},visitMixinDefinition:function(a,b){b.visitDeeper=!1},visitRuleset:function(b){if(!b.root){var c,d,e,f,g=[],h=b.rules,i=h?h.length:0;for(c=0;i>c;c++)b.rules[c]instanceof a.Extend&&(g.push(h[c]),b.extendOnEveryPath=!0);var j=b.paths;for(c=0;c=0||(i=[k.selfSelectors[0]],g=n.findMatch(j,i),g.length&&j.selfSelectors.forEach(function(b){h=n.extendSelector(g,i,b),l=new a.Extend(k.selector,k.option,0),l.selfSelectors=h,h[h.length-1].extendList=[l],m.push(l),l.ruleset=k.ruleset,l.parent_ids=l.parent_ids.concat(k.parent_ids,j.parent_ids),k.firstExtendOnThisSelectorPath&&(l.firstExtendOnThisSelectorPath=!0,k.ruleset.paths.push(h))}));if(m.length){if(this.extendChainCount++,d>100){var o="{unable to calculate}",p="{unable to calculate}";try{o=m[0].selfSelectors[0].toCSS(),p=m[0].selector.toCSS()}catch(q){}throw{message:"extend circular reference detected. One of the circular extends is currently:"+o+":extend("+p+")"}}return m.concat(n.doExtendChaining(m,c,d+1))}return m},visitRule:function(a,b){b.visitDeeper=!1},visitMixinDefinition:function(a,b){b.visitDeeper=!1},visitSelector:function(a,b){b.visitDeeper=!1},visitRuleset:function(a){if(!a.root){var b,c,d,e,f=this.allExtendsStack[this.allExtendsStack.length-1],g=[],h=this;for(d=0;d0&&k[i.matched].combinator.value!==g?i=null:i.matched++,i&&(i.finished=i.matched===k.length,i.finished&&!a.allowAfter&&(e+1j&&k>0&&(l[l.length-1].elements=l[l.length-1].elements.concat(c[j].elements.slice(k)),k=0,j++),i=f.elements.slice(k,h.index).concat([g]).concat(d.elements.slice(1)),j===h.pathIndex&&e>0?l[l.length-1].elements=l[l.length-1].elements.concat(i):(l=l.concat(c.slice(j,h.pathIndex)),l.push(new a.Selector(i))),j=h.endPathIndex,k=h.endPathElementIndex,k>=c[j].elements.length&&(k=0,j++); +return j0&&(l[l.length-1].elements=l[l.length-1].elements.concat(c[j].elements.slice(k)),j++),l=l.concat(c.slice(j,c.length))},visitRulesetOut:function(){},visitMedia:function(a){var b=a.allExtends.concat(this.allExtendsStack[this.allExtendsStack.length-1]);b=b.concat(this.doExtendChaining(b,a.allExtends)),this.allExtendsStack.push(b)},visitMediaOut:function(){this.allExtendsStack.length=this.allExtendsStack.length-1},visitDirective:function(a){var b=a.allExtends.concat(this.allExtendsStack[this.allExtendsStack.length-1]);b=b.concat(this.doExtendChaining(b,a.allExtends)),this.allExtendsStack.push(b)},visitDirectiveOut:function(){this.allExtendsStack.length=this.allExtendsStack.length-1}}}(c("./tree")),function(a){a.sourceMapOutput=function(a){this._css=[],this._rootNode=a.rootNode,this._writeSourceMap=a.writeSourceMap,this._contentsMap=a.contentsMap,this._contentsIgnoredCharsMap=a.contentsIgnoredCharsMap,this._sourceMapFilename=a.sourceMapFilename,this._outputFilename=a.outputFilename,this._sourceMapURL=a.sourceMapURL,a.sourceMapBasepath&&(this._sourceMapBasepath=a.sourceMapBasepath.replace(/\\/g,"/")),this._sourceMapRootpath=a.sourceMapRootpath,this._outputSourceFiles=a.outputSourceFiles,this._sourceMapGeneratorConstructor=a.sourceMapGenerator||c("source-map").SourceMapGenerator,this._sourceMapRootpath&&"/"!==this._sourceMapRootpath.charAt(this._sourceMapRootpath.length-1)&&(this._sourceMapRootpath+="/"),this._lineNumber=0,this._column=0},a.sourceMapOutput.prototype.normalizeFilename=function(a){return a=a.replace(/\\/g,"/"),this._sourceMapBasepath&&0===a.indexOf(this._sourceMapBasepath)&&(a=a.substring(this._sourceMapBasepath.length),("\\"===a.charAt(0)||"/"===a.charAt(0))&&(a=a.substring(1))),(this._sourceMapRootpath||"")+a},a.sourceMapOutput.prototype.add=function(a,b,c,d){if(a){var e,f,g,h,i;if(b){var j=this._contentsMap[b.filename];this._contentsIgnoredCharsMap[b.filename]&&(c-=this._contentsIgnoredCharsMap[b.filename],0>c&&(c=0),j=j.slice(this._contentsIgnoredCharsMap[b.filename])),j=j.substring(0,c),f=j.split("\n"),h=f[f.length-1]}if(e=a.split("\n"),g=e[e.length-1],b)if(d)for(i=0;i0){var e,f=JSON.stringify(this._sourceMapGenerator.toJSON());this._sourceMapURL?e=this._sourceMapURL:this._sourceMapFilename&&(e=this.normalizeFilename(this._sourceMapFilename)),this._writeSourceMap?this._writeSourceMap(f):e="data:application/json;base64,"+c("./encoder.js").encodeBase64(f),e&&this._css.push("/*# sourceMappingURL="+e+" */")}return this._css.join("")}}(c("./tree"));var y=/^(file|chrome(-extension)?|resource|qrc|app):/.test(location.protocol);w.env=w.env||("127.0.0.1"==location.hostname||"0.0.0.0"==location.hostname||"localhost"==location.hostname||location.port&&location.port.length>0||y?"development":"production");var z={debug:3,info:2,errors:1,none:0};if(w.logLevel="undefined"!=typeof w.logLevel?w.logLevel:"development"===w.env?z.debug:z.errors,w.async=w.async||!1,w.fileAsync=w.fileAsync||!1,w.poll=w.poll||(y?1e3:1500),w.functions)for(var A in w.functions)w.functions.hasOwnProperty(A)&&(w.tree.functions[A]=w.functions[A]);var B=/!dumpLineNumbers:(comments|mediaquery|all)/.exec(location.hash);B&&(w.dumpLineNumbers=B[1]);var C=/^text\/(x-)?less$/,D=null,E={};if(w.watch=function(){return w.watchMode||(w.env="development",v()),this.watchMode=!0,!0},w.unwatch=function(){return clearInterval(w.watchTimer),this.watchMode=!1,!1},/!watch/.test(location.hash)&&w.watch(),"development"!=w.env)try{D="undefined"==typeof a.localStorage?null:a.localStorage}catch(F){}var G=document.getElementsByTagName("link");w.sheets=[];for(var H=0;H Date: Sat, 28 Jun 2014 17:37:55 +0100 Subject: [PATCH 251/321] Limit full previews for 2 hours We've been getting more and more spammers using JS Bin to create either phishing pages, or using the JS to redirect. We have an internal method to blacklist these spammers, but JS Bin's weak spot is that anyone can create anonymous bins and link to the full output (i.e. without any of the JS Bin bits - like a mini geocities). It's been getting worse as time goes on, so I'm moving to a model that allows full previews for 2 hours, then automatically redirects to the /edit view - which at the very least, informs the visitor that they're actually on jsbin.com and not being phished. I will adjust this change so that it only applies to *new* bins since the release of this code. If you create your bins as registered user, this has no effect for you. However, if you're registered and creating spam, it'll in breach of our T&Cs, so we will remove your account - be nice! --- lib/handlers/bin.js | 25 +++++++++++++++++++++++++ lib/routes.js | 4 ++-- 2 files changed, 27 insertions(+), 2 deletions(-) diff --git a/lib/handlers/bin.js b/lib/handlers/bin.js index 841e3267..ac3662d6 100644 --- a/lib/handlers/bin.js +++ b/lib/handlers/bin.js @@ -149,6 +149,31 @@ module.exports = Observable.extend({ req.embed = true; next(); }, + testPreviewAllowed: function (req, res, next) { + /** + * if the bin does not have a user who create it + * and it was made 2 hours ago + * then redirect to the /edit url + */ + var user = undefsafe(req, 'bin.metadata.name'); + if (user === 'anonymous' || !user) { + var created = req.bin.created; + // test the time created + if ((Date.now() - created.getTime()) / 1000 / 60 > 120) { + var msg = 'This bin was created anonymously and it\'s free preview time has expired.'; + + if (!req.session.user) { + msg += ' Get a free unrestricted account'; + } else { + msg += ' Clone it create to enable the full preview'; + } + res.flash(req.flash.NOTIFICATION, msg); + return res.redirect(this.helpers.urlForBin(req.bin) + '/edit'); + } + } + // console.log(req.bin); + next(); + }, getBinPreview: function (req, res, next) { // if we're loading a username/last(-:n)? and no 'n' is present // it breaks quiet, leaving it as undefined, here we manually diff --git a/lib/routes.js b/lib/routes.js index 423c8a25..7e4833f2 100644 --- a/lib/routes.js +++ b/lib/routes.js @@ -491,8 +491,8 @@ module.exports = function (app) { app.post('/:bin/:rev/log', spike.postLog); // Preview - app.get('/:bin/:quiet(quiet)?', spike.getStream, binHandler.getBinPreview); - app.get('/:bin/:rev?/:quiet(quiet)?', spike.getStream, binHandler.getBinPreview); + app.get('/:bin/:quiet(quiet)?', binHandler.testPreviewAllowed, spike.getStream, binHandler.getBinPreview); + app.get('/:bin/:rev?/:quiet(quiet)?', binHandler.testPreviewAllowed, spike.getStream, binHandler.getBinPreview); app.get('/:bin/:rev?/stats', tag('stats'), spike.getStream); app.get('/test/error/:num', function (req, res, next) { From 834a097c1b3d2cfcf9a35e075b4a262a2ce07392 Mon Sep 17 00:00:00 2001 From: Remy Sharp Date: Sat, 28 Jun 2014 17:54:57 +0100 Subject: [PATCH 252/321] remove console --- lib/handlers/bin.js | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/handlers/bin.js b/lib/handlers/bin.js index ac3662d6..eece0083 100644 --- a/lib/handlers/bin.js +++ b/lib/handlers/bin.js @@ -171,7 +171,6 @@ module.exports = Observable.extend({ return res.redirect(this.helpers.urlForBin(req.bin) + '/edit'); } } - // console.log(req.bin); next(); }, getBinPreview: function (req, res, next) { From 65715c1409d27ef8d5ccef3416bbb52b67f186df Mon Sep 17 00:00:00 2001 From: Remy Sharp Date: Sat, 28 Jun 2014 18:28:41 +0100 Subject: [PATCH 253/321] typo --- lib/handlers/bin.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/handlers/bin.js b/lib/handlers/bin.js index eece0083..1ef8d44b 100644 --- a/lib/handlers/bin.js +++ b/lib/handlers/bin.js @@ -160,7 +160,7 @@ module.exports = Observable.extend({ var created = req.bin.created; // test the time created if ((Date.now() - created.getTime()) / 1000 / 60 > 120) { - var msg = 'This bin was created anonymously and it\'s free preview time has expired.'; + var msg = 'This bin was created anonymously and its free preview time has expired.'; if (!req.session.user) { msg += ' Get a free unrestricted account'; From 92989ce18d71fe4ae11e9693cb2a29e95c0f3267 Mon Sep 17 00:00:00 2001 From: Couto Date: Mon, 30 Jun 2014 19:45:32 +0100 Subject: [PATCH 254/321] Add Bluebird library to work with promises. --- public/js/editors/libraries.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/public/js/editors/libraries.js b/public/js/editors/libraries.js index a180d8d2..45eda5df 100644 --- a/public/js/editors/libraries.js +++ b/public/js/editors/libraries.js @@ -340,6 +340,10 @@ var libraries = [ 'url': 'http://cdnjs.cloudflare.com/ajax/libs/bonsai/0.4/bonsai.min.js', 'label': 'Bonsai 0.4.latest' }, + { + 'url': '//cdnjs.cloudflare.com/ajax/libs/bluebird/1.2.2/bluebird.js', + 'label': 'Bluebird 1.2.2' + }, { 'url': 'http://jashkenas.github.io/coffee-script/extras/coffee-script.js', 'label': 'CoffeeScript' From 9dda1987e5524c6c5320d5cc647f5a5ce9dedc3f Mon Sep 17 00:00:00 2001 From: Giulia Alfonsi Date: Tue, 1 Jul 2014 01:42:58 +0100 Subject: [PATCH 255/321] Added example version of linting for css panel --- public/js/account/editor-settings.js | 3 +- public/js/editors/addons.js | 33 +- public/js/vendor/cm_addons/lint/css-lint.js | 35 + public/js/vendor/cm_addons/lint/csslint.js | 9259 +++++++++++++++++++ public/js/vendor/cm_addons/lint/lint.css | 142 + public/js/vendor/cm_addons/lint/lint.js | 376 + views/account/editor.html | 5 + 7 files changed, 9851 insertions(+), 2 deletions(-) create mode 100644 public/js/vendor/cm_addons/lint/css-lint.js create mode 100644 public/js/vendor/cm_addons/lint/csslint.js create mode 100644 public/js/vendor/cm_addons/lint/lint.css create mode 100644 public/js/vendor/cm_addons/lint/lint.js diff --git a/public/js/account/editor-settings.js b/public/js/account/editor-settings.js index 214d3b1b..28f428a3 100644 --- a/public/js/account/editor-settings.js +++ b/public/js/account/editor-settings.js @@ -83,7 +83,8 @@ 'emacs', 'sublime', 'tern', - 'matchbrackets' + 'matchbrackets', + 'csslint' ]; var $addons = {}; diff --git a/public/js/editors/addons.js b/public/js/editors/addons.js index 4d5cc2bd..692ed200 100644 --- a/public/js/editors/addons.js +++ b/public/js/editors/addons.js @@ -12,7 +12,8 @@ sublime: false, tern: false, activeline: true, - matchbrackets: false + matchbrackets: false, + csslint: false }; if (!jsbin.settings.addons) { @@ -176,6 +177,36 @@ done: function(cm) { setOption(cm, 'matchBrackets', true); } + }, + csslint: { + url: [ + '/js/vendor/cm_addons/lint/lint.css', + '/js/vendor/cm_addons/lint/csslint.js', + '/js/vendor/cm_addons/lint/css-lint.js', + '/js/vendor/cm_addons/lint/lint.js' + ], + test: function() { + return CodeMirror.defaults.lint !== undefined && + CodeMirror.helpers.lint && + CodeMirror.helpers.lint.css && + CodeMirror.optionHandlers.lint; + }, + done: function(cm) { + if (cm.getOption('mode') === 'css') { + setOption(cm, 'lintOpt', { + console: true, + consoleParent: cm.getWrapperElement().parentNode.parentNode, + line: true, + under: false, + tooltip: true + // gutter option doesn't exist, it takes from main gutters property + }); + var gutters = cm.getOption('gutters'); + gutters.push('CodeMirror-lint-markers'); + setOption(cm, 'gutters', gutters); + setOption(cm, 'lint', true); + } + } } }; diff --git a/public/js/vendor/cm_addons/lint/css-lint.js b/public/js/vendor/cm_addons/lint/css-lint.js new file mode 100644 index 00000000..1f61b479 --- /dev/null +++ b/public/js/vendor/cm_addons/lint/css-lint.js @@ -0,0 +1,35 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +// Depends on csslint.js from https://github.com/stubbornella/csslint + +// declare global: CSSLint + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { +"use strict"; + +CodeMirror.registerHelper("lint", "css", function(text) { + var found = []; + if (!window.CSSLint) return found; + var results = CSSLint.verify(text), messages = results.messages, message = null; + for ( var i = 0; i < messages.length; i++) { + message = messages[i]; + var startLine = message.line -1, endLine = message.line -1, startCol = message.col -1, endCol = message.col; + found.push({ + from: CodeMirror.Pos(startLine, startCol), + to: CodeMirror.Pos(endLine, endCol), + message: message.message, + severity : message.type + }); + } + return found; +}); + +}); diff --git a/public/js/vendor/cm_addons/lint/csslint.js b/public/js/vendor/cm_addons/lint/csslint.js new file mode 100644 index 00000000..6a60eb99 --- /dev/null +++ b/public/js/vendor/cm_addons/lint/csslint.js @@ -0,0 +1,9259 @@ +/*! +CSSLint +Copyright (c) 2013 Nicole Sullivan and Nicholas C. Zakas. All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +*/ +/* Build: v0.10.0 15-August-2013 01:07:22 */ +var exports = exports || {}; +var CSSLint = (function(){ +/*! +Parser-Lib +Copyright (c) 2009-2011 Nicholas C. Zakas. All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +*/ +/* Version v0.2.3, Build time: 19-June-2013 11:16:15 */ +var parserlib = {}; +(function(){ + + +/** + * A generic base to inherit from for any object + * that needs event handling. + * @class EventTarget + * @constructor + */ +function EventTarget(){ + + /** + * The array of listeners for various events. + * @type Object + * @property _listeners + * @private + */ + this._listeners = {}; +} + +EventTarget.prototype = { + + //restore constructor + constructor: EventTarget, + + /** + * Adds a listener for a given event type. + * @param {String} type The type of event to add a listener for. + * @param {Function} listener The function to call when the event occurs. + * @return {void} + * @method addListener + */ + addListener: function(type, listener){ + if (!this._listeners[type]){ + this._listeners[type] = []; + } + + this._listeners[type].push(listener); + }, + + /** + * Fires an event based on the passed-in object. + * @param {Object|String} event An object with at least a 'type' attribute + * or a string indicating the event name. + * @return {void} + * @method fire + */ + fire: function(event){ + if (typeof event == "string"){ + event = { type: event }; + } + if (typeof event.target != "undefined"){ + event.target = this; + } + + if (typeof event.type == "undefined"){ + throw new Error("Event object missing 'type' property."); + } + + if (this._listeners[event.type]){ + + //create a copy of the array and use that so listeners can't chane + var listeners = this._listeners[event.type].concat(); + for (var i=0, len=listeners.length; i < len; i++){ + listeners[i].call(this, event); + } + } + }, + + /** + * Removes a listener for a given event type. + * @param {String} type The type of event to remove a listener from. + * @param {Function} listener The function to remove from the event. + * @return {void} + * @method removeListener + */ + removeListener: function(type, listener){ + if (this._listeners[type]){ + var listeners = this._listeners[type]; + for (var i=0, len=listeners.length; i < len; i++){ + if (listeners[i] === listener){ + listeners.splice(i, 1); + break; + } + } + + + } + } +}; +/** + * Convenient way to read through strings. + * @namespace parserlib.util + * @class StringReader + * @constructor + * @param {String} text The text to read. + */ +function StringReader(text){ + + /** + * The input text with line endings normalized. + * @property _input + * @type String + * @private + */ + this._input = text.replace(/\n\r?/g, "\n"); + + + /** + * The row for the character to be read next. + * @property _line + * @type int + * @private + */ + this._line = 1; + + + /** + * The column for the character to be read next. + * @property _col + * @type int + * @private + */ + this._col = 1; + + /** + * The index of the character in the input to be read next. + * @property _cursor + * @type int + * @private + */ + this._cursor = 0; +} + +StringReader.prototype = { + + //restore constructor + constructor: StringReader, + + //------------------------------------------------------------------------- + // Position info + //------------------------------------------------------------------------- + + /** + * Returns the column of the character to be read next. + * @return {int} The column of the character to be read next. + * @method getCol + */ + getCol: function(){ + return this._col; + }, + + /** + * Returns the row of the character to be read next. + * @return {int} The row of the character to be read next. + * @method getLine + */ + getLine: function(){ + return this._line ; + }, + + /** + * Determines if you're at the end of the input. + * @return {Boolean} True if there's no more input, false otherwise. + * @method eof + */ + eof: function(){ + return (this._cursor == this._input.length); + }, + + //------------------------------------------------------------------------- + // Basic reading + //------------------------------------------------------------------------- + + /** + * Reads the next character without advancing the cursor. + * @param {int} count How many characters to look ahead (default is 1). + * @return {String} The next character or null if there is no next character. + * @method peek + */ + peek: function(count){ + var c = null; + count = (typeof count == "undefined" ? 1 : count); + + //if we're not at the end of the input... + if (this._cursor < this._input.length){ + + //get character and increment cursor and column + c = this._input.charAt(this._cursor + count - 1); + } + + return c; + }, + + /** + * Reads the next character from the input and adjusts the row and column + * accordingly. + * @return {String} The next character or null if there is no next character. + * @method read + */ + read: function(){ + var c = null; + + //if we're not at the end of the input... + if (this._cursor < this._input.length){ + + //if the last character was a newline, increment row count + //and reset column count + if (this._input.charAt(this._cursor) == "\n"){ + this._line++; + this._col=1; + } else { + this._col++; + } + + //get character and increment cursor and column + c = this._input.charAt(this._cursor++); + } + + return c; + }, + + //------------------------------------------------------------------------- + // Misc + //------------------------------------------------------------------------- + + /** + * Saves the current location so it can be returned to later. + * @method mark + * @return {void} + */ + mark: function(){ + this._bookmark = { + cursor: this._cursor, + line: this._line, + col: this._col + }; + }, + + reset: function(){ + if (this._bookmark){ + this._cursor = this._bookmark.cursor; + this._line = this._bookmark.line; + this._col = this._bookmark.col; + delete this._bookmark; + } + }, + + //------------------------------------------------------------------------- + // Advanced reading + //------------------------------------------------------------------------- + + /** + * Reads up to and including the given string. Throws an error if that + * string is not found. + * @param {String} pattern The string to read. + * @return {String} The string when it is found. + * @throws Error when the string pattern is not found. + * @method readTo + */ + readTo: function(pattern){ + + var buffer = "", + c; + + /* + * First, buffer must be the same length as the pattern. + * Then, buffer must end with the pattern or else reach the + * end of the input. + */ + while (buffer.length < pattern.length || buffer.lastIndexOf(pattern) != buffer.length - pattern.length){ + c = this.read(); + if (c){ + buffer += c; + } else { + throw new Error("Expected \"" + pattern + "\" at line " + this._line + ", col " + this._col + "."); + } + } + + return buffer; + + }, + + /** + * Reads characters while each character causes the given + * filter function to return true. The function is passed + * in each character and either returns true to continue + * reading or false to stop. + * @param {Function} filter The function to read on each character. + * @return {String} The string made up of all characters that passed the + * filter check. + * @method readWhile + */ + readWhile: function(filter){ + + var buffer = "", + c = this.read(); + + while(c !== null && filter(c)){ + buffer += c; + c = this.read(); + } + + return buffer; + + }, + + /** + * Reads characters that match either text or a regular expression and + * returns those characters. If a match is found, the row and column + * are adjusted; if no match is found, the reader's state is unchanged. + * reading or false to stop. + * @param {String|RegExp} matchter If a string, then the literal string + * value is searched for. If a regular expression, then any string + * matching the pattern is search for. + * @return {String} The string made up of all characters that matched or + * null if there was no match. + * @method readMatch + */ + readMatch: function(matcher){ + + var source = this._input.substring(this._cursor), + value = null; + + //if it's a string, just do a straight match + if (typeof matcher == "string"){ + if (source.indexOf(matcher) === 0){ + value = this.readCount(matcher.length); + } + } else if (matcher instanceof RegExp){ + if (matcher.test(source)){ + value = this.readCount(RegExp.lastMatch.length); + } + } + + return value; + }, + + + /** + * Reads a given number of characters. If the end of the input is reached, + * it reads only the remaining characters and does not throw an error. + * @param {int} count The number of characters to read. + * @return {String} The string made up the read characters. + * @method readCount + */ + readCount: function(count){ + var buffer = ""; + + while(count--){ + buffer += this.read(); + } + + return buffer; + } + +}; +/** + * Type to use when a syntax error occurs. + * @class SyntaxError + * @namespace parserlib.util + * @constructor + * @param {String} message The error message. + * @param {int} line The line at which the error occurred. + * @param {int} col The column at which the error occurred. + */ +function SyntaxError(message, line, col){ + + /** + * The column at which the error occurred. + * @type int + * @property col + */ + this.col = col; + + /** + * The line at which the error occurred. + * @type int + * @property line + */ + this.line = line; + + /** + * The text representation of the unit. + * @type String + * @property text + */ + this.message = message; + +} + +//inherit from Error +SyntaxError.prototype = new Error(); +/** + * Base type to represent a single syntactic unit. + * @class SyntaxUnit + * @namespace parserlib.util + * @constructor + * @param {String} text The text of the unit. + * @param {int} line The line of text on which the unit resides. + * @param {int} col The column of text on which the unit resides. + */ +function SyntaxUnit(text, line, col, type){ + + + /** + * The column of text on which the unit resides. + * @type int + * @property col + */ + this.col = col; + + /** + * The line of text on which the unit resides. + * @type int + * @property line + */ + this.line = line; + + /** + * The text representation of the unit. + * @type String + * @property text + */ + this.text = text; + + /** + * The type of syntax unit. + * @type int + * @property type + */ + this.type = type; +} + +/** + * Create a new syntax unit based solely on the given token. + * Convenience method for creating a new syntax unit when + * it represents a single token instead of multiple. + * @param {Object} token The token object to represent. + * @return {parserlib.util.SyntaxUnit} The object representing the token. + * @static + * @method fromToken + */ +SyntaxUnit.fromToken = function(token){ + return new SyntaxUnit(token.value, token.startLine, token.startCol); +}; + +SyntaxUnit.prototype = { + + //restore constructor + constructor: SyntaxUnit, + + /** + * Returns the text representation of the unit. + * @return {String} The text representation of the unit. + * @method valueOf + */ + valueOf: function(){ + return this.toString(); + }, + + /** + * Returns the text representation of the unit. + * @return {String} The text representation of the unit. + * @method toString + */ + toString: function(){ + return this.text; + } + +}; +/*global StringReader, SyntaxError*/ + +/** + * Generic TokenStream providing base functionality. + * @class TokenStreamBase + * @namespace parserlib.util + * @constructor + * @param {String|StringReader} input The text to tokenize or a reader from + * which to read the input. + */ +function TokenStreamBase(input, tokenData){ + + /** + * The string reader for easy access to the text. + * @type StringReader + * @property _reader + * @private + */ + this._reader = input ? new StringReader(input.toString()) : null; + + /** + * Token object for the last consumed token. + * @type Token + * @property _token + * @private + */ + this._token = null; + + /** + * The array of token information. + * @type Array + * @property _tokenData + * @private + */ + this._tokenData = tokenData; + + /** + * Lookahead token buffer. + * @type Array + * @property _lt + * @private + */ + this._lt = []; + + /** + * Lookahead token buffer index. + * @type int + * @property _ltIndex + * @private + */ + this._ltIndex = 0; + + this._ltIndexCache = []; +} + +/** + * Accepts an array of token information and outputs + * an array of token data containing key-value mappings + * and matching functions that the TokenStream needs. + * @param {Array} tokens An array of token descriptors. + * @return {Array} An array of processed token data. + * @method createTokenData + * @static + */ +TokenStreamBase.createTokenData = function(tokens){ + + var nameMap = [], + typeMap = {}, + tokenData = tokens.concat([]), + i = 0, + len = tokenData.length+1; + + tokenData.UNKNOWN = -1; + tokenData.unshift({name:"EOF"}); + + for (; i < len; i++){ + nameMap.push(tokenData[i].name); + tokenData[tokenData[i].name] = i; + if (tokenData[i].text){ + typeMap[tokenData[i].text] = i; + } + } + + tokenData.name = function(tt){ + return nameMap[tt]; + }; + + tokenData.type = function(c){ + return typeMap[c]; + }; + + return tokenData; +}; + +TokenStreamBase.prototype = { + + //restore constructor + constructor: TokenStreamBase, + + //------------------------------------------------------------------------- + // Matching methods + //------------------------------------------------------------------------- + + /** + * Determines if the next token matches the given token type. + * If so, that token is consumed; if not, the token is placed + * back onto the token stream. You can pass in any number of + * token types and this will return true if any of the token + * types is found. + * @param {int|int[]} tokenTypes Either a single token type or an array of + * token types that the next token might be. If an array is passed, + * it's assumed that the token can be any of these. + * @param {variant} channel (Optional) The channel to read from. If not + * provided, reads from the default (unnamed) channel. + * @return {Boolean} True if the token type matches, false if not. + * @method match + */ + match: function(tokenTypes, channel){ + + //always convert to an array, makes things easier + if (!(tokenTypes instanceof Array)){ + tokenTypes = [tokenTypes]; + } + + var tt = this.get(channel), + i = 0, + len = tokenTypes.length; + + while(i < len){ + if (tt == tokenTypes[i++]){ + return true; + } + } + + //no match found, put the token back + this.unget(); + return false; + }, + + /** + * Determines if the next token matches the given token type. + * If so, that token is consumed; if not, an error is thrown. + * @param {int|int[]} tokenTypes Either a single token type or an array of + * token types that the next token should be. If an array is passed, + * it's assumed that the token must be one of these. + * @param {variant} channel (Optional) The channel to read from. If not + * provided, reads from the default (unnamed) channel. + * @return {void} + * @method mustMatch + */ + mustMatch: function(tokenTypes, channel){ + + var token; + + //always convert to an array, makes things easier + if (!(tokenTypes instanceof Array)){ + tokenTypes = [tokenTypes]; + } + + if (!this.match.apply(this, arguments)){ + token = this.LT(1); + throw new SyntaxError("Expected " + this._tokenData[tokenTypes[0]].name + + " at line " + token.startLine + ", col " + token.startCol + ".", token.startLine, token.startCol); + } + }, + + //------------------------------------------------------------------------- + // Consuming methods + //------------------------------------------------------------------------- + + /** + * Keeps reading from the token stream until either one of the specified + * token types is found or until the end of the input is reached. + * @param {int|int[]} tokenTypes Either a single token type or an array of + * token types that the next token should be. If an array is passed, + * it's assumed that the token must be one of these. + * @param {variant} channel (Optional) The channel to read from. If not + * provided, reads from the default (unnamed) channel. + * @return {void} + * @method advance + */ + advance: function(tokenTypes, channel){ + + while(this.LA(0) !== 0 && !this.match(tokenTypes, channel)){ + this.get(); + } + + return this.LA(0); + }, + + /** + * Consumes the next token from the token stream. + * @return {int} The token type of the token that was just consumed. + * @method get + */ + get: function(channel){ + + var tokenInfo = this._tokenData, + reader = this._reader, + value, + i =0, + len = tokenInfo.length, + found = false, + token, + info; + + //check the lookahead buffer first + if (this._lt.length && this._ltIndex >= 0 && this._ltIndex < this._lt.length){ + + i++; + this._token = this._lt[this._ltIndex++]; + info = tokenInfo[this._token.type]; + + //obey channels logic + while((info.channel !== undefined && channel !== info.channel) && + this._ltIndex < this._lt.length){ + this._token = this._lt[this._ltIndex++]; + info = tokenInfo[this._token.type]; + i++; + } + + //here be dragons + if ((info.channel === undefined || channel === info.channel) && + this._ltIndex <= this._lt.length){ + this._ltIndexCache.push(i); + return this._token.type; + } + } + + //call token retriever method + token = this._getToken(); + + //if it should be hidden, don't save a token + if (token.type > -1 && !tokenInfo[token.type].hide){ + + //apply token channel + token.channel = tokenInfo[token.type].channel; + + //save for later + this._token = token; + this._lt.push(token); + + //save space that will be moved (must be done before array is truncated) + this._ltIndexCache.push(this._lt.length - this._ltIndex + i); + + //keep the buffer under 5 items + if (this._lt.length > 5){ + this._lt.shift(); + } + + //also keep the shift buffer under 5 items + if (this._ltIndexCache.length > 5){ + this._ltIndexCache.shift(); + } + + //update lookahead index + this._ltIndex = this._lt.length; + } + + /* + * Skip to the next token if: + * 1. The token type is marked as hidden. + * 2. The token type has a channel specified and it isn't the current channel. + */ + info = tokenInfo[token.type]; + if (info && + (info.hide || + (info.channel !== undefined && channel !== info.channel))){ + return this.get(channel); + } else { + //return just the type + return token.type; + } + }, + + /** + * Looks ahead a certain number of tokens and returns the token type at + * that position. This will throw an error if you lookahead past the + * end of input, past the size of the lookahead buffer, or back past + * the first token in the lookahead buffer. + * @param {int} The index of the token type to retrieve. 0 for the + * current token, 1 for the next, -1 for the previous, etc. + * @return {int} The token type of the token in the given position. + * @method LA + */ + LA: function(index){ + var total = index, + tt; + if (index > 0){ + //TODO: Store 5 somewhere + if (index > 5){ + throw new Error("Too much lookahead."); + } + + //get all those tokens + while(total){ + tt = this.get(); + total--; + } + + //unget all those tokens + while(total < index){ + this.unget(); + total++; + } + } else if (index < 0){ + + if(this._lt[this._ltIndex+index]){ + tt = this._lt[this._ltIndex+index].type; + } else { + throw new Error("Too much lookbehind."); + } + + } else { + tt = this._token.type; + } + + return tt; + + }, + + /** + * Looks ahead a certain number of tokens and returns the token at + * that position. This will throw an error if you lookahead past the + * end of input, past the size of the lookahead buffer, or back past + * the first token in the lookahead buffer. + * @param {int} The index of the token type to retrieve. 0 for the + * current token, 1 for the next, -1 for the previous, etc. + * @return {Object} The token of the token in the given position. + * @method LA + */ + LT: function(index){ + + //lookahead first to prime the token buffer + this.LA(index); + + //now find the token, subtract one because _ltIndex is already at the next index + return this._lt[this._ltIndex+index-1]; + }, + + /** + * Returns the token type for the next token in the stream without + * consuming it. + * @return {int} The token type of the next token in the stream. + * @method peek + */ + peek: function(){ + return this.LA(1); + }, + + /** + * Returns the actual token object for the last consumed token. + * @return {Token} The token object for the last consumed token. + * @method token + */ + token: function(){ + return this._token; + }, + + /** + * Returns the name of the token for the given token type. + * @param {int} tokenType The type of token to get the name of. + * @return {String} The name of the token or "UNKNOWN_TOKEN" for any + * invalid token type. + * @method tokenName + */ + tokenName: function(tokenType){ + if (tokenType < 0 || tokenType > this._tokenData.length){ + return "UNKNOWN_TOKEN"; + } else { + return this._tokenData[tokenType].name; + } + }, + + /** + * Returns the token type value for the given token name. + * @param {String} tokenName The name of the token whose value should be returned. + * @return {int} The token type value for the given token name or -1 + * for an unknown token. + * @method tokenName + */ + tokenType: function(tokenName){ + return this._tokenData[tokenName] || -1; + }, + + /** + * Returns the last consumed token to the token stream. + * @method unget + */ + unget: function(){ + //if (this._ltIndex > -1){ + if (this._ltIndexCache.length){ + this._ltIndex -= this._ltIndexCache.pop();//--; + this._token = this._lt[this._ltIndex - 1]; + } else { + throw new Error("Too much lookahead."); + } + } + +}; + + + + +parserlib.util = { +StringReader: StringReader, +SyntaxError : SyntaxError, +SyntaxUnit : SyntaxUnit, +EventTarget : EventTarget, +TokenStreamBase : TokenStreamBase +}; +})(); + + +/* +Parser-Lib +Copyright (c) 2009-2011 Nicholas C. Zakas. All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +*/ +/* Version v0.2.3, Build time: 19-June-2013 11:16:15 */ +(function(){ +var EventTarget = parserlib.util.EventTarget, +TokenStreamBase = parserlib.util.TokenStreamBase, +StringReader = parserlib.util.StringReader, +SyntaxError = parserlib.util.SyntaxError, +SyntaxUnit = parserlib.util.SyntaxUnit; + + +var Colors = { + aliceblue :"#f0f8ff", + antiquewhite :"#faebd7", + aqua :"#00ffff", + aquamarine :"#7fffd4", + azure :"#f0ffff", + beige :"#f5f5dc", + bisque :"#ffe4c4", + black :"#000000", + blanchedalmond :"#ffebcd", + blue :"#0000ff", + blueviolet :"#8a2be2", + brown :"#a52a2a", + burlywood :"#deb887", + cadetblue :"#5f9ea0", + chartreuse :"#7fff00", + chocolate :"#d2691e", + coral :"#ff7f50", + cornflowerblue :"#6495ed", + cornsilk :"#fff8dc", + crimson :"#dc143c", + cyan :"#00ffff", + darkblue :"#00008b", + darkcyan :"#008b8b", + darkgoldenrod :"#b8860b", + darkgray :"#a9a9a9", + darkgreen :"#006400", + darkkhaki :"#bdb76b", + darkmagenta :"#8b008b", + darkolivegreen :"#556b2f", + darkorange :"#ff8c00", + darkorchid :"#9932cc", + darkred :"#8b0000", + darksalmon :"#e9967a", + darkseagreen :"#8fbc8f", + darkslateblue :"#483d8b", + darkslategray :"#2f4f4f", + darkturquoise :"#00ced1", + darkviolet :"#9400d3", + deeppink :"#ff1493", + deepskyblue :"#00bfff", + dimgray :"#696969", + dodgerblue :"#1e90ff", + firebrick :"#b22222", + floralwhite :"#fffaf0", + forestgreen :"#228b22", + fuchsia :"#ff00ff", + gainsboro :"#dcdcdc", + ghostwhite :"#f8f8ff", + gold :"#ffd700", + goldenrod :"#daa520", + gray :"#808080", + green :"#008000", + greenyellow :"#adff2f", + honeydew :"#f0fff0", + hotpink :"#ff69b4", + indianred :"#cd5c5c", + indigo :"#4b0082", + ivory :"#fffff0", + khaki :"#f0e68c", + lavender :"#e6e6fa", + lavenderblush :"#fff0f5", + lawngreen :"#7cfc00", + lemonchiffon :"#fffacd", + lightblue :"#add8e6", + lightcoral :"#f08080", + lightcyan :"#e0ffff", + lightgoldenrodyellow :"#fafad2", + lightgray :"#d3d3d3", + lightgreen :"#90ee90", + lightpink :"#ffb6c1", + lightsalmon :"#ffa07a", + lightseagreen :"#20b2aa", + lightskyblue :"#87cefa", + lightslategray :"#778899", + lightsteelblue :"#b0c4de", + lightyellow :"#ffffe0", + lime :"#00ff00", + limegreen :"#32cd32", + linen :"#faf0e6", + magenta :"#ff00ff", + maroon :"#800000", + mediumaquamarine:"#66cdaa", + mediumblue :"#0000cd", + mediumorchid :"#ba55d3", + mediumpurple :"#9370d8", + mediumseagreen :"#3cb371", + mediumslateblue :"#7b68ee", + mediumspringgreen :"#00fa9a", + mediumturquoise :"#48d1cc", + mediumvioletred :"#c71585", + midnightblue :"#191970", + mintcream :"#f5fffa", + mistyrose :"#ffe4e1", + moccasin :"#ffe4b5", + navajowhite :"#ffdead", + navy :"#000080", + oldlace :"#fdf5e6", + olive :"#808000", + olivedrab :"#6b8e23", + orange :"#ffa500", + orangered :"#ff4500", + orchid :"#da70d6", + palegoldenrod :"#eee8aa", + palegreen :"#98fb98", + paleturquoise :"#afeeee", + palevioletred :"#d87093", + papayawhip :"#ffefd5", + peachpuff :"#ffdab9", + peru :"#cd853f", + pink :"#ffc0cb", + plum :"#dda0dd", + powderblue :"#b0e0e6", + purple :"#800080", + red :"#ff0000", + rosybrown :"#bc8f8f", + royalblue :"#4169e1", + saddlebrown :"#8b4513", + salmon :"#fa8072", + sandybrown :"#f4a460", + seagreen :"#2e8b57", + seashell :"#fff5ee", + sienna :"#a0522d", + silver :"#c0c0c0", + skyblue :"#87ceeb", + slateblue :"#6a5acd", + slategray :"#708090", + snow :"#fffafa", + springgreen :"#00ff7f", + steelblue :"#4682b4", + tan :"#d2b48c", + teal :"#008080", + thistle :"#d8bfd8", + tomato :"#ff6347", + turquoise :"#40e0d0", + violet :"#ee82ee", + wheat :"#f5deb3", + white :"#ffffff", + whitesmoke :"#f5f5f5", + yellow :"#ffff00", + yellowgreen :"#9acd32", + //CSS2 system colors http://www.w3.org/TR/css3-color/#css2-system + activeBorder :"Active window border.", + activecaption :"Active window caption.", + appworkspace :"Background color of multiple document interface.", + background :"Desktop background.", + buttonface :"The face background color for 3-D elements that appear 3-D due to one layer of surrounding border.", + buttonhighlight :"The color of the border facing the light source for 3-D elements that appear 3-D due to one layer of surrounding border.", + buttonshadow :"The color of the border away from the light source for 3-D elements that appear 3-D due to one layer of surrounding border.", + buttontext :"Text on push buttons.", + captiontext :"Text in caption, size box, and scrollbar arrow box.", + graytext :"Grayed (disabled) text. This color is set to #000 if the current display driver does not support a solid gray color.", + highlight :"Item(s) selected in a control.", + highlighttext :"Text of item(s) selected in a control.", + inactiveborder :"Inactive window border.", + inactivecaption :"Inactive window caption.", + inactivecaptiontext :"Color of text in an inactive caption.", + infobackground :"Background color for tooltip controls.", + infotext :"Text color for tooltip controls.", + menu :"Menu background.", + menutext :"Text in menus.", + scrollbar :"Scroll bar gray area.", + threeddarkshadow :"The color of the darker (generally outer) of the two borders away from the light source for 3-D elements that appear 3-D due to two concentric layers of surrounding border.", + threedface :"The face background color for 3-D elements that appear 3-D due to two concentric layers of surrounding border.", + threedhighlight :"The color of the lighter (generally outer) of the two borders facing the light source for 3-D elements that appear 3-D due to two concentric layers of surrounding border.", + threedlightshadow :"The color of the darker (generally inner) of the two borders facing the light source for 3-D elements that appear 3-D due to two concentric layers of surrounding border.", + threedshadow :"The color of the lighter (generally inner) of the two borders away from the light source for 3-D elements that appear 3-D due to two concentric layers of surrounding border.", + window :"Window background.", + windowframe :"Window frame.", + windowtext :"Text in windows." +}; +/*global SyntaxUnit, Parser*/ +/** + * Represents a selector combinator (whitespace, +, >). + * @namespace parserlib.css + * @class Combinator + * @extends parserlib.util.SyntaxUnit + * @constructor + * @param {String} text The text representation of the unit. + * @param {int} line The line of text on which the unit resides. + * @param {int} col The column of text on which the unit resides. + */ +function Combinator(text, line, col){ + + SyntaxUnit.call(this, text, line, col, Parser.COMBINATOR_TYPE); + + /** + * The type of modifier. + * @type String + * @property type + */ + this.type = "unknown"; + + //pretty simple + if (/^\s+$/.test(text)){ + this.type = "descendant"; + } else if (text == ">"){ + this.type = "child"; + } else if (text == "+"){ + this.type = "adjacent-sibling"; + } else if (text == "~"){ + this.type = "sibling"; + } + +} + +Combinator.prototype = new SyntaxUnit(); +Combinator.prototype.constructor = Combinator; + + +/*global SyntaxUnit, Parser*/ +/** + * Represents a media feature, such as max-width:500. + * @namespace parserlib.css + * @class MediaFeature + * @extends parserlib.util.SyntaxUnit + * @constructor + * @param {SyntaxUnit} name The name of the feature. + * @param {SyntaxUnit} value The value of the feature or null if none. + */ +function MediaFeature(name, value){ + + SyntaxUnit.call(this, "(" + name + (value !== null ? ":" + value : "") + ")", name.startLine, name.startCol, Parser.MEDIA_FEATURE_TYPE); + + /** + * The name of the media feature + * @type String + * @property name + */ + this.name = name; + + /** + * The value for the feature or null if there is none. + * @type SyntaxUnit + * @property value + */ + this.value = value; +} + +MediaFeature.prototype = new SyntaxUnit(); +MediaFeature.prototype.constructor = MediaFeature; + + +/*global SyntaxUnit, Parser*/ +/** + * Represents an individual media query. + * @namespace parserlib.css + * @class MediaQuery + * @extends parserlib.util.SyntaxUnit + * @constructor + * @param {String} modifier The modifier "not" or "only" (or null). + * @param {String} mediaType The type of media (i.e., "print"). + * @param {Array} parts Array of selectors parts making up this selector. + * @param {int} line The line of text on which the unit resides. + * @param {int} col The column of text on which the unit resides. + */ +function MediaQuery(modifier, mediaType, features, line, col){ + + SyntaxUnit.call(this, (modifier ? modifier + " ": "") + (mediaType ? mediaType : "") + (mediaType && features.length > 0 ? " and " : "") + features.join(" and "), line, col, Parser.MEDIA_QUERY_TYPE); + + /** + * The media modifier ("not" or "only") + * @type String + * @property modifier + */ + this.modifier = modifier; + + /** + * The mediaType (i.e., "print") + * @type String + * @property mediaType + */ + this.mediaType = mediaType; + + /** + * The parts that make up the selector. + * @type Array + * @property features + */ + this.features = features; + +} + +MediaQuery.prototype = new SyntaxUnit(); +MediaQuery.prototype.constructor = MediaQuery; + + +/*global Tokens, TokenStream, SyntaxError, Properties, Validation, ValidationError, SyntaxUnit, + PropertyValue, PropertyValuePart, SelectorPart, SelectorSubPart, Selector, + PropertyName, Combinator, MediaFeature, MediaQuery, EventTarget */ + +/** + * A CSS3 parser. + * @namespace parserlib.css + * @class Parser + * @constructor + * @param {Object} options (Optional) Various options for the parser: + * starHack (true|false) to allow IE6 star hack as valid, + * underscoreHack (true|false) to interpret leading underscores + * as IE6-7 targeting for known properties, ieFilters (true|false) + * to indicate that IE < 8 filters should be accepted and not throw + * syntax errors. + */ +function Parser(options){ + + //inherit event functionality + EventTarget.call(this); + + + this.options = options || {}; + + this._tokenStream = null; +} + +//Static constants +Parser.DEFAULT_TYPE = 0; +Parser.COMBINATOR_TYPE = 1; +Parser.MEDIA_FEATURE_TYPE = 2; +Parser.MEDIA_QUERY_TYPE = 3; +Parser.PROPERTY_NAME_TYPE = 4; +Parser.PROPERTY_VALUE_TYPE = 5; +Parser.PROPERTY_VALUE_PART_TYPE = 6; +Parser.SELECTOR_TYPE = 7; +Parser.SELECTOR_PART_TYPE = 8; +Parser.SELECTOR_SUB_PART_TYPE = 9; + +Parser.prototype = function(){ + + var proto = new EventTarget(), //new prototype + prop, + additions = { + + //restore constructor + constructor: Parser, + + //instance constants - yuck + DEFAULT_TYPE : 0, + COMBINATOR_TYPE : 1, + MEDIA_FEATURE_TYPE : 2, + MEDIA_QUERY_TYPE : 3, + PROPERTY_NAME_TYPE : 4, + PROPERTY_VALUE_TYPE : 5, + PROPERTY_VALUE_PART_TYPE : 6, + SELECTOR_TYPE : 7, + SELECTOR_PART_TYPE : 8, + SELECTOR_SUB_PART_TYPE : 9, + + //----------------------------------------------------------------- + // Grammar + //----------------------------------------------------------------- + + _stylesheet: function(){ + + /* + * stylesheet + * : [ CHARSET_SYM S* STRING S* ';' ]? + * [S|CDO|CDC]* [ import [S|CDO|CDC]* ]* + * [ namespace [S|CDO|CDC]* ]* + * [ [ ruleset | media | page | font_face | keyframes ] [S|CDO|CDC]* ]* + * ; + */ + + var tokenStream = this._tokenStream, + charset = null, + count, + token, + tt; + + this.fire("startstylesheet"); + + //try to read character set + this._charset(); + + this._skipCruft(); + + //try to read imports - may be more than one + while (tokenStream.peek() == Tokens.IMPORT_SYM){ + this._import(); + this._skipCruft(); + } + + //try to read namespaces - may be more than one + while (tokenStream.peek() == Tokens.NAMESPACE_SYM){ + this._namespace(); + this._skipCruft(); + } + + //get the next token + tt = tokenStream.peek(); + + //try to read the rest + while(tt > Tokens.EOF){ + + try { + + switch(tt){ + case Tokens.MEDIA_SYM: + this._media(); + this._skipCruft(); + break; + case Tokens.PAGE_SYM: + this._page(); + this._skipCruft(); + break; + case Tokens.FONT_FACE_SYM: + this._font_face(); + this._skipCruft(); + break; + case Tokens.KEYFRAMES_SYM: + this._keyframes(); + this._skipCruft(); + break; + case Tokens.VIEWPORT_SYM: + this._viewport(); + this._skipCruft(); + break; + case Tokens.UNKNOWN_SYM: //unknown @ rule + tokenStream.get(); + if (!this.options.strict){ + + //fire error event + this.fire({ + type: "error", + error: null, + message: "Unknown @ rule: " + tokenStream.LT(0).value + ".", + line: tokenStream.LT(0).startLine, + col: tokenStream.LT(0).startCol + }); + + //skip braces + count=0; + while (tokenStream.advance([Tokens.LBRACE, Tokens.RBRACE]) == Tokens.LBRACE){ + count++; //keep track of nesting depth + } + + while(count){ + tokenStream.advance([Tokens.RBRACE]); + count--; + } + + } else { + //not a syntax error, rethrow it + throw new SyntaxError("Unknown @ rule.", tokenStream.LT(0).startLine, tokenStream.LT(0).startCol); + } + break; + case Tokens.S: + this._readWhitespace(); + break; + default: + if(!this._ruleset()){ + + //error handling for known issues + switch(tt){ + case Tokens.CHARSET_SYM: + token = tokenStream.LT(1); + this._charset(false); + throw new SyntaxError("@charset not allowed here.", token.startLine, token.startCol); + case Tokens.IMPORT_SYM: + token = tokenStream.LT(1); + this._import(false); + throw new SyntaxError("@import not allowed here.", token.startLine, token.startCol); + case Tokens.NAMESPACE_SYM: + token = tokenStream.LT(1); + this._namespace(false); + throw new SyntaxError("@namespace not allowed here.", token.startLine, token.startCol); + default: + tokenStream.get(); //get the last token + this._unexpectedToken(tokenStream.token()); + } + + } + } + } catch(ex) { + if (ex instanceof SyntaxError && !this.options.strict){ + this.fire({ + type: "error", + error: ex, + message: ex.message, + line: ex.line, + col: ex.col + }); + } else { + throw ex; + } + } + + tt = tokenStream.peek(); + } + + if (tt != Tokens.EOF){ + this._unexpectedToken(tokenStream.token()); + } + + this.fire("endstylesheet"); + }, + + _charset: function(emit){ + var tokenStream = this._tokenStream, + charset, + token, + line, + col; + + if (tokenStream.match(Tokens.CHARSET_SYM)){ + line = tokenStream.token().startLine; + col = tokenStream.token().startCol; + + this._readWhitespace(); + tokenStream.mustMatch(Tokens.STRING); + + token = tokenStream.token(); + charset = token.value; + + this._readWhitespace(); + tokenStream.mustMatch(Tokens.SEMICOLON); + + if (emit !== false){ + this.fire({ + type: "charset", + charset:charset, + line: line, + col: col + }); + } + } + }, + + _import: function(emit){ + /* + * import + * : IMPORT_SYM S* + * [STRING|URI] S* media_query_list? ';' S* + */ + + var tokenStream = this._tokenStream, + tt, + uri, + importToken, + mediaList = []; + + //read import symbol + tokenStream.mustMatch(Tokens.IMPORT_SYM); + importToken = tokenStream.token(); + this._readWhitespace(); + + tokenStream.mustMatch([Tokens.STRING, Tokens.URI]); + + //grab the URI value + uri = tokenStream.token().value.replace(/(?:url\()?["']([^"']+)["']\)?/, "$1"); + + this._readWhitespace(); + + mediaList = this._media_query_list(); + + //must end with a semicolon + tokenStream.mustMatch(Tokens.SEMICOLON); + this._readWhitespace(); + + if (emit !== false){ + this.fire({ + type: "import", + uri: uri, + media: mediaList, + line: importToken.startLine, + col: importToken.startCol + }); + } + + }, + + _namespace: function(emit){ + /* + * namespace + * : NAMESPACE_SYM S* [namespace_prefix S*]? [STRING|URI] S* ';' S* + */ + + var tokenStream = this._tokenStream, + line, + col, + prefix, + uri; + + //read import symbol + tokenStream.mustMatch(Tokens.NAMESPACE_SYM); + line = tokenStream.token().startLine; + col = tokenStream.token().startCol; + this._readWhitespace(); + + //it's a namespace prefix - no _namespace_prefix() method because it's just an IDENT + if (tokenStream.match(Tokens.IDENT)){ + prefix = tokenStream.token().value; + this._readWhitespace(); + } + + tokenStream.mustMatch([Tokens.STRING, Tokens.URI]); + /*if (!tokenStream.match(Tokens.STRING)){ + tokenStream.mustMatch(Tokens.URI); + }*/ + + //grab the URI value + uri = tokenStream.token().value.replace(/(?:url\()?["']([^"']+)["']\)?/, "$1"); + + this._readWhitespace(); + + //must end with a semicolon + tokenStream.mustMatch(Tokens.SEMICOLON); + this._readWhitespace(); + + if (emit !== false){ + this.fire({ + type: "namespace", + prefix: prefix, + uri: uri, + line: line, + col: col + }); + } + + }, + + _media: function(){ + /* + * media + * : MEDIA_SYM S* media_query_list S* '{' S* ruleset* '}' S* + * ; + */ + var tokenStream = this._tokenStream, + line, + col, + mediaList;// = []; + + //look for @media + tokenStream.mustMatch(Tokens.MEDIA_SYM); + line = tokenStream.token().startLine; + col = tokenStream.token().startCol; + + this._readWhitespace(); + + mediaList = this._media_query_list(); + + tokenStream.mustMatch(Tokens.LBRACE); + this._readWhitespace(); + + this.fire({ + type: "startmedia", + media: mediaList, + line: line, + col: col + }); + + while(true) { + if (tokenStream.peek() == Tokens.PAGE_SYM){ + this._page(); + } else if (tokenStream.peek() == Tokens.FONT_FACE_SYM){ + this._font_face(); + } else if (!this._ruleset()){ + break; + } + } + + tokenStream.mustMatch(Tokens.RBRACE); + this._readWhitespace(); + + this.fire({ + type: "endmedia", + media: mediaList, + line: line, + col: col + }); + }, + + + //CSS3 Media Queries + _media_query_list: function(){ + /* + * media_query_list + * : S* [media_query [ ',' S* media_query ]* ]? + * ; + */ + var tokenStream = this._tokenStream, + mediaList = []; + + + this._readWhitespace(); + + if (tokenStream.peek() == Tokens.IDENT || tokenStream.peek() == Tokens.LPAREN){ + mediaList.push(this._media_query()); + } + + while(tokenStream.match(Tokens.COMMA)){ + this._readWhitespace(); + mediaList.push(this._media_query()); + } + + return mediaList; + }, + + /* + * Note: "expression" in the grammar maps to the _media_expression + * method. + + */ + _media_query: function(){ + /* + * media_query + * : [ONLY | NOT]? S* media_type S* [ AND S* expression ]* + * | expression [ AND S* expression ]* + * ; + */ + var tokenStream = this._tokenStream, + type = null, + ident = null, + token = null, + expressions = []; + + if (tokenStream.match(Tokens.IDENT)){ + ident = tokenStream.token().value.toLowerCase(); + + //since there's no custom tokens for these, need to manually check + if (ident != "only" && ident != "not"){ + tokenStream.unget(); + ident = null; + } else { + token = tokenStream.token(); + } + } + + this._readWhitespace(); + + if (tokenStream.peek() == Tokens.IDENT){ + type = this._media_type(); + if (token === null){ + token = tokenStream.token(); + } + } else if (tokenStream.peek() == Tokens.LPAREN){ + if (token === null){ + token = tokenStream.LT(1); + } + expressions.push(this._media_expression()); + } + + if (type === null && expressions.length === 0){ + return null; + } else { + this._readWhitespace(); + while (tokenStream.match(Tokens.IDENT)){ + if (tokenStream.token().value.toLowerCase() != "and"){ + this._unexpectedToken(tokenStream.token()); + } + + this._readWhitespace(); + expressions.push(this._media_expression()); + } + } + + return new MediaQuery(ident, type, expressions, token.startLine, token.startCol); + }, + + //CSS3 Media Queries + _media_type: function(){ + /* + * media_type + * : IDENT + * ; + */ + return this._media_feature(); + }, + + /** + * Note: in CSS3 Media Queries, this is called "expression". + * Renamed here to avoid conflict with CSS3 Selectors + * definition of "expression". Also note that "expr" in the + * grammar now maps to "expression" from CSS3 selectors. + * @method _media_expression + * @private + */ + _media_expression: function(){ + /* + * expression + * : '(' S* media_feature S* [ ':' S* expr ]? ')' S* + * ; + */ + var tokenStream = this._tokenStream, + feature = null, + token, + expression = null; + + tokenStream.mustMatch(Tokens.LPAREN); + + feature = this._media_feature(); + this._readWhitespace(); + + if (tokenStream.match(Tokens.COLON)){ + this._readWhitespace(); + token = tokenStream.LT(1); + expression = this._expression(); + } + + tokenStream.mustMatch(Tokens.RPAREN); + this._readWhitespace(); + + return new MediaFeature(feature, (expression ? new SyntaxUnit(expression, token.startLine, token.startCol) : null)); + }, + + //CSS3 Media Queries + _media_feature: function(){ + /* + * media_feature + * : IDENT + * ; + */ + var tokenStream = this._tokenStream; + + tokenStream.mustMatch(Tokens.IDENT); + + return SyntaxUnit.fromToken(tokenStream.token()); + }, + + //CSS3 Paged Media + _page: function(){ + /* + * page: + * PAGE_SYM S* IDENT? pseudo_page? S* + * '{' S* [ declaration | margin ]? [ ';' S* [ declaration | margin ]? ]* '}' S* + * ; + */ + var tokenStream = this._tokenStream, + line, + col, + identifier = null, + pseudoPage = null; + + //look for @page + tokenStream.mustMatch(Tokens.PAGE_SYM); + line = tokenStream.token().startLine; + col = tokenStream.token().startCol; + + this._readWhitespace(); + + if (tokenStream.match(Tokens.IDENT)){ + identifier = tokenStream.token().value; + + //The value 'auto' may not be used as a page name and MUST be treated as a syntax error. + if (identifier.toLowerCase() === "auto"){ + this._unexpectedToken(tokenStream.token()); + } + } + + //see if there's a colon upcoming + if (tokenStream.peek() == Tokens.COLON){ + pseudoPage = this._pseudo_page(); + } + + this._readWhitespace(); + + this.fire({ + type: "startpage", + id: identifier, + pseudo: pseudoPage, + line: line, + col: col + }); + + this._readDeclarations(true, true); + + this.fire({ + type: "endpage", + id: identifier, + pseudo: pseudoPage, + line: line, + col: col + }); + + }, + + //CSS3 Paged Media + _margin: function(){ + /* + * margin : + * margin_sym S* '{' declaration [ ';' S* declaration? ]* '}' S* + * ; + */ + var tokenStream = this._tokenStream, + line, + col, + marginSym = this._margin_sym(); + + if (marginSym){ + line = tokenStream.token().startLine; + col = tokenStream.token().startCol; + + this.fire({ + type: "startpagemargin", + margin: marginSym, + line: line, + col: col + }); + + this._readDeclarations(true); + + this.fire({ + type: "endpagemargin", + margin: marginSym, + line: line, + col: col + }); + return true; + } else { + return false; + } + }, + + //CSS3 Paged Media + _margin_sym: function(){ + + /* + * margin_sym : + * TOPLEFTCORNER_SYM | + * TOPLEFT_SYM | + * TOPCENTER_SYM | + * TOPRIGHT_SYM | + * TOPRIGHTCORNER_SYM | + * BOTTOMLEFTCORNER_SYM | + * BOTTOMLEFT_SYM | + * BOTTOMCENTER_SYM | + * BOTTOMRIGHT_SYM | + * BOTTOMRIGHTCORNER_SYM | + * LEFTTOP_SYM | + * LEFTMIDDLE_SYM | + * LEFTBOTTOM_SYM | + * RIGHTTOP_SYM | + * RIGHTMIDDLE_SYM | + * RIGHTBOTTOM_SYM + * ; + */ + + var tokenStream = this._tokenStream; + + if(tokenStream.match([Tokens.TOPLEFTCORNER_SYM, Tokens.TOPLEFT_SYM, + Tokens.TOPCENTER_SYM, Tokens.TOPRIGHT_SYM, Tokens.TOPRIGHTCORNER_SYM, + Tokens.BOTTOMLEFTCORNER_SYM, Tokens.BOTTOMLEFT_SYM, + Tokens.BOTTOMCENTER_SYM, Tokens.BOTTOMRIGHT_SYM, + Tokens.BOTTOMRIGHTCORNER_SYM, Tokens.LEFTTOP_SYM, + Tokens.LEFTMIDDLE_SYM, Tokens.LEFTBOTTOM_SYM, Tokens.RIGHTTOP_SYM, + Tokens.RIGHTMIDDLE_SYM, Tokens.RIGHTBOTTOM_SYM])) + { + return SyntaxUnit.fromToken(tokenStream.token()); + } else { + return null; + } + + }, + + _pseudo_page: function(){ + /* + * pseudo_page + * : ':' IDENT + * ; + */ + + var tokenStream = this._tokenStream; + + tokenStream.mustMatch(Tokens.COLON); + tokenStream.mustMatch(Tokens.IDENT); + + //TODO: CSS3 Paged Media says only "left", "center", and "right" are allowed + + return tokenStream.token().value; + }, + + _font_face: function(){ + /* + * font_face + * : FONT_FACE_SYM S* + * '{' S* declaration [ ';' S* declaration ]* '}' S* + * ; + */ + var tokenStream = this._tokenStream, + line, + col; + + //look for @page + tokenStream.mustMatch(Tokens.FONT_FACE_SYM); + line = tokenStream.token().startLine; + col = tokenStream.token().startCol; + + this._readWhitespace(); + + this.fire({ + type: "startfontface", + line: line, + col: col + }); + + this._readDeclarations(true); + + this.fire({ + type: "endfontface", + line: line, + col: col + }); + }, + + _viewport: function(){ + /* + * viewport + * : VIEWPORT_SYM S* + * '{' S* declaration? [ ';' S* declaration? ]* '}' S* + * ; + */ + var tokenStream = this._tokenStream, + line, + col; + + tokenStream.mustMatch(Tokens.VIEWPORT_SYM); + line = tokenStream.token().startLine; + col = tokenStream.token().startCol; + + this._readWhitespace(); + + this.fire({ + type: "startviewport", + line: line, + col: col + }); + + this._readDeclarations(true); + + this.fire({ + type: "endviewport", + line: line, + col: col + }); + + }, + + _operator: function(inFunction){ + + /* + * operator (outside function) + * : '/' S* | ',' S* | /( empty )/ + * operator (inside function) + * : '/' S* | '+' S* | '*' S* | '-' S* /( empty )/ + * ; + */ + + var tokenStream = this._tokenStream, + token = null; + + if (tokenStream.match([Tokens.SLASH, Tokens.COMMA]) || + (inFunction && tokenStream.match([Tokens.PLUS, Tokens.STAR, Tokens.MINUS]))){ + token = tokenStream.token(); + this._readWhitespace(); + } + return token ? PropertyValuePart.fromToken(token) : null; + + }, + + _combinator: function(){ + + /* + * combinator + * : PLUS S* | GREATER S* | TILDE S* | S+ + * ; + */ + + var tokenStream = this._tokenStream, + value = null, + token; + + if(tokenStream.match([Tokens.PLUS, Tokens.GREATER, Tokens.TILDE])){ + token = tokenStream.token(); + value = new Combinator(token.value, token.startLine, token.startCol); + this._readWhitespace(); + } + + return value; + }, + + _unary_operator: function(){ + + /* + * unary_operator + * : '-' | '+' + * ; + */ + + var tokenStream = this._tokenStream; + + if (tokenStream.match([Tokens.MINUS, Tokens.PLUS])){ + return tokenStream.token().value; + } else { + return null; + } + }, + + _property: function(){ + + /* + * property + * : IDENT S* + * ; + */ + + var tokenStream = this._tokenStream, + value = null, + hack = null, + tokenValue, + token, + line, + col; + + //check for star hack - throws error if not allowed + if (tokenStream.peek() == Tokens.STAR && this.options.starHack){ + tokenStream.get(); + token = tokenStream.token(); + hack = token.value; + line = token.startLine; + col = token.startCol; + } + + if(tokenStream.match(Tokens.IDENT)){ + token = tokenStream.token(); + tokenValue = token.value; + + //check for underscore hack - no error if not allowed because it's valid CSS syntax + if (tokenValue.charAt(0) == "_" && this.options.underscoreHack){ + hack = "_"; + tokenValue = tokenValue.substring(1); + } + + value = new PropertyName(tokenValue, hack, (line||token.startLine), (col||token.startCol)); + this._readWhitespace(); + } + + return value; + }, + + //Augmented with CSS3 Selectors + _ruleset: function(){ + /* + * ruleset + * : selectors_group + * '{' S* declaration? [ ';' S* declaration? ]* '}' S* + * ; + */ + + var tokenStream = this._tokenStream, + tt, + selectors; + + + /* + * Error Recovery: If even a single selector fails to parse, + * then the entire ruleset should be thrown away. + */ + try { + selectors = this._selectors_group(); + } catch (ex){ + if (ex instanceof SyntaxError && !this.options.strict){ + + //fire error event + this.fire({ + type: "error", + error: ex, + message: ex.message, + line: ex.line, + col: ex.col + }); + + //skip over everything until closing brace + tt = tokenStream.advance([Tokens.RBRACE]); + if (tt == Tokens.RBRACE){ + //if there's a right brace, the rule is finished so don't do anything + } else { + //otherwise, rethrow the error because it wasn't handled properly + throw ex; + } + + } else { + //not a syntax error, rethrow it + throw ex; + } + + //trigger parser to continue + return true; + } + + //if it got here, all selectors parsed + if (selectors){ + + this.fire({ + type: "startrule", + selectors: selectors, + line: selectors[0].line, + col: selectors[0].col + }); + + this._readDeclarations(true); + + this.fire({ + type: "endrule", + selectors: selectors, + line: selectors[0].line, + col: selectors[0].col + }); + + } + + return selectors; + + }, + + //CSS3 Selectors + _selectors_group: function(){ + + /* + * selectors_group + * : selector [ COMMA S* selector ]* + * ; + */ + var tokenStream = this._tokenStream, + selectors = [], + selector; + + selector = this._selector(); + if (selector !== null){ + + selectors.push(selector); + while(tokenStream.match(Tokens.COMMA)){ + this._readWhitespace(); + selector = this._selector(); + if (selector !== null){ + selectors.push(selector); + } else { + this._unexpectedToken(tokenStream.LT(1)); + } + } + } + + return selectors.length ? selectors : null; + }, + + //CSS3 Selectors + _selector: function(){ + /* + * selector + * : simple_selector_sequence [ combinator simple_selector_sequence ]* + * ; + */ + + var tokenStream = this._tokenStream, + selector = [], + nextSelector = null, + combinator = null, + ws = null; + + //if there's no simple selector, then there's no selector + nextSelector = this._simple_selector_sequence(); + if (nextSelector === null){ + return null; + } + + selector.push(nextSelector); + + do { + + //look for a combinator + combinator = this._combinator(); + + if (combinator !== null){ + selector.push(combinator); + nextSelector = this._simple_selector_sequence(); + + //there must be a next selector + if (nextSelector === null){ + this._unexpectedToken(tokenStream.LT(1)); + } else { + + //nextSelector is an instance of SelectorPart + selector.push(nextSelector); + } + } else { + + //if there's not whitespace, we're done + if (this._readWhitespace()){ + + //add whitespace separator + ws = new Combinator(tokenStream.token().value, tokenStream.token().startLine, tokenStream.token().startCol); + + //combinator is not required + combinator = this._combinator(); + + //selector is required if there's a combinator + nextSelector = this._simple_selector_sequence(); + if (nextSelector === null){ + if (combinator !== null){ + this._unexpectedToken(tokenStream.LT(1)); + } + } else { + + if (combinator !== null){ + selector.push(combinator); + } else { + selector.push(ws); + } + + selector.push(nextSelector); + } + } else { + break; + } + + } + } while(true); + + return new Selector(selector, selector[0].line, selector[0].col); + }, + + //CSS3 Selectors + _simple_selector_sequence: function(){ + /* + * simple_selector_sequence + * : [ type_selector | universal ] + * [ HASH | class | attrib | pseudo | negation ]* + * | [ HASH | class | attrib | pseudo | negation ]+ + * ; + */ + + var tokenStream = this._tokenStream, + + //parts of a simple selector + elementName = null, + modifiers = [], + + //complete selector text + selectorText= "", + + //the different parts after the element name to search for + components = [ + //HASH + function(){ + return tokenStream.match(Tokens.HASH) ? + new SelectorSubPart(tokenStream.token().value, "id", tokenStream.token().startLine, tokenStream.token().startCol) : + null; + }, + this._class, + this._attrib, + this._pseudo, + this._negation + ], + i = 0, + len = components.length, + component = null, + found = false, + line, + col; + + + //get starting line and column for the selector + line = tokenStream.LT(1).startLine; + col = tokenStream.LT(1).startCol; + + elementName = this._type_selector(); + if (!elementName){ + elementName = this._universal(); + } + + if (elementName !== null){ + selectorText += elementName; + } + + while(true){ + + //whitespace means we're done + if (tokenStream.peek() === Tokens.S){ + break; + } + + //check for each component + while(i < len && component === null){ + component = components[i++].call(this); + } + + if (component === null){ + + //we don't have a selector + if (selectorText === ""){ + return null; + } else { + break; + } + } else { + i = 0; + modifiers.push(component); + selectorText += component.toString(); + component = null; + } + } + + + return selectorText !== "" ? + new SelectorPart(elementName, modifiers, selectorText, line, col) : + null; + }, + + //CSS3 Selectors + _type_selector: function(){ + /* + * type_selector + * : [ namespace_prefix ]? element_name + * ; + */ + + var tokenStream = this._tokenStream, + ns = this._namespace_prefix(), + elementName = this._element_name(); + + if (!elementName){ + /* + * Need to back out the namespace that was read due to both + * type_selector and universal reading namespace_prefix + * first. Kind of hacky, but only way I can figure out + * right now how to not change the grammar. + */ + if (ns){ + tokenStream.unget(); + if (ns.length > 1){ + tokenStream.unget(); + } + } + + return null; + } else { + if (ns){ + elementName.text = ns + elementName.text; + elementName.col -= ns.length; + } + return elementName; + } + }, + + //CSS3 Selectors + _class: function(){ + /* + * class + * : '.' IDENT + * ; + */ + + var tokenStream = this._tokenStream, + token; + + if (tokenStream.match(Tokens.DOT)){ + tokenStream.mustMatch(Tokens.IDENT); + token = tokenStream.token(); + return new SelectorSubPart("." + token.value, "class", token.startLine, token.startCol - 1); + } else { + return null; + } + + }, + + //CSS3 Selectors + _element_name: function(){ + /* + * element_name + * : IDENT + * ; + */ + + var tokenStream = this._tokenStream, + token; + + if (tokenStream.match(Tokens.IDENT)){ + token = tokenStream.token(); + return new SelectorSubPart(token.value, "elementName", token.startLine, token.startCol); + + } else { + return null; + } + }, + + //CSS3 Selectors + _namespace_prefix: function(){ + /* + * namespace_prefix + * : [ IDENT | '*' ]? '|' + * ; + */ + var tokenStream = this._tokenStream, + value = ""; + + //verify that this is a namespace prefix + if (tokenStream.LA(1) === Tokens.PIPE || tokenStream.LA(2) === Tokens.PIPE){ + + if(tokenStream.match([Tokens.IDENT, Tokens.STAR])){ + value += tokenStream.token().value; + } + + tokenStream.mustMatch(Tokens.PIPE); + value += "|"; + + } + + return value.length ? value : null; + }, + + //CSS3 Selectors + _universal: function(){ + /* + * universal + * : [ namespace_prefix ]? '*' + * ; + */ + var tokenStream = this._tokenStream, + value = "", + ns; + + ns = this._namespace_prefix(); + if(ns){ + value += ns; + } + + if(tokenStream.match(Tokens.STAR)){ + value += "*"; + } + + return value.length ? value : null; + + }, + + //CSS3 Selectors + _attrib: function(){ + /* + * attrib + * : '[' S* [ namespace_prefix ]? IDENT S* + * [ [ PREFIXMATCH | + * SUFFIXMATCH | + * SUBSTRINGMATCH | + * '=' | + * INCLUDES | + * DASHMATCH ] S* [ IDENT | STRING ] S* + * ]? ']' + * ; + */ + + var tokenStream = this._tokenStream, + value = null, + ns, + token; + + if (tokenStream.match(Tokens.LBRACKET)){ + token = tokenStream.token(); + value = token.value; + value += this._readWhitespace(); + + ns = this._namespace_prefix(); + + if (ns){ + value += ns; + } + + tokenStream.mustMatch(Tokens.IDENT); + value += tokenStream.token().value; + value += this._readWhitespace(); + + if(tokenStream.match([Tokens.PREFIXMATCH, Tokens.SUFFIXMATCH, Tokens.SUBSTRINGMATCH, + Tokens.EQUALS, Tokens.INCLUDES, Tokens.DASHMATCH])){ + + value += tokenStream.token().value; + value += this._readWhitespace(); + + tokenStream.mustMatch([Tokens.IDENT, Tokens.STRING]); + value += tokenStream.token().value; + value += this._readWhitespace(); + } + + tokenStream.mustMatch(Tokens.RBRACKET); + + return new SelectorSubPart(value + "]", "attribute", token.startLine, token.startCol); + } else { + return null; + } + }, + + //CSS3 Selectors + _pseudo: function(){ + + /* + * pseudo + * : ':' ':'? [ IDENT | functional_pseudo ] + * ; + */ + + var tokenStream = this._tokenStream, + pseudo = null, + colons = ":", + line, + col; + + if (tokenStream.match(Tokens.COLON)){ + + if (tokenStream.match(Tokens.COLON)){ + colons += ":"; + } + + if (tokenStream.match(Tokens.IDENT)){ + pseudo = tokenStream.token().value; + line = tokenStream.token().startLine; + col = tokenStream.token().startCol - colons.length; + } else if (tokenStream.peek() == Tokens.FUNCTION){ + line = tokenStream.LT(1).startLine; + col = tokenStream.LT(1).startCol - colons.length; + pseudo = this._functional_pseudo(); + } + + if (pseudo){ + pseudo = new SelectorSubPart(colons + pseudo, "pseudo", line, col); + } + } + + return pseudo; + }, + + //CSS3 Selectors + _functional_pseudo: function(){ + /* + * functional_pseudo + * : FUNCTION S* expression ')' + * ; + */ + + var tokenStream = this._tokenStream, + value = null; + + if(tokenStream.match(Tokens.FUNCTION)){ + value = tokenStream.token().value; + value += this._readWhitespace(); + value += this._expression(); + tokenStream.mustMatch(Tokens.RPAREN); + value += ")"; + } + + return value; + }, + + //CSS3 Selectors + _expression: function(){ + /* + * expression + * : [ [ PLUS | '-' | DIMENSION | NUMBER | STRING | IDENT ] S* ]+ + * ; + */ + + var tokenStream = this._tokenStream, + value = ""; + + while(tokenStream.match([Tokens.PLUS, Tokens.MINUS, Tokens.DIMENSION, + Tokens.NUMBER, Tokens.STRING, Tokens.IDENT, Tokens.LENGTH, + Tokens.FREQ, Tokens.ANGLE, Tokens.TIME, + Tokens.RESOLUTION, Tokens.SLASH])){ + + value += tokenStream.token().value; + value += this._readWhitespace(); + } + + return value.length ? value : null; + + }, + + //CSS3 Selectors + _negation: function(){ + /* + * negation + * : NOT S* negation_arg S* ')' + * ; + */ + + var tokenStream = this._tokenStream, + line, + col, + value = "", + arg, + subpart = null; + + if (tokenStream.match(Tokens.NOT)){ + value = tokenStream.token().value; + line = tokenStream.token().startLine; + col = tokenStream.token().startCol; + value += this._readWhitespace(); + arg = this._negation_arg(); + value += arg; + value += this._readWhitespace(); + tokenStream.match(Tokens.RPAREN); + value += tokenStream.token().value; + + subpart = new SelectorSubPart(value, "not", line, col); + subpart.args.push(arg); + } + + return subpart; + }, + + //CSS3 Selectors + _negation_arg: function(){ + /* + * negation_arg + * : type_selector | universal | HASH | class | attrib | pseudo + * ; + */ + + var tokenStream = this._tokenStream, + args = [ + this._type_selector, + this._universal, + function(){ + return tokenStream.match(Tokens.HASH) ? + new SelectorSubPart(tokenStream.token().value, "id", tokenStream.token().startLine, tokenStream.token().startCol) : + null; + }, + this._class, + this._attrib, + this._pseudo + ], + arg = null, + i = 0, + len = args.length, + elementName, + line, + col, + part; + + line = tokenStream.LT(1).startLine; + col = tokenStream.LT(1).startCol; + + while(i < len && arg === null){ + + arg = args[i].call(this); + i++; + } + + //must be a negation arg + if (arg === null){ + this._unexpectedToken(tokenStream.LT(1)); + } + + //it's an element name + if (arg.type == "elementName"){ + part = new SelectorPart(arg, [], arg.toString(), line, col); + } else { + part = new SelectorPart(null, [arg], arg.toString(), line, col); + } + + return part; + }, + + _declaration: function(){ + + /* + * declaration + * : property ':' S* expr prio? + * | /( empty )/ + * ; + */ + + var tokenStream = this._tokenStream, + property = null, + expr = null, + prio = null, + error = null, + invalid = null, + propertyName= ""; + + property = this._property(); + if (property !== null){ + + tokenStream.mustMatch(Tokens.COLON); + this._readWhitespace(); + + expr = this._expr(); + + //if there's no parts for the value, it's an error + if (!expr || expr.length === 0){ + this._unexpectedToken(tokenStream.LT(1)); + } + + prio = this._prio(); + + /* + * If hacks should be allowed, then only check the root + * property. If hacks should not be allowed, treat + * _property or *property as invalid properties. + */ + propertyName = property.toString(); + if (this.options.starHack && property.hack == "*" || + this.options.underscoreHack && property.hack == "_") { + + propertyName = property.text; + } + + try { + this._validateProperty(propertyName, expr); + } catch (ex) { + invalid = ex; + } + + this.fire({ + type: "property", + property: property, + value: expr, + important: prio, + line: property.line, + col: property.col, + invalid: invalid + }); + + return true; + } else { + return false; + } + }, + + _prio: function(){ + /* + * prio + * : IMPORTANT_SYM S* + * ; + */ + + var tokenStream = this._tokenStream, + result = tokenStream.match(Tokens.IMPORTANT_SYM); + + this._readWhitespace(); + return result; + }, + + _expr: function(inFunction){ + /* + * expr + * : term [ operator term ]* + * ; + */ + + var tokenStream = this._tokenStream, + values = [], + //valueParts = [], + value = null, + operator = null; + + value = this._term(); + if (value !== null){ + + values.push(value); + + do { + operator = this._operator(inFunction); + + //if there's an operator, keep building up the value parts + if (operator){ + values.push(operator); + } /*else { + //if there's not an operator, you have a full value + values.push(new PropertyValue(valueParts, valueParts[0].line, valueParts[0].col)); + valueParts = []; + }*/ + + value = this._term(); + + if (value === null){ + break; + } else { + values.push(value); + } + } while(true); + } + + //cleanup + /*if (valueParts.length){ + values.push(new PropertyValue(valueParts, valueParts[0].line, valueParts[0].col)); + }*/ + + return values.length > 0 ? new PropertyValue(values, values[0].line, values[0].col) : null; + }, + + _term: function(){ + + /* + * term + * : unary_operator? + * [ NUMBER S* | PERCENTAGE S* | LENGTH S* | ANGLE S* | + * TIME S* | FREQ S* | function | ie_function ] + * | STRING S* | IDENT S* | URI S* | UNICODERANGE S* | hexcolor + * ; + */ + + var tokenStream = this._tokenStream, + unary = null, + value = null, + token, + line, + col; + + //returns the operator or null + unary = this._unary_operator(); + if (unary !== null){ + line = tokenStream.token().startLine; + col = tokenStream.token().startCol; + } + + //exception for IE filters + if (tokenStream.peek() == Tokens.IE_FUNCTION && this.options.ieFilters){ + + value = this._ie_function(); + if (unary === null){ + line = tokenStream.token().startLine; + col = tokenStream.token().startCol; + } + + //see if there's a simple match + } else if (tokenStream.match([Tokens.NUMBER, Tokens.PERCENTAGE, Tokens.LENGTH, + Tokens.ANGLE, Tokens.TIME, + Tokens.FREQ, Tokens.STRING, Tokens.IDENT, Tokens.URI, Tokens.UNICODE_RANGE])){ + + value = tokenStream.token().value; + if (unary === null){ + line = tokenStream.token().startLine; + col = tokenStream.token().startCol; + } + this._readWhitespace(); + } else { + + //see if it's a color + token = this._hexcolor(); + if (token === null){ + + //if there's no unary, get the start of the next token for line/col info + if (unary === null){ + line = tokenStream.LT(1).startLine; + col = tokenStream.LT(1).startCol; + } + + //has to be a function + if (value === null){ + + /* + * This checks for alpha(opacity=0) style of IE + * functions. IE_FUNCTION only presents progid: style. + */ + if (tokenStream.LA(3) == Tokens.EQUALS && this.options.ieFilters){ + value = this._ie_function(); + } else { + value = this._function(); + } + } + + /*if (value === null){ + return null; + //throw new Error("Expected identifier at line " + tokenStream.token().startLine + ", character " + tokenStream.token().startCol + "."); + }*/ + + } else { + value = token.value; + if (unary === null){ + line = token.startLine; + col = token.startCol; + } + } + + } + + return value !== null ? + new PropertyValuePart(unary !== null ? unary + value : value, line, col) : + null; + + }, + + _function: function(){ + + /* + * function + * : FUNCTION S* expr ')' S* + * ; + */ + + var tokenStream = this._tokenStream, + functionText = null, + expr = null, + lt; + + if (tokenStream.match(Tokens.FUNCTION)){ + functionText = tokenStream.token().value; + this._readWhitespace(); + expr = this._expr(true); + functionText += expr; + + //START: Horrible hack in case it's an IE filter + if (this.options.ieFilters && tokenStream.peek() == Tokens.EQUALS){ + do { + + if (this._readWhitespace()){ + functionText += tokenStream.token().value; + } + + //might be second time in the loop + if (tokenStream.LA(0) == Tokens.COMMA){ + functionText += tokenStream.token().value; + } + + tokenStream.match(Tokens.IDENT); + functionText += tokenStream.token().value; + + tokenStream.match(Tokens.EQUALS); + functionText += tokenStream.token().value; + + //functionText += this._term(); + lt = tokenStream.peek(); + while(lt != Tokens.COMMA && lt != Tokens.S && lt != Tokens.RPAREN){ + tokenStream.get(); + functionText += tokenStream.token().value; + lt = tokenStream.peek(); + } + } while(tokenStream.match([Tokens.COMMA, Tokens.S])); + } + + //END: Horrible Hack + + tokenStream.match(Tokens.RPAREN); + functionText += ")"; + this._readWhitespace(); + } + + return functionText; + }, + + _ie_function: function(){ + + /* (My own extension) + * ie_function + * : IE_FUNCTION S* IDENT '=' term [S* ','? IDENT '=' term]+ ')' S* + * ; + */ + + var tokenStream = this._tokenStream, + functionText = null, + expr = null, + lt; + + //IE function can begin like a regular function, too + if (tokenStream.match([Tokens.IE_FUNCTION, Tokens.FUNCTION])){ + functionText = tokenStream.token().value; + + do { + + if (this._readWhitespace()){ + functionText += tokenStream.token().value; + } + + //might be second time in the loop + if (tokenStream.LA(0) == Tokens.COMMA){ + functionText += tokenStream.token().value; + } + + tokenStream.match(Tokens.IDENT); + functionText += tokenStream.token().value; + + tokenStream.match(Tokens.EQUALS); + functionText += tokenStream.token().value; + + //functionText += this._term(); + lt = tokenStream.peek(); + while(lt != Tokens.COMMA && lt != Tokens.S && lt != Tokens.RPAREN){ + tokenStream.get(); + functionText += tokenStream.token().value; + lt = tokenStream.peek(); + } + } while(tokenStream.match([Tokens.COMMA, Tokens.S])); + + tokenStream.match(Tokens.RPAREN); + functionText += ")"; + this._readWhitespace(); + } + + return functionText; + }, + + _hexcolor: function(){ + /* + * There is a constraint on the color that it must + * have either 3 or 6 hex-digits (i.e., [0-9a-fA-F]) + * after the "#"; e.g., "#000" is OK, but "#abcd" is not. + * + * hexcolor + * : HASH S* + * ; + */ + + var tokenStream = this._tokenStream, + token = null, + color; + + if(tokenStream.match(Tokens.HASH)){ + + //need to do some validation here + + token = tokenStream.token(); + color = token.value; + if (!/#[a-f0-9]{3,6}/i.test(color)){ + throw new SyntaxError("Expected a hex color but found '" + color + "' at line " + token.startLine + ", col " + token.startCol + ".", token.startLine, token.startCol); + } + this._readWhitespace(); + } + + return token; + }, + + //----------------------------------------------------------------- + // Animations methods + //----------------------------------------------------------------- + + _keyframes: function(){ + + /* + * keyframes: + * : KEYFRAMES_SYM S* keyframe_name S* '{' S* keyframe_rule* '}' { + * ; + */ + var tokenStream = this._tokenStream, + token, + tt, + name, + prefix = ""; + + tokenStream.mustMatch(Tokens.KEYFRAMES_SYM); + token = tokenStream.token(); + if (/^@\-([^\-]+)\-/.test(token.value)) { + prefix = RegExp.$1; + } + + this._readWhitespace(); + name = this._keyframe_name(); + + this._readWhitespace(); + tokenStream.mustMatch(Tokens.LBRACE); + + this.fire({ + type: "startkeyframes", + name: name, + prefix: prefix, + line: token.startLine, + col: token.startCol + }); + + this._readWhitespace(); + tt = tokenStream.peek(); + + //check for key + while(tt == Tokens.IDENT || tt == Tokens.PERCENTAGE) { + this._keyframe_rule(); + this._readWhitespace(); + tt = tokenStream.peek(); + } + + this.fire({ + type: "endkeyframes", + name: name, + prefix: prefix, + line: token.startLine, + col: token.startCol + }); + + this._readWhitespace(); + tokenStream.mustMatch(Tokens.RBRACE); + + }, + + _keyframe_name: function(){ + + /* + * keyframe_name: + * : IDENT + * | STRING + * ; + */ + var tokenStream = this._tokenStream, + token; + + tokenStream.mustMatch([Tokens.IDENT, Tokens.STRING]); + return SyntaxUnit.fromToken(tokenStream.token()); + }, + + _keyframe_rule: function(){ + + /* + * keyframe_rule: + * : key_list S* + * '{' S* declaration [ ';' S* declaration ]* '}' S* + * ; + */ + var tokenStream = this._tokenStream, + token, + keyList = this._key_list(); + + this.fire({ + type: "startkeyframerule", + keys: keyList, + line: keyList[0].line, + col: keyList[0].col + }); + + this._readDeclarations(true); + + this.fire({ + type: "endkeyframerule", + keys: keyList, + line: keyList[0].line, + col: keyList[0].col + }); + + }, + + _key_list: function(){ + + /* + * key_list: + * : key [ S* ',' S* key]* + * ; + */ + var tokenStream = this._tokenStream, + token, + key, + keyList = []; + + //must be least one key + keyList.push(this._key()); + + this._readWhitespace(); + + while(tokenStream.match(Tokens.COMMA)){ + this._readWhitespace(); + keyList.push(this._key()); + this._readWhitespace(); + } + + return keyList; + }, + + _key: function(){ + /* + * There is a restriction that IDENT can be only "from" or "to". + * + * key + * : PERCENTAGE + * | IDENT + * ; + */ + + var tokenStream = this._tokenStream, + token; + + if (tokenStream.match(Tokens.PERCENTAGE)){ + return SyntaxUnit.fromToken(tokenStream.token()); + } else if (tokenStream.match(Tokens.IDENT)){ + token = tokenStream.token(); + + if (/from|to/i.test(token.value)){ + return SyntaxUnit.fromToken(token); + } + + tokenStream.unget(); + } + + //if it gets here, there wasn't a valid token, so time to explode + this._unexpectedToken(tokenStream.LT(1)); + }, + + //----------------------------------------------------------------- + // Helper methods + //----------------------------------------------------------------- + + /** + * Not part of CSS grammar, but useful for skipping over + * combination of white space and HTML-style comments. + * @return {void} + * @method _skipCruft + * @private + */ + _skipCruft: function(){ + while(this._tokenStream.match([Tokens.S, Tokens.CDO, Tokens.CDC])){ + //noop + } + }, + + /** + * Not part of CSS grammar, but this pattern occurs frequently + * in the official CSS grammar. Split out here to eliminate + * duplicate code. + * @param {Boolean} checkStart Indicates if the rule should check + * for the left brace at the beginning. + * @param {Boolean} readMargins Indicates if the rule should check + * for margin patterns. + * @return {void} + * @method _readDeclarations + * @private + */ + _readDeclarations: function(checkStart, readMargins){ + /* + * Reads the pattern + * S* '{' S* declaration [ ';' S* declaration ]* '}' S* + * or + * S* '{' S* [ declaration | margin ]? [ ';' S* [ declaration | margin ]? ]* '}' S* + * Note that this is how it is described in CSS3 Paged Media, but is actually incorrect. + * A semicolon is only necessary following a declaration is there's another declaration + * or margin afterwards. + */ + var tokenStream = this._tokenStream, + tt; + + + this._readWhitespace(); + + if (checkStart){ + tokenStream.mustMatch(Tokens.LBRACE); + } + + this._readWhitespace(); + + try { + + while(true){ + + if (tokenStream.match(Tokens.SEMICOLON) || (readMargins && this._margin())){ + //noop + } else if (this._declaration()){ + if (!tokenStream.match(Tokens.SEMICOLON)){ + break; + } + } else { + break; + } + + //if ((!this._margin() && !this._declaration()) || !tokenStream.match(Tokens.SEMICOLON)){ + // break; + //} + this._readWhitespace(); + } + + tokenStream.mustMatch(Tokens.RBRACE); + this._readWhitespace(); + + } catch (ex) { + if (ex instanceof SyntaxError && !this.options.strict){ + + //fire error event + this.fire({ + type: "error", + error: ex, + message: ex.message, + line: ex.line, + col: ex.col + }); + + //see if there's another declaration + tt = tokenStream.advance([Tokens.SEMICOLON, Tokens.RBRACE]); + if (tt == Tokens.SEMICOLON){ + //if there's a semicolon, then there might be another declaration + this._readDeclarations(false, readMargins); + } else if (tt != Tokens.RBRACE){ + //if there's a right brace, the rule is finished so don't do anything + //otherwise, rethrow the error because it wasn't handled properly + throw ex; + } + + } else { + //not a syntax error, rethrow it + throw ex; + } + } + + }, + + /** + * In some cases, you can end up with two white space tokens in a + * row. Instead of making a change in every function that looks for + * white space, this function is used to match as much white space + * as necessary. + * @method _readWhitespace + * @return {String} The white space if found, empty string if not. + * @private + */ + _readWhitespace: function(){ + + var tokenStream = this._tokenStream, + ws = ""; + + while(tokenStream.match(Tokens.S)){ + ws += tokenStream.token().value; + } + + return ws; + }, + + + /** + * Throws an error when an unexpected token is found. + * @param {Object} token The token that was found. + * @method _unexpectedToken + * @return {void} + * @private + */ + _unexpectedToken: function(token){ + throw new SyntaxError("Unexpected token '" + token.value + "' at line " + token.startLine + ", col " + token.startCol + ".", token.startLine, token.startCol); + }, + + /** + * Helper method used for parsing subparts of a style sheet. + * @return {void} + * @method _verifyEnd + * @private + */ + _verifyEnd: function(){ + if (this._tokenStream.LA(1) != Tokens.EOF){ + this._unexpectedToken(this._tokenStream.LT(1)); + } + }, + + //----------------------------------------------------------------- + // Validation methods + //----------------------------------------------------------------- + _validateProperty: function(property, value){ + Validation.validate(property, value); + }, + + //----------------------------------------------------------------- + // Parsing methods + //----------------------------------------------------------------- + + parse: function(input){ + this._tokenStream = new TokenStream(input, Tokens); + this._stylesheet(); + }, + + parseStyleSheet: function(input){ + //just passthrough + return this.parse(input); + }, + + parseMediaQuery: function(input){ + this._tokenStream = new TokenStream(input, Tokens); + var result = this._media_query(); + + //if there's anything more, then it's an invalid selector + this._verifyEnd(); + + //otherwise return result + return result; + }, + + /** + * Parses a property value (everything after the semicolon). + * @return {parserlib.css.PropertyValue} The property value. + * @throws parserlib.util.SyntaxError If an unexpected token is found. + * @method parserPropertyValue + */ + parsePropertyValue: function(input){ + + this._tokenStream = new TokenStream(input, Tokens); + this._readWhitespace(); + + var result = this._expr(); + + //okay to have a trailing white space + this._readWhitespace(); + + //if there's anything more, then it's an invalid selector + this._verifyEnd(); + + //otherwise return result + return result; + }, + + /** + * Parses a complete CSS rule, including selectors and + * properties. + * @param {String} input The text to parser. + * @return {Boolean} True if the parse completed successfully, false if not. + * @method parseRule + */ + parseRule: function(input){ + this._tokenStream = new TokenStream(input, Tokens); + + //skip any leading white space + this._readWhitespace(); + + var result = this._ruleset(); + + //skip any trailing white space + this._readWhitespace(); + + //if there's anything more, then it's an invalid selector + this._verifyEnd(); + + //otherwise return result + return result; + }, + + /** + * Parses a single CSS selector (no comma) + * @param {String} input The text to parse as a CSS selector. + * @return {Selector} An object representing the selector. + * @throws parserlib.util.SyntaxError If an unexpected token is found. + * @method parseSelector + */ + parseSelector: function(input){ + + this._tokenStream = new TokenStream(input, Tokens); + + //skip any leading white space + this._readWhitespace(); + + var result = this._selector(); + + //skip any trailing white space + this._readWhitespace(); + + //if there's anything more, then it's an invalid selector + this._verifyEnd(); + + //otherwise return result + return result; + }, + + /** + * Parses an HTML style attribute: a set of CSS declarations + * separated by semicolons. + * @param {String} input The text to parse as a style attribute + * @return {void} + * @method parseStyleAttribute + */ + parseStyleAttribute: function(input){ + input += "}"; // for error recovery in _readDeclarations() + this._tokenStream = new TokenStream(input, Tokens); + this._readDeclarations(); + } + }; + + //copy over onto prototype + for (prop in additions){ + if (additions.hasOwnProperty(prop)){ + proto[prop] = additions[prop]; + } + } + + return proto; +}(); + + +/* +nth + : S* [ ['-'|'+']? INTEGER? {N} [ S* ['-'|'+'] S* INTEGER ]? | + ['-'|'+']? INTEGER | {O}{D}{D} | {E}{V}{E}{N} ] S* + ; +*/ + +/*global Validation, ValidationTypes, ValidationError*/ +var Properties = { + + //A + "alignment-adjust" : "auto | baseline | before-edge | text-before-edge | middle | central | after-edge | text-after-edge | ideographic | alphabetic | hanging | mathematical | | ", + "alignment-baseline" : "baseline | use-script | before-edge | text-before-edge | after-edge | text-after-edge | central | middle | ideographic | alphabetic | hanging | mathematical", + "animation" : 1, + "animation-delay" : { multi: "

    Addons

    +
    + + +
    +
    Key bindings From cb564d46d4a6f2b68434b43bb2e27427813995b3 Mon Sep 17 00:00:00 2001 From: Giulia Alfonsi Date: Tue, 1 Jul 2014 09:43:57 +0100 Subject: [PATCH 256/321] Added redrawing of the gutters by redrawing the lineNumbers option --- public/js/editors/addons.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/public/js/editors/addons.js b/public/js/editors/addons.js index 692ed200..8484cc4e 100644 --- a/public/js/editors/addons.js +++ b/public/js/editors/addons.js @@ -104,7 +104,7 @@ cm.foldCode(cm.getCursor()); }}); setOption(cm, 'foldGutter', true); - var gutters = cm.getOptions('gutters'); + var gutters = cm.getOption('gutters'); console.log('gutters', gutters); gutters.push('CodeMirror-linenumbers'); gutters.push('CodeMirror-foldgutter'); @@ -205,6 +205,9 @@ gutters.push('CodeMirror-lint-markers'); setOption(cm, 'gutters', gutters); setOption(cm, 'lint', true); + var ln = cm.getOption('lineNumbers'); + setOption(cm, 'lineNumbers', !ln); + setOption(cm, 'lineNumbers', ln); } } } From c77248e2761c503120d2a9360e8e7511cbcaf830 Mon Sep 17 00:00:00 2001 From: Giulia Alfonsi Date: Tue, 1 Jul 2014 12:08:18 +0100 Subject: [PATCH 257/321] Added csslint hinting to use user preferences on to what interfaces to show. --- public/js/account/editor-settings.js | 3 +- public/js/account/preferences-settings.js | 31 +++++++-- public/js/editors/addons.js | 65 +++++++++++-------- .../{cm_addons/lint => csslint}/csslint.js | 0 views/account/editor.html | 7 +- views/account/preferences.html | 23 +++++++ 6 files changed, 90 insertions(+), 39 deletions(-) rename public/js/vendor/{cm_addons/lint => csslint}/csslint.js (100%) diff --git a/public/js/account/editor-settings.js b/public/js/account/editor-settings.js index 28f428a3..214d3b1b 100644 --- a/public/js/account/editor-settings.js +++ b/public/js/account/editor-settings.js @@ -83,8 +83,7 @@ 'emacs', 'sublime', 'tern', - 'matchbrackets', - 'csslint' + 'matchbrackets' ]; var $addons = {}; diff --git a/public/js/account/preferences-settings.js b/public/js/account/preferences-settings.js index 8b84b4e7..c06aec00 100644 --- a/public/js/account/preferences-settings.js +++ b/public/js/account/preferences-settings.js @@ -24,15 +24,24 @@ // Setup variables var $csrf = $('#_csrf'); + var hintsShow = { + console: true, + line: true, + under: false, + tooltip: true, + gutter: true + }; var currentSettings = { panels: [], includejs: true, focusedPanel: 'html', + assetUrl: '', jshint: true, jshintOptions: '', - // csshint: false, + jshintShow: hintsShow, + csshint: false, // csshintOptions: '', - assetUrl: '', + csshintShow: hintsShow }; var $saveStatus = $('span.status'); var saveTimer = null; @@ -42,13 +51,13 @@ var $includejs = $('#includejs').prop('checked', currentSettings.includejs); var $focusedPanel = $('#focused-panel').val(currentSettings.focusedPanel); var $assetUrl = $('#asset-url').val(currentSettings.assetUrl); - var hints = ['js']; - // var hints = ['js', 'css']; + var hints = ['js', 'css']; var $hints = {}; var $hintsOptions = {}; var $hintsOptWrapper = {}; var hintsOptionsVal = {}; var $hintsOptError = {}; + var $hintsShow = {}; // var jshints = { // 'forin': 'About unsafe for..in', @@ -84,6 +93,13 @@ $hintsOptions[hints[m]] = $('#' + hints[m] + 'hintOptions') .val(hintsOptionsVal[hints[m]]); $hintsOptError[hints[m]] = $('#' + hints[m] + 'hintOptError'); + + $hintsShow[hints[m]] = {}; + for (var key in hintsShow) { + if (hintsShow.hasOwnProperty(key)) { + $hintsShow[hints[m]][key] = $('#' + hints[m] + 'hintShow-' + key).prop('checked', currentSettings[hints[m] + 'hintShow'][key]); + } + } } // for (var prop in jshints) { @@ -119,6 +135,13 @@ } catch (e) { $hintsOptError[ hints[m] ].html(e).addClass('show'); } + + localStorageSettings[ hints[m] + 'hintShow'] = {}; + for (var key in hintsShow) { + if (hintsShow.hasOwnProperty(key)) { + localStorageSettings[ hints[m] + 'hintShow'][key] = $hintsShow[hints[m]][key].prop('checked'); + } + } } localStorageSettings.includejs = $includejs.prop('checked'); diff --git a/public/js/editors/addons.js b/public/js/editors/addons.js index 8484cc4e..dc8e44ff 100644 --- a/public/js/editors/addons.js +++ b/public/js/editors/addons.js @@ -12,14 +12,21 @@ sublime: false, tern: false, activeline: true, - matchbrackets: false, - csslint: false + matchbrackets: false }; if (!jsbin.settings.addons) { jsbin.settings.addons = defaults; } + + var settingsHints = {}; + ['js', 'css'].forEach(function (val) { + var h = val + 'hint'; + settingsHints[h] = (jsbin.settings[h] !== undefined) ? jsbin.settings[h] : true; + }); + var settingsAddons = $.extend({}, jsbin.settings.addons, settingsHints); + var addons = { closebrackets: { url: '/js/vendor/codemirror4/addon/edit/closebrackets.js', @@ -178,37 +185,18 @@ setOption(cm, 'matchBrackets', true); } }, - csslint: { + csshint: { url: [ + '/js/vendor/csslint/csslint.js', '/js/vendor/cm_addons/lint/lint.css', - '/js/vendor/cm_addons/lint/csslint.js', '/js/vendor/cm_addons/lint/css-lint.js', '/js/vendor/cm_addons/lint/lint.js' ], test: function() { - return CodeMirror.defaults.lint !== undefined && - CodeMirror.helpers.lint && - CodeMirror.helpers.lint.css && - CodeMirror.optionHandlers.lint; + return hintingTest('css'); }, done: function(cm) { - if (cm.getOption('mode') === 'css') { - setOption(cm, 'lintOpt', { - console: true, - consoleParent: cm.getWrapperElement().parentNode.parentNode, - line: true, - under: false, - tooltip: true - // gutter option doesn't exist, it takes from main gutters property - }); - var gutters = cm.getOption('gutters'); - gutters.push('CodeMirror-lint-markers'); - setOption(cm, 'gutters', gutters); - setOption(cm, 'lint', true); - var ln = cm.getOption('lineNumbers'); - setOption(cm, 'lineNumbers', !ln); - setOption(cm, 'lineNumbers', ln); - } + hintingDone(cm); } } }; @@ -267,11 +255,34 @@ }; } - var options = Object.keys(jsbin.settings.addons); + function hintingTest(mode) { + return CodeMirror.defaults.lint !== undefined && + CodeMirror.helpers.lint && + CodeMirror.helpers.lint[mode] && + CodeMirror.optionHandlers.lint; + } + + function hintingDone(cm) { + var mode = cm.getOption('mode'); + var opt = $.extend({}, jsbin.settings[mode + 'hintShow']); + opt.consoleParent = cm.getWrapperElement().parentNode.parentNode; + setOption(cm, 'lintOpt', opt); + if (opt.gutter) { + var gutters = cm.getOption('gutters'); + gutters.push('CodeMirror-lint-markers'); + setOption(cm, 'gutters', gutters); + setOption(cm, 'lint', true); + var ln = cm.getOption('lineNumbers'); + setOption(cm, 'lineNumbers', !ln); + setOption(cm, 'lineNumbers', ln); + } + } + + var options = Object.keys(settingsAddons); function loadAddon(key) { var addon = addons[key]; - if (addon && jsbin.settings.addons[key]) { + if (addon && settingsAddons[key]) { if (typeof addon.url === 'string') { addon.url = [addon.url]; } diff --git a/public/js/vendor/cm_addons/lint/csslint.js b/public/js/vendor/csslint/csslint.js similarity index 100% rename from public/js/vendor/cm_addons/lint/csslint.js rename to public/js/vendor/csslint/csslint.js diff --git a/views/account/editor.html b/views/account/editor.html index 8a70afab..54b28251 100644 --- a/views/account/editor.html +++ b/views/account/editor.html @@ -97,12 +97,7 @@
    -

    Addons

    -
    - - -
    - +

    Addons

    Key bindings diff --git a/views/account/preferences.html b/views/account/preferences.html index 2567e907..e3fc3292 100644 --- a/views/account/preferences.html +++ b/views/account/preferences.html @@ -49,11 +49,34 @@
    +
    + JSHint show errors in: + + + + + +
    +
    +
    + + +
    + +
    + CSSLint show errors in: + + + + + +
    + From 12b8acf516303941b53b6040e5f41746561d3519 Mon Sep 17 00:00:00 2001 From: Giulia Alfonsi Date: Tue, 1 Jul 2014 13:37:02 +0100 Subject: [PATCH 259/321] Hide console, errors, warnings when zero --- public/js/vendor/cm_addons/lint/lint.js | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/public/js/vendor/cm_addons/lint/lint.js b/public/js/vendor/cm_addons/lint/lint.js index ff53b81d..9223ca35 100644 --- a/public/js/vendor/cm_addons/lint/lint.js +++ b/public/js/vendor/cm_addons/lint/lint.js @@ -179,9 +179,20 @@ if (cm.consolelint.warning === 0) counterWclass = ' dis'; if (cm.consolelint.error === 1) es = ''; if (cm.consolelint.warning === 1) ws = ''; - cm.consolelint.head.innerHTML = ' ' + - cm.consolelint.error + ' error' + es + ' ' + + cm.consolelint.head.innerHTML = ''; + if (counterEclass && counterWclass) { + cm.consolelint.head.style.display = 'none'; + return; + } + cm.consolelint.head.style.display = ''; + if (!counterEclass) { + cm.consolelint.head.innerHTML += ' ' + + cm.consolelint.error + ' error' + es + ' '; + } + if (!counterWclass) { + cm.consolelint.head.innerHTML += ' ' + cm.consolelint.warning + ' warning' + ws; + } } function consoleClick(event, cm) { From 40a4268589fd8f7e31d1d032a4b731da8604a9d2 Mon Sep 17 00:00:00 2001 From: Giulia Alfonsi Date: Tue, 1 Jul 2014 15:52:20 +0100 Subject: [PATCH 260/321] Added open/close console error functionalities and new size editors event --- public/js/editors/addons.js | 13 +++++++++++++ public/js/editors/panel.js | 10 ++-------- public/js/vendor/cm_addons/lint/lint.js | 4 ++++ 3 files changed, 19 insertions(+), 8 deletions(-) diff --git a/public/js/editors/addons.js b/public/js/editors/addons.js index 0a9e7571..44a6c9d6 100644 --- a/public/js/editors/addons.js +++ b/public/js/editors/addons.js @@ -19,6 +19,7 @@ jsbin.settings.addons = defaults; } + var detailsSupport = 'open' in document.createElement('details'); var settingsHints = {}; ['js', 'css'].forEach(function (val) { @@ -277,6 +278,18 @@ setOption(cm, 'lineNumbers', !ln); setOption(cm, 'lineNumbers', ln); } + if (opt.console) { + $document.trigger('sizeeditors'); + $(cm.consolelint.head).on('click', function() { + if (!detailsSupport) { + $(this).nextAll().toggle(); + } + // trigger a resize after the click has completed and the details is close + setTimeout(function () { + $document.trigger('sizeeditors'); + }, 10); + }); + } } var options = Object.keys(settingsAddons); diff --git a/public/js/editors/panel.js b/public/js/editors/panel.js index 670a2c3b..665014ba 100644 --- a/public/js/editors/panel.js +++ b/public/js/editors/panel.js @@ -444,14 +444,8 @@ Panel.prototype = { var height = panel.editor.scroller.closest('.panel').outerHeight(), offset = 0; // offset = panel.$el.find('> .label').outerHeight(); - - // special case for the javascript panel - if (panel.name === 'javascript') { - if ($error === null) { // it wasn't there right away, so we populate - $error = panel.$el.find('details'); - } - offset += ($error.filter(':visible').height() || 0); - } + $error = panel.$el.find('details'); + offset += ($error.filter(':visible').height() || 0); if (!jsbin.lameEditor) { editor.scroller.height(height - offset); diff --git a/public/js/vendor/cm_addons/lint/lint.js b/public/js/vendor/cm_addons/lint/lint.js index 9223ca35..97b5012c 100644 --- a/public/js/vendor/cm_addons/lint/lint.js +++ b/public/js/vendor/cm_addons/lint/lint.js @@ -182,9 +182,12 @@ cm.consolelint.head.innerHTML = ''; if (counterEclass && counterWclass) { cm.consolelint.head.style.display = 'none'; + cm.consolelint.logs.style.display = 'none'; + $document.trigger('sizeeditors'); return; } cm.consolelint.head.style.display = ''; + cm.consolelint.logs.style.display = ''; if (!counterEclass) { cm.consolelint.head.innerHTML += ' ' + cm.consolelint.error + ' error' + es + ' '; @@ -193,6 +196,7 @@ cm.consolelint.head.innerHTML += ' ' + cm.consolelint.warning + ' warning' + ws; } + $document.trigger('sizeeditors'); } function consoleClick(event, cm) { From 9ca40cb319377accacfc9edc0acebee8be17ba60 Mon Sep 17 00:00:00 2001 From: Giulia Alfonsi Date: Tue, 1 Jul 2014 15:57:29 +0100 Subject: [PATCH 261/321] New style for console error panel --- public/js/vendor/cm_addons/lint/lint.css | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/public/js/vendor/cm_addons/lint/lint.css b/public/js/vendor/cm_addons/lint/lint.css index bfe5f2ba..3e50ffe1 100644 --- a/public/js/vendor/cm_addons/lint/lint.css +++ b/public/js/vendor/cm_addons/lint/lint.css @@ -97,10 +97,8 @@ padding: 2px 5px 3px; } .console-wrapper { - /*position: absolute;*/ - /*bottom: 0;*/ - /*background: #fff;*/ - /*z-index: 10;*/ + background: #FFF; + color: #333; } .console-log-head { background: #ecf2fa; From 4eb90654c17f32bc0b68aa05921043537e702d93 Mon Sep 17 00:00:00 2001 From: Giulia Alfonsi Date: Tue, 1 Jul 2014 16:08:56 +0100 Subject: [PATCH 262/321] Added linting for javascript --- public/js/editors/addons.js | 23 ++- .../vendor/cm_addons/lint/javascript-lint.js | 132 ++++++++++++++++++ scripts.json | 2 - 3 files changed, 153 insertions(+), 4 deletions(-) create mode 100644 public/js/vendor/cm_addons/lint/javascript-lint.js diff --git a/public/js/editors/addons.js b/public/js/editors/addons.js index 44a6c9d6..242c1441 100644 --- a/public/js/editors/addons.js +++ b/public/js/editors/addons.js @@ -199,6 +199,22 @@ done: function(cm) { hintingDone(cm); } + }, + jshint: { + url: [ + '/js/vendor/jshint/jshint.js', + '/js/vendor/cm_addons/lint/lint.css', + '/js/vendor/cm_addons/lint/javascript-lint.js', + '/js/vendor/cm_addons/lint/lint.js' + ], + test: function() { + return hintingTest('javascript'); + }, + done: function(cm) { + hintingDone(cm, { + 'eqnull': true + }); + } } }; @@ -263,8 +279,11 @@ CodeMirror.optionHandlers.lint; } - function hintingDone(cm) { + function hintingDone(cm, defhintOptions) { var mode = cm.getOption('mode'); + if (mode === 'javascript') { + mode = 'js'; + } var opt = $.extend({}, jsbin.settings[mode + 'hintShow']); opt.consoleParent = cm.getWrapperElement().parentNode.parentNode; setOption(cm, 'lintOpt', opt); @@ -272,7 +291,7 @@ var gutters = cm.getOption('gutters'); gutters.push('CodeMirror-lint-markers'); setOption(cm, 'gutters', gutters); - setOption(cm, 'lintRules', jsbin.settings[mode + 'hintOptions']); + setOption(cm, 'lintRules', $.extend({}, defhintOptions, jsbin.settings[mode + 'hintOptions'])); setOption(cm, 'lint', true); var ln = cm.getOption('lineNumbers'); setOption(cm, 'lineNumbers', !ln); diff --git a/public/js/vendor/cm_addons/lint/javascript-lint.js b/public/js/vendor/cm_addons/lint/javascript-lint.js new file mode 100644 index 00000000..bbb51083 --- /dev/null +++ b/public/js/vendor/cm_addons/lint/javascript-lint.js @@ -0,0 +1,132 @@ +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { + "use strict"; + // declare global: JSHINT + + var bogus = [ "Dangerous comment" ]; + + var warnings = [ [ "Expected '{'", + "Statement body should be inside '{ }' braces." ] ]; + + var errors = [ "Missing semicolon", "Extra comma", "Missing property name", + "Unmatched ", " and instead saw", " is not defined", + "Unclosed string", "Stopping, unable to continue" ]; + + function validator(text, options) { + JSHINT(text, options); + var errors = JSHINT.data().errors, result = []; + if (errors) parseErrors(errors, result); + return result; + } + + CodeMirror.registerHelper("lint", "javascript", validator); + + function cleanup(error) { + // All problems are warnings by default + fixWith(error, warnings, "warning", true); + fixWith(error, errors, "error"); + + return isBogus(error) ? null : error; + } + + function fixWith(error, fixes, severity, force) { + var description, fix, find, replace, found; + + description = error.description; + + for ( var i = 0; i < fixes.length; i++) { + fix = fixes[i]; + find = (typeof fix === "string" ? fix : fix[0]); + replace = (typeof fix === "string" ? null : fix[1]); + found = description.indexOf(find) !== -1; + + if (force || found) { + error.severity = severity; + } + if (found && replace) { + error.description = replace; + } + } + } + + function isBogus(error) { + var description = error.description; + for ( var i = 0; i < bogus.length; i++) { + if (description.indexOf(bogus[i]) !== -1) { + return true; + } + } + return false; + } + + function parseErrors(errors, output) { + for ( var i = 0; i < errors.length; i++) { + var error = errors[i]; + if (error) { + var linetabpositions, index; + + linetabpositions = []; + + // This next block is to fix a problem in jshint. Jshint + // replaces + // all tabs with spaces then performs some checks. The error + // positions (character/space) are then reported incorrectly, + // not taking the replacement step into account. Here we look + // at the evidence line and try to adjust the character position + // to the correct value. + if (error.evidence) { + // Tab positions are computed once per line and cached + var tabpositions = linetabpositions[error.line]; + if (!tabpositions) { + var evidence = error.evidence; + tabpositions = []; + // ugggh phantomjs does not like this + // forEachChar(evidence, function(item, index) { + Array.prototype.forEach.call(evidence, function(item, + index) { + if (item === '\t') { + // First col is 1 (not 0) to match error + // positions + tabpositions.push(index + 1); + } + }); + linetabpositions[error.line] = tabpositions; + } + if (tabpositions.length > 0) { + var pos = error.character; + tabpositions.forEach(function(tabposition) { + if (pos > tabposition) pos -= 1; + }); + error.character = pos; + } + } + + var start = error.character - 1, end = start + 1; + if (error.evidence) { + index = error.evidence.substring(start).search(/.\b/); + if (index > -1) { + end += index; + } + } + + // Convert to format expected by validation service + error.description = error.reason;// + "(jshint)"; + error.start = error.character; + error.end = end; + error = cleanup(error); + + if (error) + output.push({message: error.description, + severity: error.severity, + from: CodeMirror.Pos(error.line - 1, start), + to: CodeMirror.Pos(error.line - 1, end)}); + } + } + } +}); diff --git a/scripts.json b/scripts.json index 43a72655..835caf0d 100644 --- a/scripts.json +++ b/scripts.json @@ -4,7 +4,6 @@ "/js/vendor/jquery-migrate.js", "/js/vendor/pretty-date.js", "/js/vendor/polyfills.js", - "/js/vendor/jshint/jshint.js", "/js/vendor/codemirror4/lib/codemirror.js", "/js/vendor/codemirror4/mode/xml/xml.js", "/js/vendor/codemirror4/mode/css/css.js", @@ -33,7 +32,6 @@ "/js/render/live.js", "/js/editors/keycontrol.js", "/js/render/console.js", - "/js/chrome/errors.js", "/js/processors/processor.js", "/js/editors/panel.js", "/js/editors/editors.js", From 948a543ca4ed9d989f0f557eb7d60162eb85e54e Mon Sep 17 00:00:00 2001 From: Giulia Alfonsi Date: Tue, 1 Jul 2014 17:16:50 +0100 Subject: [PATCH 263/321] Added linting for html panel --- public/js/account/preferences-settings.js | 9 +++-- public/js/editors/addons.js | 30 +++++++++++++++-- public/js/vendor/cm_addons/lint/html-lint.js | 35 ++++++++++++++++++++ public/js/vendor/htmlhint/htmlhint.js | 8 +++++ views/account/preferences.html | 31 ++++++++++++++--- 5 files changed, 104 insertions(+), 9 deletions(-) create mode 100644 public/js/vendor/cm_addons/lint/html-lint.js create mode 100644 public/js/vendor/htmlhint/htmlhint.js diff --git a/public/js/account/preferences-settings.js b/public/js/account/preferences-settings.js index 190f631b..c5949608 100644 --- a/public/js/account/preferences-settings.js +++ b/public/js/account/preferences-settings.js @@ -41,7 +41,10 @@ jshintShow: hintsShow, csshint: false, csshintOptions: '', - csshintShow: hintsShow + csshintShow: hintsShow, + htmlhint: false, + htmlhintOptions: '', + htmlhintShow: hintsShow }; var $saveStatus = $('span.status'); var saveTimer = null; @@ -51,7 +54,7 @@ var $includejs = $('#includejs').prop('checked', currentSettings.includejs); var $focusedPanel = $('#focused-panel').val(currentSettings.focusedPanel); var $assetUrl = $('#asset-url').val(currentSettings.assetUrl); - var hints = ['js', 'css']; + var hints = ['js', 'css', 'html']; var $hints = {}; var $hintsOptions = {}; var $hintsOptWrapper = {}; @@ -77,7 +80,7 @@ } for (var m = 0; m < hints.length; m++) { - $hintsOptWrapper[hints[m]] = $('#' + hints[m] + 'hintOptWrapper') + $hintsOptWrapper[hints[m]] = $('.' + hints[m] + 'hintOptWrapper') .toggle(currentSettings[ hints[m] + 'hint' ]); $hints[hints[m]] = $('#' + hints[m] + 'hint') .prop('checked', currentSettings[ hints[m] + 'hint' ]) diff --git a/public/js/editors/addons.js b/public/js/editors/addons.js index 242c1441..b287a566 100644 --- a/public/js/editors/addons.js +++ b/public/js/editors/addons.js @@ -22,9 +22,18 @@ var detailsSupport = 'open' in document.createElement('details'); var settingsHints = {}; - ['js', 'css'].forEach(function (val) { + var settingsHintsShow = {}; + var hintsShow = { + console: true, + line: true, + under: false, + tooltip: true, + gutter: true + }; + ['js', 'css', 'html'].forEach(function (val) { var h = val + 'hint'; settingsHints[h] = (jsbin.settings[h] !== undefined) ? jsbin.settings[h] : true; + settingsHintsShow[h] = $.extend({}, hintsShow, jsbin.settings[h + 'Show']); }); var settingsAddons = $.extend({}, jsbin.settings.addons, settingsHints); @@ -215,6 +224,20 @@ 'eqnull': true }); } + }, + htmlhint: { + url: [ + '/js/vendor/htmlhint/htmlhint.js', + '/js/vendor/cm_addons/lint/lint.css', + '/js/vendor/cm_addons/lint/html-lint.js', + '/js/vendor/cm_addons/lint/lint.js' + ], + test: function() { + return hintingTest('html'); + }, + done: function(cm) { + hintingDone(cm); + } } }; @@ -284,7 +307,10 @@ if (mode === 'javascript') { mode = 'js'; } - var opt = $.extend({}, jsbin.settings[mode + 'hintShow']); + if (mode === 'htmlmixed') { + mode = 'html'; + } + var opt = $.extend({}, settingsHintsShow[mode + 'hint']); opt.consoleParent = cm.getWrapperElement().parentNode.parentNode; setOption(cm, 'lintOpt', opt); if (opt.gutter) { diff --git a/public/js/vendor/cm_addons/lint/html-lint.js b/public/js/vendor/cm_addons/lint/html-lint.js new file mode 100644 index 00000000..ba9b15c8 --- /dev/null +++ b/public/js/vendor/cm_addons/lint/html-lint.js @@ -0,0 +1,35 @@ +// Depends on htmlhint.js from https://github.com/yaniswang/HTMLHint + +// declare global: HTMLHint + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { + "use strict"; + + function validator(text, options) { + var found = []; + if (!window.HTMLHint) return found; + var results = HTMLHint.verify(text, options), messages = results, message = null; + for ( var i = 0; i < messages.length; i++) { + message = messages[i]; + var startLine = message.line -1, endLine = message.line -1, startCol = message.col -1, endCol = message.col; + found.push({ + from: CodeMirror.Pos(startLine, startCol), + to: CodeMirror.Pos(endLine, endCol), + message: message.message, + severity : message.type + }); + } + return found; + } + + CodeMirror.registerHelper('lint', 'html', validator); + CodeMirror.registerHelper('lint', 'htmlmixed', validator); + +}); diff --git a/public/js/vendor/htmlhint/htmlhint.js b/public/js/vendor/htmlhint/htmlhint.js new file mode 100644 index 00000000..366cf7d5 --- /dev/null +++ b/public/js/vendor/htmlhint/htmlhint.js @@ -0,0 +1,8 @@ +/*! + * HTMLHint v0.9.6 + * https://github.com/yaniswang/HTMLHint + * + * (c) 2013 Yanis Wang . + * MIT Licensed + */ +var HTMLHint=function(e){var t={};return t.version="0.9.6",t.rules={},t.defaultRuleset={"tagname-lowercase":!0,"attr-lowercase":!0,"attr-value-double-quotes":!0,"doctype-first":!0,"tag-pair":!0,"spec-char-escape":!0,"id-unique":!0,"src-not-empty":!0,"attr-no-duplication":!0},t.addRule=function(e){t.rules[e.id]=e},t.verify=function(a,n){a=a.replace(/^\s*/i,function(t,a){return n===e&&(n={}),a.replace(/(?:^|,)\s*([^:]+)\s*:\s*([^,\s]+)/g,function(e,t,a){"false"===a?a=!1:"true"===a&&(a=!0),n[t]=a}),""}),(n===e||0===Object.keys(n).length)&&(n=t.defaultRuleset);var i,r=new HTMLParser,s=new t.Reporter(a.split(/\r?\n/),n),o=t.rules;for(var l in n)i=o[l],i!==e&&n[l]!==!1&&i.init(r,s,n[l]);return r.parse(a),s.messages},t}();"object"==typeof exports&&exports&&(exports.HTMLHint=HTMLHint),function(e){var t=function(){var e=this;e._init.apply(e,arguments)};t.prototype={_init:function(e,t){var a=this;a.lines=e,a.ruleset=t,a.messages=[]},error:function(e,t,a,n,i){this.report("error",e,t,a,n,i)},warn:function(e,t,a,n,i){this.report("warning",e,t,a,n,i)},info:function(e,t,a,n,i){this.report("info",e,t,a,n,i)},report:function(e,t,a,n,i,r){var s=this;s.messages.push({type:e,message:t,raw:r,evidence:s.lines[a-1],line:a,col:n,rule:{id:i.id,description:i.description,link:"https://github.com/yaniswang/HTMLHint/wiki/"+i.id}})}},e.Reporter=t}(HTMLHint);var HTMLParser=function(e){var t=function(){var e=this;e._init.apply(e,arguments)};return t.prototype={_init:function(){var e=this;e._listeners={},e._mapCdataTags=e.makeMap("script,style"),e._arrBlocks=[]},makeMap:function(e){for(var t={},a=e.split(","),n=0;a.length>n;n++)t[a[n]]=!0;return t},parse:function(t){function a(t,a,n,i){var r=n-w+1;i===e&&(i={}),i.raw=a,i.pos=n,i.line=b,i.col=r,L.push(i),c.fire(t,i);for(var s;s=p.exec(a);)b++,w=n+p.lastIndex}var n,i,r,s,o,l,d,u,c=this,f=c._mapCdataTags,g=/<(?:\/([^\s>]+)\s*|!--([\s\S]*?)--|!([^>]*?)|([\w\-:]+)((?:\s+[\w\-:]+(?:\s*=\s*(?:"[^"]*"|'[^']*'|[^\s"']+))?)*?)\s*(\/?))>/g,m=/\s*([\w\-:]+)(?:\s*=\s*(?:(")([^"]*)"|(')([^']*)'|([^\s"']+)))?/g,p=/\r?\n/g,v=0,h=0,w=0,b=1,L=c._arrBlocks;for(c.fire("start",{pos:0,line:1,col:1});n=g.exec(t);)if(i=n.index,i>v&&(u=t.substring(v,i),o?d.push(u):a("text",u,v)),v=g.lastIndex,!(r=n[1])||(o&&r===o&&(u=d.join(""),a("cdata",u,h,{tagName:o,attrs:l}),o=null,l=null,d=null),o))if(o)d.push(n[0]);else if(r=n[4]){s=[];for(var H,y=n[5],T=0;H=m.exec(y);){var x=H[1],M=H[2]?H[2]:H[4]?H[4]:"",R=H[3]?H[3]:H[5]?H[5]:H[6]?H[6]:"";s.push({name:x,value:R,quote:M,index:H.index,raw:H[0]}),T+=H[0].length}T===y.length?(a("tagstart",n[0],i,{tagName:r,attrs:s,close:n[6]}),f[r]&&(o=r,l=s.concat(),d=[],h=v)):a("text",n[0],i)}else(n[2]||n[3])&&a("comment",n[0],i,{content:n[2]||n[3],"long":n[2]?!0:!1});else a("tagend",n[0],i,{tagName:r});t.length>v&&(u=t.substring(v,t.length),a("text",u,v)),c.fire("end",{pos:v,line:b,col:v-w+1})},addListener:function(t,a){for(var n,i=this._listeners,r=t.split(/[,\s]/),s=0,o=r.length;o>s;s++)n=r[s],i[n]===e&&(i[n]=[]),i[n].push(a)},fire:function(t,a){a===e&&(a={}),a.type=t;var n=this,i=[],r=n._listeners[t],s=n._listeners.all;r!==e&&(i=i.concat(r)),s!==e&&(i=i.concat(s));for(var o=0,l=i.length;l>o;o++)i[o].call(n,a)},removeListener:function(t,a){var n=this._listeners[t];if(n!==e)for(var i=0,r=n.length;r>i;i++)if(n[i]===a){n.splice(i,1);break}},fixPos:function(e,t){var a,n=e.raw.substr(0,t),i=n.split(/\r?\n/),r=i.length-1,s=e.line;return r>0?(s+=r,a=i[r].length+1):a=e.col+t,{line:s,col:a}},getMapAttrs:function(e){for(var t,a={},n=0,i=e.length;i>n;n++)t=e[n],a[t.name]=t.value;return a}},t}();"object"==typeof exports&&exports&&(exports.HTMLParser=HTMLParser),HTMLHint.addRule({id:"attr-lowercase",description:"Attribute name must be lowercase.",init:function(e,t){var a=this;e.addListener("tagstart",function(e){for(var n,i=e.attrs,r=e.col+e.tagName.length+1,s=0,o=i.length;o>s;s++){n=i[s];var l=n.name;l!==l.toLowerCase()&&t.error("Attribute name [ "+l+" ] must be lower case.",e.line,r+n.index,a,n.raw)}})}}),HTMLHint.addRule({id:"attr-no-duplication",description:"Attribute name can not been duplication.",init:function(e,t){var a=this;e.addListener("tagstart",function(e){for(var n,i,r=e.attrs,s=e.col+e.tagName.length+1,o={},l=0,d=r.length;d>l;l++)n=r[l],i=n.name,o[i]===!0&&t.error("The name of attribute [ "+n.name+" ] been duplication.",e.line,s+n.index,a,n.raw),o[i]=!0})}}),HTMLHint.addRule({id:"attr-unsafe-chars",description:"Attribute value cant not use unsafe chars.",init:function(e,t){var a=this;e.addListener("tagstart",function(e){for(var n,i=e.attrs,r=e.col+e.tagName.length+1,s=/[\u0000-\u001f\u007f-\u009f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/,o=0,l=i.length;l>o;o++)n=i[o],s.test(n.value)===!0&&t.warn("The value of attribute [ "+n.name+" ] cant not use unsafe chars.",e.line,r+n.index,a,n.raw)})}}),HTMLHint.addRule({id:"attr-value-double-quotes",description:"Attribute value must closed by double quotes.",init:function(e,t){var a=this;e.addListener("tagstart",function(e){for(var n,i=e.attrs,r=e.col+e.tagName.length+1,s=0,o=i.length;o>s;s++)n=i[s],(""!==n.value&&'"'!==n.quote||""===n.value&&"'"===n.quote)&&t.error("The value of attribute [ "+n.name+" ] must closed by double quotes.",e.line,r+n.index,a,n.raw)})}}),HTMLHint.addRule({id:"attr-value-not-empty",description:"Attribute must set value.",init:function(e,t){var a=this;e.addListener("tagstart",function(e){for(var n,i=e.attrs,r=e.col+e.tagName.length+1,s=0,o=i.length;o>s;s++)n=i[s],""===n.quote&&""===n.value&&t.warn("The attribute [ "+n.name+" ] must set value.",e.line,r+n.index,a,n.raw)})}}),HTMLHint.addRule({id:"csslint",description:"Scan css with csslint.",init:function(e,t,a){var n=this;e.addListener("cdata",function(e){if("style"===e.tagName.toLowerCase()){var i;if(i="object"==typeof exports&&require?require("csslint").CSSLint.verify:CSSLint.verify,void 0!==a){var r=e.line-1,s=e.col-1;try{var o=i(e.raw,a).messages;o.forEach(function(e){var a=e.line;t["warning"===e.type?"warn":"error"]("["+e.rule.id+"] "+e.message,r+a,(1===a?s:0)+e.col,n,e.evidence)})}catch(l){}}}})}}),HTMLHint.addRule({id:"doctype-first",description:"Doctype must be first.",init:function(e,t){var a=this,n=function(i){"start"===i.type||"text"===i.type&&/^\s*$/.test(i.raw)||(("comment"!==i.type&&i.long===!1||/^DOCTYPE\s+/i.test(i.content)===!1)&&t.error("Doctype must be first.",i.line,i.col,a,i.raw),e.removeListener("all",n))};e.addListener("all",n)}}),HTMLHint.addRule({id:"doctype-html5",description:"Doctype must be html5.",init:function(e,t){function a(e){e.long===!1&&"doctype html"!==e.content.toLowerCase()&&t.warn("Doctype must be html5.",e.line,e.col,i,e.raw)}function n(){e.removeListener("comment",a),e.removeListener("tagstart",n)}var i=this;e.addListener("all",a),e.addListener("tagstart",n)}}),HTMLHint.addRule({id:"head-script-disabled",description:"The script tag can not be used in head.",init:function(e,t){function a(e){"script"===e.tagName.toLowerCase()&&t.warn("The script tag can not be used in head.",e.line,e.col,i,e.raw)}function n(t){"head"===t.tagName.toLowerCase()&&(e.removeListener("tagstart",a),e.removeListener("tagstart",n))}var i=this;e.addListener("tagstart",a),e.addListener("tagend",n)}}),HTMLHint.addRule({id:"href-abs-or-rel",description:"Href must be absolute or relative.",init:function(e,t,a){var n=this,i="abs"===a?"absolute":"relative";e.addListener("tagstart",function(e){for(var a,r=e.attrs,s=e.col+e.tagName.length+1,o=0,l=r.length;l>o;o++)if(a=r[o],"href"===a.name){("absolute"===i&&/^\w+?:/.test(a.value)===!1||"relative"===i&&/^https?:\/\//.test(a.value)===!0)&&t.warn("The value of href [ "+a.value+" ] must be "+i+".",e.line,s+a.index,n,a.raw);break}})}}),HTMLHint.addRule({id:"id-class-ad-disabled",description:"Id and class can not use ad keyword, it will blocked by adblock software.",init:function(e,t){var a=this;e.addListener("tagstart",function(e){for(var n,i,r=e.attrs,s=e.col+e.tagName.length+1,o=0,l=r.length;l>o;o++)n=r[o],i=n.name,/^(id|class)$/i.test(i)&&/(^|[-\_])ad([-\_]|$)/i.test(n.value)&&t.warn("The value of "+i+" can not use ad keyword.",e.line,s+n.index,a,n.raw)})}}),HTMLHint.addRule({id:"id-class-value",description:"Id and class value must meet some rules.",init:function(e,t,a){var n,i=this,r={underline:{regId:/^[a-z\d]+(_[a-z\d]+)*$/,message:"Id and class value must lower case and split by underline."},dash:{regId:/^[a-z\d]+(-[a-z\d]+)*$/,message:"Id and class value must lower case and split by dash."},hump:{regId:/^[a-z][a-zA-Z\d]*([A-Z][a-zA-Z\d]*)*$/,message:"Id and class value must meet hump style."}};if(n="string"==typeof a?r[a]:a,n&&n.regId){var s=n.regId,o=n.message;e.addListener("tagstart",function(e){for(var a,n=e.attrs,r=e.col+e.tagName.length+1,l=0,d=n.length;d>l;l++)if(a=n[l],"id"===a.name.toLowerCase()&&s.test(a.value)===!1&&t.warn(o,e.line,r+a.index,i,a.raw),"class"===a.name.toLowerCase())for(var u,c=a.value.split(/\s+/g),f=0,g=c.length;g>f;f++)u=c[f],u&&s.test(u)===!1&&t.warn(o,e.line,r+a.index,i,u)})}}}),HTMLHint.addRule({id:"id-unique",description:"Id must be unique.",init:function(e,t){var a=this,n={};e.addListener("tagstart",function(e){for(var i,r,s=e.attrs,o=e.col+e.tagName.length+1,l=0,d=s.length;d>l;l++)if(i=s[l],"id"===i.name.toLowerCase()){r=i.value,r&&(void 0===n[r]?n[r]=1:n[r]++,n[r]>1&&t.error("Id redefinition of [ "+r+" ].",e.line,o+i.index,a,i.raw));break}})}}),HTMLHint.addRule({id:"img-alt-require",description:"Alt of img tag must be set value.",init:function(e,t){var a=this;e.addListener("tagstart",function(e){if("img"===e.tagName.toLowerCase()){for(var n=e.attrs,i=!1,r=0,s=n.length;s>r;r++)if("alt"===n[r].name.toLowerCase()){i=!0;break}i===!1&&t.warn("Alt of img tag must be set value.",e.line,e.col,a,e.raw)}})}}),HTMLHint.addRule({id:"jshint",description:"Scan script with jshint.",init:function(e,t,a){var n=this;e.addListener("cdata",function(i){if("script"===i.tagName.toLowerCase()){var r=e.getMapAttrs(i.attrs),s=r.type;if(void 0!==r.src||s&&/^(text\/javascript)$/i.test(s)===!1)return;var o;if(o="object"==typeof exports&&require?require("jshint").JSHINT:JSHINT,void 0!==a){var l=i.line-1,d=i.col-1,u=i.raw.replace(/\t/g," ");try{var c=o(u,a);c===!1&&o.errors.forEach(function(e){var a=e.line;t.warn(e.reason,l+a,(1===a?d:0)+e.character,n,e.evidence)})}catch(f){}}}})}}),HTMLHint.addRule({id:"space-tab-mixed-disabled",description:"Spaces and tabs can not mixed in front of line.",init:function(e,t){var a=this;e.addListener("text",function(n){for(var i,r=n.raw,s=/(^|\r?\n)( +\t|\t+ )/g;i=s.exec(r);){var o=e.fixPos(n,i.index+i[1].length);t.warn("Mixed spaces and tabs in front of line.",o.line,1,a,n.raw)}})}}),HTMLHint.addRule({id:"spec-char-escape",description:"Special characters must be escaped.",init:function(e,t){var a=this;e.addListener("text",function(n){for(var i,r=n.raw,s=/[<>]/g;i=s.exec(r);){var o=e.fixPos(n,i.index);t.error("Special characters must be escaped : [ "+i[0]+" ].",o.line,o.col,a,n.raw)}})}}),HTMLHint.addRule({id:"src-not-empty",description:"Src of img(script,link) must set value.",init:function(e,t){var a=this;e.addListener("tagstart",function(e){for(var n,i=e.tagName,r=e.attrs,s=e.col+i.length+1,o=0,l=r.length;l>o;o++)n=r[o],(/^(img|script|embed|bgsound|iframe)$/.test(i)===!0&&"src"===n.name||"link"===i&&"href"===n.name||"object"===i&&"data"===n.name)&&""===n.value&&t.error("[ "+n.name+"] of [ "+i+" ] must set value.",e.line,s+n.index,a,n.raw)})}}),HTMLHint.addRule({id:"style-disabled",description:"Style tag can not be use.",init:function(e,t){var a=this;e.addListener("tagstart",function(e){"style"===e.tagName.toLowerCase()&&t.warn("Style tag can not be use.",e.line,e.col,a,e.raw)})}}),HTMLHint.addRule({id:"tag-pair",description:"Tag must be paired.",init:function(e,t){var a=this,n=[],i=e.makeMap("area,base,basefont,br,col,frame,hr,img,input,isindex,link,meta,param,embed");e.addListener("tagstart",function(e){var t=e.tagName.toLowerCase();void 0!==i[t]||e.close||n.push(t)}),e.addListener("tagend",function(e){for(var i=e.tagName.toLowerCase(),r=n.length-1;r>=0&&n[r]!==i;r--);if(r>=0){for(var s=[],o=n.length-1;o>r;o--)s.push("");s.length>0&&t.error("Tag must be paired, Missing: [ "+s.join("")+" ]",e.line,e.col,a,e.raw),n.length=r}else t.error("Tag must be paired, No start tag: [ "+e.raw+" ]",e.line,e.col,a,e.raw)}),e.addListener("end",function(e){for(var i=[],r=n.length-1;r>=0;r--)i.push("");i.length>0&&t.error("Tag must be paired, Missing: [ "+i.join("")+" ]",e.line,e.col,a,"")})}}),HTMLHint.addRule({id:"tag-self-close",description:"The empty tag must closed by self.",init:function(e,t){var a=this,n=e.makeMap("area,base,basefont,br,col,frame,hr,img,input,isindex,link,meta,param,embed");e.addListener("tagstart",function(e){var i=e.tagName.toLowerCase();void 0!==n[i]&&(e.close||t.warn("The empty tag : [ "+i+" ] must closed by self.",e.line,e.col,a,e.raw))})}}),HTMLHint.addRule({id:"tagname-lowercase",description:"Tagname must be lowercase.",init:function(e,t){var a=this;e.addListener("tagstart,tagend",function(e){var n=e.tagName;n!==n.toLowerCase()&&t.error("Tagname [ "+n+" ] must be lower case.",e.line,e.col,a,e.raw)})}}); \ No newline at end of file diff --git a/views/account/preferences.html b/views/account/preferences.html index 14eb7c0c..fe1256b4 100644 --- a/views/account/preferences.html +++ b/views/account/preferences.html @@ -49,7 +49,7 @@
    -
    +
    JSHint show errors in: @@ -58,17 +58,19 @@
    -
    +
    +
    +
    -
    +
    CSSLint show errors in: @@ -77,11 +79,32 @@
    -
    +
    +
    + +
    + + +
    + +
    + HTMLHint show errors in: + + + + + +
    + +
    + + +
    + From 2d667b2ec561550a3ba18029b86ad10ae063d2b9 Mon Sep 17 00:00:00 2001 From: Giulia Alfonsi Date: Tue, 1 Jul 2014 18:52:46 +0100 Subject: [PATCH 264/321] Fixed compatibility problems between html and htmlmixed mode --- public/js/editors/addons.js | 11 ++++++++++- public/js/vendor/cm_addons/lint/html-lint.js | 7 ++----- public/js/vendor/cm_addons/lint/lint.js | 3 +++ 3 files changed, 15 insertions(+), 6 deletions(-) diff --git a/public/js/editors/addons.js b/public/js/editors/addons.js index b287a566..c5a48866 100644 --- a/public/js/editors/addons.js +++ b/public/js/editors/addons.js @@ -206,6 +206,9 @@ return hintingTest('css'); }, done: function(cm) { + if (cm.getOption('mode') !== 'css') { + return; + } hintingDone(cm); } }, @@ -220,6 +223,9 @@ return hintingTest('javascript'); }, done: function(cm) { + if (cm.getOption('mode') !== 'javascript') { + return; + } hintingDone(cm, { 'eqnull': true }); @@ -233,9 +239,12 @@ '/js/vendor/cm_addons/lint/lint.js' ], test: function() { - return hintingTest('html'); + return hintingTest('htmlmixed'); }, done: function(cm) { + if (cm.getOption('mode') !== 'htmlmixed') { + return; + } hintingDone(cm); } } diff --git a/public/js/vendor/cm_addons/lint/html-lint.js b/public/js/vendor/cm_addons/lint/html-lint.js index ba9b15c8..a6d77253 100644 --- a/public/js/vendor/cm_addons/lint/html-lint.js +++ b/public/js/vendor/cm_addons/lint/html-lint.js @@ -12,7 +12,7 @@ })(function(CodeMirror) { "use strict"; - function validator(text, options) { + CodeMirror.registerHelper("lint", "htmlmixed", function(text, options) { var found = []; if (!window.HTMLHint) return found; var results = HTMLHint.verify(text, options), messages = results, message = null; @@ -27,9 +27,6 @@ }); } return found; - } - - CodeMirror.registerHelper('lint', 'html', validator); - CodeMirror.registerHelper('lint', 'htmlmixed', validator); + }); }); diff --git a/public/js/vendor/cm_addons/lint/lint.js b/public/js/vendor/cm_addons/lint/lint.js index 97b5012c..f931702a 100644 --- a/public/js/vendor/cm_addons/lint/lint.js +++ b/public/js/vendor/cm_addons/lint/lint.js @@ -68,6 +68,9 @@ if (options instanceof Function) return {getAnnotations: options}; if (!options || options === true) options = {}; if (!options.getAnnotations) options.getAnnotations = cm.getHelper(CodeMirror.Pos(0, 0), 'lint'); + if (!options.getAnnotations && cm.getOption('mode') === 'htmlmixed') { + options.getAnnotations = CodeMirror.helpers.lint.htmlmixed; + } if (!options.getAnnotations) throw new Error('Required option "getAnnotations" missing (lint addon)'); return options; } From ca818c3594ecde44e360faab3d364bf8d596cc3a Mon Sep 17 00:00:00 2001 From: Giulia Alfonsi Date: Tue, 1 Jul 2014 19:04:27 +0100 Subject: [PATCH 265/321] Added coffee script linking - to finish --- public/js/account/preferences-settings.js | 7 +- public/js/editors/addons.js | 19 +- public/js/editors/panel.js | 23 +- .../cm_addons/lint/coffeescript-lint.js | 38 + public/js/vendor/coffeelint/coffeelint.js | 2324 +++++++++++++++++ views/account/preferences.html | 21 + 6 files changed, 2418 insertions(+), 14 deletions(-) create mode 100644 public/js/vendor/cm_addons/lint/coffeescript-lint.js create mode 100644 public/js/vendor/coffeelint/coffeelint.js diff --git a/public/js/account/preferences-settings.js b/public/js/account/preferences-settings.js index c5949608..9d65a0f9 100644 --- a/public/js/account/preferences-settings.js +++ b/public/js/account/preferences-settings.js @@ -44,7 +44,10 @@ csshintShow: hintsShow, htmlhint: false, htmlhintOptions: '', - htmlhintShow: hintsShow + htmlhintShow: hintsShow, + coffeescripthint: false, + coffeescripthintOptions: '', + coffeescripthintShow: hintsShow }; var $saveStatus = $('span.status'); var saveTimer = null; @@ -54,7 +57,7 @@ var $includejs = $('#includejs').prop('checked', currentSettings.includejs); var $focusedPanel = $('#focused-panel').val(currentSettings.focusedPanel); var $assetUrl = $('#asset-url').val(currentSettings.assetUrl); - var hints = ['js', 'css', 'html']; + var hints = ['js', 'css', 'html', 'coffeescript']; var $hints = {}; var $hintsOptions = {}; var $hintsOptWrapper = {}; diff --git a/public/js/editors/addons.js b/public/js/editors/addons.js index c5a48866..a2952e5c 100644 --- a/public/js/editors/addons.js +++ b/public/js/editors/addons.js @@ -30,7 +30,7 @@ tooltip: true, gutter: true }; - ['js', 'css', 'html'].forEach(function (val) { + ['js', 'css', 'html', 'coffeescript'].forEach(function (val) { var h = val + 'hint'; settingsHints[h] = (jsbin.settings[h] !== undefined) ? jsbin.settings[h] : true; settingsHintsShow[h] = $.extend({}, hintsShow, jsbin.settings[h + 'Show']); @@ -247,6 +247,23 @@ } hintingDone(cm); } + }, + coffeescripthint: { + url: [ + '/js/vendor/coffeelint/coffeelint.js', + '/js/vendor/cm_addons/lint/lint.css', + '/js/vendor/cm_addons/lint/coffeescript-lint.js', + '/js/vendor/cm_addons/lint/lint.js' + ], + test: function() { + return hintingTest('coffeescript'); + }, + done: function(cm) { + if (cm.getOption('mode') !== 'coffeescript') { + return; + } + hintingDone(cm); + } } }; diff --git a/public/js/editors/panel.js b/public/js/editors/panel.js index 665014ba..aa534f53 100644 --- a/public/js/editors/panel.js +++ b/public/js/editors/panel.js @@ -75,17 +75,18 @@ var Panel = function (name, settings) { } // this is nasty and wrong, but I'm going to put here anyway .i.. - if (this.id === 'javascript') { - this.on('processor', function (e, preprocessor) { - if (preprocessor === 'none') { - jshintEnabled = true; - checkForErrors(); - } else { - jshintEnabled = false; - $error.hide(); - } - }); - } + // removed as we have a different way to check for errors + // if (this.id === 'javascript') { + // this.on('processor', function (e, preprocessor) { + // if (preprocessor === 'none') { + // jshintEnabled = true; + // checkForErrors(); + // } else { + // jshintEnabled = false; + // $error.hide(); + // } + // }); + // } if (settings.editor) { cmSettings = { diff --git a/public/js/vendor/cm_addons/lint/coffeescript-lint.js b/public/js/vendor/cm_addons/lint/coffeescript-lint.js new file mode 100644 index 00000000..6df17f8f --- /dev/null +++ b/public/js/vendor/cm_addons/lint/coffeescript-lint.js @@ -0,0 +1,38 @@ +// Depends on coffeelint.js from http://www.coffeelint.org/js/coffeelint.js + +// declare global: coffeelint + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { +"use strict"; + +CodeMirror.registerHelper("lint", "coffeescript", function(text) { + var found = []; + var parseError = function(err) { + var loc = err.lineNumber; + found.push({from: CodeMirror.Pos(loc-1, 0), + to: CodeMirror.Pos(loc, 0), + severity: err.level, + message: err.message}); + }; + try { + var res = coffeelint.lint(text); + for(var i = 0; i < res.length; i++) { + parseError(res[i]); + } + } catch(e) { + found.push({from: CodeMirror.Pos(e.location.first_line, 0), + to: CodeMirror.Pos(e.location.last_line, e.location.last_column), + severity: 'error', + message: e.message}); + } + return found; +}); + +}); diff --git a/public/js/vendor/coffeelint/coffeelint.js b/public/js/vendor/coffeelint/coffeelint.js new file mode 100644 index 00000000..a2fd8da0 --- /dev/null +++ b/public/js/vendor/coffeelint/coffeelint.js @@ -0,0 +1,2324 @@ +!function(e){if("object"==typeof exports)module.exports=e();else if("function"==typeof define&&define.amd)define(e);else{var f;"undefined"!=typeof window?f=window:"undefined"!=typeof global?f=global:"undefined"!=typeof self&&(f=self),f.coffeelint=e()}}(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);throw new Error("Cannot find module '"+o+"'")}var f=n[o]={exports:{}};t[o][0].call(f.exports,function(e){var n=t[o][1][e];return s(n?n:e)},f,f.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o", + "main": "./lib/coffeelint.js", + "engines": { + "node": ">=0.8.0" + }, + "repository": { + "type": "git", + "url": "git://github.com/clutchski/coffeelint.git" + }, + "bin": { + "coffeelint": "./bin/coffeelint" + }, + "dependencies": { + "browserify": "~3.37", + "coffee-script": "~1.7", + "coffeeify": "~0.6.0", + "glob": "^4.0.0", + "optimist": "^0.6.1", + "resolve": "^0.6.3" + }, + "devDependencies": { + "vows": ">=0.6.0", + "underscore": ">=1.4.4" + }, + "licenses": [ + { + "type": "MIT", + "url": "http://github.com/clutchski/coffeelint/raw/master/LICENSE" + } + ], + "scripts": { + "pretest": "cake compile", + "test": "coffee vowsrunner.coffee --spec test/*.coffee test/*.litcoffee", + "posttest": "npm run lint", + "prepublish": "cake prepublish", + "publish": "cake publish", + "install": "cake install", + "lint": "cake compile && ./bin/coffeelint -f coffeelint.json src/*.coffee test/*.coffee test/*.litcoffee", + "lint-csv": "cake compile && ./bin/coffeelint --csv -f coffeelint.json src/*.coffee test/*.coffee", + "lint-jslint": "cake compile && ./bin/coffeelint --jslint -f coffeelint.json src/*.coffee test/*.coffee", + "compile": "cake compile" + } +} + +},{}],2:[function(_dereq_,module,exports){ +var ASTApi, ASTLinter, BaseLinter, hasChildren, node_children, + __hasProp = {}.hasOwnProperty, + __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }; + +BaseLinter = _dereq_('./base_linter.coffee'); + +node_children = { + Class: ['variable', 'parent', 'body'], + Code: ['params', 'body'], + For: ['body', 'source', 'guard', 'step'], + If: ['condition', 'body', 'elseBody'], + Obj: ['properties'], + Op: ['first', 'second'], + Switch: ['subject', 'cases', 'otherwise'], + Try: ['attempt', 'recovery', 'ensure'], + Value: ['base', 'properties'], + While: ['condition', 'guard', 'body'] +}; + +hasChildren = function(node, children) { + var _ref; + return (node != null ? (_ref = node.children) != null ? _ref.length : void 0 : void 0) === children.length && (node != null ? node.children.every(function(elem, i) { + return elem === children[i]; + }) : void 0); +}; + +ASTApi = (function() { + function ASTApi(config) { + this.config = config; + } + + ASTApi.prototype.getNodeName = function(node) { + var children, name, _ref; + name = node != null ? (_ref = node.constructor) != null ? _ref.name : void 0 : void 0; + if (node_children[name]) { + return name; + } else { + for (name in node_children) { + if (!__hasProp.call(node_children, name)) continue; + children = node_children[name]; + if (hasChildren(node, children)) { + return name; + } + } + } + }; + + return ASTApi; + +})(); + +module.exports = ASTLinter = (function(_super) { + __extends(ASTLinter, _super); + + function ASTLinter(source, config, rules, CoffeeScript) { + this.CoffeeScript = CoffeeScript; + ASTLinter.__super__.constructor.call(this, source, config, rules); + this.astApi = new ASTApi(this.config); + } + + ASTLinter.prototype.acceptRule = function(rule) { + return typeof rule.lintAST === 'function'; + }; + + ASTLinter.prototype.lint = function() { + var coffeeError, err, errors, rule, v, _i, _len, _ref; + errors = []; + try { + this.node = this.CoffeeScript.nodes(this.source); + } catch (_error) { + coffeeError = _error; + err = this._parseCoffeeScriptError(coffeeError); + if (err != null) { + errors.push(err); + } + return errors; + } + _ref = this.rules; + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + rule = _ref[_i]; + this.astApi.createError = (function(_this) { + return function(attrs) { + if (attrs == null) { + attrs = {}; + } + return _this.createError(rule.rule.name, attrs); + }; + })(this); + rule.errors = errors; + v = this.normalizeResult(rule, rule.lintAST(this.node, this.astApi)); + if (v != null) { + return v; + } + } + return errors; + }; + + ASTLinter.prototype._parseCoffeeScriptError = function(coffeeError) { + var attrs, lineNumber, match, message, rule; + rule = this.config['coffeescript_error']; + message = coffeeError.toString(); + lineNumber = -1; + if (coffeeError.location != null) { + lineNumber = coffeeError.location.first_line + 1; + } else { + match = /line (\d+)/.exec(message); + if ((match != null ? match.length : void 0) > 1) { + lineNumber = parseInt(match[1], 10); + } + } + attrs = { + message: message, + level: rule.level, + lineNumber: lineNumber + }; + return this.createError('coffeescript_error', attrs); + }; + + return ASTLinter; + +})(BaseLinter); + + +},{"./base_linter.coffee":3}],3:[function(_dereq_,module,exports){ +var BaseLinter, defaults, extend, + __slice = [].slice; + +extend = function() { + var destination, k, source, sources, v, _i, _len; + destination = arguments[0], sources = 2 <= arguments.length ? __slice.call(arguments, 1) : []; + for (_i = 0, _len = sources.length; _i < _len; _i++) { + source = sources[_i]; + for (k in source) { + v = source[k]; + destination[k] = v; + } + } + return destination; +}; + +defaults = function(source, defaults) { + return extend({}, defaults, source); +}; + +module.exports = BaseLinter = (function() { + function BaseLinter(source, config, rules) { + this.source = source; + this.config = config; + this.setupRules(rules); + } + + BaseLinter.prototype.isObject = function(obj) { + return obj === Object(obj); + }; + + BaseLinter.prototype.createError = function(ruleName, attrs) { + var level; + if (attrs == null) { + attrs = {}; + } + if (attrs.level == null) { + attrs.level = this.config[ruleName].level; + } + level = attrs.level; + if (level !== 'ignore' && level !== 'warn' && level !== 'error') { + throw new Error("unknown level " + level); + } + if (level === 'error' || level === 'warn') { + attrs.rule = ruleName; + return defaults(attrs, this.config[ruleName]); + } else { + return null; + } + }; + + BaseLinter.prototype.acceptRule = function(rule) { + throw new Error("acceptRule needs to be overridden in the subclass"); + }; + + BaseLinter.prototype.setupRules = function(rules) { + var RuleConstructor, level, name, rule, _results; + this.rules = []; + _results = []; + for (name in rules) { + RuleConstructor = rules[name]; + level = this.config[name].level; + if (level === 'error' || level === 'warn') { + rule = new RuleConstructor(this, this.config); + if (this.acceptRule(rule)) { + _results.push(this.rules.push(rule)); + } else { + _results.push(void 0); + } + } else if (level !== 'ignore') { + throw new Error("unknown level " + level); + } else { + _results.push(void 0); + } + } + return _results; + }; + + BaseLinter.prototype.normalizeResult = function(p, result) { + if (result === true) { + return this.createError(p.rule.name); + } + if (this.isObject(result)) { + return this.createError(p.rule.name, result); + } + }; + + return BaseLinter; + +})(); + + +},{}],4:[function(_dereq_,module,exports){ + +/* +CoffeeLint + +Copyright (c) 2011 Matthew Perpick. +CoffeeLint is freely distributable under the MIT license. + */ +var ASTLinter, CoffeeScript, ERROR, IGNORE, LexicalLinter, LineLinter, RULES, WARN, cache, coffeelint, defaults, difference, extend, hasSyntaxError, mergeDefaultConfig, nodeRequire, packageJSON, _rules, + __slice = [].slice, + __indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; }; + +coffeelint = exports; + +nodeRequire = _dereq_; + +if (typeof window !== "undefined" && window !== null) { + CoffeeScript = window.CoffeeScript; +} else { + CoffeeScript = nodeRequire('coffee-script'); +} + +packageJSON = _dereq_('./../package.json'); + +coffeelint.VERSION = packageJSON.version; + +ERROR = 'error'; + +WARN = 'warn'; + +IGNORE = 'ignore'; + +coffeelint.RULES = RULES = _dereq_('./rules.coffee'); + +extend = function() { + var destination, k, source, sources, v, _i, _len; + destination = arguments[0], sources = 2 <= arguments.length ? __slice.call(arguments, 1) : []; + for (_i = 0, _len = sources.length; _i < _len; _i++) { + source = sources[_i]; + for (k in source) { + v = source[k]; + destination[k] = v; + } + } + return destination; +}; + +defaults = function(source, defaults) { + return extend({}, defaults, source); +}; + +difference = function(a, b) { + var j, _ref, _results; + j = 0; + _results = []; + while (j < a.length) { + if (_ref = a[j], __indexOf.call(b, _ref) >= 0) { + _results.push(a.splice(j, 1)); + } else { + _results.push(j++); + } + } + return _results; +}; + +LineLinter = _dereq_('./line_linter.coffee'); + +LexicalLinter = _dereq_('./lexical_linter.coffee'); + +ASTLinter = _dereq_('./ast_linter.coffee'); + +cache = null; + +mergeDefaultConfig = function(userConfig) { + var config, rule, ruleConfig; + config = {}; + for (rule in RULES) { + ruleConfig = RULES[rule]; + config[rule] = defaults(userConfig[rule], ruleConfig); + } + return config; +}; + +coffeelint.invertLiterate = function(source) { + var line, newSource, _i, _len, _ref; + source = CoffeeScript.helpers.invertLiterate(source); + newSource = ""; + _ref = source.split("\n"); + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + line = _ref[_i]; + if (line.match(/^#/)) { + line = line.replace(/\s*$/, ''); + } + line = line.replace(/^\s{4}/g, ''); + newSource += "" + line + "\n"; + } + return newSource; +}; + +_rules = {}; + +coffeelint.registerRule = function(RuleConstructor, ruleName) { + var e, name, p, _ref, _ref1; + if (ruleName == null) { + ruleName = void 0; + } + p = new RuleConstructor; + name = (p != null ? (_ref = p.rule) != null ? _ref.name : void 0 : void 0) || "(unknown)"; + e = function(msg) { + throw new Error("Invalid rule: " + name + " " + msg); + }; + if (p.rule == null) { + e("Rules must provide rule attribute with a default configuration."); + } + if (p.rule.name == null) { + e("Rule defaults require a name"); + } + if ((ruleName != null) && ruleName !== p.rule.name) { + e("Mismatched rule name: " + ruleName); + } + if (p.rule.message == null) { + e("Rule defaults require a message"); + } + if (p.rule.description == null) { + e("Rule defaults require a description"); + } + if ((_ref1 = p.rule.level) !== 'ignore' && _ref1 !== 'warn' && _ref1 !== 'error') { + e("Default level must be 'ignore', 'warn', or 'error'"); + } + if (typeof p.lintToken === 'function') { + if (!p.tokens) { + e("'tokens' is required for 'lintToken'"); + } + } else if (typeof p.lintLine !== 'function' && typeof p.lintAST !== 'function') { + e("Rules must implement lintToken, lintLine, or lintAST"); + } + RULES[p.rule.name] = p.rule; + return _rules[p.rule.name] = RuleConstructor; +}; + +coffeelint.getRules = function() { + var key, output, _i, _len, _ref; + output = {}; + _ref = Object.keys(RULES).sort(); + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + key = _ref[_i]; + output[key] = RULES[key]; + } + return output; +}; + +coffeelint.registerRule(_dereq_('./rules/arrow_spacing.coffee')); + +coffeelint.registerRule(_dereq_('./rules/no_tabs.coffee')); + +coffeelint.registerRule(_dereq_('./rules/no_trailing_whitespace.coffee')); + +coffeelint.registerRule(_dereq_('./rules/max_line_length.coffee')); + +coffeelint.registerRule(_dereq_('./rules/line_endings.coffee')); + +coffeelint.registerRule(_dereq_('./rules/no_trailing_semicolons.coffee')); + +coffeelint.registerRule(_dereq_('./rules/indentation.coffee')); + +coffeelint.registerRule(_dereq_('./rules/camel_case_classes.coffee')); + +coffeelint.registerRule(_dereq_('./rules/colon_assignment_spacing.coffee')); + +coffeelint.registerRule(_dereq_('./rules/no_implicit_braces.coffee')); + +coffeelint.registerRule(_dereq_('./rules/no_plusplus.coffee')); + +coffeelint.registerRule(_dereq_('./rules/no_throwing_strings.coffee')); + +coffeelint.registerRule(_dereq_('./rules/no_backticks.coffee')); + +coffeelint.registerRule(_dereq_('./rules/no_implicit_parens.coffee')); + +coffeelint.registerRule(_dereq_('./rules/no_empty_param_list.coffee')); + +coffeelint.registerRule(_dereq_('./rules/no_stand_alone_at.coffee')); + +coffeelint.registerRule(_dereq_('./rules/space_operators.coffee')); + +coffeelint.registerRule(_dereq_('./rules/duplicate_key.coffee')); + +coffeelint.registerRule(_dereq_('./rules/empty_constructor_needs_parens.coffee')); + +coffeelint.registerRule(_dereq_('./rules/cyclomatic_complexity.coffee')); + +coffeelint.registerRule(_dereq_('./rules/newlines_after_classes.coffee')); + +coffeelint.registerRule(_dereq_('./rules/no_unnecessary_fat_arrows.coffee')); + +coffeelint.registerRule(_dereq_('./rules/missing_fat_arrows.coffee')); + +coffeelint.registerRule(_dereq_('./rules/non_empty_constructor_needs_parens.coffee')); + +coffeelint.registerRule(_dereq_('./rules/no_unnecessary_double_quotes.coffee')); + +coffeelint.registerRule(_dereq_('./rules/no_debugger.coffee')); + +coffeelint.registerRule(_dereq_('./rules/no_interpolation_in_single_quotes.coffee')); + +coffeelint.registerRule(_dereq_('./rules/no_empty_functions.coffee')); + +hasSyntaxError = function(source) { + try { + CoffeeScript.tokens(source); + return false; + } catch (_error) {} + return true; +}; + +coffeelint.lint = function(source, userConfig, literate) { + var all_errors, astErrors, block_config, cmd, config, disabled, disabled_initially, e, errors, i, l, lexErrors, lexicalLinter, lineErrors, lineLinter, name, next_line, r, ruleLoader, rules, s, tokensByLine, _i, _j, _k, _len, _len1, _ref, _ref1, _ref2, _ref3, _ref4; + if (userConfig == null) { + userConfig = {}; + } + if (literate == null) { + literate = false; + } + try { + ruleLoader = nodeRequire('./ruleLoader'); + ruleLoader.loadFromConfig(this, userConfig); + } catch (_error) {} + if (cache != null) { + cache.setConfig(userConfig); + } + if (cache != null ? cache.has(source) : void 0) { + return cache != null ? cache.get(source) : void 0; + } + if (literate) { + source = this.invertLiterate(source); + } + for (name in userConfig) { + if (name !== 'coffeescript_error' && name !== '_comment') { + if (_rules[name] == null) { + void 0; + } + } + } + config = mergeDefaultConfig(userConfig); + disabled_initially = []; + _ref = source.split('\n'); + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + l = _ref[_i]; + s = LineLinter.configStatement.exec(l); + if ((s != null ? s.length : void 0) > 2 && __indexOf.call(s, 'enable') >= 0) { + _ref1 = s.slice(1); + for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) { + r = _ref1[_j]; + if (r !== 'enable' && r !== 'disable') { + if (!(r in config && ((_ref2 = config[r].level) === 'warn' || _ref2 === 'error'))) { + disabled_initially.push(r); + config[r] = { + level: 'error' + }; + } + } + } + } + } + astErrors = new ASTLinter(source, config, _rules, CoffeeScript).lint(); + errors = [].concat(astErrors); + if (!hasSyntaxError(source)) { + lexicalLinter = new LexicalLinter(source, config, _rules, CoffeeScript); + lexErrors = lexicalLinter.lint(); + errors = errors.concat(lexErrors); + tokensByLine = lexicalLinter.tokensByLine; + lineLinter = new LineLinter(source, config, _rules, tokensByLine, literate); + lineErrors = lineLinter.lint(); + errors = errors.concat(lineErrors); + block_config = lineLinter.block_config; + } else { + block_config = { + enable: {}, + disable: {} + }; + } + errors.sort(function(a, b) { + return a.lineNumber - b.lineNumber; + }); + all_errors = errors; + errors = []; + disabled = disabled_initially; + next_line = 0; + for (i = _k = 0, _ref3 = source.split('\n').length; 0 <= _ref3 ? _k < _ref3 : _k > _ref3; i = 0 <= _ref3 ? ++_k : --_k) { + for (cmd in block_config) { + rules = block_config[cmd][i]; + if (rules != null) { + ({ + 'disable': function() { + return disabled = disabled.concat(rules); + }, + 'enable': function() { + difference(disabled, rules); + if (rules.length === 0) { + return disabled = disabled_initially; + } + } + })[cmd](); + } + } + while (next_line === i && all_errors.length > 0) { + next_line = all_errors[0].lineNumber - 1; + e = all_errors[0]; + if (e.lineNumber === i + 1 || (e.lineNumber == null)) { + e = all_errors.shift(); + if (_ref4 = e.rule, __indexOf.call(disabled, _ref4) < 0) { + errors.push(e); + } + } + } + } + if (cache != null) { + cache.set(source, errors); + } + return errors; +}; + +coffeelint.setCache = function(obj) { + return cache = obj; +}; + + +},{"./../package.json":1,"./ast_linter.coffee":2,"./lexical_linter.coffee":5,"./line_linter.coffee":6,"./rules.coffee":7,"./rules/arrow_spacing.coffee":8,"./rules/camel_case_classes.coffee":9,"./rules/colon_assignment_spacing.coffee":10,"./rules/cyclomatic_complexity.coffee":11,"./rules/duplicate_key.coffee":12,"./rules/empty_constructor_needs_parens.coffee":13,"./rules/indentation.coffee":14,"./rules/line_endings.coffee":15,"./rules/max_line_length.coffee":16,"./rules/missing_fat_arrows.coffee":17,"./rules/newlines_after_classes.coffee":18,"./rules/no_backticks.coffee":19,"./rules/no_debugger.coffee":20,"./rules/no_empty_functions.coffee":21,"./rules/no_empty_param_list.coffee":22,"./rules/no_implicit_braces.coffee":23,"./rules/no_implicit_parens.coffee":24,"./rules/no_interpolation_in_single_quotes.coffee":25,"./rules/no_plusplus.coffee":26,"./rules/no_stand_alone_at.coffee":27,"./rules/no_tabs.coffee":28,"./rules/no_throwing_strings.coffee":29,"./rules/no_trailing_semicolons.coffee":30,"./rules/no_trailing_whitespace.coffee":31,"./rules/no_unnecessary_double_quotes.coffee":32,"./rules/no_unnecessary_fat_arrows.coffee":33,"./rules/non_empty_constructor_needs_parens.coffee":34,"./rules/space_operators.coffee":35}],5:[function(_dereq_,module,exports){ +var BaseLinter, LexicalLinter, TokenApi, + __hasProp = {}.hasOwnProperty, + __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }, + __indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; }; + +TokenApi = (function() { + function TokenApi(CoffeeScript, source, config, tokensByLine) { + this.config = config; + this.tokensByLine = tokensByLine; + this.tokens = CoffeeScript.tokens(source); + this.lines = source.split('\n'); + this.tokensByLine = {}; + } + + TokenApi.prototype.i = 0; + + TokenApi.prototype.peek = function(n) { + if (n == null) { + n = 1; + } + return this.tokens[this.i + n] || null; + }; + + return TokenApi; + +})(); + +BaseLinter = _dereq_('./base_linter.coffee'); + +module.exports = LexicalLinter = (function(_super) { + __extends(LexicalLinter, _super); + + function LexicalLinter(source, config, rules, CoffeeScript) { + LexicalLinter.__super__.constructor.call(this, source, config, rules); + this.tokenApi = new TokenApi(CoffeeScript, source, this.config, this.tokensByLine); + this.tokensByLine = this.tokenApi.tokensByLine; + } + + LexicalLinter.prototype.acceptRule = function(rule) { + return typeof rule.lintToken === 'function'; + }; + + LexicalLinter.prototype.lint = function() { + var error, errors, i, token, _i, _j, _len, _len1, _ref, _ref1; + errors = []; + _ref = this.tokenApi.tokens; + for (i = _i = 0, _len = _ref.length; _i < _len; i = ++_i) { + token = _ref[i]; + this.tokenApi.i = i; + _ref1 = this.lintToken(token); + for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) { + error = _ref1[_j]; + errors.push(error); + } + } + return errors; + }; + + LexicalLinter.prototype.lintToken = function(token) { + var errors, lineNumber, rule, type, v, value, _base, _i, _len, _ref, _ref1; + type = token[0], value = token[1], lineNumber = token[2]; + if (typeof lineNumber === "object") { + if (type === 'OUTDENT' || type === 'INDENT') { + lineNumber = lineNumber.last_line; + } else { + lineNumber = lineNumber.first_line; + } + } + if ((_base = this.tokensByLine)[lineNumber] == null) { + _base[lineNumber] = []; + } + this.tokensByLine[lineNumber].push(token); + this.lineNumber = lineNumber || this.lineNumber || 0; + this.tokenApi.lineNumber = this.lineNumber; + errors = []; + _ref = this.rules; + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + rule = _ref[_i]; + if (!(_ref1 = token[0], __indexOf.call(rule.tokens, _ref1) >= 0)) { + continue; + } + v = this.normalizeResult(rule, rule.lintToken(token, this.tokenApi)); + if (v != null) { + errors.push(v); + } + } + return errors; + }; + + LexicalLinter.prototype.createError = function(ruleName, attrs) { + if (attrs == null) { + attrs = {}; + } + attrs.lineNumber = this.lineNumber + 1; + attrs.line = this.tokenApi.lines[this.lineNumber]; + return LexicalLinter.__super__.createError.call(this, ruleName, attrs); + }; + + return LexicalLinter; + +})(BaseLinter); + + +},{"./base_linter.coffee":3}],6:[function(_dereq_,module,exports){ +var BaseLinter, LineApi, LineLinter, configStatement, + __hasProp = {}.hasOwnProperty, + __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }; + +LineApi = (function() { + function LineApi(source, config, tokensByLine, literate) { + this.config = config; + this.tokensByLine = tokensByLine; + this.literate = literate; + this.line = null; + this.lines = source.split('\n'); + this.lineCount = this.lines.length; + this.context = { + "class": { + inClass: false, + lastUnemptyLineInClass: null, + classIndents: null + } + }; + } + + LineApi.prototype.lineNumber = 0; + + LineApi.prototype.isLiterate = function() { + return this.literate; + }; + + LineApi.prototype.maintainClassContext = function(line) { + if (this.context["class"].inClass) { + if (this.lineHasToken('INDENT')) { + this.context["class"].classIndents++; + } else if (this.lineHasToken('OUTDENT')) { + this.context["class"].classIndents--; + if (this.context["class"].classIndents === 0) { + this.context["class"].inClass = false; + this.context["class"].classIndents = null; + } + } + if (this.context["class"].inClass && !line.match(/^\s*$/)) { + this.context["class"].lastUnemptyLineInClass = this.lineNumber; + } + } else { + if (!line.match(/\\s*/)) { + this.context["class"].lastUnemptyLineInClass = null; + } + if (this.lineHasToken('CLASS')) { + this.context["class"].inClass = true; + this.context["class"].lastUnemptyLineInClass = this.lineNumber; + this.context["class"].classIndents = 0; + } + } + return null; + }; + + LineApi.prototype.isLastLine = function() { + return this.lineNumber === this.lineCount - 1; + }; + + LineApi.prototype.lineHasToken = function(tokenType, lineNumber) { + var token, tokens, _i, _len; + if (tokenType == null) { + tokenType = null; + } + if (lineNumber == null) { + lineNumber = null; + } + lineNumber = lineNumber != null ? lineNumber : this.lineNumber; + if (tokenType == null) { + return this.tokensByLine[lineNumber] != null; + } else { + tokens = this.tokensByLine[lineNumber]; + if (tokens == null) { + return null; + } + for (_i = 0, _len = tokens.length; _i < _len; _i++) { + token = tokens[_i]; + if (token[0] === tokenType) { + return true; + } + } + return false; + } + }; + + LineApi.prototype.getLineTokens = function() { + return this.tokensByLine[this.lineNumber] || []; + }; + + return LineApi; + +})(); + +BaseLinter = _dereq_('./base_linter.coffee'); + +configStatement = /coffeelint:\s*(disable|enable)(?:=([\w\s,]*))?/; + +module.exports = LineLinter = (function(_super) { + __extends(LineLinter, _super); + + LineLinter.configStatement = configStatement; + + function LineLinter(source, config, rules, tokensByLine, literate) { + if (literate == null) { + literate = false; + } + LineLinter.__super__.constructor.call(this, source, config, rules); + this.lineApi = new LineApi(source, config, tokensByLine, literate); + this.block_config = { + enable: {}, + disable: {} + }; + } + + LineLinter.prototype.acceptRule = function(rule) { + return typeof rule.lintLine === 'function'; + }; + + LineLinter.prototype.lint = function() { + var error, errors, line, lineNumber, _i, _j, _len, _len1, _ref, _ref1; + errors = []; + _ref = this.lineApi.lines; + for (lineNumber = _i = 0, _len = _ref.length; _i < _len; lineNumber = ++_i) { + line = _ref[lineNumber]; + this.lineApi.lineNumber = this.lineNumber = lineNumber; + this.lineApi.maintainClassContext(line); + this.collectInlineConfig(line); + _ref1 = this.lintLine(line); + for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) { + error = _ref1[_j]; + errors.push(error); + } + } + return errors; + }; + + LineLinter.prototype.lintLine = function(line) { + var errors, rule, v, _i, _len, _ref; + errors = []; + _ref = this.rules; + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + rule = _ref[_i]; + v = this.normalizeResult(rule, rule.lintLine(line, this.lineApi)); + if (v != null) { + errors.push(v); + } + } + return errors; + }; + + LineLinter.prototype.collectInlineConfig = function(line) { + var cmd, r, result, rules, _i, _len, _ref; + result = configStatement.exec(line); + if (result != null) { + cmd = result[1]; + rules = []; + if (result[2] != null) { + _ref = result[2].split(','); + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + r = _ref[_i]; + rules.push(r.replace(/^\s+|\s+$/g, "")); + } + } + this.block_config[cmd][this.lineNumber] = rules; + } + return null; + }; + + LineLinter.prototype.createError = function(rule, attrs) { + var _ref; + if (attrs == null) { + attrs = {}; + } + attrs.lineNumber = this.lineNumber + 1; + attrs.level = (_ref = this.config[rule]) != null ? _ref.level : void 0; + return LineLinter.__super__.createError.call(this, rule, attrs); + }; + + return LineLinter; + +})(BaseLinter); + + +},{"./base_linter.coffee":3}],7:[function(_dereq_,module,exports){ +var ERROR, IGNORE, WARN; + +ERROR = 'error'; + +WARN = 'warn'; + +IGNORE = 'ignore'; + +module.exports = { + coffeescript_error: { + level: ERROR, + message: '' + } +}; + + +},{}],8:[function(_dereq_,module,exports){ +var ArrowSpacing; + +module.exports = ArrowSpacing = (function() { + function ArrowSpacing() {} + + ArrowSpacing.prototype.rule = { + name: 'arrow_spacing', + level: 'ignore', + message: 'Function arrow (->) must be spaced properly', + description: "

    This rule checks to see that there is spacing before and after\nthe arrow operator that declares a function. This rule is disabled\nby default.

    Note that if arrow_spacing is enabled, and you\npass an empty function as a parameter, arrow_spacing will accept\neither a space or no space in-between the arrow operator and the\nparenthesis

    \n
    # Both of this will not trigger an error,\n# even with arrow_spacing enabled.\nx(-> 3)\nx( -> 3)\n\n# However, this will trigger an error\nx((a,b)-> 3)\n\n
    " + }; + + ArrowSpacing.prototype.tokens = ['->']; + + ArrowSpacing.prototype.lintToken = function(token, tokenApi) { + var pp; + pp = tokenApi.peek(-1); + if (!token.spaced && (pp[1] === "(" && (pp.generated == null)) && tokenApi.peek(1)[0] === 'INDENT' && tokenApi.peek(2)[0] === 'OUTDENT') { + return null; + } else if (!(((token.spaced != null) || (token.newLine != null) || this.atEof(tokenApi)) && (((pp.spaced != null) || pp[0] === 'TERMINATOR') || (pp.generated != null) || pp[0] === "INDENT" || (pp[1] === "(" && (pp.generated == null))))) { + return true; + } else { + return null; + } + }; + + ArrowSpacing.prototype.atEof = function(tokenApi) { + var i, token, tokens, _i, _len, _ref, _ref1; + tokens = tokenApi.tokens, i = tokenApi.i; + _ref = tokens.slice(i + 1); + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + token = _ref[_i]; + if (!(token.generated || ((_ref1 = token[0]) === 'OUTDENT' || _ref1 === 'TERMINATOR'))) { + return false; + } + } + return true; + }; + + return ArrowSpacing; + +})(); + + +},{}],9:[function(_dereq_,module,exports){ +var CamelCaseClasses, regexes; + +regexes = { + camelCase: /^[A-Z][a-zA-Z\d]*$/ +}; + +module.exports = CamelCaseClasses = (function() { + function CamelCaseClasses() {} + + CamelCaseClasses.prototype.rule = { + name: 'camel_case_classes', + level: 'error', + message: 'Class names should be camel cased', + description: "This rule mandates that all class names are CamelCased. Camel\ncasing class names is a generally accepted way of distinguishing\nconstructor functions - which require the 'new' prefix to behave\nproperly - from plain old functions.\n
    \n# Good!\nclass BoaConstrictor\n\n# Bad!\nclass boaConstrictor\n\n
    \nThis rule is enabled by default." + }; + + CamelCaseClasses.prototype.tokens = ['CLASS']; + + CamelCaseClasses.prototype.lintToken = function(token, tokenApi) { + var className, offset, _ref, _ref1, _ref2; + if ((token.newLine != null) || ((_ref = tokenApi.peek()[0]) === 'INDENT' || _ref === 'EXTENDS')) { + return null; + } + className = null; + offset = 1; + while (!className) { + if (((_ref1 = tokenApi.peek(offset + 1)) != null ? _ref1[0] : void 0) === '.') { + offset += 2; + } else if (((_ref2 = tokenApi.peek(offset)) != null ? _ref2[0] : void 0) === '@') { + offset += 1; + } else { + className = tokenApi.peek(offset)[1]; + } + } + if (!regexes.camelCase.test(className)) { + return { + context: "class name: " + className + }; + } + }; + + return CamelCaseClasses; + +})(); + + +},{}],10:[function(_dereq_,module,exports){ +var ColonAssignmentSpacing; + +module.exports = ColonAssignmentSpacing = (function() { + function ColonAssignmentSpacing() {} + + ColonAssignmentSpacing.prototype.rule = { + name: 'colon_assignment_spacing', + level: 'ignore', + message: 'Colon assignment without proper spacing', + spacing: { + left: 0, + right: 0 + }, + description: "

    This rule checks to see that there is spacing before and\nafter the colon in a colon assignment (i.e., classes, objects).\nThe spacing amount is specified by\nspacing.left and spacing.right, respectively.\nA zero value means no spacing required.\n

    \n
    \n#\n# If spacing.left and spacing.right is 1\n#\n\n# Good\nobject = {spacing : true}\nclass Dog\n  canBark : true\n\n# Bad\nobject = {spacing: true}\nclass Cat\n  canBark: false\n
    " + }; + + ColonAssignmentSpacing.prototype.tokens = [':']; + + ColonAssignmentSpacing.prototype.lintToken = function(token, tokenApi) { + var checkSpacing, getSpaceFromToken, isLeftSpaced, isRightSpaced, leftSpacing, nextToken, previousToken, rightSpacing, spacingAllowances, _ref, _ref1; + spacingAllowances = tokenApi.config[this.rule.name].spacing; + previousToken = tokenApi.peek(-1); + nextToken = tokenApi.peek(1); + getSpaceFromToken = function(direction) { + switch (direction) { + case 'left': + return token[2].first_column - previousToken[2].last_column - 1; + case 'right': + return nextToken[2].first_column - token[2].first_column - 1; + } + }; + checkSpacing = function(direction) { + var isSpaced, spacing; + spacing = getSpaceFromToken(direction); + isSpaced = spacing < 0 ? true : spacing === parseInt(spacingAllowances[direction]); + return [isSpaced, spacing]; + }; + _ref = checkSpacing('left'), isLeftSpaced = _ref[0], leftSpacing = _ref[1]; + _ref1 = checkSpacing('right'), isRightSpaced = _ref1[0], rightSpacing = _ref1[1]; + if (isLeftSpaced && isRightSpaced) { + return null; + } else { + return { + context: "Incorrect spacing around column " + token[2].first_column + ".\nExpected left: " + spacingAllowances.left + ", right: " + spacingAllowances.right + ".\nGot left: " + leftSpacing + ", right: " + rightSpacing + "." + }; + } + }; + + return ColonAssignmentSpacing; + +})(); + + +},{}],11:[function(_dereq_,module,exports){ +var NoTabs; + +module.exports = NoTabs = (function() { + function NoTabs() {} + + NoTabs.prototype.rule = { + name: 'cyclomatic_complexity', + value: 10, + level: 'ignore', + message: 'The cyclomatic complexity is too damn high', + description: 'Examine the complexity of your application.' + }; + + NoTabs.prototype.getComplexity = function(node) { + var complexity, name, _ref; + name = this.astApi.getNodeName(node); + complexity = name === 'If' || name === 'While' || name === 'For' || name === 'Try' ? 1 : name === 'Op' && ((_ref = node.operator) === '&&' || _ref === '||') ? 1 : name === 'Switch' ? node.cases.length : 0; + return complexity; + }; + + NoTabs.prototype.lintAST = function(node, astApi) { + this.astApi = astApi; + this.lintNode(node); + return void 0; + }; + + NoTabs.prototype.lintNode = function(node, line) { + var complexity, error, name, rule, _ref; + name = (_ref = this.astApi) != null ? _ref.getNodeName(node) : void 0; + complexity = this.getComplexity(node); + node.eachChild((function(_this) { + return function(childNode) { + var nodeLine; + nodeLine = childNode.locationData.first_line; + if (childNode) { + return complexity += _this.lintNode(childNode, nodeLine); + } + }; + })(this)); + rule = this.astApi.config[this.rule.name]; + if (name === 'Code' && complexity >= rule.value) { + error = this.astApi.createError({ + context: complexity + 1, + lineNumber: line + 1, + lineNumberEnd: node.locationData.last_line + 1 + }); + if (error) { + this.errors.push(error); + } + } + return complexity; + }; + + return NoTabs; + +})(); + + +},{}],12:[function(_dereq_,module,exports){ +var DuplicateKey; + +module.exports = DuplicateKey = (function() { + DuplicateKey.prototype.rule = { + name: 'duplicate_key', + level: 'error', + message: 'Duplicate key defined in object or class', + description: "Prevents defining duplicate keys in object literals and classes" + }; + + DuplicateKey.prototype.tokens = ['IDENTIFIER', "{", "}"]; + + function DuplicateKey() { + this.braceScopes = []; + } + + DuplicateKey.prototype.lintToken = function(_arg, tokenApi) { + var type; + type = _arg[0]; + if (type === "{" || type === "}") { + this.lintBrace.apply(this, arguments); + return void 0; + } + if (type === "IDENTIFIER") { + return this.lintIdentifier.apply(this, arguments); + } + }; + + DuplicateKey.prototype.lintIdentifier = function(token, tokenApi) { + var key, nextToken, previousToken; + key = token[1]; + if (this.currentScope == null) { + return null; + } + nextToken = tokenApi.peek(1); + if (nextToken[1] !== ':') { + return null; + } + previousToken = tokenApi.peek(-1); + if (previousToken[0] === '@') { + key = "@" + key; + } + key = "identifier-" + key; + if (this.currentScope[key]) { + return true; + } else { + this.currentScope[key] = token; + return null; + } + }; + + DuplicateKey.prototype.lintBrace = function(token) { + if (token[0] === '{') { + if (this.currentScope != null) { + this.braceScopes.push(this.currentScope); + } + this.currentScope = {}; + } else { + this.currentScope = this.braceScopes.pop(); + } + return null; + }; + + return DuplicateKey; + +})(); + + +},{}],13:[function(_dereq_,module,exports){ +var EmptyConstructorNeedsParens; + +module.exports = EmptyConstructorNeedsParens = (function() { + function EmptyConstructorNeedsParens() {} + + EmptyConstructorNeedsParens.prototype.rule = { + name: 'empty_constructor_needs_parens', + level: 'ignore', + message: 'Invoking a constructor without parens and without arguments', + description: "Requires constructors with no parameters to include the parens" + }; + + EmptyConstructorNeedsParens.prototype.tokens = ['UNARY']; + + EmptyConstructorNeedsParens.prototype.lintToken = function(token, tokenApi) { + var expectedCallStart, expectedIdentifier, identifierIndex; + if (token[1] === 'new') { + identifierIndex = 1; + while (true) { + expectedIdentifier = tokenApi.peek(identifierIndex); + expectedCallStart = tokenApi.peek(identifierIndex + 1); + if ((expectedIdentifier != null ? expectedIdentifier[0] : void 0) === 'IDENTIFIER') { + if ((expectedCallStart != null ? expectedCallStart[0] : void 0) === '.') { + identifierIndex += 2; + continue; + } + } + break; + } + if ((expectedIdentifier != null ? expectedIdentifier[0] : void 0) === 'IDENTIFIER' && (expectedCallStart != null)) { + return this.handleExpectedCallStart(expectedCallStart); + } + } + }; + + EmptyConstructorNeedsParens.prototype.handleExpectedCallStart = function(expectedCallStart) { + if (expectedCallStart[0] !== 'CALL_START') { + return true; + } + }; + + return EmptyConstructorNeedsParens; + +})(); + + +},{}],14:[function(_dereq_,module,exports){ +var Indentation; + +module.exports = Indentation = (function() { + Indentation.prototype.rule = { + name: 'indentation', + value: 2, + level: 'error', + message: 'Line contains inconsistent indentation', + description: "This rule imposes a standard number of spaces to be used for\nindentation. Since whitespace is significant in CoffeeScript, it's\ncritical that a project chooses a standard indentation format and\nstays consistent. Other roads lead to darkness.
     #\nEnabling this option will prevent this ugly\n# but otherwise valid CoffeeScript.\ntwoSpaces = () ->\n  fourSpaces = () ->\n      eightSpaces = () ->\n            'this is valid CoffeeScript'\n\n\n
    \nTwo space indentation is enabled by default." + }; + + Indentation.prototype.tokens = ['INDENT', "[", "]"]; + + function Indentation() { + this.arrayTokens = []; + } + + Indentation.prototype.lintToken = function(token, tokenApi) { + var currentLine, expected, ignoreIndent, isArrayIndent, isInterpIndent, isMultiline, lineNumber, lines, numIndents, prevNum, previous, previousIndentation, previousLine, previousSymbol, type, _ref; + type = token[0], numIndents = token[1], lineNumber = token[2]; + if (type === "[" || type === "]") { + this.lintArray(token); + return void 0; + } + if (token.generated != null) { + return null; + } + previous = tokenApi.peek(-2); + isInterpIndent = previous && previous[0] === '+'; + previous = tokenApi.peek(-1); + isArrayIndent = this.inArray() && (previous != null ? previous.newLine : void 0); + previousSymbol = (_ref = tokenApi.peek(-1)) != null ? _ref[0] : void 0; + isMultiline = previousSymbol === '=' || previousSymbol === ','; + ignoreIndent = isInterpIndent || isArrayIndent || isMultiline; + if (this.isChainedCall(tokenApi)) { + lines = tokenApi.lines, lineNumber = tokenApi.lineNumber; + currentLine = lines[lineNumber]; + prevNum = 1; + while (/^\s*(#|$)/.test(lines[lineNumber - prevNum])) { + prevNum += 1; + } + previousLine = lines[lineNumber - prevNum]; + previousIndentation = previousLine.match(/^(\s*)/)[1].length; + numIndents = currentLine.match(/^(\s*)/)[1].length; + numIndents -= previousIndentation; + } + expected = tokenApi.config[this.rule.name].value; + if (!ignoreIndent && numIndents !== expected) { + return { + context: "Expected " + expected + " got " + numIndents + }; + } + }; + + Indentation.prototype.inArray = function() { + return this.arrayTokens.length > 0; + }; + + Indentation.prototype.lintArray = function(token) { + if (token[0] === '[') { + this.arrayTokens.push(token); + } else if (token[0] === ']') { + this.arrayTokens.pop(); + } + return null; + }; + + Indentation.prototype.isChainedCall = function(tokenApi) { + var i, lastNewLineIndex, lines, t, token, tokens; + tokens = tokenApi.tokens, i = tokenApi.i; + lines = (function() { + var _i, _len, _ref, _results; + _ref = tokens.slice(0, +i + 1 || 9e9); + _results = []; + for (i = _i = 0, _len = _ref.length; _i < _len; i = ++_i) { + token = _ref[i]; + if (token.newLine != null) { + _results.push(i); + } + } + return _results; + })(); + lastNewLineIndex = lines ? lines[lines.length - 2] : null; + if (lastNewLineIndex == null) { + return false; + } + tokens = [tokens[lastNewLineIndex], tokens[lastNewLineIndex + 1]]; + return !!((function() { + var _i, _len, _results; + _results = []; + for (_i = 0, _len = tokens.length; _i < _len; _i++) { + t = tokens[_i]; + if (t && t[0] === '.') { + _results.push(t); + } + } + return _results; + })()).length; + }; + + return Indentation; + +})(); + + +},{}],15:[function(_dereq_,module,exports){ +var LineEndings; + +module.exports = LineEndings = (function() { + function LineEndings() {} + + LineEndings.prototype.rule = { + name: 'line_endings', + level: 'ignore', + value: 'unix', + message: 'Line contains incorrect line endings', + description: "This rule ensures your project uses only windows or\nunix line endings. This rule is disabled by default." + }; + + LineEndings.prototype.lintLine = function(line, lineApi) { + var ending, lastChar, valid, _ref; + ending = (_ref = lineApi.config[this.rule.name]) != null ? _ref.value : void 0; + if (!ending || lineApi.isLastLine() || !line) { + return null; + } + lastChar = line[line.length - 1]; + valid = (function() { + if (ending === 'windows') { + return lastChar === '\r'; + } else if (ending === 'unix') { + return lastChar !== '\r'; + } else { + throw new Error("unknown line ending type: " + ending); + } + })(); + if (!valid) { + return { + context: "Expected " + ending + }; + } else { + return null; + } + }; + + return LineEndings; + +})(); + + +},{}],16:[function(_dereq_,module,exports){ +var MaxLineLength, regexes; + +regexes = { + literateComment: /^\#\s/, + longUrlComment: /^\s*\#\s*http[^\s]+$/ +}; + +module.exports = MaxLineLength = (function() { + function MaxLineLength() {} + + MaxLineLength.prototype.rule = { + name: 'max_line_length', + value: 80, + level: 'error', + limitComments: true, + message: 'Line exceeds maximum allowed length', + description: "This rule imposes a maximum line length on your code. Python's style\nguide does a good job explaining why you might want to limit the\nlength of your lines, though this is a matter of taste.\n\nLines can be no longer than eighty characters by default." + }; + + MaxLineLength.prototype.lintLine = function(line, lineApi) { + var limitComments, lineLength, max, _ref, _ref1; + max = (_ref = lineApi.config[this.rule.name]) != null ? _ref.value : void 0; + limitComments = (_ref1 = lineApi.config[this.rule.name]) != null ? _ref1.limitComments : void 0; + lineLength = line.trimRight().length; + if (lineApi.isLiterate() && regexes.literateComment.test(line)) { + lineLength -= 2; + } + if (max && max < lineLength && !regexes.longUrlComment.test(line)) { + if (!limitComments) { + if (lineApi.getLineTokens().length === 0) { + return; + } + } + return { + context: "Length is " + lineLength + ", max is " + max + }; + } + }; + + return MaxLineLength; + +})(); + + +},{}],17:[function(_dereq_,module,exports){ +var MissingFatArrows, any, + __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }, + __indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; }; + +any = function(arr, test) { + return arr.reduce((function(res, elt) { + return res || test(elt); + }), false); +}; + +module.exports = MissingFatArrows = (function() { + function MissingFatArrows() { + this.isFatArrowCode = __bind(this.isFatArrowCode, this); + this.isThis = __bind(this.isThis, this); + this.isObject = __bind(this.isObject, this); + this.isValue = __bind(this.isValue, this); + this.isClass = __bind(this.isClass, this); + this.isCode = __bind(this.isCode, this); + } + + MissingFatArrows.prototype.rule = { + name: 'missing_fat_arrows', + level: 'ignore', + message: 'Used `this` in a function without a fat arrow', + description: "Warns when you use `this` inside a function that wasn't defined\nwith a fat arrow. This rule does not apply to methods defined in a\nclass, since they have `this` bound to the class instance (or the\nclass itself, for class methods).\n\nIt is impossible to statically determine whether a function using\n`this` will be bound with the correct `this` value due to language\nfeatures like `Function.prototype.call` and\n`Function.prototype.bind`, so this rule may produce false positives." + }; + + MissingFatArrows.prototype.lintAST = function(node, astApi) { + this.astApi = astApi; + this.lintNode(node); + return void 0; + }; + + MissingFatArrows.prototype.lintNode = function(node, methods) { + var error; + if (methods == null) { + methods = []; + } + if ((!this.isFatArrowCode(node)) && (__indexOf.call(methods, node) < 0) && (this.needsFatArrow(node))) { + error = this.astApi.createError({ + lineNumber: node.locationData.first_line + 1 + }); + this.errors.push(error); + } + return node.eachChild((function(_this) { + return function(child) { + return _this.lintNode(child, (function() { + switch (false) { + case !this.isClass(node): + return this.methodsOfClass(node); + case !this.isCode(node): + return []; + default: + return methods; + } + }).call(_this)); + }; + })(this)); + }; + + MissingFatArrows.prototype.isCode = function(node) { + return this.astApi.getNodeName(node) === 'Code'; + }; + + MissingFatArrows.prototype.isClass = function(node) { + return this.astApi.getNodeName(node) === 'Class'; + }; + + MissingFatArrows.prototype.isValue = function(node) { + return this.astApi.getNodeName(node) === 'Value'; + }; + + MissingFatArrows.prototype.isObject = function(node) { + return this.astApi.getNodeName(node) === 'Obj'; + }; + + MissingFatArrows.prototype.isThis = function(node) { + return this.isValue(node) && node.base.value === 'this'; + }; + + MissingFatArrows.prototype.isFatArrowCode = function(node) { + return this.isCode(node) && node.bound; + }; + + MissingFatArrows.prototype.needsFatArrow = function(node) { + return this.isCode(node) && (any(node.params, (function(_this) { + return function(param) { + return param.contains(_this.isThis) != null; + }; + })(this)) || (node.body.contains(this.isThis) != null)); + }; + + MissingFatArrows.prototype.methodsOfClass = function(classNode) { + var bodyNodes, returnNode; + bodyNodes = classNode.body.expressions; + returnNode = bodyNodes[bodyNodes.length - 1]; + if ((returnNode != null) && this.isValue(returnNode) && this.isObject(returnNode.base)) { + return returnNode.base.properties.map(function(assignNode) { + return assignNode.value; + }).filter(this.isCode); + } else { + return []; + } + }; + + return MissingFatArrows; + +})(); + + +},{}],18:[function(_dereq_,module,exports){ +var NewlinesAfterClasses; + +module.exports = NewlinesAfterClasses = (function() { + function NewlinesAfterClasses() {} + + NewlinesAfterClasses.prototype.rule = { + name: 'newlines_after_classes', + value: 3, + level: 'ignore', + message: 'Wrong count of newlines between a class and other code', + description: "Checks the number of newlines between classes and other code" + }; + + NewlinesAfterClasses.prototype.lintLine = function(line, lineApi) { + var context, ending, got, lineNumber; + ending = lineApi.config[this.rule.name].value; + if (!ending || lineApi.isLastLine()) { + return null; + } + lineNumber = lineApi.lineNumber, context = lineApi.context; + if (!context["class"].inClass && (context["class"].lastUnemptyLineInClass != null) && (lineNumber - context["class"].lastUnemptyLineInClass) !== ending) { + got = lineNumber - context["class"].lastUnemptyLineInClass; + return { + context: "Expected " + ending + " got " + got + }; + } + return null; + }; + + return NewlinesAfterClasses; + +})(); + + +},{}],19:[function(_dereq_,module,exports){ +var NoBackticks; + +module.exports = NoBackticks = (function() { + function NoBackticks() {} + + NoBackticks.prototype.rule = { + name: 'no_backticks', + level: 'error', + message: 'Backticks are forbidden', + description: "Backticks allow snippets of JavaScript to be embedded in\nCoffeeScript. While some folks consider backticks useful in a few\nniche circumstances, they should be avoided because so none of\nJavaScript's \"bad parts\", like with and eval,\nsneak into CoffeeScript.\nThis rule is enabled by default." + }; + + NoBackticks.prototype.tokens = ["JS"]; + + NoBackticks.prototype.lintToken = function(token, tokenApi) { + return true; + }; + + return NoBackticks; + +})(); + + +},{}],20:[function(_dereq_,module,exports){ +var NoDebugger; + +module.exports = NoDebugger = (function() { + function NoDebugger() {} + + NoDebugger.prototype.rule = { + name: 'no_debugger', + level: 'warn', + message: 'Debugger statements will cause warnings', + description: "This rule detects the `debugger` statement.\nThis rule is `warn` by default." + }; + + NoDebugger.prototype.tokens = ["DEBUGGER"]; + + NoDebugger.prototype.lintToken = function(token, tokenApi) { + return { + context: "found '" + token[0] + "'" + }; + }; + + return NoDebugger; + +})(); + + +},{}],21:[function(_dereq_,module,exports){ +var NoEmptyFunctions, isEmptyCode; + +isEmptyCode = function(node, astApi) { + var nodeName; + nodeName = astApi.getNodeName(node); + return nodeName === 'Code' && node.body.isEmpty(); +}; + +module.exports = NoEmptyFunctions = (function() { + function NoEmptyFunctions() {} + + NoEmptyFunctions.prototype.rule = { + name: 'no_empty_functions', + level: 'ignore', + message: 'Empty function', + description: "Disallows declaring empty functions. The goal of this rule is that\nunintentional empty callbacks can be detected:\n
    \nsomeFunctionWithCallback ->\ndoSomethingSignificant()\n\n
    \nThe problem is that the call to\ndoSomethingSignificant will be made regardless\nof someFunctionWithCallback's execution. It can\nbe because you did not indent the call to\ndoSomethingSignificant properly.\n\nIf you really meant that someFunctionWithCallback\nshould call a callback that does nothing, you can write your code\nthis way:\n
    \nsomeFunctionWithCallback ->\n    undefined\ndoSomethingSignificant()\n\n
    " + }; + + NoEmptyFunctions.prototype.lintAST = function(node, astApi) { + this.lintNode(node, astApi); + return void 0; + }; + + NoEmptyFunctions.prototype.lintNode = function(node, astApi) { + var error; + if (isEmptyCode(node, astApi)) { + error = astApi.createError({ + lineNumber: node.locationData.first_line + 1 + }); + this.errors.push(error); + } + return node.eachChild((function(_this) { + return function(child) { + return _this.lintNode(child, astApi); + }; + })(this)); + }; + + return NoEmptyFunctions; + +})(); + + +},{}],22:[function(_dereq_,module,exports){ +var NoEmptyParamList; + +module.exports = NoEmptyParamList = (function() { + function NoEmptyParamList() {} + + NoEmptyParamList.prototype.rule = { + name: 'no_empty_param_list', + level: 'ignore', + message: 'Empty parameter list is forbidden', + description: "This rule prohibits empty parameter lists in function definitions.\n
    \n# The empty parameter list in here is unnecessary:\nmyFunction = () ->\n\n# We might favor this instead:\nmyFunction = ->\n\n
    \nEmpty parameter lists are permitted by default." + }; + + NoEmptyParamList.prototype.tokens = ["PARAM_START"]; + + NoEmptyParamList.prototype.lintToken = function(token, tokenApi) { + var nextType; + nextType = tokenApi.peek()[0]; + return nextType === 'PARAM_END'; + }; + + return NoEmptyParamList; + +})(); + + +},{}],23:[function(_dereq_,module,exports){ +var NoImplicitBraces; + +module.exports = NoImplicitBraces = (function() { + function NoImplicitBraces() {} + + NoImplicitBraces.prototype.rule = { + name: 'no_implicit_braces', + level: 'ignore', + message: 'Implicit braces are forbidden', + strict: true, + description: "This rule prohibits implicit braces when declaring object literals.\nImplicit braces can make code more difficult to understand,\nespecially when used in combination with optional parenthesis.\n
    \n# Do you find this code ambiguous? Is it a\n# function call with three arguments or four?\nmyFunction a, b, 1:2, 3:4\n\n# While the same code written in a more\n# explicit manner has no ambiguity.\nmyFunction(a, b, {1:2, 3:4})\n\n
    \nImplicit braces are permitted by default, since their use is\nidiomatic CoffeeScript." + }; + + NoImplicitBraces.prototype.tokens = ["{"]; + + NoImplicitBraces.prototype.lintToken = function(token, tokenApi) { + var previousToken; + if (token.generated) { + if (!tokenApi.config[this.rule.name].strict) { + previousToken = tokenApi.peek(-1)[0]; + if (previousToken === 'INDENT') { + return; + } + } + return this.isPartOfClass(tokenApi); + } + }; + + NoImplicitBraces.prototype.isPartOfClass = function(tokenApi) { + var i, t; + i = -1; + while (true) { + t = tokenApi.peek(i); + if ((t == null) || t[0] === 'TERMINATOR') { + return true; + } + if (t[0] === 'CLASS') { + return null; + } + i -= 1; + } + }; + + return NoImplicitBraces; + +})(); + + +},{}],24:[function(_dereq_,module,exports){ +var NoImplicitParens; + +module.exports = NoImplicitParens = (function() { + function NoImplicitParens() {} + + NoImplicitParens.prototype.rule = { + name: 'no_implicit_parens', + strict: true, + level: 'ignore', + message: 'Implicit parens are forbidden', + description: "This rule prohibits implicit parens on function calls.\n
    \n# Some folks don't like this style of coding.\nmyFunction a, b, c\n\n# And would rather it always be written like this:\nmyFunction(a, b, c)\n\n
    \nImplicit parens are permitted by default, since their use is\nidiomatic CoffeeScript." + }; + + NoImplicitParens.prototype.tokens = ["CALL_END"]; + + NoImplicitParens.prototype.lintToken = function(token, tokenApi) { + var i, t; + if (token.generated) { + if (tokenApi.config[this.rule.name].strict !== false) { + return true; + } else { + i = -1; + while (true) { + t = tokenApi.peek(i); + if ((t == null) || t[0] === 'CALL_START') { + return true; + } + if (t.newLine) { + return null; + } + i -= 1; + } + } + } + }; + + return NoImplicitParens; + +})(); + + +},{}],25:[function(_dereq_,module,exports){ +var NoInterpolationInSingleQuotes; + +module.exports = NoInterpolationInSingleQuotes = (function() { + function NoInterpolationInSingleQuotes() {} + + NoInterpolationInSingleQuotes.prototype.rule = { + name: 'no_interpolation_in_single_quotes', + level: 'ignore', + message: 'Interpolation in single quoted strings is forbidden', + description: 'This rule prohibits string interpolation in a single quoted string.\n
    \n# String interpolation in single quotes is not allowed:\nfoo = \'#{bar}\'\n\n# Double quotes is OK of course\nfoo = "#{bar}"\n\n
    \nString interpolation in single quoted strings is permitted by \ndefault.' + }; + + NoInterpolationInSingleQuotes.prototype.tokens = ['STRING']; + + NoInterpolationInSingleQuotes.prototype.lintToken = function(token, tokenApi) { + var hasInterpolation, tokenValue; + tokenValue = token[1]; + hasInterpolation = tokenValue.match(/#\{[^}]+\}/); + return hasInterpolation; + }; + + return NoInterpolationInSingleQuotes; + +})(); + + +},{}],26:[function(_dereq_,module,exports){ +var NoPlusPlus; + +module.exports = NoPlusPlus = (function() { + function NoPlusPlus() {} + + NoPlusPlus.prototype.rule = { + name: 'no_plusplus', + level: 'ignore', + message: 'The increment and decrement operators are forbidden', + description: "This rule forbids the increment and decrement arithmetic operators.\nSome people believe the ++ and -- to be cryptic\nand the cause of bugs due to misunderstandings of their precedence\nrules.\nThis rule is disabled by default." + }; + + NoPlusPlus.prototype.tokens = ["++", "--"]; + + NoPlusPlus.prototype.lintToken = function(token, tokenApi) { + return { + context: "found '" + token[0] + "'" + }; + }; + + return NoPlusPlus; + +})(); + + +},{}],27:[function(_dereq_,module,exports){ +var NoStandAloneAt; + +module.exports = NoStandAloneAt = (function() { + function NoStandAloneAt() {} + + NoStandAloneAt.prototype.rule = { + name: 'no_stand_alone_at', + level: 'ignore', + message: '@ must not be used stand alone', + description: "This rule checks that no stand alone @ are in use, they are\ndiscouraged. Further information in CoffeScript issue \n#1601" + }; + + NoStandAloneAt.prototype.tokens = ["@"]; + + NoStandAloneAt.prototype.lintToken = function(token, tokenApi) { + var isDot, isIdentifier, isIndexStart, isValidProtoProperty, nextToken, protoProperty, spaced; + nextToken = tokenApi.peek(); + spaced = token.spaced; + isIdentifier = nextToken[0] === 'IDENTIFIER'; + isIndexStart = nextToken[0] === 'INDEX_START'; + isDot = nextToken[0] === '.'; + if (nextToken[0] === '::') { + protoProperty = tokenApi.peek(2); + isValidProtoProperty = protoProperty[0] === 'IDENTIFIER'; + } + if (spaced || (!isIdentifier && !isIndexStart && !isDot && !isValidProtoProperty)) { + return true; + } + }; + + return NoStandAloneAt; + +})(); + + +},{}],28:[function(_dereq_,module,exports){ +var NoTabs, indentationRegex, + __indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; }; + +indentationRegex = /\S/; + +module.exports = NoTabs = (function() { + function NoTabs() {} + + NoTabs.prototype.rule = { + name: 'no_tabs', + level: 'error', + message: 'Line contains tab indentation', + description: "This rule forbids tabs in indentation. Enough said. It is enabled by\ndefault." + }; + + NoTabs.prototype.lintLine = function(line, lineApi) { + var indentation; + indentation = line.split(indentationRegex)[0]; + if (lineApi.lineHasToken() && __indexOf.call(indentation, '\t') >= 0) { + return true; + } else { + return null; + } + }; + + return NoTabs; + +})(); + + +},{}],29:[function(_dereq_,module,exports){ +var NoThrowingStrings; + +module.exports = NoThrowingStrings = (function() { + function NoThrowingStrings() {} + + NoThrowingStrings.prototype.rule = { + name: 'no_throwing_strings', + level: 'error', + message: 'Throwing strings is forbidden', + description: "This rule forbids throwing string literals or interpolations. While\nJavaScript (and CoffeeScript by extension) allow any expression to\nbe thrown, it is best to only throw Error objects,\nbecause they contain valuable debugging information like the stack\ntrace. Because of JavaScript's dynamic nature, CoffeeLint cannot\nensure you are always throwing instances of Error. It will\nonly catch the simple but real case of throwing literal strings.\n
    \n# CoffeeLint will catch this:\nthrow \"i made a boo boo\"\n\n# ... but not this:\nthrow getSomeString()\n\n
    \nThis rule is enabled by default." + }; + + NoThrowingStrings.prototype.tokens = ["THROW"]; + + NoThrowingStrings.prototype.lintToken = function(token, tokenApi) { + var n1, n2, nextIsString, _ref; + _ref = [tokenApi.peek(), tokenApi.peek(2)], n1 = _ref[0], n2 = _ref[1]; + nextIsString = n1[0] === 'STRING' || (n1[0] === '(' && n2[0] === 'STRING'); + return nextIsString; + }; + + return NoThrowingStrings; + +})(); + + +},{}],30:[function(_dereq_,module,exports){ +var NoTrailingSemicolons, regexes, + __slice = [].slice; + +regexes = { + trailingSemicolon: /;\r?$/ +}; + +module.exports = NoTrailingSemicolons = (function() { + function NoTrailingSemicolons() {} + + NoTrailingSemicolons.prototype.rule = { + name: 'no_trailing_semicolons', + level: 'error', + message: 'Line contains a trailing semicolon', + description: "This rule prohibits trailing semicolons, since they are needless\ncruft in CoffeeScript.\n
    \n# This semicolon is meaningful.\nx = '1234'; console.log(x)\n\n# This semicolon is redundant.\nalert('end of line');\n\n
    \nTrailing semicolons are forbidden by default." + }; + + NoTrailingSemicolons.prototype.lintLine = function(line, lineApi) { + var endPos, first, hasNewLine, hasSemicolon, last, lineTokens, newLine, startCounter, startPos, _i, _ref, _ref1; + lineTokens = lineApi.getLineTokens(); + if (lineTokens.length === 1 && ((_ref = lineTokens[0][0]) === 'TERMINATOR' || _ref === 'HERECOMMENT')) { + return; + } + newLine = line; + if (lineTokens.length > 1 && lineTokens[lineTokens.length - 1][0] === 'TERMINATOR') { + startPos = lineTokens[lineTokens.length - 2][2].last_column + 1; + endPos = lineTokens[lineTokens.length - 1][2].first_column; + if (startPos !== endPos) { + startCounter = startPos; + while (line[startCounter] !== "#" && startCounter < line.length) { + startCounter++; + } + newLine = line.substring(0, startCounter).replace(/\s*$/, ''); + } + } + hasSemicolon = regexes.trailingSemicolon.test(newLine); + first = 2 <= lineTokens.length ? __slice.call(lineTokens, 0, _i = lineTokens.length - 1) : (_i = 0, []), last = lineTokens[_i++]; + hasNewLine = last && (last.newLine != null); + if (hasSemicolon && !hasNewLine && lineApi.lineHasToken() && !((_ref1 = last[0]) === 'STRING' || _ref1 === 'IDENTIFIER')) { + return true; + } + }; + + return NoTrailingSemicolons; + +})(); + + +},{}],31:[function(_dereq_,module,exports){ +var NoTrailingWhitespace, regexes; + +regexes = { + trailingWhitespace: /[^\s]+[\t ]+\r?$/, + onlySpaces: /^[\t ]+\r?$/, + lineHasComment: /^\s*[^\#]*\#/ +}; + +module.exports = NoTrailingWhitespace = (function() { + function NoTrailingWhitespace() {} + + NoTrailingWhitespace.prototype.rule = { + name: 'no_trailing_whitespace', + level: 'error', + message: 'Line ends with trailing whitespace', + allowed_in_comments: false, + allowed_in_empty_lines: true, + description: "This rule forbids trailing whitespace in your code, since it is\nneedless cruft. It is enabled by default." + }; + + NoTrailingWhitespace.prototype.lintLine = function(line, lineApi) { + var str, token, tokens, _i, _len, _ref, _ref1, _ref2; + if (!((_ref = lineApi.config['no_trailing_whitespace']) != null ? _ref.allowed_in_empty_lines : void 0)) { + if (regexes.onlySpaces.test(line)) { + return true; + } + } + if (regexes.trailingWhitespace.test(line)) { + if (!((_ref1 = lineApi.config['no_trailing_whitespace']) != null ? _ref1.allowed_in_comments : void 0)) { + return true; + } + line = line; + tokens = lineApi.tokensByLine[lineApi.lineNumber]; + if (!tokens) { + return null; + } + _ref2 = (function() { + var _j, _len, _results; + _results = []; + for (_j = 0, _len = tokens.length; _j < _len; _j++) { + token = tokens[_j]; + if (token[0] === 'STRING') { + _results.push(token[1]); + } + } + return _results; + })(); + for (_i = 0, _len = _ref2.length; _i < _len; _i++) { + str = _ref2[_i]; + line = line.replace(str, 'STRING'); + } + if (!regexes.lineHasComment.test(line)) { + return true; + } + } + }; + + return NoTrailingWhitespace; + +})(); + + +},{}],32:[function(_dereq_,module,exports){ +var NoUnnecessaryDoubleQuotes; + +module.exports = NoUnnecessaryDoubleQuotes = (function() { + function NoUnnecessaryDoubleQuotes() {} + + NoUnnecessaryDoubleQuotes.prototype.rule = { + name: 'no_unnecessary_double_quotes', + level: 'ignore', + message: 'Unnecessary double quotes are forbidden', + description: 'This rule prohibits double quotes unless string interpolation is \nused or the string contains single quotes.\n
    \n# Double quotes are discouraged:\nfoo = "bar"\n\n# Unless string interpolation is used:\nfoo = "#{bar}baz"\n\n# Or they prevent cumbersome escaping:\nfoo = "I\'m just following the \'rules\'"\n\n
    \nDouble quotes are permitted by default.' + }; + + NoUnnecessaryDoubleQuotes.prototype.tokens = ['STRING']; + + NoUnnecessaryDoubleQuotes.prototype.lintToken = function(token, tokenApi) { + var hasLegalConstructs, stringValue, tokenValue; + tokenValue = token[1]; + stringValue = tokenValue.match(/^\"(.*)\"$/); + if (!stringValue) { + return false; + } + hasLegalConstructs = this.isInterpolated(tokenApi) || this.containsSingleQuote(tokenValue); + return !hasLegalConstructs; + }; + + NoUnnecessaryDoubleQuotes.prototype.isInterpolated = function(tokenApi) { + var currentIndex, i, isInterpolated, lineTokens, token, tokenName, _i, _ref; + currentIndex = tokenApi.i; + isInterpolated = false; + lineTokens = tokenApi.tokensByLine[tokenApi.lineNumber]; + for (i = _i = 1; 1 <= currentIndex ? _i <= currentIndex : _i >= currentIndex; i = 1 <= currentIndex ? ++_i : --_i) { + token = tokenApi.peek(-i); + tokenName = token[0]; + if (tokenName === ')' && token.stringEnd) { + break; + } else if (tokenName === '(' && ((_ref = token.origin) != null ? _ref[1] : void 0) === "string interpolation") { + isInterpolated = true; + break; + } + } + return isInterpolated; + }; + + NoUnnecessaryDoubleQuotes.prototype.containsSingleQuote = function(tokenValue) { + return tokenValue.indexOf("'") !== -1; + }; + + return NoUnnecessaryDoubleQuotes; + +})(); + + +},{}],33:[function(_dereq_,module,exports){ +var NoUnnecessaryFatArrows, any, + __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }; + +any = function(arr, test) { + return arr.reduce((function(res, elt) { + return res || test(elt); + }), false); +}; + +module.exports = NoUnnecessaryFatArrows = (function() { + function NoUnnecessaryFatArrows() { + this.needsFatArrow = __bind(this.needsFatArrow, this); + this.isThis = __bind(this.isThis, this); + } + + NoUnnecessaryFatArrows.prototype.rule = { + name: 'no_unnecessary_fat_arrows', + level: 'warn', + message: 'Unnecessary fat arrow', + description: "Disallows defining functions with fat arrows when `this`\nis not used within the function." + }; + + NoUnnecessaryFatArrows.prototype.lintAST = function(node, astApi) { + this.astApi = astApi; + this.lintNode(node); + return void 0; + }; + + NoUnnecessaryFatArrows.prototype.lintNode = function(node) { + var error; + if ((this.isFatArrowCode(node)) && (!this.needsFatArrow(node))) { + error = this.astApi.createError({ + lineNumber: node.locationData.first_line + 1 + }); + this.errors.push(error); + } + return node.eachChild((function(_this) { + return function(child) { + return _this.lintNode(child); + }; + })(this)); + }; + + NoUnnecessaryFatArrows.prototype.isCode = function(node) { + return this.astApi.getNodeName(node) === 'Code'; + }; + + NoUnnecessaryFatArrows.prototype.isFatArrowCode = function(node) { + return this.isCode(node) && node.bound; + }; + + NoUnnecessaryFatArrows.prototype.isValue = function(node) { + return this.astApi.getNodeName(node) === 'Value'; + }; + + NoUnnecessaryFatArrows.prototype.isThis = function(node) { + return this.isValue(node) && node.base.value === 'this'; + }; + + NoUnnecessaryFatArrows.prototype.needsFatArrow = function(node) { + return this.isCode(node) && (any(node.params, (function(_this) { + return function(param) { + return param.contains(_this.isThis) != null; + }; + })(this)) || (node.body.contains(this.isThis) != null) || (node.body.contains((function(_this) { + return function(child) { + if (!_this.astApi.getNodeName(child)) { + return (child.isSuper != null) && child.isSuper; + } else { + return _this.isFatArrowCode(child) && _this.needsFatArrow(child); + } + }; + })(this)) != null)); + }; + + return NoUnnecessaryFatArrows; + +})(); + + +},{}],34:[function(_dereq_,module,exports){ +var NonEmptyConstructorNeedsParens, ParentClass, + __hasProp = {}.hasOwnProperty, + __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }; + +ParentClass = _dereq_('./empty_constructor_needs_parens.coffee'); + +module.exports = NonEmptyConstructorNeedsParens = (function(_super) { + __extends(NonEmptyConstructorNeedsParens, _super); + + function NonEmptyConstructorNeedsParens() { + return NonEmptyConstructorNeedsParens.__super__.constructor.apply(this, arguments); + } + + NonEmptyConstructorNeedsParens.prototype.rule = { + name: 'non_empty_constructor_needs_parens', + level: 'ignore', + message: 'Invoking a constructor without parens and with arguments', + description: "Requires constructors with parameters to include the parens" + }; + + NonEmptyConstructorNeedsParens.prototype.handleExpectedCallStart = function(expectedCallStart) { + if (expectedCallStart[0] === 'CALL_START' && expectedCallStart.generated) { + return true; + } + }; + + return NonEmptyConstructorNeedsParens; + +})(ParentClass); + + +},{"./empty_constructor_needs_parens.coffee":13}],35:[function(_dereq_,module,exports){ +var SpaceOperators, + __indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; }; + +module.exports = SpaceOperators = (function() { + SpaceOperators.prototype.rule = { + name: 'space_operators', + level: 'ignore', + message: 'Operators must be spaced properly', + description: "This rule enforces that operators have space around them." + }; + + SpaceOperators.prototype.tokens = ["+", "-", "=", "**", "MATH", "COMPARE", "LOGIC", "COMPOUND_ASSIGN", "(", ")", "CALL_START", "CALL_END"]; + + function SpaceOperators() { + this.callTokens = []; + this.parenTokens = []; + } + + SpaceOperators.prototype.lintToken = function(_arg, tokenApi) { + var type; + type = _arg[0]; + if (type === "CALL_START" || type === "CALL_END") { + this.lintCall.apply(this, arguments); + return void 0; + } + if (type === "(" || type === ")") { + this.lintParens.apply(this, arguments); + return void 0; + } + if (type === "+" || type === "-") { + return this.lintPlus.apply(this, arguments); + } else { + return this.lintMath.apply(this, arguments); + } + }; + + SpaceOperators.prototype.lintPlus = function(token, tokenApi) { + var isUnary, p, unaries, _ref; + if (this.isInInterpolation() || this.isInExtendedRegex()) { + return null; + } + p = tokenApi.peek(-1); + unaries = ['TERMINATOR', '(', '=', '-', '+', ',', 'CALL_START', 'INDEX_START', '..', '...', 'COMPARE', 'IF', 'THROW', 'LOGIC', 'POST_IF', ':', '[', 'INDENT', 'COMPOUND_ASSIGN', 'RETURN', 'MATH', 'BY', 'LEADING_WHEN']; + isUnary = !p ? false : (_ref = p[0], __indexOf.call(unaries, _ref) >= 0); + if ((isUnary && token.spaced) || (!isUnary && !token.spaced && !token.newLine)) { + return { + context: token[1] + }; + } else { + return null; + } + }; + + SpaceOperators.prototype.lintMath = function(token, tokenApi) { + if (!token.spaced && !token.newLine) { + return { + context: token[1] + }; + } else { + return null; + } + }; + + SpaceOperators.prototype.isInExtendedRegex = function() { + var t, _i, _len, _ref; + _ref = this.callTokens; + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + t = _ref[_i]; + if (t.isRegex) { + return true; + } + } + return false; + }; + + SpaceOperators.prototype.lintCall = function(token, tokenApi) { + var p; + if (token[0] === 'CALL_START') { + p = tokenApi.peek(-1); + token.isRegex = p && p[0] === 'IDENTIFIER' && p[1] === 'RegExp'; + this.callTokens.push(token); + } else { + this.callTokens.pop(); + } + return null; + }; + + SpaceOperators.prototype.isInInterpolation = function() { + var t, _i, _len, _ref; + _ref = this.parenTokens; + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + t = _ref[_i]; + if (t.isInterpolation) { + return true; + } + } + return false; + }; + + SpaceOperators.prototype.lintParens = function(token, tokenApi) { + var i, n1, n2, p1; + if (token[0] === '(') { + p1 = tokenApi.peek(-1); + n1 = tokenApi.peek(1); + n2 = tokenApi.peek(2); + i = n1 && n2 && n1[0] === 'STRING' && n2[0] === '+'; + token.isInterpolation = i; + this.parenTokens.push(token); + } else { + this.parenTokens.pop(); + } + return null; + }; + + return SpaceOperators; + +})(); + + +},{}]},{},[4]) +(4) +}); \ No newline at end of file diff --git a/views/account/preferences.html b/views/account/preferences.html index fe1256b4..12b73cd9 100644 --- a/views/account/preferences.html +++ b/views/account/preferences.html @@ -105,6 +105,27 @@
    +
    + +
    + + +
    + +
    + CoffeeLint show errors in: + + + + + +
    + +
    + + +
    + From 9e7de5497db82eabd6e44d1ddca958505fd1e730 Mon Sep 17 00:00:00 2001 From: Giulia Alfonsi Date: Tue, 1 Jul 2014 19:14:52 +0100 Subject: [PATCH 266/321] Better test for coffeescript --- public/js/editors/addons.js | 3 +- .../cm_addons/lint/coffeescript-lint.js | 44 +++++++++---------- 2 files changed, 24 insertions(+), 23 deletions(-) diff --git a/public/js/editors/addons.js b/public/js/editors/addons.js index a2952e5c..33dc0cde 100644 --- a/public/js/editors/addons.js +++ b/public/js/editors/addons.js @@ -256,7 +256,8 @@ '/js/vendor/cm_addons/lint/lint.js' ], test: function() { - return hintingTest('coffeescript'); + return hintingTest('coffeescript') && + coffeelint !== undefined; }, done: function(cm) { if (cm.getOption('mode') !== 'coffeescript') { diff --git a/public/js/vendor/cm_addons/lint/coffeescript-lint.js b/public/js/vendor/cm_addons/lint/coffeescript-lint.js index 6df17f8f..7d706f34 100644 --- a/public/js/vendor/cm_addons/lint/coffeescript-lint.js +++ b/public/js/vendor/cm_addons/lint/coffeescript-lint.js @@ -10,29 +10,29 @@ else // Plain browser env mod(CodeMirror); })(function(CodeMirror) { -"use strict"; + "use strict"; -CodeMirror.registerHelper("lint", "coffeescript", function(text) { - var found = []; - var parseError = function(err) { - var loc = err.lineNumber; - found.push({from: CodeMirror.Pos(loc-1, 0), - to: CodeMirror.Pos(loc, 0), - severity: err.level, - message: err.message}); - }; - try { - var res = coffeelint.lint(text); - for(var i = 0; i < res.length; i++) { - parseError(res[i]); + CodeMirror.registerHelper("lint", "coffeescript", function(text, options) { + var found = []; + var parseError = function(err) { + var loc = err.lineNumber; + found.push({from: CodeMirror.Pos(loc-1, 0), + to: CodeMirror.Pos(loc, 0), + severity: err.level, + message: err.message}); + }; + try { + var res = coffeelint.lint(text, options); + for(var i = 0; i < res.length; i++) { + parseError(res[i]); + } + } catch(e) { + found.push({from: CodeMirror.Pos(e.location.first_line, 0), + to: CodeMirror.Pos(e.location.last_line, e.location.last_column), + severity: 'error', + message: e.message}); } - } catch(e) { - found.push({from: CodeMirror.Pos(e.location.first_line, 0), - to: CodeMirror.Pos(e.location.last_line, e.location.last_column), - severity: 'error', - message: e.message}); - } - return found; -}); + return found; + }); }); From fab38ee40a21c5944bcb415cc70aa4dac18b2c5f Mon Sep 17 00:00:00 2001 From: Giulia Alfonsi Date: Tue, 1 Jul 2014 19:17:59 +0100 Subject: [PATCH 267/321] Better test for css, html, js lint --- public/js/editors/addons.js | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/public/js/editors/addons.js b/public/js/editors/addons.js index 33dc0cde..af4fba73 100644 --- a/public/js/editors/addons.js +++ b/public/js/editors/addons.js @@ -203,7 +203,8 @@ '/js/vendor/cm_addons/lint/lint.js' ], test: function() { - return hintingTest('css'); + return hintingTest('css') && + CSSLint !== undefined; }, done: function(cm) { if (cm.getOption('mode') !== 'css') { @@ -220,7 +221,8 @@ '/js/vendor/cm_addons/lint/lint.js' ], test: function() { - return hintingTest('javascript'); + return hintingTest('javascript') && + JSHINT !== undefined; }, done: function(cm) { if (cm.getOption('mode') !== 'javascript') { @@ -239,7 +241,8 @@ '/js/vendor/cm_addons/lint/lint.js' ], test: function() { - return hintingTest('htmlmixed'); + return hintingTest('htmlmixed') && + HTMLHint !== undefined; }, done: function(cm) { if (cm.getOption('mode') !== 'htmlmixed') { From 893ea57ddfb14ca23d56711e73916bd784e9dc43 Mon Sep 17 00:00:00 2001 From: Giulia Alfonsi Date: Wed, 2 Jul 2014 10:29:02 +0100 Subject: [PATCH 268/321] Minified versions of the linking libraries --- public/js/editors/addons.js | 6 +++--- public/js/vendor/coffeelint/coffeelint.min.js | 1 + public/js/vendor/csslint/csslint.min.js | 1 + public/js/vendor/jshint/jshint.min.js | 1 + 4 files changed, 6 insertions(+), 3 deletions(-) create mode 100644 public/js/vendor/coffeelint/coffeelint.min.js create mode 100644 public/js/vendor/csslint/csslint.min.js create mode 100644 public/js/vendor/jshint/jshint.min.js diff --git a/public/js/editors/addons.js b/public/js/editors/addons.js index af4fba73..f0a1016d 100644 --- a/public/js/editors/addons.js +++ b/public/js/editors/addons.js @@ -197,7 +197,7 @@ }, csshint: { url: [ - '/js/vendor/csslint/csslint.js', + '/js/vendor/csslint/csslint.min.js', '/js/vendor/cm_addons/lint/lint.css', '/js/vendor/cm_addons/lint/css-lint.js', '/js/vendor/cm_addons/lint/lint.js' @@ -215,7 +215,7 @@ }, jshint: { url: [ - '/js/vendor/jshint/jshint.js', + '/js/vendor/jshint/jshint.min.js', '/js/vendor/cm_addons/lint/lint.css', '/js/vendor/cm_addons/lint/javascript-lint.js', '/js/vendor/cm_addons/lint/lint.js' @@ -253,7 +253,7 @@ }, coffeescripthint: { url: [ - '/js/vendor/coffeelint/coffeelint.js', + '/js/vendor/coffeelint/coffeelint.min.js', '/js/vendor/cm_addons/lint/lint.css', '/js/vendor/cm_addons/lint/coffeescript-lint.js', '/js/vendor/cm_addons/lint/lint.js' diff --git a/public/js/vendor/coffeelint/coffeelint.min.js b/public/js/vendor/coffeelint/coffeelint.min.js new file mode 100644 index 00000000..64de92f7 --- /dev/null +++ b/public/js/vendor/coffeelint/coffeelint.min.js @@ -0,0 +1 @@ +!function(e){if("object"==typeof exports)module.exports=e();else if("function"==typeof define&&define.amd)define(e);else{var t;"undefined"!=typeof window?t=window:"undefined"!=typeof global?t=global:"undefined"!=typeof self&&(t=self),t.coffeelint=e()}}(function(){var e,t,n;return function r(e,t,n){function i(o,u){if(!t[o]){if(!e[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(s)return s(o,!0);throw new Error("Cannot find module '"+o+"'")}var f=t[o]={exports:{}};e[o][0].call(f.exports,function(t){var n=e[o][1][t];return i(n?n:t)},f,f.exports,r,e,t,n)}return t[o].exports}var s=typeof require=="function"&&require;for(var o=0;o",main:"./lib/coffeelint.js",engines:{node:">=0.8.0"},repository:{type:"git",url:"git://github.com/clutchski/coffeelint.git"},bin:{coffeelint:"./bin/coffeelint"},dependencies:{browserify:"~3.37","coffee-script":"~1.7",coffeeify:"~0.6.0",glob:"^4.0.0",optimist:"^0.6.1",resolve:"^0.6.3"},devDependencies:{vows:">=0.6.0",underscore:">=1.4.4"},licenses:[{type:"MIT",url:"http://github.com/clutchski/coffeelint/raw/master/LICENSE"}],scripts:{pretest:"cake compile",test:"coffee vowsrunner.coffee --spec test/*.coffee test/*.litcoffee",posttest:"npm run lint",prepublish:"cake prepublish",publish:"cake publish",install:"cake install",lint:"cake compile && ./bin/coffeelint -f coffeelint.json src/*.coffee test/*.coffee test/*.litcoffee","lint-csv":"cake compile && ./bin/coffeelint --csv -f coffeelint.json src/*.coffee test/*.coffee","lint-jslint":"cake compile && ./bin/coffeelint --jslint -f coffeelint.json src/*.coffee test/*.coffee",compile:"cake compile"}}},{}],2:[function(e,t,n){var r,i,s,o,u,a={}.hasOwnProperty,f=function(e,t){function r(){this.constructor=e}for(var n in t){if(a.call(t,n))e[n]=t[n]}r.prototype=t.prototype;e.prototype=new r;e.__super__=t.prototype;return e};s=e("./base_linter.coffee");u={Class:["variable","parent","body"],Code:["params","body"],For:["body","source","guard","step"],If:["condition","body","elseBody"],Obj:["properties"],Op:["first","second"],Switch:["subject","cases","otherwise"],Try:["attempt","recovery","ensure"],Value:["base","properties"],While:["condition","guard","body"]};o=function(e,t){var n;return(e!=null?(n=e.children)!=null?n.length:void 0:void 0)===t.length&&(e!=null?e.children.every(function(e,n){return e===t[n]}):void 0)};r=function(){function e(e){this.config=e}e.prototype.getNodeName=function(e){var t,n,r;n=e!=null?(r=e.constructor)!=null?r.name:void 0:void 0;if(u[n]){return n}else{for(n in u){if(!a.call(u,n))continue;t=u[n];if(o(e,t)){return n}}}};return e}();t.exports=i=function(e){function t(e,n,i,s){this.CoffeeScript=s;t.__super__.constructor.call(this,e,n,i);this.astApi=new r(this.config)}f(t,e);t.prototype.acceptRule=function(e){return typeof e.lintAST==="function"};t.prototype.lint=function(){var e,t,n,r,i,s,o,u;n=[];try{this.node=this.CoffeeScript.nodes(this.source)}catch(a){e=a;t=this._parseCoffeeScriptError(e);if(t!=null){n.push(t)}return n}u=this.rules;for(s=0,o=u.length;s1){n=parseInt(r[1],10)}}t={message:i,level:s.level,lineNumber:n};return this.createError("coffeescript_error",t)};return t}(s)},{"./base_linter.coffee":3}],3:[function(e,t,n){var r,i,s,o=[].slice;s=function(){var e,t,n,r,i,s,u;e=arguments[0],r=2<=arguments.length?o.call(arguments,1):[];for(s=0,u=r.length;s=0){i.push(e.splice(n,1))}else{i.push(n++)}}return i};a=e("./line_linter.coffee");u=e("./lexical_linter.coffee");r=e("./ast_linter.coffee");c=null;g=function(e){var t,n,r;t={};for(n in f){r=f[n];t[n]=p(e[n],r)}return t};h.invertLiterate=function(e){var t,n,r,s,o;e=i.helpers.invertLiterate(e);n="";o=e.split("\n");for(r=0,s=o.length;r2&&S.call(P,"enable")>=0){U=P.slice(1);for(j=0,q=U.length;jW;x=0<=W?++F:--F){for(l in f){D=f[l][x];if(D!=null){(({disable:function(){return p=p.concat(D)},enable:function(){d(p,D);if(D.length===0){return p=v}}}))[l]()}}while(O===x&&s.length>0){O=s[0].lineNumber-1;b=s[0];if(b.lineNumber===x+1||b.lineNumber==null){b=s.shift();if(X=b.rule,S.call(p,X)<0){E.push(b)}}}}if(c!=null){c.set(e,E)}return E};h.setCache=function(e){return c=e}},{"./../package.json":1,"./ast_linter.coffee":2,"./lexical_linter.coffee":5,"./line_linter.coffee":6,"./rules.coffee":7,"./rules/arrow_spacing.coffee":8,"./rules/camel_case_classes.coffee":9,"./rules/colon_assignment_spacing.coffee":10,"./rules/cyclomatic_complexity.coffee":11,"./rules/duplicate_key.coffee":12,"./rules/empty_constructor_needs_parens.coffee":13,"./rules/indentation.coffee":14,"./rules/line_endings.coffee":15,"./rules/max_line_length.coffee":16,"./rules/missing_fat_arrows.coffee":17,"./rules/newlines_after_classes.coffee":18,"./rules/no_backticks.coffee":19,"./rules/no_debugger.coffee":20,"./rules/no_empty_functions.coffee":21,"./rules/no_empty_param_list.coffee":22,"./rules/no_implicit_braces.coffee":23,"./rules/no_implicit_parens.coffee":24,"./rules/no_interpolation_in_single_quotes.coffee":25,"./rules/no_plusplus.coffee":26,"./rules/no_stand_alone_at.coffee":27,"./rules/no_tabs.coffee":28,"./rules/no_throwing_strings.coffee":29,"./rules/no_trailing_semicolons.coffee":30,"./rules/no_trailing_whitespace.coffee":31,"./rules/no_unnecessary_double_quotes.coffee":32,"./rules/no_unnecessary_fat_arrows.coffee":33,"./rules/non_empty_constructor_needs_parens.coffee":34,"./rules/space_operators.coffee":35}],5:[function(e,t,n){var r,i,s,o={}.hasOwnProperty,u=function(e,t){function r(){this.constructor=e}for(var n in t){if(o.call(t,n))e[n]=t[n]}r.prototype=t.prototype;e.prototype=new r;e.__super__=t.prototype;return e},a=[].indexOf||function(e){for(var t=0,n=this.length;t=0)){continue}s=this.normalizeResult(r,r.lintToken(e,this.tokenApi));if(s!=null){t.push(s)}}return t};t.prototype.createError=function(e,n){if(n==null){n={}}n.lineNumber=this.lineNumber+1;n.line=this.tokenApi.lines[this.lineNumber];return t.__super__.createError.call(this,e,n)};return t}(r)},{"./base_linter.coffee":3}],6:[function(e,t,n){var r,i,s,o,u={}.hasOwnProperty,a=function(e,t){function r(){this.constructor=e}for(var n in t){if(u.call(t,n))e[n]=t[n]}r.prototype=t.prototype;e.prototype=new r;e.__super__=t.prototype;return e};i=function(){function e(e,t,n,r){this.config=t;this.tokensByLine=n;this.literate=r;this.line=null;this.lines=e.split("\n");this.lineCount=this.lines.length;this.context={"class":{inClass:false,lastUnemptyLineInClass:null,classIndents:null}}}e.prototype.lineNumber=0;e.prototype.isLiterate=function(){return this.literate};e.prototype.maintainClassContext=function(e){if(this.context["class"].inClass){if(this.lineHasToken("INDENT")){this.context["class"].classIndents++}else if(this.lineHasToken("OUTDENT")){this.context["class"].classIndents--;if(this.context["class"].classIndents===0){this.context["class"].inClass=false;this.context["class"].classIndents=null}}if(this.context["class"].inClass&&!e.match(/^\s*$/)){this.context["class"].lastUnemptyLineInClass=this.lineNumber}}else{if(!e.match(/\\s*/)){this.context["class"].lastUnemptyLineInClass=null}if(this.lineHasToken("CLASS")){this.context["class"].inClass=true;this.context["class"].lastUnemptyLineInClass=this.lineNumber;this.context["class"].classIndents=0}}return null};e.prototype.isLastLine=function(){return this.lineNumber===this.lineCount-1};e.prototype.lineHasToken=function(e,t){var n,r,i,s;if(e==null){e=null}if(t==null){t=null}t=t!=null?t:this.lineNumber;if(e==null){return this.tokensByLine[t]!=null}else{r=this.tokensByLine[t];if(r==null){return null}for(i=0,s=r.length;i) must be spaced properly",description:"

    This rule checks to see that there is spacing before and after\nthe arrow operator that declares a function. This rule is disabled\nby default.

    Note that if arrow_spacing is enabled, and you\npass an empty function as a parameter, arrow_spacing will accept\neither a space or no space in-between the arrow operator and the\nparenthesis

    \n
    # Both of this will not trigger an error,\n# even with arrow_spacing enabled.\nx(-> 3)\nx( -> 3)\n\n# However, this will trigger an error\nx((a,b)-> 3)\n\n
    "};e.prototype.tokens=["->"];e.prototype.lintToken=function(e,t){var n;n=t.peek(-1);if(!e.spaced&&n[1]==="("&&n.generated==null&&t.peek(1)[0]==="INDENT"&&t.peek(2)[0]==="OUTDENT"){return null}else if(!((e.spaced!=null||e.newLine!=null||this.atEof(t))&&(n.spaced!=null||n[0]==="TERMINATOR"||n.generated!=null||n[0]==="INDENT"||n[1]==="("&&n.generated==null))){return true}else{return null}};e.prototype.atEof=function(e){var t,n,r,i,s,o,u;r=e.tokens,t=e.i;o=r.slice(t+1);for(i=0,s=o.length;i\n# Good!\nclass BoaConstrictor\n\n# Bad!\nclass boaConstrictor\n\n\nThis rule is enabled by default."};e.prototype.tokens=["CLASS"];e.prototype.lintToken=function(e,t){var n,r,s,o,u;if(e.newLine!=null||(s=t.peek()[0])==="INDENT"||s==="EXTENDS"){return null}n=null;r=1;while(!n){if(((o=t.peek(r+1))!=null?o[0]:void 0)==="."){r+=2}else if(((u=t.peek(r))!=null?u[0]:void 0)==="@"){r+=1}else{n=t.peek(r)[1]}}if(!i.camelCase.test(n)){return{context:"class name: "+n}}};return e}()},{}],10:[function(e,t,n){var r;t.exports=r=function(){function e(){}e.prototype.rule={name:"colon_assignment_spacing",level:"ignore",message:"Colon assignment without proper spacing",spacing:{left:0,right:0},description:"

    This rule checks to see that there is spacing before and\nafter the colon in a colon assignment (i.e., classes, objects).\nThe spacing amount is specified by\nspacing.left and spacing.right, respectively.\nA zero value means no spacing required.\n

    \n
    \n#\n# If spacing.left and spacing.right is 1\n#\n\n# Good\nobject = {spacing : true}\nclass Dog\n  canBark : true\n\n# Bad\nobject = {spacing: true}\nclass Cat\n  canBark: false\n
    "};e.prototype.tokens=[":"];e.prototype.lintToken=function(e,t){var n,r,i,s,o,u,a,f,l,c,h;l=t.config[this.rule.name].spacing;a=t.peek(-1);u=t.peek(1);r=function(t){switch(t){case"left":return e[2].first_column-a[2].last_column-1;case"right":return u[2].first_column-e[2].first_column-1}};n=function(e){var t,n;n=r(e);t=n<0?true:n===parseInt(l[e]);return[t,n]};c=n("left"),i=c[0],o=c[1];h=n("right"),s=h[0],f=h[1];if(i&&s){return null}else{return{context:"Incorrect spacing around column "+e[2].first_column+".\nExpected left: "+l.left+", right: "+l.right+".\nGot left: "+o+", right: "+f+"."}}};return e}()},{}],11:[function(e,t,n){var r;t.exports=r=function(){function e(){}e.prototype.rule={name:"cyclomatic_complexity",value:10,level:"ignore",message:"The cyclomatic complexity is too damn high",description:"Examine the complexity of your application."};e.prototype.getComplexity=function(e){var t,n,r;n=this.astApi.getNodeName(e);t=n==="If"||n==="While"||n==="For"||n==="Try"?1:n==="Op"&&((r=e.operator)==="&&"||r==="||")?1:n==="Switch"?e.cases.length:0;return t};e.prototype.lintAST=function(e,t){this.astApi=t;this.lintNode(e);return void 0};e.prototype.lintNode=function(e,t){var n,r,i,s,o;i=(o=this.astApi)!=null?o.getNodeName(e):void 0;n=this.getComplexity(e);e.eachChild(function(e){return function(t){var r;r=t.locationData.first_line;if(t){return n+=e.lintNode(t,r)}}}(this));s=this.astApi.config[this.rule.name];if(i==="Code"&&n>=s.value){r=this.astApi.createError({context:n+1,lineNumber:t+1,lineNumberEnd:e.locationData.last_line+1});if(r){this.errors.push(r)}}return n};return e}()},{}],12:[function(e,t,n){var r;t.exports=r=function(){function e(){this.braceScopes=[]}e.prototype.rule={name:"duplicate_key",level:"error",message:"Duplicate key defined in object or class",description:"Prevents defining duplicate keys in object literals and classes"};e.prototype.tokens=["IDENTIFIER","{","}"];e.prototype.lintToken=function(e,t){var n;n=e[0];if(n==="{"||n==="}"){this.lintBrace.apply(this,arguments);return void 0}if(n==="IDENTIFIER"){return this.lintIdentifier.apply(this,arguments)}};e.prototype.lintIdentifier=function(e,t){var n,r,i;n=e[1];if(this.currentScope==null){return null}r=t.peek(1);if(r[1]!==":"){return null}i=t.peek(-1);if(i[0]==="@"){n="@"+n}n="identifier-"+n;if(this.currentScope[n]){return true}else{this.currentScope[n]=e;return null}};e.prototype.lintBrace=function(e){if(e[0]==="{"){if(this.currentScope!=null){this.braceScopes.push(this.currentScope)}this.currentScope={}}else{this.currentScope=this.braceScopes.pop()}return null};return e}()},{}],13:[function(e,t,n){var r;t.exports=r=function(){function e(){}e.prototype.rule={name:"empty_constructor_needs_parens",level:"ignore",message:"Invoking a constructor without parens and without arguments",description:"Requires constructors with no parameters to include the parens"};e.prototype.tokens=["UNARY"];e.prototype.lintToken=function(e,t){var n,r,i;if(e[1]==="new"){i=1;while(true){r=t.peek(i);n=t.peek(i+1);if((r!=null?r[0]:void 0)==="IDENTIFIER"){if((n!=null?n[0]:void 0)==="."){i+=2;continue}}break}if((r!=null?r[0]:void 0)==="IDENTIFIER"&&n!=null){return this.handleExpectedCallStart(n)}}};e.prototype.handleExpectedCallStart=function(e){if(e[0]!=="CALL_START"){return true}};return e}()},{}],14:[function(e,t,n){var r;t.exports=r=function(){function e(){this.arrayTokens=[]}e.prototype.rule={name:"indentation",value:2,level:"error",message:"Line contains inconsistent indentation",description:"This rule imposes a standard number of spaces to be used for\nindentation. Since whitespace is significant in CoffeeScript, it's\ncritical that a project chooses a standard indentation format and\nstays consistent. Other roads lead to darkness.
     #\nEnabling this option will prevent this ugly\n# but otherwise valid CoffeeScript.\ntwoSpaces = () ->\n  fourSpaces = () ->\n      eightSpaces = () ->\n            'this is valid CoffeeScript'\n\n\n
    \nTwo space indentation is enabled by default."};e.prototype.tokens=["INDENT","[","]"];e.prototype.lintToken=function(e,t){var n,r,i,s,o,u,a,f,l,c,h,p,d,v,m,g;m=e[0],l=e[1],a=e[2];if(m==="["||m==="]"){this.lintArray(e);return void 0}if(e.generated!=null){return null}h=t.peek(-2);o=h&&h[0]==="+";h=t.peek(-1);s=this.inArray()&&(h!=null?h.newLine:void 0);v=(g=t.peek(-1))!=null?g[0]:void 0;u=v==="="||v===",";i=o||s||u;if(this.isChainedCall(t)){f=t.lines,a=t.lineNumber;n=f[a];c=1;while(/^\s*(#|$)/.test(f[a-c])){c+=1}d=f[a-c];p=d.match(/^(\s*)/)[1].length;l=n.match(/^(\s*)/)[1].length;l-=p}r=t.config[this.rule.name].value;if(!i&&l!==r){return{context:"Expected "+r+" got "+l}}};e.prototype.inArray=function(){return this.arrayTokens.length>0};e.prototype.lintArray=function(e){if(e[0]==="["){this.arrayTokens.push(e)}else if(e[0]==="]"){this.arrayTokens.pop()}return null};e.prototype.isChainedCall=function(e){var t,n,r,i,s,o;o=e.tokens,t=e.i;r=function(){var e,n,r,i;r=o.slice(0,+t+1||9e9);i=[];for(t=e=0,n=r.length;ewindows or\nunix line endings. This rule is disabled by default."};e.prototype.lintLine=function(e,t){var n,r,i,s;n=(s=t.config[this.rule.name])!=null?s.value:void 0;if(!n||t.isLastLine()||!e){return null}r=e[e.length-1];i=function(){if(n==="windows"){return r==="\r"}else if(n==="unix"){return r!=="\r"}else{throw new Error("unknown line ending type: "+n)}}();if(!i){return{context:"Expected "+n}}else{return null}};return e}()},{}],16:[function(e,t,n){var r,i;i={literateComment:/^\#\s/,longUrlComment:/^\s*\#\s*http[^\s]+$/};t.exports=r=function(){function e(){}e.prototype.rule={name:"max_line_length",value:80,level:"error",limitComments:true,message:"Line exceeds maximum allowed length",description:'This rule imposes a maximum line length on your code. Python\'s style\nguide does a good job explaining why you might want to limit the\nlength of your lines, though this is a matter of taste.\n\nLines can be no longer than eighty characters by default.'};e.prototype.lintLine=function(e,t){var n,r,s,o,u;s=(o=t.config[this.rule.name])!=null?o.value:void 0;n=(u=t.config[this.rule.name])!=null?u.limitComments:void 0;r=e.trimRight().length;if(t.isLiterate()&&i.literateComment.test(e)){r-=2}if(s&&swith and eval,\nsneak into CoffeeScript.\nThis rule is enabled by default.'};e.prototype.tokens=["JS"];e.prototype.lintToken=function(e,t){return true};return e}()},{}],20:[function(e,t,n){var r;t.exports=r=function(){function e(){}e.prototype.rule={name:"no_debugger",level:"warn",message:"Debugger statements will cause warnings",description:"This rule detects the `debugger` statement.\nThis rule is `warn` by default."};e.prototype.tokens=["DEBUGGER"];e.prototype.lintToken=function(e,t){return{context:"found '"+e[0]+"'"}};return e}()},{}],21:[function(e,t,n){var r,i;i=function(e,t){var n;n=t.getNodeName(e);return n==="Code"&&e.body.isEmpty()};t.exports=r=function(){function e(){}e.prototype.rule={name:"no_empty_functions",level:"ignore",message:"Empty function",description:"Disallows declaring empty functions. The goal of this rule is that\nunintentional empty callbacks can be detected:\n
    \nsomeFunctionWithCallback ->\ndoSomethingSignificant()\n\n
    \nThe problem is that the call to\ndoSomethingSignificant will be made regardless\nof someFunctionWithCallback's execution. It can\nbe because you did not indent the call to\ndoSomethingSignificant properly.\n\nIf you really meant that someFunctionWithCallback\nshould call a callback that does nothing, you can write your code\nthis way:\n
    \nsomeFunctionWithCallback ->\n    undefined\ndoSomethingSignificant()\n\n
    "};e.prototype.lintAST=function(e,t){this.lintNode(e,t);return void 0};e.prototype.lintNode=function(e,t){var n;if(i(e,t)){n=t.createError({lineNumber:e.locationData.first_line+1});this.errors.push(n)}return e.eachChild(function(e){return function(n){return e.lintNode(n,t)}}(this))};return e}()},{}],22:[function(e,t,n){var r;t.exports=r=function(){function e(){}e.prototype.rule={name:"no_empty_param_list",level:"ignore",message:"Empty parameter list is forbidden",description:"This rule prohibits empty parameter lists in function definitions.\n
    \n# The empty parameter list in here is unnecessary:\nmyFunction = () ->\n\n# We might favor this instead:\nmyFunction = ->\n\n
    \nEmpty parameter lists are permitted by default."};e.prototype.tokens=["PARAM_START"];e.prototype.lintToken=function(e,t){var n;n=t.peek()[0];return n==="PARAM_END"};return e}()},{}],23:[function(e,t,n){var r;t.exports=r=function(){function e(){}e.prototype.rule={name:"no_implicit_braces",level:"ignore",message:"Implicit braces are forbidden",strict:true,description:"This rule prohibits implicit braces when declaring object literals.\nImplicit braces can make code more difficult to understand,\nespecially when used in combination with optional parenthesis.\n
    \n# Do you find this code ambiguous? Is it a\n# function call with three arguments or four?\nmyFunction a, b, 1:2, 3:4\n\n# While the same code written in a more\n# explicit manner has no ambiguity.\nmyFunction(a, b, {1:2, 3:4})\n\n
    \nImplicit braces are permitted by default, since their use is\nidiomatic CoffeeScript."};e.prototype.tokens=["{"];e.prototype.lintToken=function(e,t){var n;if(e.generated){if(!t.config[this.rule.name].strict){n=t.peek(-1)[0];if(n==="INDENT"){return}}return this.isPartOfClass(t)}};e.prototype.isPartOfClass=function(e){var t,n;t=-1;while(true){n=e.peek(t);if(n==null||n[0]==="TERMINATOR"){return true}if(n[0]==="CLASS"){return null}t-=1}};return e}()},{}],24:[function(e,t,n){var r;t.exports=r=function(){function e(){}e.prototype.rule={name:"no_implicit_parens",strict:true,level:"ignore",message:"Implicit parens are forbidden",description:"This rule prohibits implicit parens on function calls.\n
    \n# Some folks don't like this style of coding.\nmyFunction a, b, c\n\n# And would rather it always be written like this:\nmyFunction(a, b, c)\n\n
    \nImplicit parens are permitted by default, since their use is\nidiomatic CoffeeScript."};e.prototype.tokens=["CALL_END"];e.prototype.lintToken=function(e,t){var n,r;if(e.generated){if(t.config[this.rule.name].strict!==false){return true}else{n=-1;while(true){r=t.peek(n);if(r==null||r[0]==="CALL_START"){return true}if(r.newLine){return null}n-=1}}}};return e}()},{}],25:[function(e,t,n){var r;t.exports=r=function(){function e(){}e.prototype.rule={name:"no_interpolation_in_single_quotes",level:"ignore",message:"Interpolation in single quoted strings is forbidden",description:"This rule prohibits string interpolation in a single quoted string.\n
    \n# String interpolation in single quotes is not allowed:\nfoo = '#{bar}'\n\n# Double quotes is OK of course\nfoo = \"#{bar}\"\n\n
    \nString interpolation in single quoted strings is permitted by \ndefault."};e.prototype.tokens=["STRING"];e.prototype.lintToken=function(e,t){var n,r;r=e[1];n=r.match(/#\{[^}]+\}/);return n};return e}()},{}],26:[function(e,t,n){var r;t.exports=r=function(){function e(){}e.prototype.rule={name:"no_plusplus",level:"ignore",message:"The increment and decrement operators are forbidden",description:"This rule forbids the increment and decrement arithmetic operators.\nSome people believe the ++ and -- to be cryptic\nand the cause of bugs due to misunderstandings of their precedence\nrules.\nThis rule is disabled by default."};e.prototype.tokens=["++","--"];e.prototype.lintToken=function(e,t){return{context:"found '"+e[0]+"'"}};return e}()},{}],27:[function(e,t,n){var r;t.exports=r=function(){function e(){}e.prototype.rule={name:"no_stand_alone_at",level:"ignore",message:"@ must not be used stand alone",description:'This rule checks that no stand alone @ are in use, they are\ndiscouraged. Further information in CoffeScript issue \n#1601'};e.prototype.tokens=["@"];e.prototype.lintToken=function(e,t){var n,r,i,s,o,u,a;o=t.peek();a=e.spaced;r=o[0]==="IDENTIFIER";i=o[0]==="INDEX_START";n=o[0]===".";if(o[0]==="::"){u=t.peek(2);s=u[0]==="IDENTIFIER"}if(a||!r&&!i&&!n&&!s){return true}};return e}()},{}],28:[function(e,t,n){var r,i,s=[].indexOf||function(e){for(var t=0,n=this.length;t=0){return true}else{return null}};return e}()},{}],29:[function(e,t,n){var r;t.exports=r=function(){function e(){}e.prototype.rule={name:"no_throwing_strings",level:"error",message:"Throwing strings is forbidden",description:'This rule forbids throwing string literals or interpolations. While\nJavaScript (and CoffeeScript by extension) allow any expression to\nbe thrown, it is best to only throw Error objects,\nbecause they contain valuable debugging information like the stack\ntrace. Because of JavaScript\'s dynamic nature, CoffeeLint cannot\nensure you are always throwing instances of Error. It will\nonly catch the simple but real case of throwing literal strings.\n
    \n# CoffeeLint will catch this:\nthrow "i made a boo boo"\n\n# ... but not this:\nthrow getSomeString()\n\n
    \nThis rule is enabled by default.'};e.prototype.tokens=["THROW"];e.prototype.lintToken=function(e,t){var n,r,i,s;s=[t.peek(),t.peek(2)],n=s[0],r=s[1];i=n[0]==="STRING"||n[0]==="("&&r[0]==="STRING";return i};return e}()},{}],30:[function(e,t,n){var r,i,s=[].slice;i={trailingSemicolon:/;\r?$/};t.exports=r=function(){function e(){}e.prototype.rule={name:"no_trailing_semicolons",level:"error",message:"Line contains a trailing semicolon",description:"This rule prohibits trailing semicolons, since they are needless\ncruft in CoffeeScript.\n
    \n# This semicolon is meaningful.\nx = '1234'; console.log(x)\n\n# This semicolon is redundant.\nalert('end of line');\n\n
    \nTrailing semicolons are forbidden by default."};e.prototype.lintLine=function(e,t){var n,r,o,u,a,f,l,c,h,p,d,v;f=t.getLineTokens();if(f.length===1&&((d=f[0][0])==="TERMINATOR"||d==="HERECOMMENT")){return}l=e;if(f.length>1&&f[f.length-1][0]==="TERMINATOR"){h=f[f.length-2][2].last_column+1;n=f[f.length-1][2].first_column;if(h!==n){c=h;while(e[c]!=="#"&&c\n# Double quotes are discouraged:\nfoo = "bar"\n\n# Unless string interpolation is used:\nfoo = "#{bar}baz"\n\n# Or they prevent cumbersome escaping:\nfoo = "I\'m just following the \'rules\'"\n\n\nDouble quotes are permitted by default.'};e.prototype.tokens=["STRING"];e.prototype.lintToken=function(e,t){var n,r,i;i=e[1];r=i.match(/^\"(.*)\"$/);if(!r){return false}n=this.isInterpolated(t)||this.containsSingleQuote(i);return!n};e.prototype.isInterpolated=function(e){var t,n,r,i,s,o,u,a;t=e.i;r=false;i=e.tokensByLine[e.lineNumber];for(n=u=1;1<=t?u<=t:u>=t;n=1<=t?++u:--u){s=e.peek(-n);o=s[0];if(o===")"&&s.stringEnd){break}else if(o==="("&&((a=s.origin)!=null?a[1]:void 0)==="string interpolation"){r=true;break}}return r};e.prototype.containsSingleQuote=function(e){return e.indexOf("'")!==-1};return e}()},{}],33:[function(e,t,n){var r,i,s=function(e,t){return function(){return e.apply(t,arguments)}};i=function(e,t){return e.reduce(function(e,n){return e||t(n)},false)};t.exports=r=function(){function e(){this.needsFatArrow=s(this.needsFatArrow,this);this.isThis=s(this.isThis,this)}e.prototype.rule={name:"no_unnecessary_fat_arrows",level:"warn",message:"Unnecessary fat arrow",description:"Disallows defining functions with fat arrows when `this`\nis not used within the function."};e.prototype.lintAST=function(e,t){this.astApi=t;this.lintNode(e);return void 0};e.prototype.lintNode=function(e){var t;if(this.isFatArrowCode(e)&&!this.needsFatArrow(e)){t=this.astApi.createError({lineNumber:e.locationData.first_line+1});this.errors.push(t)}return e.eachChild(function(e){return function(t){return e.lintNode(t)}}(this))};e.prototype.isCode=function(e){return this.astApi.getNodeName(e)==="Code"};e.prototype.isFatArrowCode=function(e){return this.isCode(e)&&e.bound};e.prototype.isValue=function(e){return this.astApi.getNodeName(e)==="Value"};e.prototype.isThis=function(e){return this.isValue(e)&&e.base.value==="this"};e.prototype.needsFatArrow=function(e){return this.isCode(e)&&(i(e.params,function(e){return function(t){return t.contains(e.isThis)!=null}}(this))||e.body.contains(this.isThis)!=null||e.body.contains(function(e){return function(t){if(!e.astApi.getNodeName(t)){return t.isSuper!=null&&t.isSuper}else{return e.isFatArrowCode(t)&&e.needsFatArrow(t)}}}(this))!=null)};return e}()},{}],34:[function(e,t,n){var r,i,s={}.hasOwnProperty,o=function(e,t){function r(){this.constructor=e}for(var n in t){if(s.call(t,n))e[n]=t[n]}r.prototype=t.prototype;e.prototype=new r;e.__super__=t.prototype;return e};i=e("./empty_constructor_needs_parens.coffee");t.exports=r=function(e){function t(){return t.__super__.constructor.apply(this,arguments)}o(t,e);t.prototype.rule={name:"non_empty_constructor_needs_parens",level:"ignore",message:"Invoking a constructor without parens and with arguments",description:"Requires constructors with parameters to include the parens"};t.prototype.handleExpectedCallStart=function(e){if(e[0]==="CALL_START"&&e.generated){return true}};return t}(i)},{"./empty_constructor_needs_parens.coffee":13}],35:[function(e,t,n){var r,i=[].indexOf||function(e){for(var t=0,n=this.length;t=0);if(n&&e.spaced||!n&&!e.spaced&&!e.newLine){return{context:e[1]}}else{return null}};e.prototype.lintMath=function(e,t){if(!e.spaced&&!e.newLine){return{context:e[1]}}else{return null}};e.prototype.isInExtendedRegex=function(){var e,t,n,r;r=this.callTokens;for(t=0,n=r.length;t=0&&this._ltIndex-1&&!t[u.type].hide){u.channel=t[u.type].channel;this._token=u;this._lt.push(u);this._ltIndexCache.push(this._lt.length-this._ltIndex+i);if(this._lt.length>5){this._lt.shift()}if(this._ltIndexCache.length>5){this._ltIndexCache.shift()}this._ltIndex=this._lt.length}a=t[u.type];if(a&&(a.hide||a.channel!==undefined&&e!==a.channel)){return this.get(e)}else{return u.type}},LA:function(e){var t=e,n;if(e>0){if(e>5){throw new Error("Too much lookahead.")}while(t){n=this.get();t--}while(tthis._tokenData.length){return"UNKNOWN_TOKEN"}else{return this._tokenData[e].name}},tokenType:function(e){return this._tokenData[e]||-1},unget:function(){if(this._ltIndexCache.length){this._ltIndex-=this._ltIndexCache.pop();this._token=this._lt[this._ltIndex-1]}else{throw new Error("Too much lookahead.")}}};parserlib.util={StringReader:t,SyntaxError:n,SyntaxUnit:r,EventTarget:e,TokenStreamBase:i}})();(function(){function Combinator(e,t,n){SyntaxUnit.call(this,e,t,n,Parser.COMBINATOR_TYPE);this.type="unknown";if(/^\s+$/.test(e)){this.type="descendant"}else if(e==">"){this.type="child"}else if(e=="+"){this.type="adjacent-sibling"}else if(e=="~"){this.type="sibling"}}function MediaFeature(e,t){SyntaxUnit.call(this,"("+e+(t!==null?":"+t:"")+")",e.startLine,e.startCol,Parser.MEDIA_FEATURE_TYPE);this.name=e;this.value=t}function MediaQuery(e,t,n,r,i){SyntaxUnit.call(this,(e?e+" ":"")+(t?t:"")+(t&&n.length>0?" and ":"")+n.join(" and "),r,i,Parser.MEDIA_QUERY_TYPE);this.modifier=e;this.mediaType=t;this.features=n}function Parser(e){EventTarget.call(this);this.options=e||{};this._tokenStream=null}function PropertyName(e,t,n,r){SyntaxUnit.call(this,e,n,r,Parser.PROPERTY_NAME_TYPE);this.hack=t}function PropertyValue(e,t,n){SyntaxUnit.call(this,e.join(" "),t,n,Parser.PROPERTY_VALUE_TYPE);this.parts=e}function PropertyValueIterator(e){this._i=0;this._parts=e.parts;this._marks=[];this.value=e}function PropertyValuePart(text,line,col){SyntaxUnit.call(this,text,line,col,Parser.PROPERTY_VALUE_PART_TYPE);this.type="unknown";var temp;if(/^([+\-]?[\d\.]+)([a-z]+)$/i.test(text)){this.type="dimension";this.value=+RegExp.$1;this.units=RegExp.$2;switch(this.units.toLowerCase()){case"em":case"rem":case"ex":case"px":case"cm":case"mm":case"in":case"pt":case"pc":case"ch":case"vh":case"vw":case"vm":this.type="length";break;case"deg":case"rad":case"grad":this.type="angle";break;case"ms":case"s":this.type="time";break;case"hz":case"khz":this.type="frequency";break;case"dpi":case"dpcm":this.type="resolution";break}}else if(/^([+\-]?[\d\.]+)%$/i.test(text)){this.type="percentage";this.value=+RegExp.$1}else if(/^([+\-]?[\d\.]+)%$/i.test(text)){this.type="percentage";this.value=+RegExp.$1}else if(/^([+\-]?\d+)$/i.test(text)){this.type="integer";this.value=+RegExp.$1}else if(/^([+\-]?[\d\.]+)$/i.test(text)){this.type="number";this.value=+RegExp.$1}else if(/^#([a-f0-9]{3,6})/i.test(text)){this.type="color";temp=RegExp.$1;if(temp.length==3){this.red=parseInt(temp.charAt(0)+temp.charAt(0),16);this.green=parseInt(temp.charAt(1)+temp.charAt(1),16);this.blue=parseInt(temp.charAt(2)+temp.charAt(2),16)}else{this.red=parseInt(temp.substring(0,2),16);this.green=parseInt(temp.substring(2,4),16);this.blue=parseInt(temp.substring(4,6),16)}}else if(/^rgb\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\)/i.test(text)){this.type="color";this.red=+RegExp.$1;this.green=+RegExp.$2;this.blue=+RegExp.$3}else if(/^rgb\(\s*(\d+)%\s*,\s*(\d+)%\s*,\s*(\d+)%\s*\)/i.test(text)){this.type="color";this.red=+RegExp.$1*255/100;this.green=+RegExp.$2*255/100;this.blue=+RegExp.$3*255/100}else if(/^rgba\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*,\s*([\d\.]+)\s*\)/i.test(text)){this.type="color";this.red=+RegExp.$1;this.green=+RegExp.$2;this.blue=+RegExp.$3;this.alpha=+RegExp.$4}else if(/^rgba\(\s*(\d+)%\s*,\s*(\d+)%\s*,\s*(\d+)%\s*,\s*([\d\.]+)\s*\)/i.test(text)){this.type="color";this.red=+RegExp.$1*255/100;this.green=+RegExp.$2*255/100;this.blue=+RegExp.$3*255/100;this.alpha=+RegExp.$4}else if(/^hsl\(\s*(\d+)\s*,\s*(\d+)%\s*,\s*(\d+)%\s*\)/i.test(text)){this.type="color";this.hue=+RegExp.$1;this.saturation=+RegExp.$2/100;this.lightness=+RegExp.$3/100}else if(/^hsla\(\s*(\d+)\s*,\s*(\d+)%\s*,\s*(\d+)%\s*,\s*([\d\.]+)\s*\)/i.test(text)){this.type="color";this.hue=+RegExp.$1;this.saturation=+RegExp.$2/100;this.lightness=+RegExp.$3/100;this.alpha=+RegExp.$4}else if(/^url\(["']?([^\)"']+)["']?\)/i.test(text)){this.type="uri";this.uri=RegExp.$1}else if(/^([^\(]+)\(/i.test(text)){this.type="function";this.name=RegExp.$1;this.value=text}else if(/^["'][^"']*["']/.test(text)){this.type="string";this.value=eval(text)}else if(Colors[text.toLowerCase()]){this.type="color";temp=Colors[text.toLowerCase()].substring(1);this.red=parseInt(temp.substring(0,2),16);this.green=parseInt(temp.substring(2,4),16);this.blue=parseInt(temp.substring(4,6),16)}else if(/^[\,\/]$/.test(text)){this.type="operator";this.value=text}else if(/^[a-z\-\u0080-\uFFFF][a-z0-9\-\u0080-\uFFFF]*$/i.test(text)){this.type="identifier";this.value=text}}function Selector(e,t,n){SyntaxUnit.call(this,e.join(" "),t,n,Parser.SELECTOR_TYPE);this.parts=e;this.specificity=Specificity.calculate(this)}function SelectorPart(e,t,n,r,i){SyntaxUnit.call(this,n,r,i,Parser.SELECTOR_PART_TYPE);this.elementName=e;this.modifiers=t}function SelectorSubPart(e,t,n,r){SyntaxUnit.call(this,e,n,r,Parser.SELECTOR_SUB_PART_TYPE);this.type=t;this.args=[]}function Specificity(e,t,n,r){this.a=e;this.b=t;this.c=n;this.d=r}function isHexDigit(e){return e!==null&&h.test(e)}function isDigit(e){return e!==null&&/\d/.test(e)}function isWhitespace(e){return e!==null&&/\s/.test(e)}function isNewLine(e){return e!==null&&nl.test(e)}function isNameStart(e){return e!==null&&/[a-z_\u0080-\uFFFF\\]/i.test(e)}function isNameChar(e){return e!==null&&(isNameStart(e)||/[0-9\-\\]/.test(e))}function isIdentStart(e){return e!==null&&(isNameStart(e)||/\-\\/.test(e))}function mix(e,t){for(var n in t){if(t.hasOwnProperty(n)){e[n]=t[n]}}return e}function TokenStream(e){TokenStreamBase.call(this,e,Tokens)}function ValidationError(e,t,n){this.col=n;this.line=t;this.message=e}var EventTarget=parserlib.util.EventTarget,TokenStreamBase=parserlib.util.TokenStreamBase,StringReader=parserlib.util.StringReader,SyntaxError=parserlib.util.SyntaxError,SyntaxUnit=parserlib.util.SyntaxUnit;var Colors={aliceblue:"#f0f8ff",antiquewhite:"#faebd7",aqua:"#00ffff",aquamarine:"#7fffd4",azure:"#f0ffff",beige:"#f5f5dc",bisque:"#ffe4c4",black:"#000000",blanchedalmond:"#ffebcd",blue:"#0000ff",blueviolet:"#8a2be2",brown:"#a52a2a",burlywood:"#deb887",cadetblue:"#5f9ea0",chartreuse:"#7fff00",chocolate:"#d2691e",coral:"#ff7f50",cornflowerblue:"#6495ed",cornsilk:"#fff8dc",crimson:"#dc143c",cyan:"#00ffff",darkblue:"#00008b",darkcyan:"#008b8b",darkgoldenrod:"#b8860b",darkgray:"#a9a9a9",darkgreen:"#006400",darkkhaki:"#bdb76b",darkmagenta:"#8b008b",darkolivegreen:"#556b2f",darkorange:"#ff8c00",darkorchid:"#9932cc",darkred:"#8b0000",darksalmon:"#e9967a",darkseagreen:"#8fbc8f",darkslateblue:"#483d8b",darkslategray:"#2f4f4f",darkturquoise:"#00ced1",darkviolet:"#9400d3",deeppink:"#ff1493",deepskyblue:"#00bfff",dimgray:"#696969",dodgerblue:"#1e90ff",firebrick:"#b22222",floralwhite:"#fffaf0",forestgreen:"#228b22",fuchsia:"#ff00ff",gainsboro:"#dcdcdc",ghostwhite:"#f8f8ff",gold:"#ffd700",goldenrod:"#daa520",gray:"#808080",green:"#008000",greenyellow:"#adff2f",honeydew:"#f0fff0",hotpink:"#ff69b4",indianred:"#cd5c5c",indigo:"#4b0082",ivory:"#fffff0",khaki:"#f0e68c",lavender:"#e6e6fa",lavenderblush:"#fff0f5",lawngreen:"#7cfc00",lemonchiffon:"#fffacd",lightblue:"#add8e6",lightcoral:"#f08080",lightcyan:"#e0ffff",lightgoldenrodyellow:"#fafad2",lightgray:"#d3d3d3",lightgreen:"#90ee90",lightpink:"#ffb6c1",lightsalmon:"#ffa07a",lightseagreen:"#20b2aa",lightskyblue:"#87cefa",lightslategray:"#778899",lightsteelblue:"#b0c4de",lightyellow:"#ffffe0",lime:"#00ff00",limegreen:"#32cd32",linen:"#faf0e6",magenta:"#ff00ff",maroon:"#800000",mediumaquamarine:"#66cdaa",mediumblue:"#0000cd",mediumorchid:"#ba55d3",mediumpurple:"#9370d8",mediumseagreen:"#3cb371",mediumslateblue:"#7b68ee",mediumspringgreen:"#00fa9a",mediumturquoise:"#48d1cc",mediumvioletred:"#c71585",midnightblue:"#191970",mintcream:"#f5fffa",mistyrose:"#ffe4e1",moccasin:"#ffe4b5",navajowhite:"#ffdead",navy:"#000080",oldlace:"#fdf5e6",olive:"#808000",olivedrab:"#6b8e23",orange:"#ffa500",orangered:"#ff4500",orchid:"#da70d6",palegoldenrod:"#eee8aa",palegreen:"#98fb98",paleturquoise:"#afeeee",palevioletred:"#d87093",papayawhip:"#ffefd5",peachpuff:"#ffdab9",peru:"#cd853f",pink:"#ffc0cb",plum:"#dda0dd",powderblue:"#b0e0e6",purple:"#800080",red:"#ff0000",rosybrown:"#bc8f8f",royalblue:"#4169e1",saddlebrown:"#8b4513",salmon:"#fa8072",sandybrown:"#f4a460",seagreen:"#2e8b57",seashell:"#fff5ee",sienna:"#a0522d",silver:"#c0c0c0",skyblue:"#87ceeb",slateblue:"#6a5acd",slategray:"#708090",snow:"#fffafa",springgreen:"#00ff7f",steelblue:"#4682b4",tan:"#d2b48c",teal:"#008080",thistle:"#d8bfd8",tomato:"#ff6347",turquoise:"#40e0d0",violet:"#ee82ee",wheat:"#f5deb3",white:"#ffffff",whitesmoke:"#f5f5f5",yellow:"#ffff00",yellowgreen:"#9acd32",activeBorder:"Active window border.",activecaption:"Active window caption.",appworkspace:"Background color of multiple document interface.",background:"Desktop background.",buttonface:"The face background color for 3-D elements that appear 3-D due to one layer of surrounding border.",buttonhighlight:"The color of the border facing the light source for 3-D elements that appear 3-D due to one layer of surrounding border.",buttonshadow:"The color of the border away from the light source for 3-D elements that appear 3-D due to one layer of surrounding border.",buttontext:"Text on push buttons.",captiontext:"Text in caption, size box, and scrollbar arrow box.",graytext:"Grayed (disabled) text. This color is set to #000 if the current display driver does not support a solid gray color.",highlight:"Item(s) selected in a control.",highlighttext:"Text of item(s) selected in a control.",inactiveborder:"Inactive window border.",inactivecaption:"Inactive window caption.",inactivecaptiontext:"Color of text in an inactive caption.",infobackground:"Background color for tooltip controls.",infotext:"Text color for tooltip controls.",menu:"Menu background.",menutext:"Text in menus.",scrollbar:"Scroll bar gray area.",threeddarkshadow:"The color of the darker (generally outer) of the two borders away from the light source for 3-D elements that appear 3-D due to two concentric layers of surrounding border.",threedface:"The face background color for 3-D elements that appear 3-D due to two concentric layers of surrounding border.",threedhighlight:"The color of the lighter (generally outer) of the two borders facing the light source for 3-D elements that appear 3-D due to two concentric layers of surrounding border.",threedlightshadow:"The color of the darker (generally inner) of the two borders facing the light source for 3-D elements that appear 3-D due to two concentric layers of surrounding border.",threedshadow:"The color of the lighter (generally inner) of the two borders away from the light source for 3-D elements that appear 3-D due to two concentric layers of surrounding border.",window:"Window background.",windowframe:"Window frame.",windowtext:"Text in windows."};Combinator.prototype=new SyntaxUnit;Combinator.prototype.constructor=Combinator;MediaFeature.prototype=new SyntaxUnit;MediaFeature.prototype.constructor=MediaFeature;MediaQuery.prototype=new SyntaxUnit;MediaQuery.prototype.constructor=MediaQuery;Parser.DEFAULT_TYPE=0;Parser.COMBINATOR_TYPE=1;Parser.MEDIA_FEATURE_TYPE=2;Parser.MEDIA_QUERY_TYPE=3;Parser.PROPERTY_NAME_TYPE=4;Parser.PROPERTY_VALUE_TYPE=5;Parser.PROPERTY_VALUE_PART_TYPE=6;Parser.SELECTOR_TYPE=7;Parser.SELECTOR_PART_TYPE=8;Parser.SELECTOR_SUB_PART_TYPE=9;Parser.prototype=function(){var e=new EventTarget,t,n={constructor:Parser,DEFAULT_TYPE:0,COMBINATOR_TYPE:1,MEDIA_FEATURE_TYPE:2,MEDIA_QUERY_TYPE:3,PROPERTY_NAME_TYPE:4,PROPERTY_VALUE_TYPE:5,PROPERTY_VALUE_PART_TYPE:6,SELECTOR_TYPE:7,SELECTOR_PART_TYPE:8,SELECTOR_SUB_PART_TYPE:9,_stylesheet:function(){var e=this._tokenStream,t=null,n,r,i;this.fire("startstylesheet");this._charset();this._skipCruft();while(e.peek()==Tokens.IMPORT_SYM){this._import();this._skipCruft()}while(e.peek()==Tokens.NAMESPACE_SYM){this._namespace();this._skipCruft()}i=e.peek();while(i>Tokens.EOF){try{switch(i){case Tokens.MEDIA_SYM:this._media();this._skipCruft();break;case Tokens.PAGE_SYM:this._page();this._skipCruft();break;case Tokens.FONT_FACE_SYM:this._font_face();this._skipCruft();break;case Tokens.KEYFRAMES_SYM:this._keyframes();this._skipCruft();break;case Tokens.VIEWPORT_SYM:this._viewport();this._skipCruft();break;case Tokens.UNKNOWN_SYM:e.get();if(!this.options.strict){this.fire({type:"error",error:null,message:"Unknown @ rule: "+e.LT(0).value+".",line:e.LT(0).startLine,col:e.LT(0).startCol});n=0;while(e.advance([Tokens.LBRACE,Tokens.RBRACE])==Tokens.LBRACE){n++}while(n){e.advance([Tokens.RBRACE]);n--}}else{throw new SyntaxError("Unknown @ rule.",e.LT(0).startLine,e.LT(0).startCol)}break;case Tokens.S:this._readWhitespace();break;default:if(!this._ruleset()){switch(i){case Tokens.CHARSET_SYM:r=e.LT(1);this._charset(false);throw new SyntaxError("@charset not allowed here.",r.startLine,r.startCol);case Tokens.IMPORT_SYM:r=e.LT(1);this._import(false);throw new SyntaxError("@import not allowed here.",r.startLine,r.startCol);case Tokens.NAMESPACE_SYM:r=e.LT(1);this._namespace(false);throw new SyntaxError("@namespace not allowed here.",r.startLine,r.startCol);default:e.get();this._unexpectedToken(e.token())}}}}catch(s){if(s instanceof SyntaxError&&!this.options.strict){this.fire({type:"error",error:s,message:s.message,line:s.line,col:s.col})}else{throw s}}i=e.peek()}if(i!=Tokens.EOF){this._unexpectedToken(e.token())}this.fire("endstylesheet")},_charset:function(e){var t=this._tokenStream,n,r,i,s;if(t.match(Tokens.CHARSET_SYM)){i=t.token().startLine;s=t.token().startCol;this._readWhitespace();t.mustMatch(Tokens.STRING);r=t.token();n=r.value;this._readWhitespace();t.mustMatch(Tokens.SEMICOLON);if(e!==false){this.fire({type:"charset",charset:n,line:i,col:s})}}},_import:function(e){var t=this._tokenStream,n,r,i,s=[];t.mustMatch(Tokens.IMPORT_SYM);i=t.token();this._readWhitespace();t.mustMatch([Tokens.STRING,Tokens.URI]);r=t.token().value.replace(/(?:url\()?["']([^"']+)["']\)?/,"$1");this._readWhitespace();s=this._media_query_list();t.mustMatch(Tokens.SEMICOLON);this._readWhitespace();if(e!==false){this.fire({type:"import",uri:r,media:s,line:i.startLine,col:i.startCol})}},_namespace:function(e){var t=this._tokenStream,n,r,i,s;t.mustMatch(Tokens.NAMESPACE_SYM);n=t.token().startLine;r=t.token().startCol;this._readWhitespace();if(t.match(Tokens.IDENT)){i=t.token().value;this._readWhitespace()}t.mustMatch([Tokens.STRING,Tokens.URI]);s=t.token().value.replace(/(?:url\()?["']([^"']+)["']\)?/,"$1");this._readWhitespace();t.mustMatch(Tokens.SEMICOLON);this._readWhitespace();if(e!==false){this.fire({type:"namespace",prefix:i,uri:s,line:n,col:r})}},_media:function(){var e=this._tokenStream,t,n,r;e.mustMatch(Tokens.MEDIA_SYM);t=e.token().startLine;n=e.token().startCol;this._readWhitespace();r=this._media_query_list();e.mustMatch(Tokens.LBRACE);this._readWhitespace();this.fire({type:"startmedia",media:r,line:t,col:n});while(true){if(e.peek()==Tokens.PAGE_SYM){this._page()}else if(e.peek()==Tokens.FONT_FACE_SYM){this._font_face()}else if(!this._ruleset()){break}}e.mustMatch(Tokens.RBRACE);this._readWhitespace();this.fire({type:"endmedia",media:r,line:t,col:n})},_media_query_list:function(){var e=this._tokenStream,t=[];this._readWhitespace();if(e.peek()==Tokens.IDENT||e.peek()==Tokens.LPAREN){t.push(this._media_query())}while(e.match(Tokens.COMMA)){this._readWhitespace();t.push(this._media_query())}return t},_media_query:function(){var e=this._tokenStream,t=null,n=null,r=null,i=[];if(e.match(Tokens.IDENT)){n=e.token().value.toLowerCase();if(n!="only"&&n!="not"){e.unget();n=null}else{r=e.token()}}this._readWhitespace();if(e.peek()==Tokens.IDENT){t=this._media_type();if(r===null){r=e.token()}}else if(e.peek()==Tokens.LPAREN){if(r===null){r=e.LT(1)}i.push(this._media_expression())}if(t===null&&i.length===0){return null}else{this._readWhitespace();while(e.match(Tokens.IDENT)){if(e.token().value.toLowerCase()!="and"){this._unexpectedToken(e.token())}this._readWhitespace();i.push(this._media_expression())}}return new MediaQuery(n,t,i,r.startLine,r.startCol)},_media_type:function(){return this._media_feature()},_media_expression:function(){var e=this._tokenStream,t=null,n,r=null;e.mustMatch(Tokens.LPAREN);t=this._media_feature();this._readWhitespace();if(e.match(Tokens.COLON)){this._readWhitespace();n=e.LT(1);r=this._expression()}e.mustMatch(Tokens.RPAREN);this._readWhitespace();return new MediaFeature(t,r?new SyntaxUnit(r,n.startLine,n.startCol):null)},_media_feature:function(){var e=this._tokenStream;e.mustMatch(Tokens.IDENT);return SyntaxUnit.fromToken(e.token())},_page:function(){var e=this._tokenStream,t,n,r=null,i=null;e.mustMatch(Tokens.PAGE_SYM);t=e.token().startLine;n=e.token().startCol;this._readWhitespace();if(e.match(Tokens.IDENT)){r=e.token().value;if(r.toLowerCase()==="auto"){this._unexpectedToken(e.token())}}if(e.peek()==Tokens.COLON){i=this._pseudo_page()}this._readWhitespace();this.fire({type:"startpage",id:r,pseudo:i,line:t,col:n});this._readDeclarations(true,true);this.fire({type:"endpage",id:r,pseudo:i,line:t,col:n})},_margin:function(){var e=this._tokenStream,t,n,r=this._margin_sym();if(r){t=e.token().startLine;n=e.token().startCol;this.fire({type:"startpagemargin",margin:r,line:t,col:n});this._readDeclarations(true);this.fire({type:"endpagemargin",margin:r,line:t,col:n});return true}else{return false}},_margin_sym:function(){var e=this._tokenStream;if(e.match([Tokens.TOPLEFTCORNER_SYM,Tokens.TOPLEFT_SYM,Tokens.TOPCENTER_SYM,Tokens.TOPRIGHT_SYM,Tokens.TOPRIGHTCORNER_SYM,Tokens.BOTTOMLEFTCORNER_SYM,Tokens.BOTTOMLEFT_SYM,Tokens.BOTTOMCENTER_SYM,Tokens.BOTTOMRIGHT_SYM,Tokens.BOTTOMRIGHTCORNER_SYM,Tokens.LEFTTOP_SYM,Tokens.LEFTMIDDLE_SYM,Tokens.LEFTBOTTOM_SYM,Tokens.RIGHTTOP_SYM,Tokens.RIGHTMIDDLE_SYM,Tokens.RIGHTBOTTOM_SYM])){return SyntaxUnit.fromToken(e.token())}else{return null}},_pseudo_page:function(){var e=this._tokenStream;e.mustMatch(Tokens.COLON);e.mustMatch(Tokens.IDENT);return e.token().value},_font_face:function(){var e=this._tokenStream,t,n;e.mustMatch(Tokens.FONT_FACE_SYM);t=e.token().startLine;n=e.token().startCol;this._readWhitespace();this.fire({type:"startfontface",line:t,col:n});this._readDeclarations(true);this.fire({type:"endfontface",line:t,col:n})},_viewport:function(){var e=this._tokenStream,t,n;e.mustMatch(Tokens.VIEWPORT_SYM);t=e.token().startLine;n=e.token().startCol;this._readWhitespace();this.fire({type:"startviewport",line:t,col:n});this._readDeclarations(true);this.fire({type:"endviewport",line:t,col:n})},_operator:function(e){var t=this._tokenStream,n=null;if(t.match([Tokens.SLASH,Tokens.COMMA])||e&&t.match([Tokens.PLUS,Tokens.STAR,Tokens.MINUS])){n=t.token();this._readWhitespace()}return n?PropertyValuePart.fromToken(n):null},_combinator:function(){var e=this._tokenStream,t=null,n;if(e.match([Tokens.PLUS,Tokens.GREATER,Tokens.TILDE])){n=e.token();t=new Combinator(n.value,n.startLine,n.startCol);this._readWhitespace()}return t},_unary_operator:function(){var e=this._tokenStream;if(e.match([Tokens.MINUS,Tokens.PLUS])){return e.token().value}else{return null}},_property:function(){var e=this._tokenStream,t=null,n=null,r,i,s,o;if(e.peek()==Tokens.STAR&&this.options.starHack){e.get();i=e.token();n=i.value;s=i.startLine;o=i.startCol}if(e.match(Tokens.IDENT)){i=e.token();r=i.value;if(r.charAt(0)=="_"&&this.options.underscoreHack){n="_";r=r.substring(1)}t=new PropertyName(r,n,s||i.startLine,o||i.startCol);this._readWhitespace()}return t},_ruleset:function(){var e=this._tokenStream,t,n;try{n=this._selectors_group()}catch(r){if(r instanceof SyntaxError&&!this.options.strict){this.fire({type:"error",error:r,message:r.message,line:r.line,col:r.col});t=e.advance([Tokens.RBRACE]);if(t==Tokens.RBRACE){}else{throw r}}else{throw r}return true}if(n){this.fire({type:"startrule",selectors:n,line:n[0].line,col:n[0].col});this._readDeclarations(true);this.fire({type:"endrule",selectors:n,line:n[0].line,col:n[0].col})}return n},_selectors_group:function(){var e=this._tokenStream,t=[],n;n=this._selector();if(n!==null){t.push(n);while(e.match(Tokens.COMMA)){this._readWhitespace();n=this._selector();if(n!==null){t.push(n)}else{this._unexpectedToken(e.LT(1))}}}return t.length?t:null},_selector:function(){var e=this._tokenStream,t=[],n=null,r=null,i=null;n=this._simple_selector_sequence();if(n===null){return null}t.push(n);do{r=this._combinator();if(r!==null){t.push(r);n=this._simple_selector_sequence();if(n===null){this._unexpectedToken(e.LT(1))}else{t.push(n)}}else{if(this._readWhitespace()){i=new Combinator(e.token().value,e.token().startLine,e.token().startCol);r=this._combinator();n=this._simple_selector_sequence();if(n===null){if(r!==null){this._unexpectedToken(e.LT(1))}}else{if(r!==null){t.push(r)}else{t.push(i)}t.push(n)}}else{break}}}while(true);return new Selector(t,t[0].line,t[0].col)},_simple_selector_sequence:function(){var e=this._tokenStream,t=null,n=[],r="",i=[function(){return e.match(Tokens.HASH)?new SelectorSubPart(e.token().value,"id",e.token().startLine,e.token().startCol):null},this._class,this._attrib,this._pseudo,this._negation],s=0,o=i.length,u=null,a=false,f,l;f=e.LT(1).startLine;l=e.LT(1).startCol;t=this._type_selector();if(!t){t=this._universal()}if(t!==null){r+=t}while(true){if(e.peek()===Tokens.S){break}while(s1){e.unget()}}return null}else{if(t){n.text=t+n.text;n.col-=t.length}return n}},_class:function(){var e=this._tokenStream,t;if(e.match(Tokens.DOT)){e.mustMatch(Tokens.IDENT);t=e.token();return new SelectorSubPart("."+t.value,"class",t.startLine,t.startCol-1)}else{return null}},_element_name:function(){var e=this._tokenStream,t;if(e.match(Tokens.IDENT)){t=e.token();return new SelectorSubPart(t.value,"elementName",t.startLine,t.startCol)}else{return null}},_namespace_prefix:function(){var e=this._tokenStream,t="";if(e.LA(1)===Tokens.PIPE||e.LA(2)===Tokens.PIPE){if(e.match([Tokens.IDENT,Tokens.STAR])){t+=e.token().value}e.mustMatch(Tokens.PIPE);t+="|"}return t.length?t:null},_universal:function(){var e=this._tokenStream,t="",n;n=this._namespace_prefix();if(n){t+=n}if(e.match(Tokens.STAR)){t+="*"}return t.length?t:null},_attrib:function(){var e=this._tokenStream,t=null,n,r;if(e.match(Tokens.LBRACKET)){r=e.token();t=r.value;t+=this._readWhitespace();n=this._namespace_prefix();if(n){t+=n}e.mustMatch(Tokens.IDENT);t+=e.token().value;t+=this._readWhitespace();if(e.match([Tokens.PREFIXMATCH,Tokens.SUFFIXMATCH,Tokens.SUBSTRINGMATCH,Tokens.EQUALS,Tokens.INCLUDES,Tokens.DASHMATCH])){t+=e.token().value;t+=this._readWhitespace();e.mustMatch([Tokens.IDENT,Tokens.STRING]);t+=e.token().value;t+=this._readWhitespace()}e.mustMatch(Tokens.RBRACKET);return new SelectorSubPart(t+"]","attribute",r.startLine,r.startCol)}else{return null}},_pseudo:function(){var e=this._tokenStream,t=null,n=":",r,i;if(e.match(Tokens.COLON)){if(e.match(Tokens.COLON)){n+=":"}if(e.match(Tokens.IDENT)){t=e.token().value;r=e.token().startLine;i=e.token().startCol-n.length}else if(e.peek()==Tokens.FUNCTION){r=e.LT(1).startLine;i=e.LT(1).startCol-n.length;t=this._functional_pseudo()}if(t){t=new SelectorSubPart(n+t,"pseudo",r,i)}}return t},_functional_pseudo:function(){var e=this._tokenStream,t=null;if(e.match(Tokens.FUNCTION)){t=e.token().value;t+=this._readWhitespace();t+=this._expression();e.mustMatch(Tokens.RPAREN);t+=")"}return t},_expression:function(){var e=this._tokenStream,t="";while(e.match([Tokens.PLUS,Tokens.MINUS,Tokens.DIMENSION,Tokens.NUMBER,Tokens.STRING,Tokens.IDENT,Tokens.LENGTH,Tokens.FREQ,Tokens.ANGLE,Tokens.TIME,Tokens.RESOLUTION,Tokens.SLASH])){t+=e.token().value;t+=this._readWhitespace()}return t.length?t:null},_negation:function(){var e=this._tokenStream,t,n,r="",i,s=null;if(e.match(Tokens.NOT)){r=e.token().value;t=e.token().startLine;n=e.token().startCol;r+=this._readWhitespace();i=this._negation_arg();r+=i;r+=this._readWhitespace();e.match(Tokens.RPAREN);r+=e.token().value;s=new SelectorSubPart(r,"not",t,n);s.args.push(i)}return s},_negation_arg:function(){var e=this._tokenStream,t=[this._type_selector,this._universal,function(){return e.match(Tokens.HASH)?new SelectorSubPart(e.token().value,"id",e.token().startLine,e.token().startCol):null},this._class,this._attrib,this._pseudo],n=null,r=0,i=t.length,s,o,u,a;o=e.LT(1).startLine;u=e.LT(1).startCol;while(r0?new PropertyValue(n,n[0].line,n[0].col):null},_term:function(){var e=this._tokenStream,t=null,n=null,r,i,s;t=this._unary_operator();if(t!==null){i=e.token().startLine;s=e.token().startCol}if(e.peek()==Tokens.IE_FUNCTION&&this.options.ieFilters){n=this._ie_function();if(t===null){i=e.token().startLine;s=e.token().startCol}}else if(e.match([Tokens.NUMBER,Tokens.PERCENTAGE,Tokens.LENGTH,Tokens.ANGLE,Tokens.TIME,Tokens.FREQ,Tokens.STRING,Tokens.IDENT,Tokens.URI,Tokens.UNICODE_RANGE])){n=e.token().value;if(t===null){i=e.token().startLine;s=e.token().startCol}this._readWhitespace()}else{r=this._hexcolor();if(r===null){if(t===null){i=e.LT(1).startLine;s=e.LT(1).startCol}if(n===null){if(e.LA(3)==Tokens.EQUALS&&this.options.ieFilters){n=this._ie_function()}else{n=this._function()}}}else{n=r.value;if(t===null){i=r.startLine;s=r.startCol}}}return n!==null?new PropertyValuePart(t!==null?t+n:n,i,s):null},_function:function(){var e=this._tokenStream,t=null,n=null,r;if(e.match(Tokens.FUNCTION)){t=e.token().value;this._readWhitespace();n=this._expr(true);t+=n;if(this.options.ieFilters&&e.peek()==Tokens.EQUALS){do{if(this._readWhitespace()){t+=e.token().value}if(e.LA(0)==Tokens.COMMA){t+=e.token().value}e.match(Tokens.IDENT);t+=e.token().value;e.match(Tokens.EQUALS);t+=e.token().value;r=e.peek();while(r!=Tokens.COMMA&&r!=Tokens.S&&r!=Tokens.RPAREN){e.get();t+=e.token().value;r=e.peek()}}while(e.match([Tokens.COMMA,Tokens.S]))}e.match(Tokens.RPAREN);t+=")";this._readWhitespace()}return t},_ie_function:function(){var e=this._tokenStream,t=null,n=null,r;if(e.match([Tokens.IE_FUNCTION,Tokens.FUNCTION])){t=e.token().value;do{if(this._readWhitespace()){t+=e.token().value}if(e.LA(0)==Tokens.COMMA){t+=e.token().value}e.match(Tokens.IDENT);t+=e.token().value;e.match(Tokens.EQUALS);t+=e.token().value;r=e.peek();while(r!=Tokens.COMMA&&r!=Tokens.S&&r!=Tokens.RPAREN){e.get();t+=e.token().value;r=e.peek()}}while(e.match([Tokens.COMMA,Tokens.S]));e.match(Tokens.RPAREN);t+=")";this._readWhitespace()}return t},_hexcolor:function(){var e=this._tokenStream,t=null,n;if(e.match(Tokens.HASH)){t=e.token();n=t.value;if(!/#[a-f0-9]{3,6}/i.test(n)){throw new SyntaxError("Expected a hex color but found '"+n+"' at line "+t.startLine+", col "+t.startCol+".",t.startLine,t.startCol)}this._readWhitespace()}return t},_keyframes:function(){var e=this._tokenStream,t,n,r,i="";e.mustMatch(Tokens.KEYFRAMES_SYM);t=e.token();if(/^@\-([^\-]+)\-/.test(t.value)){i=RegExp.$1}this._readWhitespace();r=this._keyframe_name();this._readWhitespace();e.mustMatch(Tokens.LBRACE);this.fire({type:"startkeyframes",name:r,prefix:i,line:t.startLine,col:t.startCol});this._readWhitespace();n=e.peek();while(n==Tokens.IDENT||n==Tokens.PERCENTAGE){this._keyframe_rule();this._readWhitespace();n=e.peek()}this.fire({type:"endkeyframes",name:r,prefix:i,line:t.startLine,col:t.startCol});this._readWhitespace();e.mustMatch(Tokens.RBRACE)},_keyframe_name:function(){var e=this._tokenStream,t;e.mustMatch([Tokens.IDENT,Tokens.STRING]);return SyntaxUnit.fromToken(e.token())},_keyframe_rule:function(){var e=this._tokenStream,t,n=this._key_list();this.fire({type:"startkeyframerule",keys:n,line:n[0].line,col:n[0].col});this._readDeclarations(true);this.fire({type:"endkeyframerule",keys:n,line:n[0].line,col:n[0].col})},_key_list:function(){var e=this._tokenStream,t,n,r=[];r.push(this._key());this._readWhitespace();while(e.match(Tokens.COMMA)){this._readWhitespace();r.push(this._key());this._readWhitespace()}return r},_key:function(){var e=this._tokenStream,t;if(e.match(Tokens.PERCENTAGE)){return SyntaxUnit.fromToken(e.token())}else if(e.match(Tokens.IDENT)){t=e.token();if(/from|to/i.test(t.value)){return SyntaxUnit.fromToken(t)}e.unget()}this._unexpectedToken(e.LT(1))},_skipCruft:function(){while(this._tokenStream.match([Tokens.S,Tokens.CDO,Tokens.CDC])){}},_readDeclarations:function(e,t){var n=this._tokenStream,r;this._readWhitespace();if(e){n.mustMatch(Tokens.LBRACE)}this._readWhitespace();try{while(true){if(n.match(Tokens.SEMICOLON)||t&&this._margin()){}else if(this._declaration()){if(!n.match(Tokens.SEMICOLON)){break}}else{break}this._readWhitespace()}n.mustMatch(Tokens.RBRACE);this._readWhitespace()}catch(i){if(i instanceof SyntaxError&&!this.options.strict){this.fire({type:"error",error:i,message:i.message,line:i.line,col:i.col});r=n.advance([Tokens.SEMICOLON,Tokens.RBRACE]);if(r==Tokens.SEMICOLON){this._readDeclarations(false,t)}else if(r!=Tokens.RBRACE){throw i}}else{throw i}}},_readWhitespace:function(){var e=this._tokenStream,t="";while(e.match(Tokens.S)){t+=e.token().value}return t},_unexpectedToken:function(e){throw new SyntaxError("Unexpected token '"+e.value+"' at line "+e.startLine+", col "+e.startCol+".",e.startLine,e.startCol)},_verifyEnd:function(){if(this._tokenStream.LA(1)!=Tokens.EOF){this._unexpectedToken(this._tokenStream.LT(1))}},_validateProperty:function(e,t){Validation.validate(e,t)},parse:function(e){this._tokenStream=new TokenStream(e,Tokens);this._stylesheet()},parseStyleSheet:function(e){return this.parse(e)},parseMediaQuery:function(e){this._tokenStream=new TokenStream(e,Tokens);var t=this._media_query();this._verifyEnd();return t},parsePropertyValue:function(e){this._tokenStream=new TokenStream(e,Tokens);this._readWhitespace();var t=this._expr();this._readWhitespace();this._verifyEnd();return t},parseRule:function(e){this._tokenStream=new TokenStream(e,Tokens);this._readWhitespace();var t=this._ruleset();this._readWhitespace();this._verifyEnd();return t},parseSelector:function(e){this._tokenStream=new TokenStream(e,Tokens);this._readWhitespace();var t=this._selector();this._readWhitespace();this._verifyEnd();return t},parseStyleAttribute:function(e){e+="}";this._tokenStream=new TokenStream(e,Tokens);this._readDeclarations()}};for(t in n){if(n.hasOwnProperty(t)){e[t]=n[t]}}return e}();var Properties={"alignment-adjust":"auto | baseline | before-edge | text-before-edge | middle | central | after-edge | text-after-edge | ideographic | alphabetic | hanging | mathematical | | ","alignment-baseline":"baseline | use-script | before-edge | text-before-edge | after-edge | text-after-edge | central | middle | ideographic | alphabetic | hanging | mathematical",animation:1,"animation-delay":{multi:"
    +

    Linting

    + +
    + Show errors in + + + +
    +
    +
    + settings +
    + + +
    +
    -
    - JSHint show errors in: - - - - - -
    - -
    - - -
    - -
    - -
    - - -
    - -
    - CSSLint show errors in: - - - - - -
    - -
    - - -
    - -
    - -
    - - -
    - -
    - HTMLHint show errors in: - - - - - -
    - -
    - - -
    - -
    -
    +
    + settings +
    + + +
    +
    -
    - CoffeeLint show errors in: - - - - - +
    + + +
    + settings +
    + + +
    +
    -
    - - +
    + + +
    + settings +
    + + +
    +
    + + From 19ece34b4a6c153023afd7fe674eda64b9b41fc7 Mon Sep 17 00:00:00 2001 From: Giulia Alfonsi Date: Wed, 2 Jul 2014 14:43:36 +0100 Subject: [PATCH 270/321] Unified show settings for all lintings --- public/js/account/preferences-settings.js | 35 ++++++++++------------- public/js/editors/addons.js | 12 ++++---- 2 files changed, 22 insertions(+), 25 deletions(-) diff --git a/public/js/account/preferences-settings.js b/public/js/account/preferences-settings.js index 9d65a0f9..503df3ea 100644 --- a/public/js/account/preferences-settings.js +++ b/public/js/account/preferences-settings.js @@ -24,11 +24,11 @@ // Setup variables var $csrf = $('#_csrf'); - var hintsShow = { + var hintShow = { console: true, line: true, - under: false, - tooltip: true, + // under: false, + // tooltip: true, gutter: true }; var currentSettings = { @@ -36,18 +36,15 @@ includejs: true, focusedPanel: 'html', assetUrl: '', + hintShow: hintShow, jshint: true, jshintOptions: '', - jshintShow: hintsShow, csshint: false, csshintOptions: '', - csshintShow: hintsShow, htmlhint: false, htmlhintOptions: '', - htmlhintShow: hintsShow, coffeescripthint: false, coffeescripthintOptions: '', - coffeescripthintShow: hintsShow }; var $saveStatus = $('span.status'); var saveTimer = null; @@ -63,7 +60,7 @@ var $hintsOptWrapper = {}; var hintsOptionsVal = {}; var $hintsOptError = {}; - var $hintsShow = {}; + var $hintShow = {}; // var jshints = { // 'forin': 'About unsafe for..in', @@ -99,12 +96,11 @@ $hintsOptions[hints[m]] = $('#' + hints[m] + 'hintOptions') .val(hintsOptionsVal[hints[m]]); $hintsOptError[hints[m]] = $('#' + hints[m] + 'hintOptError'); - - $hintsShow[hints[m]] = {}; - for (var key in hintsShow) { - if (hintsShow.hasOwnProperty(key)) { - $hintsShow[hints[m]][key] = $('#' + hints[m] + 'hintShow-' + key).prop('checked', currentSettings[hints[m] + 'hintShow'][key]); - } + } + $hintShow = {}; + for (var key in hintShow) { + if (hintShow.hasOwnProperty(key)) { + $hintShow[key] = $('#hintShow-' + key).prop('checked', currentSettings.hintShow[key]); } } @@ -141,12 +137,11 @@ } catch (e) { $hintsOptError[ hints[m] ].html(e).addClass('show'); } - - localStorageSettings[ hints[m] + 'hintShow'] = {}; - for (var key in hintsShow) { - if (hintsShow.hasOwnProperty(key)) { - localStorageSettings[ hints[m] + 'hintShow'][key] = $hintsShow[hints[m]][key].prop('checked'); - } + } + localStorageSettings.hintShow = {}; + for (var key in hintShow) { + if (hintShow.hasOwnProperty(key)) { + localStorageSettings.hintShow[key] = $hintShow[key].prop('checked'); } } diff --git a/public/js/editors/addons.js b/public/js/editors/addons.js index f0a1016d..a7b022d4 100644 --- a/public/js/editors/addons.js +++ b/public/js/editors/addons.js @@ -22,8 +22,8 @@ var detailsSupport = 'open' in document.createElement('details'); var settingsHints = {}; - var settingsHintsShow = {}; - var hintsShow = { + var settingsHintShow = {}; + var hintShow = { console: true, line: true, under: false, @@ -33,8 +33,8 @@ ['js', 'css', 'html', 'coffeescript'].forEach(function (val) { var h = val + 'hint'; settingsHints[h] = (jsbin.settings[h] !== undefined) ? jsbin.settings[h] : true; - settingsHintsShow[h] = $.extend({}, hintsShow, jsbin.settings[h + 'Show']); }); + settingsHintShow = $.extend({}, hintShow, jsbin.settings.hintShow); var settingsAddons = $.extend({}, jsbin.settings.addons, settingsHints); var addons = { @@ -340,18 +340,20 @@ if (mode === 'htmlmixed') { mode = 'html'; } - var opt = $.extend({}, settingsHintsShow[mode + 'hint']); + var opt = $.extend({}, settingsHintShow); opt.consoleParent = cm.getWrapperElement().parentNode.parentNode; setOption(cm, 'lintOpt', opt); + setOption(cm, 'lintRules', $.extend({}, defhintOptions, jsbin.settings[mode + 'hintOptions'])); if (opt.gutter) { var gutters = cm.getOption('gutters'); gutters.push('CodeMirror-lint-markers'); setOption(cm, 'gutters', gutters); - setOption(cm, 'lintRules', $.extend({}, defhintOptions, jsbin.settings[mode + 'hintOptions'])); setOption(cm, 'lint', true); var ln = cm.getOption('lineNumbers'); setOption(cm, 'lineNumbers', !ln); setOption(cm, 'lineNumbers', ln); + } else { + setOption(cm, 'lint', true); } if (opt.console) { $document.trigger('sizeeditors'); From 9c0fa2cbc3ba686768ccc5a35363c5d9114db65e Mon Sep 17 00:00:00 2001 From: Remy Sharp Date: Wed, 2 Jul 2014 17:15:17 +0100 Subject: [PATCH 271/321] Make enable SSL a pro feature --- lib/features.js | 5 +++++ lib/handlers/bin.js | 22 +++++++++++++++++----- lib/middleware.js | 10 +++++++--- lib/routes.js | 3 ++- lib/utils.js | 2 +- public/js/account/preferences-settings.js | 2 ++ views/account/preferences.html | 12 ++++++++++++ 7 files changed, 46 insertions(+), 10 deletions(-) diff --git a/lib/features.js b/lib/features.js index 084d037b..6779e0ca 100644 --- a/lib/features.js +++ b/lib/features.js @@ -108,6 +108,11 @@ var flags = { return team(req); }, + // allows the user to use jsbin entirely through SSL + sslForAll: function (req) { + return alpha(req) && undefsafe(req, 'session.user.settings.ssl'); + }, + fileMenuTest: true, // live 2014-05-27 - #1414 upgrade: function (req) { diff --git a/lib/handlers/bin.js b/lib/handlers/bin.js index 841e3267..b8592c5f 100644 --- a/lib/handlers/bin.js +++ b/lib/handlers/bin.js @@ -797,7 +797,8 @@ module.exports = Observable.extend({ helpers = this.helpers, version = helpers.set('version'), created = req.flash('checksum') || {}, - root = helpers.url('', true), + ssl = features('sslForAll', req), + root = helpers.url('', true, ssl), _this = this, production = (req.cookies && req.cookies.debug) ? false : helpers.production, jsbin; @@ -809,6 +810,8 @@ module.exports = Observable.extend({ root = root.replace('://', '://' + req.subdomain + '.'); } + var statik = helpers.urlForStatic(undefined, ssl); + jsbin = this.jsbin(bin, { version: version, token: req.session._csrf, @@ -816,7 +819,7 @@ module.exports = Observable.extend({ shareRoot: features('vanity', req) ? 'http://' + req.session.user.name + '.' + req.app.get('url host') : root, metadata: bin.metadata, runner: helpers.runner, - static: helpers.urlForStatic(), + static: statik, settings: !bin.url ? config && config.settings : {}, // If we've pulled a just created bin out of the flash messages object // then we check to see if the previously created bin is the one we're @@ -904,7 +907,7 @@ module.exports = Observable.extend({ isProduction: production, concat: req.cookies && req.cookies.debug ? req.cookies.debug === 'concat' : false, root: root, - static: helpers.urlForStatic(), + static: statik, bincount: user.bincount, url: url, vanity: features('vanity', req) ? 'http://' + req.session.user.name + '.' + req.app.get('url host') : root, @@ -1042,11 +1045,20 @@ module.exports = Observable.extend({ // this value isn't always present in anonymous metadata options.metadata.last_updated = bin.created; + var statik = options.static || options.root; + var runner = this.helpers.runner; + if (statik.indexOf('https') === 0) { + // then ensure the runner is also https + if (runner.indexOf('https') === -1) { + runner = runner.replace(/http/, 'https'); + } + } + return { root: options.root, shareRoot: options.shareRoot, - runner: this.helpers.runner, - static: options.static || options.root, + runner: runner, + static: statik, version: options.version, state: { token: options.token, diff --git a/lib/middleware.js b/lib/middleware.js index 8aeb75a4..4bfac4da 100644 --- a/lib/middleware.js +++ b/lib/middleware.js @@ -6,6 +6,7 @@ var utils = require('./utils'), config = require('./config'), features = require('./features'), LZString = require('lz-string'), + undefsafe = require('undefsafe'), parse = require('url').parse; // Custom middleware used by the application. @@ -277,7 +278,10 @@ module.exports = { if (!features('sslLogin', req)) { return next(); } - var pathname = parse(req.url).pathname; + var pathname = pathIsSSL(parse(req.url).pathname); + var forceSSL = features('sslForAll', req); + + var useSSL = pathname || forceSSL; if (!config.url.ssl) { if (req.secure) { @@ -285,11 +289,11 @@ module.exports = { } } else { if (!req.secure) { - if (pathIsSSL(pathname)) { + if (useSSL) { return res.redirect('https://' + req.headers.host.replace(/:.*/, '') + req.url); } } else { - if (!pathIsSSL(pathname)) { + if (!useSSL) { return res.redirect('http://' + req.headers.host.replace(/:.*/, '') + req.url); } } diff --git a/lib/routes.js b/lib/routes.js index 423c8a25..a37a695b 100644 --- a/lib/routes.js +++ b/lib/routes.js @@ -152,9 +152,10 @@ module.exports = function (app) { // Runner app.get('/runner', function (req, res) { + var statik = sandbox.helpers.urlForStatic(undefined, features('sslForAll', req)); res.render('runner', { scripts: app.get('is_production') ? false : scripts.runner, - static: sandbox.helpers.urlForStatic() + static: statik }); }); diff --git a/lib/utils.js b/lib/utils.js index bd4c65f6..86d314d6 100644 --- a/lib/utils.js +++ b/lib/utils.js @@ -156,7 +156,7 @@ module.exports = { gravatar: function (email, size) { email = (email || '').trim().toLowerCase(); var hash = crypto.createHash('md5').update(email).digest('hex'); - return 'http://www.gravatar.com/avatar/' + hash + '?s=' + (size || 29); // 26 + return '//www.gravatar.com/avatar/' + hash + '?s=' + (size || 29); // 26 }, re: { flatten: /\s+/g, diff --git a/public/js/account/preferences-settings.js b/public/js/account/preferences-settings.js index 8b84b4e7..8902dc8e 100644 --- a/public/js/account/preferences-settings.js +++ b/public/js/account/preferences-settings.js @@ -42,6 +42,7 @@ var $includejs = $('#includejs').prop('checked', currentSettings.includejs); var $focusedPanel = $('#focused-panel').val(currentSettings.focusedPanel); var $assetUrl = $('#asset-url').val(currentSettings.assetUrl); + var $ssl = $('#ssl'); // .prop('checked', currentSettings.ssl); // checking happens server side var hints = ['js']; // var hints = ['js', 'css']; var $hints = {}; @@ -124,6 +125,7 @@ localStorageSettings.includejs = $includejs.prop('checked'); localStorageSettings.focusedPanel = $focusedPanel.val(); localStorageSettings.assetUrl = $assetUrl.val(); + localStorageSettings.ssl = $ssl.prop('checked'); localStorage.settings = JSON.stringify(localStorageSettings); console.log(localStorageSettings); diff --git a/views/account/preferences.html b/views/account/preferences.html index 2567e907..fd98902c 100644 --- a/views/account/preferences.html +++ b/views/account/preferences.html @@ -9,6 +9,18 @@
    + {{#feature request "pro"}} +

    Security

    + +
    + + +
    + +

    Note that by enabling SSL for all of JS Bin, including non-https assets in your bins will cause the iframe not to render. This is the correct behaviour for https frames containing non-secure content. Read more.

    + + {{/feature}} + {{#feature request "assets"}}

    Custom content

    If you want to link to images or additional assets, we redirect the /{{user.name}}/assets/ relative URL to your asset URL, so you can link to /{{user.name}}/assets/images/logo.png for example.

    From 434592db783b94b84a384da61103e359a7f0b7b0 Mon Sep 17 00:00:00 2001 From: Giulia Alfonsi Date: Wed, 2 Jul 2014 19:21:26 +0100 Subject: [PATCH 272/321] More appropriate tests by checking typeof for undefined objects --- public/js/editors/addons.js | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/public/js/editors/addons.js b/public/js/editors/addons.js index a7b022d4..35905809 100644 --- a/public/js/editors/addons.js +++ b/public/js/editors/addons.js @@ -166,7 +166,7 @@ ], test: function () { return jsbin.panels.panels.javascript.editor.openDialog && - (typeof window.ternBasicDefs !== undefined) && + (typeof window.ternBasicDefs !== 'undefined') && CodeMirror.showHint && CodeMirror.TernServer && CodeMirror.startTern; @@ -180,7 +180,7 @@ '/js/vendor/codemirror4/addon/selection/active-line.js' ], test: function() { - return CodeMirror.defaults.styleActiveLine !== undefined; + return (typeof CodeMirror.defaults.styleActiveLine !== 'undefined'); }, done: function(cm) { setOption(cm, 'styleActiveLine', true); @@ -189,7 +189,7 @@ matchbrackets: { url: [], test: function() { - return CodeMirror.defaults.matchBrackets !== undefined; + return (typeof CodeMirror.defaults.matchBrackets !== 'undefined'); }, done: function(cm) { setOption(cm, 'matchBrackets', true); @@ -204,7 +204,7 @@ ], test: function() { return hintingTest('css') && - CSSLint !== undefined; + (typeof CSSLint !== 'undefined'); }, done: function(cm) { if (cm.getOption('mode') !== 'css') { @@ -222,7 +222,7 @@ ], test: function() { return hintingTest('javascript') && - JSHINT !== undefined; + (typeof JSHINT !== 'undefined'); }, done: function(cm) { if (cm.getOption('mode') !== 'javascript') { @@ -242,7 +242,7 @@ ], test: function() { return hintingTest('htmlmixed') && - HTMLHint !== undefined; + (typeof HTMLHint !== 'undefined'); }, done: function(cm) { if (cm.getOption('mode') !== 'htmlmixed') { @@ -260,7 +260,7 @@ ], test: function() { return hintingTest('coffeescript') && - coffeelint !== undefined; + (typeof coffeelint !== 'undefined'); }, done: function(cm) { if (cm.getOption('mode') !== 'coffeescript') { @@ -321,12 +321,12 @@ function defaultTest(prop) { return function () { - return CodeMirror.optionHandlers[prop] !== undefined; + return (typeof CodeMirror.optionHandlers[prop] !== 'undefined'); }; } function hintingTest(mode) { - return CodeMirror.defaults.lint !== undefined && + return (typeof CodeMirror.defaults.lint !== 'undefined') && CodeMirror.helpers.lint && CodeMirror.helpers.lint[mode] && CodeMirror.optionHandlers.lint; From 615ef3bd3dada99b3ab0e6cc462d73150306b583 Mon Sep 17 00:00:00 2001 From: Giulia Alfonsi Date: Wed, 2 Jul 2014 19:22:07 +0100 Subject: [PATCH 273/321] Modified the order due to csslint creating global variable exports --- public/js/editors/addons.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/js/editors/addons.js b/public/js/editors/addons.js index 35905809..976d79b3 100644 --- a/public/js/editors/addons.js +++ b/public/js/editors/addons.js @@ -30,7 +30,7 @@ tooltip: true, gutter: true }; - ['js', 'css', 'html', 'coffeescript'].forEach(function (val) { + ['js', 'html', 'coffeescript', 'css'].forEach(function (val) { var h = val + 'hint'; settingsHints[h] = (jsbin.settings[h] !== undefined) ? jsbin.settings[h] : true; }); From 4a51eacf0ff0b02eda3ea042d0679a11527932c1 Mon Sep 17 00:00:00 2001 From: Giulia Alfonsi Date: Wed, 2 Jul 2014 19:30:00 +0100 Subject: [PATCH 274/321] Added explanation for last fix --- public/js/editors/addons.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/public/js/editors/addons.js b/public/js/editors/addons.js index 976d79b3..e5ddf9cd 100644 --- a/public/js/editors/addons.js +++ b/public/js/editors/addons.js @@ -30,6 +30,8 @@ tooltip: true, gutter: true }; + // css must go last for the moment due to CSSLint creating the + // global variable 'exports' ['js', 'html', 'coffeescript', 'css'].forEach(function (val) { var h = val + 'hint'; settingsHints[h] = (jsbin.settings[h] !== undefined) ? jsbin.settings[h] : true; From 5e6a317eb25430e3dd658a5ef215a6b580314ce5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nico=20H=C3=A4m=C3=A4l=C3=A4inen?= Date: Thu, 3 Jul 2014 11:39:52 +0300 Subject: [PATCH 275/321] Added Phaser 2.0.5 --- public/js/editors/libraries.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/public/js/editors/libraries.js b/public/js/editors/libraries.js index a180d8d2..b74c5fff 100644 --- a/public/js/editors/libraries.js +++ b/public/js/editors/libraries.js @@ -489,6 +489,10 @@ var libraries = [ { 'url': 'http://cdnjs.cloudflare.com/ajax/libs/gsap/1.11.7/TweenMax.min.js', 'label': 'GSAP 1.11.7' + }, + { + 'url': '//cdnjs.cloudflare.com/ajax/libs/phaser/2.0.5/phaser.min.js', + 'label': 'Phaser 2.0.5' } ]; From c5436ead023aa137fec3f30466b292982b10d899 Mon Sep 17 00:00:00 2001 From: Giulia Alfonsi Date: Thu, 3 Jul 2014 09:58:28 +0100 Subject: [PATCH 276/321] Make sure that CodeMirror settings tabSize and indentUnit are always numbers --- public/js/account/editor-settings.js | 6 +++--- public/js/editors/panel.js | 8 ++++++++ 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/public/js/account/editor-settings.js b/public/js/account/editor-settings.js index 214d3b1b..e9889d6c 100644 --- a/public/js/account/editor-settings.js +++ b/public/js/account/editor-settings.js @@ -32,7 +32,7 @@ theme: 'jsbin', indentUnit: 2, tabSize: 2 - } + }; // needed for the keymaps $.browser = {}; @@ -153,8 +153,8 @@ editor.setOption('lineWrapping', $lineWrapping.prop('checked')); editor.setOption('lineNumbers', $lineNumbers.prop('checked')); editor.setOption('indentWithTabs', $indentWithTabs.prop('checked')); - editor.setOption('tabSize', $tabSize.val()); - editor.setOption('indentUnit', $tabSize.val()); + editor.setOption('tabSize', parseInt($tabSize.val(), 10)); + editor.setOption('indentUnit', parseInt($tabSize.val(), 10)); editor.setOption('theme', $theme.val()); $CodeMirror.css('font-size', $fontsize.val()+'px'); editor.refresh(); diff --git a/public/js/editors/panel.js b/public/js/editors/panel.js index 670a2c3b..0afa9175 100644 --- a/public/js/editors/panel.js +++ b/public/js/editors/panel.js @@ -117,6 +117,14 @@ var Panel = function (name, settings) { profile: name /* define Zen Coding output profile */ }); + // make sure tabSize and indentUnit are numbers + if (typeof cmSettings.tabSize === 'string') { + cmSettings.tabSize = parseInt(cmSettings.tabSize, 10) || 2; + } + if (typeof cmSettings.indentUnit === 'string') { + cmSettings.indentUnit = parseInt(cmSettings.indentUnit, 10) || 2; + } + panel.editor = CodeMirror.fromTextArea(panel.el, cmSettings); panel.editor.on('highlightLines', function () { From 0c455e1ce8b81608c70b27cf73b49c39b04ec8a1 Mon Sep 17 00:00:00 2001 From: Giulia Alfonsi Date: Thu, 3 Jul 2014 10:16:21 +0100 Subject: [PATCH 277/321] #1622 Made localStorage settings takes precedence over server side user settings --- public/js/jsbin.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/public/js/jsbin.js b/public/js/jsbin.js index 0506d9e7..fd4834e2 100644 --- a/public/js/jsbin.js +++ b/public/js/jsbin.js @@ -66,10 +66,12 @@ if (storedSettings === "undefined") { storedSettings = null; } -window.jsbin.settings = $.extend(JSON.parse(storedSettings || '{}'), jsbin.settings); +// In all cases localStorage takes precedence over user settings so users can +// configure it from the console and overwrite the server delivered settings +window.jsbin.settings = $.extend(jsbin.settings, JSON.parse(storedSettings || '{}')); if (jsbin.user) { - $.extend(window.jsbin.settings, jsbin.user.settings); + window.jsbin.settings = $.extend({}, jsbin.user.settings, window.jsbin.settings); } // if the above code isn't dodgy, this for hellz bells is: jsbin.mobile = /WebKit.*Mobile.*|Android/.test(navigator.userAgent); From 6f8198253da4c1ed19e6f744a353b3c512f49317 Mon Sep 17 00:00:00 2001 From: Remy Sharp Date: Thu, 3 Jul 2014 10:45:42 +0100 Subject: [PATCH 278/321] Add a config option to control this setting --- config.default.json | 3 +++ lib/handlers/bin.js | 17 ++++++++++++++--- 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/config.default.json b/config.default.json index 06292932..a117a487 100644 --- a/config.default.json +++ b/config.default.json @@ -43,6 +43,9 @@ "server": { "logger": "default" }, + "security": { + "allowAnonymousPreview": false + }, "client": { "user": true }, diff --git a/lib/handlers/bin.js b/lib/handlers/bin.js index 1ef8d44b..65983e01 100644 --- a/lib/handlers/bin.js +++ b/lib/handlers/bin.js @@ -10,6 +10,7 @@ var async = require('asyncjs'), undefsafe = require('undefsafe'), metrics = require('../metrics'), features = require('../features'), + config = require('../config'), Promise = require('rsvp').Promise, welcomePanel = require('../welcome-panel'), Observable = utils.Observable; @@ -156,10 +157,20 @@ module.exports = Observable.extend({ * then redirect to the /edit url */ var user = undefsafe(req, 'bin.metadata.name'); - if (user === 'anonymous' || !user) { + if (config.security.allowAnonymousPreview !== true && user === 'anonymous' || !user) { var created = req.bin.created; - // test the time created - if ((Date.now() - created.getTime()) / 1000 / 60 > 120) { + + // this is hard coded for production jsbin.com - it means that all bins + // created before we released this change won't be affected by the limit + if (config.url.host === 'jsbin.com') { + if (req.bin.id < 10786492) { + return next(); + } + } + + // test the time created, and if it's older than 90 minutes, then redirect + // to the edit view. Details as to why on our blog + if ((Date.now() - created.getTime()) / 1000 / 60 > 1) { var msg = 'This bin was created anonymously and its free preview time has expired.'; if (!req.session.user) { From 97160623c5164fe4b8beb88a93735b83ced7b691 Mon Sep 17 00:00:00 2001 From: Remy Sharp Date: Thu, 3 Jul 2014 11:28:04 +0100 Subject: [PATCH 279/321] Allow free for 90 minutes Not 1 minute!!! --- lib/handlers/bin.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/handlers/bin.js b/lib/handlers/bin.js index 65983e01..2084c995 100644 --- a/lib/handlers/bin.js +++ b/lib/handlers/bin.js @@ -170,7 +170,7 @@ module.exports = Observable.extend({ // test the time created, and if it's older than 90 minutes, then redirect // to the edit view. Details as to why on our blog - if ((Date.now() - created.getTime()) / 1000 / 60 > 1) { + if ((Date.now() - created.getTime()) / 1000 / 60 > 90) { var msg = 'This bin was created anonymously and its free preview time has expired.'; if (!req.session.user) { From 92a0df375e555f25a759617c9f511ec4c9361c14 Mon Sep 17 00:00:00 2001 From: Remy Sharp Date: Thu, 3 Jul 2014 11:40:45 +0100 Subject: [PATCH 280/321] Allow content in the console to be selectable Fixes @allouis' friend's problem. They didn't want to raise a GH issue, so we have to shame them in a git commit instead! --- public/js/render/console.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/public/js/render/console.js b/public/js/render/console.js index 2c89334e..f0346176 100644 --- a/public/js/render/console.js +++ b/public/js/render/console.js @@ -583,8 +583,10 @@ var msgType = ''; jsconsole.init(document.getElementById('output')); function upgradeConsolePanel(console) { - console.$el.click(function () { - jsconsole.focus(); + console.$el.click(function (event) { + if (!$(event.target).closest('#output').length) { + jsconsole.focus(); + } }); console.reset = function () { jsconsole.reset(); From 574e38bc53c74afeb2342b23b78beee52bbf1a3f Mon Sep 17 00:00:00 2001 From: Couto Date: Thu, 3 Jul 2014 11:46:12 +0100 Subject: [PATCH 281/321] Add promises libraries. Group them into "Promises" --- public/js/editors/libraries.js | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/public/js/editors/libraries.js b/public/js/editors/libraries.js index 45eda5df..9dca0201 100644 --- a/public/js/editors/libraries.js +++ b/public/js/editors/libraries.js @@ -314,6 +314,26 @@ var libraries = [ 'label': 'Enyo 2.2.0', 'group': 'Enyo' }, + { + 'url': '//cdnjs.cloudflare.com/ajax/libs/bluebird/1.2.2/bluebird.js', + 'label': 'Bluebird 1.2.2', + 'group': 'Promises' + }, + { + 'url': 'https://www.promisejs.org/polyfills/promise-4.0.0.js', + 'label': 'Promise 4.0.0', + 'group': 'Promises' + }, + { + 'url': '//cdnjs.cloudflare.com/ajax/libs/q.js/1.0.1/q.js', + 'label': 'Q 1.0.1', + 'group': 'Promises' + }, + { + 'url': '//cdn.jsdelivr.net/rsvp/3.0.6/rsvp.js', + 'label': 'RSVP 3.0.6', + 'group': 'Promises' + }, { 'url': [ 'https://rawgithub.com/ai/autoprefixer-rails/master/vendor/autoprefixer.js' @@ -340,10 +360,6 @@ var libraries = [ 'url': 'http://cdnjs.cloudflare.com/ajax/libs/bonsai/0.4/bonsai.min.js', 'label': 'Bonsai 0.4.latest' }, - { - 'url': '//cdnjs.cloudflare.com/ajax/libs/bluebird/1.2.2/bluebird.js', - 'label': 'Bluebird 1.2.2' - }, { 'url': 'http://jashkenas.github.io/coffee-script/extras/coffee-script.js', 'label': 'CoffeeScript' From 253c8ed37397d9f976a635c7587497d21187f65b Mon Sep 17 00:00:00 2001 From: Giulia Alfonsi Date: Thu, 3 Jul 2014 15:44:11 +0100 Subject: [PATCH 282/321] Switch linking when switching language --- public/js/editors/addons.js | 16 +++++++++--- public/js/processors/processor.js | 20 +++++++++++++++ public/js/vendor/cm_addons/lint/lint.js | 33 ++++++++++++++++++++++--- 3 files changed, 63 insertions(+), 6 deletions(-) diff --git a/public/js/editors/addons.js b/public/js/editors/addons.js index e5ddf9cd..77efd5e2 100644 --- a/public/js/editors/addons.js +++ b/public/js/editors/addons.js @@ -334,7 +334,7 @@ CodeMirror.optionHandlers.lint; } - function hintingDone(cm, defhintOptions) { + window.hintingDone = function(cm, defhintOptions) { var mode = cm.getOption('mode'); if (mode === 'javascript') { mode = 'js'; @@ -348,8 +348,10 @@ setOption(cm, 'lintRules', $.extend({}, defhintOptions, jsbin.settings[mode + 'hintOptions'])); if (opt.gutter) { var gutters = cm.getOption('gutters'); - gutters.push('CodeMirror-lint-markers'); - setOption(cm, 'gutters', gutters); + if (gutters.indexOf('CodeMirror-lint-markers') === -1) { + gutters.push('CodeMirror-lint-markers'); + setOption(cm, 'gutters', gutters); + } setOption(cm, 'lint', true); var ln = cm.getOption('lineNumbers'); setOption(cm, 'lineNumbers', !ln); @@ -406,4 +408,12 @@ } }; + // External method to realod the selected addon + // may be useful in the future + // window.reloadSelectedAddon = function(addon) { + // if (options.indexOf(addon) !== -1) { + // loadAddon(addon); + // } + // }; + })(); \ No newline at end of file diff --git a/public/js/processors/processor.js b/public/js/processors/processor.js index bbc8e346..31b06fc9 100644 --- a/public/js/processors/processor.js +++ b/public/js/processors/processor.js @@ -447,6 +447,26 @@ var processors = jsbin.processors = (function () { delete jsbin.state.processors[panelId]; delete panel.type; } + + // linting + mmMode = cmMode; + if (cmMode === 'javascript') { + mmMode = 'js'; + } + if (cmMode === 'htmlmixed') { + mmMode = 'html'; + } + var isHint = panel.editor.getOption('lint'); + if (isHint) { + panel.editor.lintStop(); + } + if (jsbin.settings[mmMode + 'hint']) { + panel.editor.setOption('mode', cmMode); + if (typeof hintingDone !== 'undefined') { + panel.editor.setOption('mode', cmMode); + hintingDone(panel.editor); + } + } }; processors.reset = function (panelId) { diff --git a/public/js/vendor/cm_addons/lint/lint.js b/public/js/vendor/cm_addons/lint/lint.js index f931702a..07f1e1e6 100644 --- a/public/js/vendor/cm_addons/lint/lint.js +++ b/public/js/vendor/cm_addons/lint/lint.js @@ -1,6 +1,3 @@ -// CodeMirror, copyright (c) by Marijn Haverbeke and others -// Distributed under an MIT license: http://codemirror.net/LICENSE - (function(mod) { if (typeof exports == 'object' && typeof module == 'object') // CommonJS mod(require('../../lib/codemirror')); @@ -71,6 +68,9 @@ if (!options.getAnnotations && cm.getOption('mode') === 'htmlmixed') { options.getAnnotations = CodeMirror.helpers.lint.htmlmixed; } + if (!options.getAnnotations && cm.getOption('mode') === 'coffeescript') { + options.getAnnotations = CodeMirror.helpers.lint.coffeescript; + } if (!options.getAnnotations) throw new Error('Required option "getAnnotations" missing (lint addon)'); return options; } @@ -145,6 +145,7 @@ wrapper.appendChild(head); wrapper.appendChild(logs); cm.consolelint = { + wrapper: wrapper, logs: logs, head: head, error: 0, @@ -338,6 +339,28 @@ } } + function lintStop(cm) { + lineReset(cm); + cm.setOption('lint', false); + var opt = cm.getOption('lintOpt'); + if (opt.gutter) { + var gutters = cm.getOption('gutters'); + var pos = gutters.indexOf('CodeMirror-lint-markers'); + if (pos !== -1) { + gutters.splice(pos, 1); + cm.setOption('gutters', gutters); + var ln = cm.getOption('lineNumbers'); + cm.setOption('lineNumbers', !ln); + cm.setOption('lineNumbers', ln); + } + } + if (opt.console) { + opt.consoleParent.removeChild(cm.consolelint.wrapper); + $document.trigger('sizeeditors'); + } + cm.refresh(); + } + CodeMirror.defineOption('lint', false, function(cm, val, old) { var defaults = { console: true, @@ -387,6 +410,10 @@ CodeMirror.on(cm.getWrapperElement(), 'mouseover', state.onMouseOver); startLinting(cm); + + cm.lintStop = function() { + return lintStop(this); + }; } // probably to improve according to real case scenarios From dfb3521215fb854ddfb4a66ccfbb6787fb09900c Mon Sep 17 00:00:00 2001 From: Remy Sharp Date: Thu, 3 Jul 2014 16:26:48 +0100 Subject: [PATCH 283/321] https on output & protect jsbin.user object If users want to change their settings from the console, they have to use a key to unlock the feature. --- Gruntfile.js | 9 ++--- lib/handlers/bin.js | 4 ++- lib/middleware.js | 31 ++++++++++++----- lib/routes.js | 57 ++++++++++++++++++++++++++----- public/js/chrome/welcome-panel.js | 8 +++-- public/js/intro-start.js | 1 + public/js/jsbin.js | 31 ++++++++++++++--- public/js/outro-start.js | 1 + public/js/outro.js | 2 +- public/js/runner/proxy-console.js | 2 +- scripts.json | 1 + views/comment.html | 13 +++++-- views/index.html | 43 +++++++++++------------ 13 files changed, 148 insertions(+), 55 deletions(-) create mode 100644 public/js/intro-start.js create mode 100644 public/js/outro-start.js diff --git a/Gruntfile.js b/Gruntfile.js index b667408b..5007d7e6 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -1,3 +1,4 @@ +'use strict'; /*global module:false*/ module.exports = function (grunt) { var fs = require('fs'), @@ -32,7 +33,7 @@ module.exports = function (grunt) { } } - child = exec(cmd, function (err, stdout, stderr) { + child = exec(cmd, function (err) { if (err) { grunt.log.writeln(err.message); process.exit(err.code); @@ -96,9 +97,9 @@ module.exports = function (grunt) { }, dist: { src: [ - 'public/js/intro.js', + 'public/js/intro-start.js', '<%= scriptsRelative %>', - 'public/js/outro.js' + 'public/js/outro-start.js' ], dest: distpaths.script }, @@ -124,7 +125,7 @@ module.exports = function (grunt) { sourceMapPrefix: 2, sourceMapRoot: '/js', }, - src: '<%= scriptsRelative %>', + src: distpaths.script, //'<%= scriptsRelative %>', dest: distpaths.min }, runner: { diff --git a/lib/handlers/bin.js b/lib/handlers/bin.js index d6332cf5..d07e50fc 100644 --- a/lib/handlers/bin.js +++ b/lib/handlers/bin.js @@ -1247,7 +1247,9 @@ module.exports = Observable.extend({ context = { domain: helpers.set('url host'), - permalink: helpers.editUrlForBin(bin, true) + permalink: helpers.editUrlForBin(bin, true), + user: undefsafe(bin, 'metadata.name') || false, + year: (new Date()).getYear() + 1900 }; // Append attribution comment to header. diff --git a/lib/middleware.js b/lib/middleware.js index 4bfac4da..bbf03546 100644 --- a/lib/middleware.js +++ b/lib/middleware.js @@ -154,12 +154,17 @@ module.exports = { // Checks for a subdomain in the current url, if found it sets the // req.subdomain property. This supports existing behaviour that allows // subdomains to load custom config files. - subdomain: function (app) { + subdomain: function () { return function (req, res, next) { - var apphost = app.set('url host').split(':')[0], + var apphost = config.url.host, + outputHost = undefsafe(config, 'security.preview'), host = req.header('Host', ''), offset = host.indexOf(apphost); + if (host === outputHost) { + offset = host.indexOf(outputHost); + } + if (offset) { // Slice the host from the subdomain and subtract 1 for // trailing . on the subdomain. @@ -278,23 +283,31 @@ module.exports = { if (!features('sslLogin', req)) { return next(); } - var pathname = pathIsSSL(parse(req.url).pathname); + var pathShouldBeSecure = pathIsSSL(parse(req.url).pathname); var forceSSL = features('sslForAll', req); - var useSSL = pathname || forceSSL; + var useSSL = pathShouldBeSecure || forceSSL; if (!config.url.ssl) { if (req.secure) { + // if the request is https and we don't have a https host available in our config return res.redirect('http://' + req.headers.host.replace(/:.*/, '') + req.url); } } else { - if (!req.secure) { - if (useSSL) { - return res.redirect('https://' + req.headers.host.replace(/:.*/, '') + req.url); + // we do have https host in our config + if (req.secure) { + // we are using SSL... + if (forceSSL && pathShouldBeSecure === false) { + return next(); + } + + if (pathShouldBeSecure === false) { + req.shouldNotBeSecure = true; } } else { - if (!useSSL) { - return res.redirect('http://' + req.headers.host.replace(/:.*/, '') + req.url); + if (useSSL) { + // if the request is not https and _should be_, redirect to https + return res.redirect('https://' + req.headers.host.replace(/:.*/, '') + req.url); } } } diff --git a/lib/routes.js b/lib/routes.js index 3dbd80af..7e8e6137 100644 --- a/lib/routes.js +++ b/lib/routes.js @@ -76,6 +76,16 @@ module.exports = function (app) { }; } + function shouldNotBeSecure(req, res, next) { + // otherwise redirect to the http version + if (req.shouldNotBeSecure) { + return res.redirect('http://' + req.headers.host.replace(/:.*/, '') + req.url); + } + + // if the flag isn't present, then skip on + next(); + } + // Redirects // /about doesn't get hit in production - it goes via nginx to our learn repo @@ -142,9 +152,9 @@ module.exports = function (app) { }); // Set up the routes. - app.get('/', time('request.root'), userHandler.loadVanityURL, binHandler.loadBin, binHandler.getBinPreview); + app.get('/', shouldNotBeSecure, time('request.root'), userHandler.loadVanityURL, binHandler.loadBin, binHandler.getBinPreview); app.get('/', binHandler.getDefault); - app.get('/gist/*', binHandler.getDefault); + app.get('/gist/*', shouldNotBeSecure, binHandler.getDefault); app.post('/', binHandler.getFromPost); // sandbox @@ -245,7 +255,7 @@ module.exports = function (app) { }; }()); - app.get('/account/:page', features.route('accountPages'), renderAccountSettings); + app.get('/account/:page', shouldNotBeSecure, features.route('accountPages'), renderAccountSettings); app.get('/account', function(req, res) { res.redirect('/account/editor'); }); @@ -441,7 +451,7 @@ module.exports = function (app) { }); - app.get('/:username/last(-:n)?/:quiet(quiet)?', tag('keepLatest'), binHandler.getLatestForUser, spike.getStream, binHandler.getBinPreview); + // username shortcut routes app.get('/:username/last(-:n)?/edit', binHandler.getLatestForUser, binHandler.getBin); app.get('/:username/last(-:n)?/watch', binHandler.getLatestForUser, binHandler.live, binHandler.getBin); @@ -479,6 +489,39 @@ module.exports = function (app) { app.get('/download', binParamFromReferer, binHandler.loadBin, binHandler.downloadBin); app.get('/:bin/:rev?/download', binHandler.downloadBin); + + /** + * Full output routes + */ + var secureOutput = function (req, res, next) { + // 1. check request is supposed to be on a vanity url + // 2. if not, then check if the req.headers.host matches security.preview + // 3. if not, redirect + if (config.security.preview) { + var metadata = undefsafe(req, 'bin.metadata'); + var settings = {}; + var ssl = false; + var url; + + if (settings) { + try { + settings = JSON.parse(metadata.settings); + ssl = features('sslForAll', { session: { user: { name: metadata.name, pro: metadata.pro, settings: { ssl: settings.ssl }}}}); + } catch (e) {} + } + + url = sandbox.helpers.url(req.url, true, ssl); + + if ( (req.headers.host !== config.security.preview) || // a) host != runner host + (!req.secure && ssl) || // b) request *should* be secure + (req.secure && !ssl) ) { // c) request is secure and *should not* be + return res.redirect(301, url.replace(config.url.host, config.security.preview)); + } + } + + next(); + }; + // Source app.get('/:bin/:rev?/source', time('request.source'), binHandler.getBinSource); app.get('/:bin/:rev?.:format(js|json|css|html|md|markdown|stylus|less|coffee|jade|svg)', time('request.source'), binHandler.getBinSourceFile); @@ -487,15 +530,13 @@ module.exports = function (app) { res.redirect(301, req.path.replace(/\/js$/, '.js')); }); - // Log - not actually implemented - app.get('/:bin/:rev/log', spike.getLog); - app.post('/:bin/:rev/log', spike.postLog); - // Preview + app.get('/:username/last(-:n)?/:quiet(quiet)?', tag('keepLatest'), binHandler.getLatestForUser, spike.getStream, binHandler.getBinPreview); app.get('/:bin/:quiet(quiet)?', binHandler.testPreviewAllowed, spike.getStream, binHandler.getBinPreview); app.get('/:bin/:rev?/:quiet(quiet)?', binHandler.testPreviewAllowed, spike.getStream, binHandler.getBinPreview); app.get('/:bin/:rev?/stats', tag('stats'), spike.getStream); + // used for simple testing app.get('/test/error/:num', function (req, res, next) { next(req.params.num * 1); }); diff --git a/public/js/chrome/welcome-panel.js b/public/js/chrome/welcome-panel.js index c0ad9af5..9d7fa2f9 100644 --- a/public/js/chrome/welcome-panel.js +++ b/public/js/chrome/welcome-panel.js @@ -2,6 +2,10 @@ /*global jsbin, $, $body, $document, analytics, settings*/ 'use strict'; + if (!$('#toppanel').length) { + return; + } + if (jsbin.settings.gui === undefined) { jsbin.settings.gui = {}; } @@ -39,7 +43,7 @@ $body.addClass('toppanel-slow'); } }; - + $('.toppanel-hide').click(function(event) { event.preventDefault(); goSlow(event); @@ -51,7 +55,7 @@ showToppanel(); }); $document.keydown(function (event) { - if (event.which == 27) { + if (event.which === 27) { if ($body.hasClass('toppanel')) { removeToppanel(); } diff --git a/public/js/intro-start.js b/public/js/intro-start.js new file mode 100644 index 00000000..cac7c20e --- /dev/null +++ b/public/js/intro-start.js @@ -0,0 +1 @@ +function start(template, jsbin, window, document, undefined) { \ No newline at end of file diff --git a/public/js/jsbin.js b/public/js/jsbin.js index fd4834e2..0ec317af 100644 --- a/public/js/jsbin.js +++ b/public/js/jsbin.js @@ -1,5 +1,5 @@ try { - console.log('init'); + console.log('Dave is ready!'); } catch (e) { var console = { log: function () { @@ -57,9 +57,27 @@ function dedupe(array) { return results; } +function exposeSettings() { + 'use strict'; + if (window.jsbin instanceof Node || !window.jsbin) { // because...STUPIDITY!!! + window.jsbin = {}; // create the holding object + + if (jsbin.state.metadata && jsbin.user && jsbin.state.metadata.name === jsbin.user.name) { + window.jsbin.settings = jsbin.settings; + return; + } + + var key = 'o' + (Math.random() * 1).toString(32).slice(2); + Object.defineProperty(window, key, { + get:function () { + window.jsbin.settings = jsbin.settings; + console.log('jsbin.settings can how be modified on the console'); + } + }); + console.log('To edit settings, type this string into the console: ' + key); + } +} -window['jsbin'] || (window.jsbin = {}); -// dodgy? var storedSettings = localStorage.getItem('settings'); if (storedSettings === "undefined") { // yes, equals the *string* "undefined", then something went wrong @@ -68,11 +86,14 @@ if (storedSettings === "undefined") { // In all cases localStorage takes precedence over user settings so users can // configure it from the console and overwrite the server delivered settings -window.jsbin.settings = $.extend(jsbin.settings, JSON.parse(storedSettings || '{}')); +jsbin.settings = $.extend(jsbin.settings, JSON.parse(storedSettings || '{}')); if (jsbin.user) { - window.jsbin.settings = $.extend({}, jsbin.user.settings, window.jsbin.settings); + jsbin.settings = $.extend({}, jsbin.user.settings, jsbin.settings); } + +exposeSettings(); + // if the above code isn't dodgy, this for hellz bells is: jsbin.mobile = /WebKit.*Mobile.*|Android/.test(navigator.userAgent); jsbin.tablet = /iPad/i.test(navigator.userAgent); // sue me. diff --git a/public/js/outro-start.js b/public/js/outro-start.js new file mode 100644 index 00000000..ff30235f --- /dev/null +++ b/public/js/outro-start.js @@ -0,0 +1 @@ +} \ No newline at end of file diff --git a/public/js/outro.js b/public/js/outro.js index 08a0186d..4b3cc37b 100644 --- a/public/js/outro.js +++ b/public/js/outro.js @@ -1 +1 @@ -})(this, document); \ No newline at end of file +})(window, document); \ No newline at end of file diff --git a/public/js/runner/proxy-console.js b/public/js/runner/proxy-console.js index 8ec9cddc..9e89412b 100644 --- a/public/js/runner/proxy-console.js +++ b/public/js/runner/proxy-console.js @@ -6,7 +6,7 @@ var proxyConsole = (function () { 'use strict'; var supportsConsole = true; - try { window.console.log('runner'); } catch (e) { supportsConsole = false; } + try { window.console.log('d[ o_0 ]b'); } catch (e) { supportsConsole = false; } var proxyConsole = function() {}; diff --git a/scripts.json b/scripts.json index 43a72655..9224a498 100644 --- a/scripts.json +++ b/scripts.json @@ -54,6 +54,7 @@ "/js/chrome/infocard.js", "/js/chrome/last-bin.js", "/js/chrome/archive.js", + "/js/chrome/welcome-panel.js", "/js/chrome/app.js" ], "runner": [ diff --git a/views/comment.html b/views/comment.html index 13bf588c..c967b158 100644 --- a/views/comment.html +++ b/views/comment.html @@ -1,4 +1,11 @@ +Created using http://{{domain}} + +Copyright (c) {{year}} {{#user}}by {{.}} {{/user}}{{permalink}} + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +--> \ No newline at end of file diff --git a/views/index.html b/views/index.html index a8daf392..9fcfa549 100644 --- a/views/index.html +++ b/views/index.html @@ -15,7 +15,7 @@ - + {{#feature request "welcomePanel"}} {{> welcome_panel}} {{/feature}} @@ -558,33 +558,34 @@ Include alerts, prompts & confirm boxes">Run with JS
    {{/feature}} - -{{#if isProduction}} - - -{{else}} - {{#if concat}} - - - {{else}} - - {{#scripts}}{{/scripts}} - {{/if}} - {{#addons}}{{/addons}} -{{/if}} {{#if live}} +{{else}} + + {{#if isProduction}} + + + {{else}} + + {{#if concat}} + + {{else}} + {{#scripts}}{{/scripts}} + {{/if}} + {{#addons}}{{/addons}} + {{/if}} {{/if}} -{{#feature request "welcomePanel"}} - -{{/feature}} + From e1c6b217796767a71048be6d1564d7512468ea50 Mon Sep 17 00:00:00 2001 From: Remy Sharp Date: Thu, 3 Jul 2014 16:29:58 +0100 Subject: [PATCH 284/321] Force output to https if enable --- lib/routes.js | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/lib/routes.js b/lib/routes.js index 7e8e6137..b64d63c8 100644 --- a/lib/routes.js +++ b/lib/routes.js @@ -512,10 +512,9 @@ module.exports = function (app) { url = sandbox.helpers.url(req.url, true, ssl); - if ( (req.headers.host !== config.security.preview) || // a) host != runner host - (!req.secure && ssl) || // b) request *should* be secure - (req.secure && !ssl) ) { // c) request is secure and *should not* be - return res.redirect(301, url.replace(config.url.host, config.security.preview)); + if ( (!req.secure && ssl) || // a) request *should* be secure + (req.secure && !ssl) ) { // b) request is secure and *should not* be + return res.redirect(301, url); } } @@ -523,18 +522,18 @@ module.exports = function (app) { }; // Source - app.get('/:bin/:rev?/source', time('request.source'), binHandler.getBinSource); - app.get('/:bin/:rev?.:format(js|json|css|html|md|markdown|stylus|less|coffee|jade|svg)', time('request.source'), binHandler.getBinSourceFile); - app.get('/:bin/:rev?/:format(js)', function (req, res) { + app.get('/:bin/:rev?/source', secureOutput, time('request.source'), binHandler.getBinSource); + app.get('/:bin/:rev?.:format(js|json|css|html|md|markdown|stylus|less|coffee|jade|svg)', secureOutput, time('request.source'), binHandler.getBinSourceFile); + app.get('/:bin/:rev?/:format(js)', secureOutput, function (req, res) { // Redirect legacy /js suffix to the new .js extension. res.redirect(301, req.path.replace(/\/js$/, '.js')); }); // Preview - app.get('/:username/last(-:n)?/:quiet(quiet)?', tag('keepLatest'), binHandler.getLatestForUser, spike.getStream, binHandler.getBinPreview); - app.get('/:bin/:quiet(quiet)?', binHandler.testPreviewAllowed, spike.getStream, binHandler.getBinPreview); - app.get('/:bin/:rev?/:quiet(quiet)?', binHandler.testPreviewAllowed, spike.getStream, binHandler.getBinPreview); - app.get('/:bin/:rev?/stats', tag('stats'), spike.getStream); + app.get('/:username/last(-:n)?/:quiet(quiet)?', secureOutput, tag('keepLatest'), binHandler.getLatestForUser, spike.getStream, binHandler.getBinPreview); + app.get('/:bin/:quiet(quiet)?', secureOutput, binHandler.testPreviewAllowed, spike.getStream, binHandler.getBinPreview); + app.get('/:bin/:rev?/:quiet(quiet)?', secureOutput, binHandler.testPreviewAllowed, spike.getStream, binHandler.getBinPreview); + app.get('/:bin/:rev?/stats', tag('stats'), secureOutput, spike.getStream); // used for simple testing app.get('/test/error/:num', function (req, res, next) { From e0aca8413c8d90c66d6bb2abad857e34c6f4b472 Mon Sep 17 00:00:00 2001 From: Giulia Alfonsi Date: Thu, 3 Jul 2014 16:57:02 +0100 Subject: [PATCH 285/321] Changed the list of loaded files as addons, put as default the jshint and the css --- public/css/style.css | 143 ++++++++++++++++++++++++++++++++++++ public/js/editors/addons.js | 19 +---- scripts.json | 3 + 3 files changed, 150 insertions(+), 15 deletions(-) diff --git a/public/css/style.css b/public/css/style.css index 8146e80a..70fae5a1 100644 --- a/public/css/style.css +++ b/public/css/style.css @@ -5017,3 +5017,146 @@ a.toppanel-logo { -o-transition-duration: 120ms; transition-duration: 120ms; } + + +/* CodeMirror lint */ +/* The lint marker gutter */ +.CodeMirror-lint-markers { + width: 16px; +} + +.CodeMirror-lint-tooltip { + background-color: infobackground; + border: 1px solid black; + border-radius: 4px 4px 4px 4px; + color: infotext; + font-family: monospace; + font-size: 10pt; + overflow: hidden; + padding: 2px 5px; + position: fixed; + white-space: pre; + white-space: pre-wrap; + z-index: 100; + max-width: 600px; + opacity: 0; + transition: opacity .4s; + -moz-transition: opacity .4s; + -webkit-transition: opacity .4s; + -o-transition: opacity .4s; + -ms-transition: opacity .4s; +} + +.CodeMirror-lint-mark-error, .CodeMirror-lint-mark-warning { + background-position: left bottom; + background-repeat: repeat-x; +} + +.CodeMirror-lint-mark-error { + background-image: + url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAQAAAADCAYAAAC09K7GAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB9sJDw4cOCW1/KIAAAAZdEVYdENvbW1lbnQAQ3JlYXRlZCB3aXRoIEdJTVBXgQ4XAAAAHElEQVQI12NggIL/DAz/GdA5/xkY/qPKMDAwAADLZwf5rvm+LQAAAABJRU5ErkJggg==") + ; +} + +.CodeMirror-lint-mark-warning { + background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAQAAAADCAYAAAC09K7GAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB9sJFhQXEbhTg7YAAAAZdEVYdENvbW1lbnQAQ3JlYXRlZCB3aXRoIEdJTVBXgQ4XAAAAMklEQVQI12NkgIIvJ3QXMjAwdDN+OaEbysDA4MPAwNDNwMCwiOHLCd1zX07o6kBVGQEAKBANtobskNMAAAAASUVORK5CYII="); +} + +.lint-icon-warning:before, +.lint-icon-error:before, +.CodeMirror-lint-marker-error, .CodeMirror-lint-marker-warning { + background-position: center center; + background-repeat: no-repeat; + cursor: pointer; + display: inline-block; + height: 16px; + width: 16px; + vertical-align: middle; + position: relative; +} + +.CodeMirror-lint-message-error, .CodeMirror-lint-message-warning { + padding-left: 18px; + background-position: top left; + background-repeat: no-repeat; +} + +.lint-icon-error:before, +.CodeMirror-lint-marker-error, .CodeMirror-lint-message-error { + background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAAHlBMVEW7AAC7AACxAAC7AAC7AAAAAAC4AAC5AAD///+7AAAUdclpAAAABnRSTlMXnORSiwCK0ZKSAAAATUlEQVR42mWPOQ7AQAgDuQLx/z8csYRmPRIFIwRGnosRrpamvkKi0FTIiMASR3hhKW+hAN6/tIWhu9PDWiTGNEkTtIOucA5Oyr9ckPgAWm0GPBog6v4AAAAASUVORK5CYII="); +} + +.lint-icon-warning:before, +.CodeMirror-lint-marker-warning, .CodeMirror-lint-message-warning { + background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAANlBMVEX/uwDvrwD/uwD/uwD/uwD/uwD/uwD/uwD/uwD6twD/uwAAAADurwD2tQD7uAD+ugAAAAD/uwDhmeTRAAAADHRSTlMJ8mN1EYcbmiixgACm7WbuAAAAVklEQVR42n3PUQqAIBBFUU1LLc3u/jdbOJoW1P08DA9Gba8+YWJ6gNJoNYIBzAA2chBth5kLmG9YUoG0NHAUwFXwO9LuBQL1giCQb8gC9Oro2vp5rncCIY8L8uEx5ZkAAAAASUVORK5CYII="); +} + +.CodeMirror-lint-marker-multiple { + background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAcAAAAHCAMAAADzjKfhAAAACVBMVEUAAAAAAAC/v7914kyHAAAAAXRSTlMAQObYZgAAACNJREFUeNo1ioEJAAAIwmz/H90iFFSGJgFMe3gaLZ0od+9/AQZ0ADosbYraAAAAAElFTkSuQmCC"); + background-repeat: no-repeat; + background-position: right bottom; + width: 100%; height: 100%; +} + + +.lint-icon-warning:before, +.lint-icon-error:before { + content: ''; +} +.lint-icon-warning.dis:before, +.lint-icon-error.dis:before { + filter: url("data:image/svg+xml;utf8,#grayscale"); /* Firefox 10+, Firefox on Android */ + filter: gray; /* IE6-9 */ + -webkit-filter: grayscale(100%); +} +.lint-icon-error.dis:before { + -webkit-filter: grayscale(100%) invert(85%); +} +.lint-error { + background: #FFA; + font-size: 80%; + color: #A00; + padding: 2px 5px 3px; +} +.console-wrapper { + background: #FFF; + color: #333; +} +.console-log-head { + background: #ecf2fa; + border: 1px solid #CCC; + border-top: 0 none; + color: #6293d3; + cursor: pointer; + float: none; + font-size: 13px; + height: auto; + line-height: 19px; + margin: 0; + padding: 0.2em 0.2em 0.2em 1em; + width: auto; +} +.console-log { + border: 1px solid #CCC; + border-top: 0 none; + font-size: 13px; + height: 10.5em; + overflow: auto; +} +.console-log-line { + border-top: 1px solid #CCC; + cursor: pointer; + padding: 0.2em; +} +.console-log-line:first-child { + border-top: 0 none; +} +.console-log-line:before { + display: inline-block; + min-width: 1em; + padding-right: 0.5em; + text-align: center; +} +#console-log-line-selected { + background: #AFF; +} \ No newline at end of file diff --git a/public/js/editors/addons.js b/public/js/editors/addons.js index 77efd5e2..5ad93dde 100644 --- a/public/js/editors/addons.js +++ b/public/js/editors/addons.js @@ -200,9 +200,7 @@ csshint: { url: [ '/js/vendor/csslint/csslint.min.js', - '/js/vendor/cm_addons/lint/lint.css', - '/js/vendor/cm_addons/lint/css-lint.js', - '/js/vendor/cm_addons/lint/lint.js' + '/js/vendor/cm_addons/lint/css-lint.js' ], test: function() { return hintingTest('css') && @@ -216,12 +214,7 @@ } }, jshint: { - url: [ - '/js/vendor/jshint/jshint.min.js', - '/js/vendor/cm_addons/lint/lint.css', - '/js/vendor/cm_addons/lint/javascript-lint.js', - '/js/vendor/cm_addons/lint/lint.js' - ], + url: [], test: function() { return hintingTest('javascript') && (typeof JSHINT !== 'undefined'); @@ -238,9 +231,7 @@ htmlhint: { url: [ '/js/vendor/htmlhint/htmlhint.js', - '/js/vendor/cm_addons/lint/lint.css', - '/js/vendor/cm_addons/lint/html-lint.js', - '/js/vendor/cm_addons/lint/lint.js' + '/js/vendor/cm_addons/lint/html-lint.js' ], test: function() { return hintingTest('htmlmixed') && @@ -256,9 +247,7 @@ coffeescripthint: { url: [ '/js/vendor/coffeelint/coffeelint.min.js', - '/js/vendor/cm_addons/lint/lint.css', - '/js/vendor/cm_addons/lint/coffeescript-lint.js', - '/js/vendor/cm_addons/lint/lint.js' + '/js/vendor/cm_addons/lint/coffeescript-lint.js' ], test: function() { return hintingTest('coffeescript') && diff --git a/scripts.json b/scripts.json index 835caf0d..3e380e5e 100644 --- a/scripts.json +++ b/scripts.json @@ -4,6 +4,7 @@ "/js/vendor/jquery-migrate.js", "/js/vendor/pretty-date.js", "/js/vendor/polyfills.js", + "/js/vendor/jshint/jshint.js", "/js/vendor/codemirror4/lib/codemirror.js", "/js/vendor/codemirror4/mode/xml/xml.js", "/js/vendor/codemirror4/mode/css/css.js", @@ -15,6 +16,8 @@ "/js/vendor/cm_addons/javascript-hint.js", "/js/vendor/codemirror4/addon/edit/matchbrackets.js", "/js/vendor/codemirror4/addon/comment/comment.js", + "/js/vendor/cm_addons/lint/javascript-lint.js", + "/js/vendor/cm_addons/lint/lint.js", "/js/vendor/lz-string-1.3.3.js", "/js/vendor/cm_addons/cm-highlight-line.js", "/js/editors/snippets.cm.js", From cd8794409e7b76c2481b4dbc55275fef3698c20c Mon Sep 17 00:00:00 2001 From: Giulia Alfonsi Date: Thu, 3 Jul 2014 17:06:33 +0100 Subject: [PATCH 286/321] Changed default values for linting options --- public/js/account/preferences-settings.js | 4 ++-- public/js/editors/addons.js | 12 ++++++++---- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/public/js/account/preferences-settings.js b/public/js/account/preferences-settings.js index 503df3ea..cabf4463 100644 --- a/public/js/account/preferences-settings.js +++ b/public/js/account/preferences-settings.js @@ -26,10 +26,10 @@ var $csrf = $('#_csrf'); var hintShow = { console: true, - line: true, + line: false, // under: false, // tooltip: true, - gutter: true + gutter: false }; var currentSettings = { panels: [], diff --git a/public/js/editors/addons.js b/public/js/editors/addons.js index 5ad93dde..6fcae97a 100644 --- a/public/js/editors/addons.js +++ b/public/js/editors/addons.js @@ -25,16 +25,20 @@ var settingsHintShow = {}; var hintShow = { console: true, - line: true, + line: false, under: false, - tooltip: true, - gutter: true + tooltip: false, + gutter: false }; // css must go last for the moment due to CSSLint creating the // global variable 'exports' ['js', 'html', 'coffeescript', 'css'].forEach(function (val) { var h = val + 'hint'; - settingsHints[h] = (jsbin.settings[h] !== undefined) ? jsbin.settings[h] : true; + var d = false; + if (val === 'js') { + d = true; + } + settingsHints[h] = (jsbin.settings[h] !== undefined) ? jsbin.settings[h] : d; }); settingsHintShow = $.extend({}, hintShow, jsbin.settings.hintShow); var settingsAddons = $.extend({}, jsbin.settings.addons, settingsHints); From f5195016ecc8db9421bd9ec8c1e5263c8889d925 Mon Sep 17 00:00:00 2001 From: Remy Sharp Date: Thu, 3 Jul 2014 17:05:20 +0100 Subject: [PATCH 287/321] Tweak font size of hint settings --- public/css/account.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/css/account.css b/public/css/account.css index 2336109e..903543c6 100644 --- a/public/css/account.css +++ b/public/css/account.css @@ -188,7 +188,7 @@ span.mini-desc a { .hintOptions { font-family: SourceCodeProRegular, Menlo, Monaco, consolas, monospace !important; - font-size: 18px; + font-size: 16px; line-height: 1.2em; } From b47966a3584ad89d03bcdb82ef2e560914eef2a3 Mon Sep 17 00:00:00 2001 From: Remy Sharp Date: Thu, 3 Jul 2014 17:07:03 +0100 Subject: [PATCH 288/321] Tweak text --- views/account/editor.html | 6 +++--- views/account/preferences.html | 6 ++---- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/views/account/editor.html b/views/account/editor.html index 54b28251..9e89004f 100644 --- a/views/account/editor.html +++ b/views/account/editor.html @@ -35,8 +35,8 @@

    Customise your JS Bin editor

    -

    As soon as you make any changes, they will be automatically saved.

    - +

    Tweak JS Bin's editor to your liking and manage the addons loaded.

    +

    Settings

    @@ -97,7 +97,7 @@
    -

    Addons

    +

    Addons

    Key bindings diff --git a/views/account/preferences.html b/views/account/preferences.html index 481be1f3..2ea2ce19 100644 --- a/views/account/preferences.html +++ b/views/account/preferences.html @@ -3,9 +3,7 @@

    Default Preferences

    -

    Configure how JS Bin is set up when you create a new bin.
    - As soon as you make any changes, they will be automatically saved.

    +

    Configure how JS Bin is set up when you create a new bin, and how errors are reported.

    @@ -101,7 +99,7 @@
    - + From 39f75800dfda302af606205dd5868805f744e87d Mon Sep 17 00:00:00 2001 From: Remy Sharp Date: Thu, 3 Jul 2014 17:13:50 +0100 Subject: [PATCH 289/321] 3.15.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 902da6d0..f5779caf 100644 --- a/package.json +++ b/package.json @@ -9,7 +9,7 @@ "name": "jsbin", "description": "Collaborative JavaScript Debugging App", "main": "./lib/app", - "version": "3.14.1", + "version": "3.15.0", "preferGlobal": "true", "homepage": "http://jsbin.com", "bin": "./bin/jsbin", From 9f27585a622244a2c63e30d909240d6d59ff37ed Mon Sep 17 00:00:00 2001 From: Remy Sharp Date: Thu, 3 Jul 2014 17:57:16 +0100 Subject: [PATCH 290/321] Fix access to vars after security close --- public/js/account/preferences-settings.js | 1 - public/js/editors/addons.js | 4 ++-- public/js/jsbin.js | 10 +++++++--- public/js/vendor/cm_addons/lint/lint.js | 10 +++++----- scripts.json | 4 ++-- 5 files changed, 16 insertions(+), 13 deletions(-) diff --git a/public/js/account/preferences-settings.js b/public/js/account/preferences-settings.js index 260791d2..ca388a71 100644 --- a/public/js/account/preferences-settings.js +++ b/public/js/account/preferences-settings.js @@ -152,7 +152,6 @@ localStorageSettings.ssl = $ssl.prop('checked'); localStorage.settings = JSON.stringify(localStorageSettings); - console.log(localStorageSettings); clearTimeout(saveTimer); $saveStatus.addClass('show'); diff --git a/public/js/editors/addons.js b/public/js/editors/addons.js index 6fcae97a..73044545 100644 --- a/public/js/editors/addons.js +++ b/public/js/editors/addons.js @@ -27,7 +27,6 @@ console: true, line: false, under: false, - tooltip: false, gutter: false }; // css must go last for the moment due to CSSLint creating the @@ -40,7 +39,9 @@ } settingsHints[h] = (jsbin.settings[h] !== undefined) ? jsbin.settings[h] : d; }); + settingsHintShow = $.extend({}, hintShow, jsbin.settings.hintShow); + settingsHintShow.tooltip = settingsHintShow.gutter; var settingsAddons = $.extend({}, jsbin.settings.addons, settingsHints); var addons = { @@ -128,7 +129,6 @@ }}); setOption(cm, 'foldGutter', true); var gutters = cm.getOption('gutters'); - console.log('gutters', gutters); gutters.push('CodeMirror-linenumbers'); gutters.push('CodeMirror-foldgutter'); setOption(cm, 'gutters', gutters); diff --git a/public/js/jsbin.js b/public/js/jsbin.js index 0ec317af..66c2436f 100644 --- a/public/js/jsbin.js +++ b/public/js/jsbin.js @@ -1,11 +1,13 @@ try { console.log('Dave is ready!'); } catch (e) { - var console = { + window.console = { log: function () { // alert([].slice.call(arguments).join('\n')); }, - warn: function () {} + warn: function () {}, + trace: function () {}, + error: function () {} }; } @@ -60,7 +62,9 @@ function dedupe(array) { function exposeSettings() { 'use strict'; if (window.jsbin instanceof Node || !window.jsbin) { // because...STUPIDITY!!! - window.jsbin = {}; // create the holding object + window.jsbin = { + 'static': jsbin['static'] + }; // create the holding object if (jsbin.state.metadata && jsbin.user && jsbin.state.metadata.name === jsbin.user.name) { window.jsbin.settings = jsbin.settings; diff --git a/public/js/vendor/cm_addons/lint/lint.js b/public/js/vendor/cm_addons/lint/lint.js index 07f1e1e6..9e6012f9 100644 --- a/public/js/vendor/cm_addons/lint/lint.js +++ b/public/js/vendor/cm_addons/lint/lint.js @@ -252,11 +252,11 @@ function updateLinting(cm, annotationsNotSorted) { var state = cm.state.lint, options = state.options; - + if (cm.options.lintOpt.under) { underClear(cm); } - + if (state.hasGutter) { gutterReset(cm); } @@ -284,11 +284,11 @@ maxSeverity = getMaxSeverity(maxSeverity, severity); if (options.formatAnnotation) ann = options.formatAnnotation(ann); - + if (state.hasGutter) { tipLabel.appendChild(annotationTooltip(ann, severity)); } - + if (cm.options.lintOpt.console) { cm.consolelint.logs.appendChild(consoleLine(ann, severity, cm)); } @@ -381,7 +381,7 @@ if (!cm.options.lintRules) { cm.options.lintRules = {}; } - + if (old && old != CodeMirror.Init) { if (cm.options.lintOpt.under) { underClear(cm); diff --git a/scripts.json b/scripts.json index a4618609..52023e7f 100644 --- a/scripts.json +++ b/scripts.json @@ -30,6 +30,7 @@ "/js/chrome/splitter.js", "/js/chrome/analytics.js", "/js/chrome/settings.js", + "/js/editors/tern.js", "/js/chrome/font.js", "/js/render/render.js", "/js/render/live.js", @@ -82,8 +83,7 @@ "/js/vendor/tern/lib/infer.js", "/js/vendor/tern/plugin/doc_comment.js", "/js/editors/defs.js", - "/js/editors/definitions.js", - "/js/editors/tern.js" + "/js/editors/definitions.js" ] } } From 3071e8811e048c0ececb263d6d2d610b9743b710 Mon Sep 17 00:00:00 2001 From: Remy Sharp Date: Thu, 3 Jul 2014 17:57:31 +0100 Subject: [PATCH 291/321] 3.15.1 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index f5779caf..0c12d6c3 100644 --- a/package.json +++ b/package.json @@ -9,7 +9,7 @@ "name": "jsbin", "description": "Collaborative JavaScript Debugging App", "main": "./lib/app", - "version": "3.15.0", + "version": "3.15.1", "preferGlobal": "true", "homepage": "http://jsbin.com", "bin": "./bin/jsbin", From 3554da35ec27454746ade8baf3f80713dea1edc6 Mon Sep 17 00:00:00 2001 From: Remy Sharp Date: Thu, 3 Jul 2014 18:51:23 +0100 Subject: [PATCH 292/321] THE INSANITY!!! --- lib/middleware.js | 7 +++++-- lib/routes.js | 50 ++++++++++++++++++++++++++++++----------------- 2 files changed, 37 insertions(+), 20 deletions(-) diff --git a/lib/middleware.js b/lib/middleware.js index bbf03546..832645ef 100644 --- a/lib/middleware.js +++ b/lib/middleware.js @@ -286,7 +286,7 @@ module.exports = { var pathShouldBeSecure = pathIsSSL(parse(req.url).pathname); var forceSSL = features('sslForAll', req); - var useSSL = pathShouldBeSecure || forceSSL; + // var useSSL = pathShouldBeSecure || forceSSL; if (!config.url.ssl) { if (req.secure) { @@ -305,7 +305,10 @@ module.exports = { req.shouldNotBeSecure = true; } } else { - if (useSSL) { + // if (forceSSL) { + // return next(); + // } + if (pathShouldBeSecure) { // if the request is not https and _should be_, redirect to https return res.redirect('https://' + req.headers.host.replace(/:.*/, '') + req.url); } diff --git a/lib/routes.js b/lib/routes.js index b64d63c8..48b88eff 100644 --- a/lib/routes.js +++ b/lib/routes.js @@ -152,7 +152,20 @@ module.exports = function (app) { }); // Set up the routes. - app.get('/', shouldNotBeSecure, time('request.root'), userHandler.loadVanityURL, binHandler.loadBin, binHandler.getBinPreview); + app.get(/(?:.*\/(embed|edit|watch|download|source)|^\/$)$/, function (req, res, next) { + var ssl = features('sslForAll', req); + + if ( (!req.secure && ssl) || // a) request *should* be secure + (req.secure && !ssl) ) { // b) request is secure and *should not* be + var url = sandbox.helpers.url(req.url, true, ssl); + return res.redirect(url); + } + + next('route'); + }); + + + app.get('/', time('request.root'), userHandler.loadVanityURL, binHandler.loadBin, binHandler.getBinPreview); app.get('/', binHandler.getDefault); app.get('/gist/*', shouldNotBeSecure, binHandler.getDefault); app.post('/', binHandler.getFromPost); @@ -450,7 +463,6 @@ module.exports = function (app) { }); }); - // username shortcut routes app.get('/:username/last(-:n)?/edit', binHandler.getLatestForUser, binHandler.getBin); app.get('/:username/last(-:n)?/watch', binHandler.getLatestForUser, binHandler.live, binHandler.getBin); @@ -497,25 +509,27 @@ module.exports = function (app) { // 1. check request is supposed to be on a vanity url // 2. if not, then check if the req.headers.host matches security.preview // 3. if not, redirect - if (config.security.preview) { - var metadata = undefsafe(req, 'bin.metadata'); - var settings = {}; - var ssl = false; - var url; + var metadata = undefsafe(req, 'bin.metadata'); + var settings = {}; + var ssl = false; + var url; - if (settings) { - try { - settings = JSON.parse(metadata.settings); - ssl = features('sslForAll', { session: { user: { name: metadata.name, pro: metadata.pro, settings: { ssl: settings.ssl }}}}); - } catch (e) {} - } + if (settings) { + try { + settings = JSON.parse(metadata.settings); + ssl = features('sslForAll', { session: { user: { name: metadata.name, pro: metadata.pro, settings: { ssl: settings.ssl }}}}); + } catch (e) {} + } - url = sandbox.helpers.url(req.url, true, ssl); + if (features('sslForAll', req)) { + return next(); + } - if ( (!req.secure && ssl) || // a) request *should* be secure - (req.secure && !ssl) ) { // b) request is secure and *should not* be - return res.redirect(301, url); - } + url = sandbox.helpers.url(req.url, true, ssl); + + if ( (!req.secure && ssl) || // a) request *should* be secure + (req.secure && !ssl) ) { // b) request is secure and *should not* be + return res.redirect(url); } next(); From 1649416f78bc227915c515d540f0f45df58bd029 Mon Sep 17 00:00:00 2001 From: Remy Sharp Date: Thu, 3 Jul 2014 18:51:32 +0100 Subject: [PATCH 293/321] 3.15.2 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 0c12d6c3..7cb87020 100644 --- a/package.json +++ b/package.json @@ -9,7 +9,7 @@ "name": "jsbin", "description": "Collaborative JavaScript Debugging App", "main": "./lib/app", - "version": "3.15.1", + "version": "3.15.2", "preferGlobal": "true", "homepage": "http://jsbin.com", "bin": "./bin/jsbin", From 3a8ba24e3b33f693acf5088f468f3863a3014974 Mon Sep 17 00:00:00 2001 From: Remy Sharp Date: Thu, 3 Jul 2014 18:57:35 +0100 Subject: [PATCH 294/321] Putting production build of js in repo - faster --- .gitignore | 1 - 1 file changed, 1 deletion(-) diff --git a/.gitignore b/.gitignore index 6bd26a55..6278b38e 100644 --- a/.gitignore +++ b/.gitignore @@ -2,7 +2,6 @@ logs logs/* config.*.json public/js/jsbin*.js -public/js/prod/* .nodemonignore !config.default.json statsd.js From 6035576388a2c6dc8aeeec14c1edc7d4890b2c20 Mon Sep 17 00:00:00 2001 From: Remy Sharp Date: Thu, 3 Jul 2014 19:06:20 +0100 Subject: [PATCH 295/321] Fixed tern? Remove maps --- Gruntfile.js | 10 +++++----- public/js/jsbin.js | 2 +- scripts.json | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Gruntfile.js b/Gruntfile.js index 5007d7e6..2b9a5c9a 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -50,7 +50,7 @@ module.exports = function (grunt) { var distpaths = { script: 'public/js/prod/<%= pkg.name %>-<%= pkg.version %>.js', - map: 'public/js/prod/<%= pkg.name %>.map.json', // don't version this so we overwrite + // map: 'public/js/prod/<%= pkg.name %>.map.json', // don't version this so we overwrite min: 'public/js/prod/<%= pkg.name %>-<%= pkg.version %>.min.js', runner: 'public/js/prod/runner-<%= pkg.version %>.js', runnermin: 'public/js/prod/runner-<%= pkg.version %>.min.js' @@ -120,10 +120,10 @@ module.exports = function (grunt) { options: { banner: '/*! <%= pkg.name %> - v<%= pkg.version %> - ' + '<%= grunt.template.today("yyyy-mm-dd") %> */\n', - sourceMap: distpaths.map, - sourceMappingURL: '/js/prod/jsbin.map.json', - sourceMapPrefix: 2, - sourceMapRoot: '/js', + // sourceMap: distpaths.map, + // sourceMappingURL: '/js/prod/jsbin.map.json', + // sourceMapPrefix: 2, + // sourceMapRoot: '/js', }, src: distpaths.script, //'<%= scriptsRelative %>', dest: distpaths.min diff --git a/public/js/jsbin.js b/public/js/jsbin.js index 66c2436f..c8cd0839 100644 --- a/public/js/jsbin.js +++ b/public/js/jsbin.js @@ -66,7 +66,7 @@ function exposeSettings() { 'static': jsbin['static'] }; // create the holding object - if (jsbin.state.metadata && jsbin.user && jsbin.state.metadata.name === jsbin.user.name) { + if (jsbin.state.metadata && jsbin.user && jsbin.state.metadata.name === jsbin.user.name && jsbin.user.name) { window.jsbin.settings = jsbin.settings; return; } diff --git a/scripts.json b/scripts.json index 52023e7f..b1a4a3e6 100644 --- a/scripts.json +++ b/scripts.json @@ -30,7 +30,6 @@ "/js/chrome/splitter.js", "/js/chrome/analytics.js", "/js/chrome/settings.js", - "/js/editors/tern.js", "/js/chrome/font.js", "/js/render/render.js", "/js/render/live.js", @@ -41,6 +40,7 @@ "/js/editors/editors.js", "/js/editors/libraries.js", "/js/editors/library.js", + "/js/editors/tern.js", "/js/editors/addons.js", "/js/render/saved-history-preview.js", "/js/chrome/esc.js", From 0c62774f6865e9152e85dfbe1b720e440d507fb8 Mon Sep 17 00:00:00 2001 From: Remy Sharp Date: Thu, 3 Jul 2014 19:06:43 +0100 Subject: [PATCH 296/321] 3.15.3 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 7cb87020..1afb59fa 100644 --- a/package.json +++ b/package.json @@ -9,7 +9,7 @@ "name": "jsbin", "description": "Collaborative JavaScript Debugging App", "main": "./lib/app", - "version": "3.15.2", + "version": "3.15.3", "preferGlobal": "true", "homepage": "http://jsbin.com", "bin": "./bin/jsbin", From 37a8dcf490ceec5a1c1c4b86803275d14bf58a5e Mon Sep 17 00:00:00 2001 From: Remy Sharp Date: Thu, 3 Jul 2014 19:07:11 +0100 Subject: [PATCH 297/321] Build files --- public/js/prod/addon-tern-3.15.3.min.js | 5 + public/js/prod/jsbin-3.15.3.js | 94476 ++++++++++++++++++++++ public/js/prod/jsbin-3.15.3.min.js | 20 + public/js/prod/runner-3.15.3.js | 1482 + public/js/prod/runner-3.15.3.min.js | 1 + 5 files changed, 95984 insertions(+) create mode 100644 public/js/prod/addon-tern-3.15.3.min.js create mode 100644 public/js/prod/jsbin-3.15.3.js create mode 100644 public/js/prod/jsbin-3.15.3.min.js create mode 100644 public/js/prod/runner-3.15.3.js create mode 100644 public/js/prod/runner-3.15.3.min.js diff --git a/public/js/prod/addon-tern-3.15.3.min.js b/public/js/prod/addon-tern-3.15.3.min.js new file mode 100644 index 00000000..e1d3698b --- /dev/null +++ b/public/js/prod/addon-tern-3.15.3.min.js @@ -0,0 +1,5 @@ +!function(a){"object"==typeof exports&&"object"==typeof module?a(require("../../lib/codemirror")):"function"==typeof define&&define.amd?define(["../../lib/codemirror"],a):a(CodeMirror)}(function(a){"use strict";function b(a,b,c){var d=a.docs[b];d?c(D(a,d)):a.options.getFile?a.options.getFile(b,c):c(null)}function c(a,b,c){for(var d in a.docs){var e=a.docs[d];if(e.doc==b)return e}if(!c)for(var f=0;;++f)if(d="[doc"+(f||"")+"]",!a.docs[d]){c=d;break}return a.addDoc(c,b)}function d(a,b,d){var f=c(a,b),g=a.cachedArgHints;g&&g.doc==b&&J(g.start,d.to)<=0&&(a.cachedArgHints=null);var h=f.changed;null==h&&(f.changed=h={from:d.from.line,to:d.from.line});var i=d.from.line+(d.text.length-1);d.from.line=h.to&&(h.to=i+1),h.from>d.from.line&&(h.from=d.from.line),b.lineCount()>H&&d.to-h.from>100&&setTimeout(function(){f.changed&&f.changed.to-f.changed.from>100&&e(a,f)},200)}function e(a,b){a.server.request({files:[{type:"full",name:b.name,text:D(a,b)}]},function(a){a?window.console.error(a):b.changed=null})}function f(b,c,d){b.request(c,{type:"completions",types:!0,docs:!0,urls:!0},function(e,f){if(e)return B(b,c,e);var h=[],i="",j=f.start,k=f.end;'["'==c.getRange(F(j.line,j.ch-2),j)&&'"]'!=c.getRange(k,F(k.line,k.ch+2))&&(i='"]');for(var l=0;l=m;--l){for(var o=c.getLine(l),p=0,q=0;;){var r=o.indexOf(" ",q);if(-1==r)break;p+=i-(r+p)%i-1,q=r+1}if(g=f.column-p,"("==o.charAt(g)){n=!0;break}}if(n){var s=F(l,g),t=b.cachedArgHints;return t&&t.doc==c.getDoc()&&0==J(s,t.start)?j(b,c,h):(b.request(c,{type:"type",preferFunction:!0,end:s},function(a,d){!a&&d.type&&/^fn\(/.test(d.type)&&(b.cachedArgHints={start:q,type:k(d.type),name:d.exprName||d.name||"fn",guess:d.guess,doc:c.getDoc()},j(b,c,h))}),void 0)}}}}}function j(a,b,c){C(a);for(var d=a.cachedArgHints,e=d.type,f=v("span",d.guess?G+"fhint-guess":null,v("span",G+"fname",d.name),"("),g=0;g ":")")),e.rettype&&f.appendChild(v("span",G+"type",e.rettype));var i=b.cursorCoords(null,"page");a.activeArgHints=y(i.right+1,i.bottom,f)}function k(a){function b(b){for(var c=0,e=d;;){var f=a.charAt(d);if(b.test(f)&&!c)return a.slice(e,d);/[{\[\(]/.test(f)?++c:/[}\]\)]/.test(f)&&--c,++d}}var c=[],d=3;if(")"!=a.charAt(d))for(;;){var e=a.slice(d).match(/^([^, \(\[\{]+): /);if(e&&(d+=e[0].length,e=e[1]),c.push({name:e,type:b(/[\),]/)}),")"==a.charAt(d))break;d+=2}var f=a.slice(d).match(/^\) -> (.*)$/);return{args:c,rettype:f&&f[1]}}function l(a,b){function d(d){var e={type:"definition",variable:d||null},f=c(a,b.getDoc());a.server.request(t(a,f,e),function(c,d){if(c)return B(a,b,c);if(!d.file&&d.url)return window.open(d.url),void 0;if(d.file){var e,g=a.docs[d.file];if(g&&(e=o(g.doc,d)))return a.jumpStack.push({file:f.name,start:b.getCursor("from"),end:b.getCursor("to")}),n(a,f,g,e.start,e.end),void 0}B(a,b,"Could not find a definition.")})}p(b)?d():w(b,"Jump to variable",function(a){a&&d(a)})}function m(a,b){var d=a.jumpStack.pop(),e=d&&a.docs[d.file];e&&n(a,c(a,b.getDoc()),e,d.start,d.end)}function n(a,b,c,d,e){c.doc.setSelection(e,d),b!=c&&a.options.switchToDoc&&(C(a),a.options.switchToDoc(c.name))}function o(a,b){for(var c=b.context.slice(0,b.contextOffset).split("\n"),d=b.start.line-(c.length-1),e=F(d,(1==c.length?b.start.ch:a.getLine(d).length)-c[0].length),f=a.getLine(d).slice(e.ch),g=d+1;gl&&(h=k,j=l)}if(!h)return null;if(1==c.length?h.ch+=c[0].length:h=F(h.line+(c.length-1),c[c.length-1].length),b.start.line==b.end.line)var m=F(h.line,h.ch+(b.end.ch-b.start.ch));else var m=F(h.line+(b.end.line-b.start.line),b.end.ch);return{start:h,end:m}}function p(a){var b=a.getCursor("end"),c=a.getTokenAt(b);return c.start=0&&J(g,i.end)<=0&&(g=e.length-1))}b.setSelections(e,g)})}function s(a,b){for(var c=Object.create(null),d=0;dH&&g!==!1&&b.changed.to-b.changed.from<100&&b.changed.from<=h.line&&b.changed.to>c.end.line){e.push(u(b,h,c.end)),c.file="#0";var f=e[0].offsetLines;null!=c.start&&(c.start=F(c.start.line- -f,c.start.ch)),c.end=F(c.end.line-f,c.end.ch)}else e.push({type:"full",name:b.name,text:D(a,b)}),c.file=b.name,b.changed=null;else c.file=b.name;for(var i in a.docs){var j=a.docs[i];j.changed&&j!=b&&(e.push({type:"full",name:j.name,text:D(a,j)}),j.changed=null)}return{query:c,files:e}}function u(b,c,d){for(var e,f=b.doc,g=null,h=null,i=4,j=c.line-1,k=Math.max(0,j-50);j>=k;--j){var l=f.getLine(j),m=l.search(/\bfunction\b/);if(!(0>m)){var n=a.countColumn(l,null,i);null!=g&&n>=g||(g=n,h=j)}}null==h&&(h=k);var o=Math.min(f.lastLine(),d.line+20);if(null==g||g==a.countColumn(f.getLine(c.line),null,i))e=o;else for(e=d.line+1;o>e;++e){var n=a.countColumn(f.getLine(e),null,i);if(g>=n)break}var p=F(h,0);return{type:"part",name:b.name,offsetLines:p.line,text:f.getRange(p,F(e,0))}}function v(a,b){var c=document.createElement(a);b&&(c.className=b);for(var d=2;d",c):c(prompt(b,""))}function x(a,b){function c(){e.parentNode&&(a.off("cursorActivity",c),A(e))}var d=a.cursorCoords(),e=y(d.right+1,d.bottom,b);a.on("cursorActivity",c),a.on("blur",c),a.on("keydown",c)}function y(a,b,c){var d=v("div",G+"tooltip",c);return d.style.left=a+"px",d.style.top=b+"px",document.body.appendChild(d),d}function z(a){var b=a&&a.parentNode;b&&b.removeChild(a)}function A(a){a.style.opacity="0",setTimeout(function(){z(a)},1100)}function B(a,b,c){a.options.showError?a.options.showError(b,c):x(b,String(c))}function C(a){a.activeArgHints&&(z(a.activeArgHints),a.activeArgHints=null)}function D(a,b){var c=b.doc.getValue();return a.options.fileFilter&&(c=a.options.fileFilter(c,b.name,b.doc)),c}function E(a){function c(a,b){b&&(a.id=++e,f[e]=b),d.postMessage(a)}var d=new Worker(a.options.workerScript);d.postMessage({type:"init",defs:a.options.defs,plugins:a.options.plugins,scripts:a.options.workerDeps});var e=0,f={};d.onmessage=function(d){var e=d.data;"getFile"==e.type?b(a,e.name,function(a,b){c({type:"getFile",err:String(a),text:b,id:e.id})}):"debug"==e.type?window.console.log(e.message):e.id&&f[e.id]&&(f[e.id](e.err,e.body),delete f[e.id])},d.onerror=function(a){for(var b in f)f[b](a);f={}},this.addFile=function(a,b){c({type:"add",name:a,text:b})},this.delFile=function(a){c({type:"del",name:a})},this.request=function(a,b){c({type:"req",body:a},b)}}a.TernServer=function(a){var c=this;this.options=a||{};var e=this.options.plugins||(this.options.plugins={});e.doc_comment||(e.doc_comment=!0),this.server=this.options.useWorker?new E(this):new tern.Server({getFile:function(a,d){return b(c,a,d)},async:!0,defs:this.options.defs||[],plugins:e}),this.docs=Object.create(null),this.trackChange=function(a,b){d(c,a,b)},this.cachedArgHints=null,this.activeArgHints=null,this.jumpStack=[]},a.TernServer.prototype={addDoc:function(b,c){var d={doc:c,name:b,changed:null};return this.server.addFile(b,D(this,d)),a.on(c,"change",this.trackChange),this.docs[b]=d},delDoc:function(b){var c=this.docs[b];c&&(a.off(c.doc,"change",this.trackChange),delete this.docs[b],this.server.delFile(b))},hideDoc:function(a){C(this);var b=this.docs[a];b&&b.changed&&e(this,b)},complete:function(b){var c=this;a.showHint(b,function(a,b){return f(c,a,b)},{async:!0})},getHint:function(a,b){return f(this,a,b)},showType:function(a,b){h(this,a,b)},updateArgHints:function(a){i(this,a)},jumpToDef:function(a){l(this,a)},jumpBack:function(a){m(this,a)},rename:function(a){q(this,a)},selectName:function(a){r(this,a)},request:function(a,b,d,e){var f=this,g=c(this,a.getDoc()),h=t(this,g,b,e);this.server.request(h,function(a,c){!a&&f.options.responseFilter&&(c=f.options.responseFilter(g,b,h,a,c)),d(a,c)})}};var F=a.Pos,G="CodeMirror-Tern-",H=250,I=0,J=a.cmpPos}),function(a,b){return"object"==typeof exports&&"object"==typeof module?b(exports):"function"==typeof define&&define.amd?define(["exports"],b):(b(a.acorn||(a.acorn={})),void 0)}(this,function(a){"use strict";function b(a){lb=a||{};for(var b in pb)Object.prototype.hasOwnProperty.call(lb,b)||(lb[b]=pb[b]);ob=lb.sourceFile||null}function c(a,b){var c=qb(mb,a);b+=" ("+c.line+":"+c.column+")";var d=new SyntaxError(b);throw d.pos=a,d.loc=c,d.raisedAt=rb,d}function d(a){function b(a){if(1==a.length)return c+="return str === "+JSON.stringify(a[0])+";";c+="switch(str){";for(var b=0;b3){d.sort(function(a,b){return b.length-a.length}),c+="switch(str.length){";for(var e=0;erb&&10!==c&&13!==c&&8232!==c&&8233!==c;)++rb,c=mb.charCodeAt(rb);lb.onComment&&lb.onComment(!1,mb.slice(a+2,rb),a,rb,b,lb.locations&&new e)}function j(){for(;nb>rb;){var a=mb.charCodeAt(rb);if(32===a)++rb;else if(13===a){++rb;var b=mb.charCodeAt(rb);10===b&&++rb,lb.locations&&(++zb,Ab=rb)}else if(10===a||8232===a||8233===a)++rb,lb.locations&&(++zb,Ab=rb);else if(a>8&&14>a)++rb;else if(47===a){var b=mb.charCodeAt(rb+1);if(42===b)h();else{if(47!==b)break;i()}}else if(160===a)++rb;else{if(!(a>=5760&&Sc.test(String.fromCharCode(a))))break;++rb}}}function k(){var a=mb.charCodeAt(rb+1);return a>=48&&57>=a?y(!0):(++rb,g(uc))}function l(){var a=mb.charCodeAt(rb+1);return yb?(++rb,v()):61===a?u(yc,2):u(wc,1)}function m(){var a=mb.charCodeAt(rb+1);return 61===a?u(yc,2):u(Kc,1)}function n(a){var b=mb.charCodeAt(rb+1);return b===a?u(124===a?Bc:Cc,2):61===b?u(yc,2):u(124===a?Dc:Fc,1)}function o(){var a=mb.charCodeAt(rb+1);return 61===a?u(yc,2):u(Ec,1)}function p(a){var b=mb.charCodeAt(rb+1);return b===a?45==b&&62==mb.charCodeAt(rb+2)&&Xc.test(mb.slice(Cb,rb))?(rb+=3,i(),j(),t()):u(zc,2):61===b?u(yc,2):u(Jc,1)}function q(a){var b=mb.charCodeAt(rb+1),c=1;return b===a?(c=62===a&&62===mb.charCodeAt(rb+2)?3:2,61===mb.charCodeAt(rb+c)?u(yc,c+1):u(Ic,c)):33==b&&60==a&&45==mb.charCodeAt(rb+2)&&45==mb.charCodeAt(rb+3)?(rb+=4,i(),j(),t()):(61===b&&(c=61===mb.charCodeAt(rb+2)?3:2),u(Hc,c))}function r(a){var b=mb.charCodeAt(rb+1);return 61===b?u(Gc,61===mb.charCodeAt(rb+2)?3:2):u(61===a?xc:Ac,1)}function s(a){switch(a){case 46:return k();case 40:return++rb,g(pc);case 41:return++rb,g(qc);case 59:return++rb,g(sc);case 44:return++rb,g(rc);case 91:return++rb,g(lc);case 93:return++rb,g(mc);case 123:return++rb,g(nc);case 125:return++rb,g(oc);case 58:return++rb,g(tc);case 63:return++rb,g(vc);case 48:var b=mb.charCodeAt(rb+1);if(120===b||88===b)return x();case 49:case 50:case 51:case 52:case 53:case 54:case 55:case 56:case 57:return y(!1);case 34:case 39:return z(a);case 47:return l(a);case 37:case 42:return m();case 124:case 38:return n(a);case 94:return o();case 43:case 45:return p(a);case 60:case 62:return q(a);case 61:case 33:return r(a);case 126:return u(Ac,1)}return!1}function t(a){if(a?rb=sb+1:sb=rb,lb.locations&&(ub=new e),a)return v();if(rb>=nb)return g(Mb);var b=mb.charCodeAt(rb);if(Zc(b)||92===b)return C();var d=s(b);if(d===!1){var f=String.fromCharCode(b);if("\\"===f||Vc.test(f))return C();c(rb,"Unexpected character '"+f+"'")}return d}function u(a,b){var c=mb.slice(rb,rb+b);rb+=b,g(a,c)}function v(){for(var a,b,d="",e=rb;;){rb>=nb&&c(e,"Unterminated regular expression");var f=mb.charAt(rb);if(Xc.test(f)&&c(e,"Unterminated regular expression"),a)a=!1;else{if("["===f)b=!0;else if("]"===f&&b)b=!1;else if("/"===f&&!b)break;a="\\"===f}++rb}var d=mb.slice(e,rb);++rb;var h=B();h&&!/^[gmsiy]*$/.test(h)&&c(e,"Invalid regexp flag");try{var i=new RegExp(d,h)}catch(j){j instanceof SyntaxError&&c(e,j.message),c(j)}return g(Jb,i)}function w(a,b){for(var c=rb,d=0,e=0,f=null==b?1/0:b;f>e;++e){var g,h=mb.charCodeAt(rb);if(g=h>=97?h-97+10:h>=65?h-65+10:h>=48&&57>=h?h-48:1/0,g>=a)break;++rb,d=d*a+g}return rb===c||null!=b&&rb-c!==b?null:d}function x(){rb+=2;var a=w(16);return null==a&&c(sb+2,"Expected hexadecimal number"),Zc(mb.charCodeAt(rb))&&c(rb,"Identifier directly after number"),g(Ib,a)}function y(a){var b=rb,d=!1,e=48===mb.charCodeAt(rb);a||null!==w(10)||c(b,"Invalid number"),46===mb.charCodeAt(rb)&&(++rb,w(10),d=!0);var f=mb.charCodeAt(rb);(69===f||101===f)&&(f=mb.charCodeAt(++rb),(43===f||45===f)&&++rb,null===w(10)&&c(b,"Invalid number"),d=!0),Zc(mb.charCodeAt(rb))&&c(rb,"Identifier directly after number");var h,i=mb.slice(b,rb);return d?h=parseFloat(i):e&&1!==i.length?/[89]/.test(i)||Gb?c(b,"Invalid number"):h=parseInt(i,8):h=parseInt(i,10),g(Ib,h)}function z(a){rb++;for(var b="";;){rb>=nb&&c(sb,"Unterminated string constant");var d=mb.charCodeAt(rb);if(d===a)return++rb,g(Kb,b);if(92===d){d=mb.charCodeAt(++rb);var e=/^[0-7]+/.exec(mb.slice(rb,rb+3));for(e&&(e=e[0]);e&&parseInt(e,8)>255;)e=e.slice(0,-1);if("0"===e&&(e=null),++rb,e)Gb&&c(rb-2,"Octal literal in strict mode"),b+=String.fromCharCode(parseInt(e,8)),rb+=e.length-1;else switch(d){case 110:b+="\n";break;case 114:b+="\r";break;case 120:b+=String.fromCharCode(A(2));break;case 117:b+=String.fromCharCode(A(4));break;case 85:b+=String.fromCharCode(A(8));break;case 116:b+=" ";break;case 98:b+="\b";break;case 118:b+=" ";break;case 102:b+="\f";break;case 48:b+="\0";break;case 13:10===mb.charCodeAt(rb)&&++rb;case 10:lb.locations&&(Ab=rb,++zb);break;default:b+=String.fromCharCode(d)}}else(13===d||10===d||8232===d||8233===d)&&c(sb,"Unterminated string constant"),b+=String.fromCharCode(d),++rb}}function A(a){var b=w(16,a);return null===b&&c(sb,"Bad character escape sequence"),b}function B(){Mc=!1;for(var a,b=!0,d=rb;;){var e=mb.charCodeAt(rb);if($c(e))Mc&&(a+=mb.charAt(rb)),++rb;else{if(92!==e)break;Mc||(a=mb.slice(d,rb)),Mc=!0,117!=mb.charCodeAt(++rb)&&c(rb,"Expecting Unicode escape sequence \\uXXXX"),++rb;var f=A(4),g=String.fromCharCode(f);g||c(rb-1,"Invalid Unicode escape"),(b?Zc(f):$c(f))||c(rb-4,"Invalid Unicode escape"),a+=g}b=!1}return Mc?a:mb.slice(d,rb)}function C(){var a=B(),b=Lb;return!Mc&&Rc(a)&&(b=kc[a]),g(b,a)}function D(){Bb=sb,Cb=tb,Db=vb,t()}function E(a){if(Gb=a,rb=sb,lb.locations)for(;Ab>rb;)Ab=mb.lastIndexOf("\n",Ab-2)+1,--zb;j(),t()}function F(){this.type=null,this.start=sb,this.end=null}function G(){this.start=ub,this.end=null,null!==ob&&(this.source=ob)}function H(){var a=new F;return lb.locations&&(a.loc=new G),lb.directSourceFile&&(a.sourceFile=lb.directSourceFile),lb.ranges&&(a.range=[sb,0]),a}function I(a){var b=new F;return b.start=a.start,lb.locations&&(b.loc=new G,b.loc.start=a.loc.start),lb.ranges&&(b.range=[a.range[0],0]),b}function J(a,b){return a.type=b,a.end=Cb,lb.locations&&(a.loc.end=Db),lb.ranges&&(a.range[1]=Cb),a}function K(a){return lb.ecmaVersion>=5&&"ExpressionStatement"===a.type&&"Literal"===a.expression.type&&"use strict"===a.expression.value}function L(a){return wb===a?(D(),!0):void 0}function M(){return!lb.strictSemicolons&&(wb===Mb||wb===oc||Xc.test(mb.slice(Cb,sb)))}function N(){L(sc)||M()||P()}function O(a){wb===a?D():P()}function P(){c(sb,"Unexpected token")}function Q(a){"Identifier"!==a.type&&"MemberExpression"!==a.type&&c(a.start,"Assigning to rvalue"),Gb&&"Identifier"===a.type&&Qc(a.name)&&c(a.start,"Assigning to "+a.name+" in strict mode")}function R(a){Bb=Cb=rb,lb.locations&&(Db=new e),Eb=Gb=null,Fb=[],t();var b=a||H(),c=!0;for(a||(b.body=[]);wb!==Mb;){var d=S();b.body.push(d),c&&K(d)&&E(!0),c=!1}return J(b,"Program")}function S(){(wb===wc||wb===yc&&"/="==xb)&&t(!0);var a=wb,b=H();switch(a){case Nb:case Qb:D();var d=a===Nb;L(sc)||M()?b.label=null:wb!==Lb?P():(b.label=kb(),N());for(var e=0;eb){var e=I(a);e.left=a,e.operator=xb;var f=wb;D(),e.right=ab(bb(),d,c);var g=J(e,f===Bc||f===Cc?"LogicalExpression":"BinaryExpression");return ab(g,b,c)}return a}function bb(){if(wb.prefix){var a=H(),b=wb.isUpdate;return a.operator=xb,a.prefix=!0,yb=!0,D(),a.argument=bb(),b?Q(a.argument):Gb&&"delete"===a.operator&&"Identifier"===a.argument.type&&c(a.start,"Deleting local variable in strict mode"),J(a,b?"UpdateExpression":"UnaryExpression")}for(var d=cb();wb.postfix&&!M();){var a=I(d);a.operator=xb,a.prefix=!1,a.argument=d,Q(d),D(),d=J(a,"UpdateExpression")}return d}function cb(){return db(eb())}function db(a,b){if(L(uc)){var c=I(a);return c.object=a,c.property=kb(!0),c.computed=!1,db(J(c,"MemberExpression"),b)}if(L(lc)){var c=I(a);return c.object=a,c.property=Y(),c.computed=!0,O(mc),db(J(c,"MemberExpression"),b)}if(!b&&L(pc)){var c=I(a);return c.callee=a,c.arguments=jb(qc,!1),db(J(c,"CallExpression"),b)}return a}function eb(){switch(wb){case fc:var a=H();return D(),J(a,"ThisExpression");case Lb:return kb();case Ib:case Kb:case Jb:var a=H();return a.value=xb,a.raw=mb.slice(sb,tb),D(),J(a,"Literal");case gc:case hc:case ic:var a=H();return a.value=wb.atomValue,a.raw=wb.keyword,D(),J(a,"Literal");case pc:var b=ub,c=sb;D();var d=Y();return d.start=c,d.end=tb,lb.locations&&(d.loc.start=b,d.loc.end=vb),lb.ranges&&(d.range=[c,tb]),O(qc),d;case lc:var a=H();return D(),a.elements=jb(mc,!0,!0),J(a,"ArrayExpression");case nc:return gb();case Xb:var a=H();return D(),ib(a,!1);case ec:return fb();default:P()}}function fb(){var a=H();return D(),a.callee=db(eb(),!0),a.arguments=L(pc)?jb(qc,!1):Hb,J(a,"NewExpression")}function gb(){var a=H(),b=!0,d=!1;for(a.properties=[],D();!L(oc);){if(b)b=!1;else if(O(rc),lb.allowTrailingCommas&&L(oc))break;var e,f={key:hb()},g=!1;if(L(tc)?(f.value=Y(!0),e=f.kind="init"):lb.ecmaVersion>=5&&"Identifier"===f.key.type&&("get"===f.key.name||"set"===f.key.name)?(g=d=!0,e=f.kind=f.key.name,f.key=hb(),wb!==pc&&P(),f.value=ib(H(),!1)):P(),"Identifier"===f.key.type&&(Gb||d))for(var h=0;hg?a.id:a.params[g];if((Pc(h.name)||Qc(h.name))&&c(h.start,"Defining '"+h.name+"' in strict mode"),g>=0)for(var i=0;g>i;++i)h.name===a.params[i].name&&c(h.start,"Argument name clash in strict mode")}return J(a,b?"FunctionDeclaration":"FunctionExpression")}function jb(a,b,c){for(var d=[],e=!0;!L(a);){if(e)e=!1;else if(O(rc),b&&lb.allowTrailingCommas&&L(a))break;c&&wb===rc?d.push(null):d.push(Y(!0))}return d}function kb(a){var b=H();return a&&"everywhere"==lb.forbidReserved&&(a=!1),wb===Lb?(!a&&(lb.forbidReserved&&(3===lb.ecmaVersion?Nc:Oc)(xb)||Gb&&Pc(xb))&&-1==mb.slice(sb,tb).indexOf("\\")&&c(sb,"The keyword '"+xb+"' is reserved"),b.name=xb):a&&wb.keyword?b.name=wb.keyword:P(),yb=!1,D(),J(b,"Identifier")}a.version="0.4.1";var lb,mb,nb,ob;a.parse=function(a,c){return mb=String(a),nb=mb.length,b(c),f(),R(lb.program)};var pb=a.defaultOptions={ecmaVersion:5,strictSemicolons:!1,allowTrailingCommas:!0,forbidReserved:!1,allowReturnOutsideFunction:!1,locations:!1,onComment:null,ranges:!1,program:null,sourceFile:null,directSourceFile:null},qb=a.getLineInfo=function(a,b){for(var c=1,d=0;;){Yc.lastIndex=d;var e=Yc.exec(a);if(!(e&&e.indexa?36===a:91>a?!0:97>a?95===a:123>a?!0:a>=170&&Vc.test(String.fromCharCode(a))},$c=a.isIdentifierChar=function(a){return 48>a?36===a:58>a?!0:65>a?!1:91>a?!0:97>a?95===a:123>a?!0:a>=170&&Wc.test(String.fromCharCode(a))},_c={kind:"loop"},ad={kind:"switch"}}),function(a,b){return"object"==typeof exports&&"object"==typeof module?b(exports,require("./acorn")):"function"==typeof define&&define.amd?define(["exports","./acorn"],b):(b(a.acorn||(a.acorn={}),a.acorn),void 0)}(this,function(a,b){"use strict";function c(){if(bb=hb.end,Y.locations&&(fb=hb.endLoc),hb=ib.length?ib.shift():d(),hb.start>=db){for(;hb.start>=db;)cb=db,db=l(cb)+1; +eb=m(cb)}}function d(){for(;;)try{return $()}catch(a){if(!(a instanceof SyntaxError))throw a;var c=a.message,d=a.raisedAt,f=!0;if(/unterminated/i.test(c))if(d=l(a.pos),/string/.test(c))f={start:a.pos,end:d,type:ab.string,value:Z.slice(a.pos+1,d)};else if(/regular expr/i.test(c)){var g=Z.slice(a.pos,d);try{g=new RegExp(g)}catch(a){}f={start:a.pos,end:d,type:ab.regexp,value:g}}else f=!1;else if(/invalid (unicode|regexp|number)|expecting unicode|octal literal|is reserved|directly after number/i.test(c))for(;d]/.test(b)||/[enwfd]/.test(b)&&/\b(keywords|case|else|return|throw|new|in|(instance|type)of|delete|void)$/.test(Z.slice(a-10,a));$.jumpTo(a,c)}function f(a){var b={start:a.start,end:a.end,type:a.type,value:a.value};return Y.locations&&(b.startLoc=a.startLoc,b.endLoc=a.endLoc),b}function g(a){for(ib.length||(hb=f(hb));a>ib.length;)ib.push(f(d()));return ib[a-1]}function h(a){return 10===a||13===a||8232===a||8329===a}function i(a){return 14>a&&a>8||32===a||160===a||h(a)}function j(){_.push(eb)}function k(){eb=_.pop()}function l(a){for(;aeb&&o()&&(!d||db>=Z.length||m(db)=cb;--a){var b=Z.charCodeAt(a);if(9!==b&&32!==b)return!1}return!0}function p(a){this.type=null,this.start=a,this.end=null}function q(a){this.start=a||hb.startLoc||{line:1,column:0},this.end=null,null!==gb&&(this.source=gb)}function r(){var a=new p(hb.start);return Y.locations&&(a.loc=new q),Y.directSourceFile&&(a.sourceFile=Y.directSourceFile),a}function s(a){var b=new p(a.start);return Y.locations&&(b.loc=new q(a.loc.start)),b}function t(a,b){return a.type=b,a.end=bb,Y.locations&&(a.loc.end=fb),a}function u(){if(Y.locations){var a=new q;return a.end=a.start,a}}function v(){var a=new p(hb.start);return a.type="Identifier",a.end=hb.start,a.name="✖",a.loc=u(),a}function w(a){return"✖"==a.name}function x(a){return hb.type===a?(c(),!0):void 0}function y(){return hb.type===ab.eof||hb.type===ab.braceR||jb.test(Z.slice(bb,hb.start))}function z(){x(ab.semi)}function A(a){return x(a)?!0:g(1).type==a?(c(),c(),!0):g(2).type==a?(c(),c(),c(),!0):void 0}function B(a){return"Identifier"===a.type||"MemberExpression"===a.type?a:v()}function C(){var a=r();for(a.body=[];hb.type!==ab.eof;)a.body.push(D());return t(a,"Program")}function D(){var a=hb.type,b=r();switch(a){case ab._break:case ab._continue:c();var d=a===ab._break;return b.label=hb.type===ab.name?V():null,z(),t(b,d?"BreakStatement":"ContinueStatement");case ab._debugger:return c(),z(),t(b,"DebuggerStatement");case ab._do:return c(),b.body=D(),b.test=x(ab._while)?J():v(),z(),t(b,"DoWhileStatement");case ab._for:if(c(),j(),A(ab.parenL),hb.type===ab.semi)return F(b,null);if(hb.type===ab._var){var e=r();return c(),H(e,!0),1===e.declarations.length&&x(ab._in)?G(b,e):F(b,e)}var e=I(!1,!0);return x(ab._in)?G(b,B(e)):F(b,e);case ab._function:return c(),W(b,!0);case ab._if:return c(),b.test=J(),b.consequent=D(),b.alternate=x(ab._else)?D():null,t(b,"IfStatement");case ab._return:return c(),x(ab.semi)||y()?b.argument=null:(b.argument=I(),z()),t(b,"ReturnStatement");case ab._switch:var f=eb,g=cb;c(),b.discriminant=J(),b.cases=[],j(),A(ab.braceL);for(var h;!n(ab.braceR,f,g,!0);)if(hb.type===ab._case||hb.type===ab._default){var i=hb.type===ab._case;h&&t(h,"SwitchCase"),b.cases.push(h=r()),h.consequent=[],c(),h.test=i?I():null,A(ab.colon)}else h||(b.cases.push(h=r()),h.consequent=[],h.test=null),h.consequent.push(D());return h&&t(h,"SwitchCase"),k(),x(ab.braceR),t(b,"SwitchStatement");case ab._throw:return c(),b.argument=I(),z(),t(b,"ThrowStatement");case ab._try:if(c(),b.block=E(),b.handler=null,hb.type===ab._catch){var l=r();c(),A(ab.parenL),l.param=V(),A(ab.parenR),l.guard=null,l.body=E(),b.handler=t(l,"CatchClause")}return b.finalizer=x(ab._finally)?E():null,b.handler||b.finalizer?t(b,"TryStatement"):b.block;case ab._var:return c(),b=H(b),z(),b;case ab._while:return c(),b.test=J(),b.body=D(),t(b,"WhileStatement");case ab._with:return c(),b.object=J(),b.body=D(),t(b,"WithStatement");case ab.braceL:return E();case ab.semi:return c(),t(b,"EmptyStatement");default:var m=I();return w(m)?(c(),hb.type===ab.eof?t(b,"EmptyStatement"):D()):a===ab.name&&"Identifier"===m.type&&x(ab.colon)?(b.body=D(),b.label=m,t(b,"LabeledStatement")):(b.expression=m,z(),t(b,"ExpressionStatement"))}}function E(){var a=r();j(),A(ab.braceL);var b=eb,c=cb;for(a.body=[];!n(ab.braceR,b,c,!0);)a.body.push(D());return k(),x(ab.braceR),t(a,"BlockStatement")}function F(a,b){return a.init=b,a.test=a.update=null,x(ab.semi)&&hb.type!==ab.semi&&(a.test=I()),x(ab.semi)&&hb.type!==ab.parenR&&(a.update=I()),k(),A(ab.parenR),a.body=D(),t(a,"ForStatement")}function G(a,b){return a.left=b,a.right=I(),k(),A(ab.parenR),a.body=D(),t(a,"ForInStatement")}function H(a,b){for(a.declarations=[],a.kind="var";hb.type===ab.name;){var c=r();if(c.id=V(),c.init=x(ab.eq)?I(!0,b):null,a.declarations.push(t(c,"VariableDeclarator")),!x(ab.comma))break}if(!a.declarations.length){var c=r();c.id=v(),a.declarations.push(t(c,"VariableDeclarator"))}return t(a,"VariableDeclaration")}function I(a,b){var c=K(b);if(!a&&hb.type===ab.comma){var d=s(c);for(d.expressions=[c];x(ab.comma);)d.expressions.push(K(b));return t(d,"SequenceExpression")}return c}function J(){j(),A(ab.parenL);var a=I();return k(),A(ab.parenR),a}function K(a){var b=L(a);if(hb.type.isAssign){var d=s(b);return d.operator=hb.value,d.left=B(b),c(),d.right=K(a),t(d,"AssignmentExpression")}return b}function L(a){var b=M(a);if(x(ab.question)){var c=s(b);return c.test=b,c.consequent=I(!0),c.alternate=A(ab.colon)?I(!0,a):v(),t(c,"ConditionalExpression")}return b}function M(a){var b=eb,c=cb;return N(O(a),-1,a,b,c)}function N(a,b,d,e,f){if(cb!=f&&e>eb&&o())return a;var g=hb.type.binop;if(null!=g&&(!d||hb.type!==ab._in)&&g>b){var h=s(a);h.left=a,h.operator=hb.value,c(),h.right=cb!=f&&e>eb&&o()?v():N(O(d),g,d,e,f);var h=t(h,/&&|\|\|/.test(h.operator)?"LogicalExpression":"BinaryExpression");return N(h,b,d,e,f)}return a}function O(a){if(hb.type.prefix){var b=r(),d=hb.type.isUpdate;return b.operator=hb.value,b.prefix=!0,c(),b.argument=O(a),d&&(b.argument=B(b.argument)),t(b,d?"UpdateExpression":"UnaryExpression")}for(var e=P();hb.type.postfix&&!y();){var b=s(e);b.operator=hb.value,b.prefix=!1,b.argument=B(e),c(),e=t(b,"UpdateExpression")}return e}function P(){return Q(R(),!1,eb,cb)}function Q(a,b,d,e){for(;;){if(cb!=e&&d>=eb&&o()){if(hb.type!=ab.dot||eb!=d)return a;--d}if(x(ab.dot)){var f=s(a);f.object=a,f.property=cb!=e&&d>=eb&&o()?v():U()||v(),f.computed=!1,a=t(f,"MemberExpression")}else if(hb.type==ab.bracketL){j(),c();var f=s(a);f.object=a,f.property=I(),f.computed=!0,k(),A(ab.bracketR),a=t(f,"MemberExpression")}else{if(b||hb.type!=ab.parenL)return a;j();var f=s(a);f.callee=a,f.arguments=X(ab.parenR),a=t(f,"CallExpression")}}}function R(){switch(hb.type){case ab._this:var a=r();return c(),t(a,"ThisExpression");case ab.name:return V();case ab.num:case ab.string:case ab.regexp:var a=r();return a.value=hb.value,a.raw=Z.slice(hb.start,hb.end),c(),t(a,"Literal");case ab._null:case ab._true:case ab._false:var a=r();return a.value=hb.type.atomValue,a.raw=hb.type.keyword,c(),t(a,"Literal");case ab.parenL:var b=hb.start;c();var d=I();return d.start=b,d.end=hb.end,A(ab.parenR),d;case ab.bracketL:var a=r();return j(),a.elements=X(ab.bracketR),t(a,"ArrayExpression");case ab.braceL:return T();case ab._function:var a=r();return c(),W(a,!1);case ab._new:return S();default:return v()}}function S(){var a=r(),b=eb,d=cb;return c(),a.callee=Q(R(),!0,b,d),hb.type==ab.parenL?(j(),a.arguments=X(ab.parenR)):a.arguments=[],t(a,"NewExpression")}function T(){var a=r();a.properties=[],j(),c();for(var b=eb,d=cb;!n(ab.braceR,b,d);){var e=U();if(e){var f,g={key:e},h=!1;if(x(ab.colon))g.value=I(!0),f=g.kind="init";else{if(!(Y.ecmaVersion>=5&&"Identifier"===g.key.type)||"get"!==g.key.name&&"set"!==g.key.name){c(),x(ab.comma);continue}h=!0,f=g.kind=g.key.name,g.key=U()||v(),g.value=W(r(),!1)}a.properties.push(g),x(ab.comma)}else w(I(!0))&&c(),x(ab.comma)}return k(),x(ab.braceR),t(a,"ObjectExpression")}function U(){return hb.type===ab.num||hb.type===ab.string?R():hb.type===ab.name||hb.type.keyword?V():void 0}function V(){var a=r();return a.name=hb.type===ab.name?hb.value:hb.type.keyword,c(),t(a,"Identifier")}function W(a,b){for(a.id=hb.type===ab.name?V():b?v():null,a.params=[],j(),A(ab.parenL);hb.type==ab.name;)a.params.push(V()),x(ab.comma);return k(),x(ab.parenR),a.body=E(),t(a,b?"FunctionDeclaration":"FunctionExpression")}function X(a){var b=eb,d=cb,e=[],f=db;for(c(),cb>f&&(f=cb);!n(a,b+(f>=cb?1:0),d);){var g=I(!0);if(w(g)){if(n(a,b,d))break;c()}else e.push(g);for(;x(ab.comma););}return k(),x(a),e}var Y,Z,$,_,ab=b.tokTypes;a.parse_dammit=function(a,d){return d||(d={}),Z=String(a),Y=d,d.tabSize||(d.tabSize=4),$=b.tokenize(a,d),gb=Y.sourceFile||null,_=[],db=0,ib.length=0,c(),C()};var bb,cb,db,eb,fb,gb,hb={start:0,end:0},ib=[],jb=/[\n\r\u2028\u2029]/}),function(a){return"object"==typeof exports&&"object"==typeof module?a(exports):"function"==typeof define&&define.amd?define(["exports"],a):(a((this.acorn||(this.acorn={})).walk={}),void 0)}(function(a){"use strict";function b(a){return"string"==typeof a?function(b){return b==a}:a?a:function(){return!0}}function c(a,b){this.node=a,this.state=b}function d(a,b,c){c(a,b)}function e(){}function f(a,b){return{vars:Object.create(null),prev:a,isCatch:b}}function g(a){for(;a.isCatch;)a=a.prev;return a}a.simple=function(b,c,d,e){function f(a,b,e){var g=e||a.type,h=c[g];d[g](a,b,f),h&&h(a,b)}d||(d=a.base),f(b,e)},a.recursive=function(b,c,d,e){function f(a,b,c){g[c||a.type](a,b,f)}var g=d?a.make(d,e):e;f(b,c)},a.findNodeAt=function(d,e,f,g,h,i){g=b(g);try{h||(h=a.base);var j=function(a,b,d){var i=d||a.type;if((null==e||a.start<=e)&&(null==f||a.end>=f)&&h[i](a,b,j),g(i,a)&&(null==e||a.start==e)&&(null==f||a.end==f))throw new c(a,b)};j(d,i)}catch(k){if(k instanceof c)return k;throw k}},a.findNodeAround=function(d,e,f,g,h){f=b(f);try{g||(g=a.base);var i=function(a,b,d){var h=d||a.type;if(!(a.start>e||a.end=e&&f(h,a))throw new c(a,b);g[h](a,b,i)}};i(d,h)}catch(j){if(j instanceof c)return j;throw j}},a.findNodeBefore=function(d,e,f,g,h){f=b(f),g||(g=a.base);var i,j=function(a,b,d){if(!(a.start>e)){var h=d||a.type;a.end<=e&&(!i||i.node.endb?a:a.slice(0,b)}function p(a,b,c){var d=Math.max(0,c-500),e=null;if(!/^\s*$/.test(a))for(;;){var f=b.indexOf(a,d);if(0>f||f>c+500)break;(null==e||Math.abs(e-c)>Math.abs(f-c))&&(e=f),d=f+a.length}return e}function q(a){for(var b=0;a;++b,a=a.prev);return b}function r(a){var b=new Error(a);return b.name="TernError",b}function s(a,c,d){var f=d.match(/^#(\d+)$/);if(!f)return n(a.files,d);var g=c[f[1]];if(!g)throw r("Reference to unknown file "+d);if("full"==g.type)return n(a.files,g.name);var h=g.backing=n(a.files,g.name),i=g.offset;g.offsetLines&&(i={line:g.offsetLines,ch:0}),g.offset=i=w(h,null==g.offsetLines?g.offset:{line:g.offsetLines,ch:0},!0);var j=o(g.text),k=p(j,h.text,i),l=null==k?Math.max(0,h.text.lastIndexOf("\n",i)):k;return b.withContext(a.cx,function(){b.purgeTypes(g.name,l,l+g.text.length);var c,d=g.text;if(c=d.match(/(?:"([^"]*)"|([\w$]+))\s*:\s*function\b/)){var f=e.findNodeAround(g.backing.ast,l,"ObjectExpression");if(f&&f.node.objType)var i={type:f.node.objType,prop:c[2]||c[1]}}if(k&&(c=j.match(/^(.*?)\bfunction\b/))){for(var m=c[1].length,n="",o=0;m>o;++o)n+=" ";d=n+d.slice(m);var p=!0}var r=b.scopeAt(h.ast,l,h.scope),s=b.scopeAt(h.ast,l+d.length,h.scope),t=g.scope=q(r)o;++o)x.args[o].propagate(y.args[o]);x.self.propagate(y.self),y.retval.propagate(x.retval)}}}),g}function t(a){return"number"==typeof a||"object"==typeof a&&"number"==typeof a.line&&"number"==typeof a.ch}function u(a){if(a.query){if("string"!=typeof a.query.type)return".query.type must be a string";if(a.query.start&&!t(a.query.start))return".query.start must be a position";if(a.query.end&&!t(a.query.end))return".query.end must be a position"}if(a.files){if(!Array.isArray(a.files))return"Files property must be an array";for(var b=0;bf;){if(++f,e=c.indexOf("\n",e)+1,0==e)return null;0==f%S&&d.push(e)}return e}function w(a,b,c){if("number"!=typeof b){var d=v(a,b.line);if(null==d){if(!c)throw r("File doesn't contain a line "+b.line);b=a.text.length}else b=d+b.ch}if(b>a.text.length){if(!c)throw r("Position "+b+" is outside of file.");b=a.text.length}return b}function x(a,b){if(!a)return{line:0,ch:0};for(var c,d,e=a.lineOffsets||(a.lineOffsets=[0]),f=a.text,g=e.length-1;g>=0;--g)e[g]<=b&&(c=g*S,d=e[g]);for(;;){var h=f.indexOf("\n",d);if(h>=b||0>h)break;d=h+1,++c}return{line:c,ch:b-d}}function y(a,b,c){if(a.lineCharPositions){var d=x(b,c);return"part"==b.type&&(d.line+=null!=b.offsetLines?b.offsetLines:x(b.backing,b.offset).line),d}return c+("part"==b.type?b.offset:0)}function z(a){for(var b in a)null==a[b]&&delete a[b];return a}function A(a,b,c){null!=c&&(a[b]=c)}function B(a,b){"string"!=typeof a&&(a=a.name,b=b.name);var c=/^[A-Z]/.test(a),d=/^[A-Z]/.test(b);return c==d?b>a?-1:a==b?0:1:c?1:-1}function C(a,b,c){return"Literal"==a.type&&"string"==typeof a.value&&a.start==b-1&&a.end<=c+1}function D(a,c,e){function f(d,e,f){if(!(c.omitObjectPrototype!==!1&&e==a.cx.protos.Object&&!j||c.filter!==!1&&j&&0!=(c.caseInsensitive?d.toLowerCase():d).indexOf(j))){for(var g=0;g=2&&c.guess!==!1)for(var n in a.cx.props)f(n,a.cx.props[n][0],0)}else b.forAllLocalsAt(e.ast,g,e.scope,f);return c.sort!==!1&&k.sort(B),{start:y(c,e,g),end:y(c,e,h),completions:k}}function E(a,b){var c=b.prefix,d=[];for(var e in a.cx.props)""==e||c&&0!=e.indexOf(c)||d.push(e);return b.sort!==!1&&d.sort(B),{completions:d}}function F(a,c,d){var e=T(d,c);b.resetGuessing();var f=b.expressionType(e);if(f=c.preferFunction?f.getFunctionType()||f.getType():f.getType(),"Identifier"==e.node.type)var g=e.node.name;else if("MemberExpression"==e.node.type&&!e.node.computed)var g=e.node.property.name;if(null!=c.depth&&"number"!=typeof c.depth)throw r(".query.depth must be a number");var h={guess:b.didGuess(),type:b.toString(f,c.depth),name:f&&f.name,exprName:g};return f&&H(f,h),z(h)}function G(a,c,d){var e=T(d,c),f=b.expressionType(e),g={url:f.url,doc:f.doc},h=f.getType();return h&&H(h,g),z(g)}function H(a,c){c.url||(c.url=a.url),c.doc||(c.doc=a.doc),c.origin||(c.origin=a.origin);var d,e=b.cx().protos;!c.url&&!c.doc&&a.proto&&(d=a.proto.hasCtor)&&a.proto!=e.Object&&a.proto!=e.Function&&a.proto!=e.Array&&(c.url=d.url,c.doc=d.doc)}function I(a,c,d){var e=T(d,c);b.resetGuessing();var f=b.expressionType(e);if(b.didGuess())return{};var g=U(f),h={url:f.url,doc:f.doc,origin:f.origin};if(f.types)for(var i=f.types.length-1;i>=0;--i){var j=f.types[i];H(j,h),g||(g=U(j))}if(g&&g.node){var k=g.node.sourceFile||n(a.files,g.origin),l=y(c,k,g.node.start),m=y(c,k,g.node.end);h.start=l,h.end=m,h.file=g.origin;var o=Math.max(0,g.node.start-50);h.contextOffset=g.node.start-o,h.context=k.text.slice(o,o+50)}else g&&(h.file=g.origin,V(a,c,g,h));return z(h)}function J(a,c,d,e,f){function g(a){return function(b,d){if(f)for(var e=d;e!=i;e=e.prev){var g=e.hasProp(f);if(g)throw r("Renaming `"+h+"` to `"+f+"` would make a variable at line "+(x(a,b.start).line+1)+" point to the definition at line "+(x(a,g.name.start).line+1))}k.push({file:a.name,start:y(c,a,b.start),end:y(c,a,b.end)})}}for(var h=e.node.name,i=e.state;i&&!(h in i.props);i=i.prev);if(!i)throw r("Could not find a definition for "+h+" "+!!a.cx.topScope.props.x);var j,k=[];if(i.node){if(j="local",f){for(var l=i.prev;l&&!(f in l.props);l=l.prev);l&&b.findRefs(i.node,i,f,l,function(a){throw r("Renaming `"+h+"` to `"+f+"` would shadow the definition used at line "+(x(d,a.start).line+1))})}b.findRefs(i.node,i,h,i,g(d))}else{j="global";for(var m=0;m=f)return K(a,b,d,h)}throw r("Not at a variable or property name.")}function M(a,b,c){if("string"!=typeof b.newName)throw r(".query.newName should be a string");var d=T(c,b);if(!d||"Identifier"!=d.node.type)throw r("Not at a variable.");var e=J(a,b,c,d,b.newName),f=e.refs;delete e.refs,e.files=a.files.map(function(a){return a.name});for(var g=e.changes=[],h=0;h40&&(d.reset(),m(d,function(){}))})},findFile:function(a){return n(this.files,a)},flush:function(a){var c=this.cx;m(this,function(d){return d?a(d):(b.withContext(c,a),void 0)})},startAsyncAction:function(){++this.pending},finishAsyncAction:function(a){a&&(this.asyncError=a),0==--this.pending&&this.signal("everythingFetched")}});var S=25,T=a.findQueryExpr=function(a,c,d){if(null==c.end)throw r("missing .query.end field");if(c.variable){var e=b.scopeAt(a.ast,w(a,c.end),a.scope);return{node:{type:"Identifier",name:c.variable,start:c.end,end:c.end+1},state:e}}var f=c.start&&w(a,c.start),g=w(a,c.end),h=b.findExpressionAt(a.ast,f,g,a.scope);if(h)return h;if(h=b.findExpressionAround(a.ast,f,g,a.scope),h&&(d||(null==f?g:f)-h.node.start<20||h.node.end-g<20))return h;throw r("No expression at the given position.")},U=a.getSpan=function(a){if(a.origin){if(a.originNode){var b=a.originNode;return/^Function/.test(b.type)&&b.id&&(b=b.id),{origin:a.origin,node:b}}return a.span?{origin:a.origin,span:a.span}:void 0}},V=a.storeSpan=function(a,b,c,d){if(d.origin=c.origin,c.span){var e=/^(\d+)\[(\d+):(\d+)\]-(\d+)\[(\d+):(\d+)\]$/.exec(c.span);d.start=b.lineCharPositions?{line:Number(e[2]),ch:Number(e[3])}:Number(e[1]),d.end=b.lineCharPositions?{line:Number(e[5]),ch:Number(e[6])}:Number(e[4])}else{var f=n(a.files,c.origin);d.start=y(b,f,c.node.start),d.end=y(b,f,c.node.end)}};a.version="0.5.1"}),function(a){return"object"==typeof exports&&"object"==typeof module?exports.init=a:"function"==typeof define&&define.amd?define({init:a}):(tern.def={init:a},void 0)}(function(a,b){"use strict";function c(a,b){return Object.prototype.hasOwnProperty.call(a,b)}function d(a,c,d,f){var g=new m(a,null,d,f).parseType(c,!0);if(/^fn\(/.test(a))for(var h=0;h ")?c&&this.spec.indexOf("!",this.pos)>-1?(i=b.ANull,k=this.pos,j=this.parseRetType()):i=this.parseType():i=b.ANull,c&&(l=this.base)?b.Fn.call(this.base,a,b.ANull,d,e,i):l=new b.Fn(a,b.ANull,d,e,i),j&&(l.computeRet=j),null!=k&&(l.computeRetSource=this.spec.slice(k,this.pos)),l},parseType:function(a,c){if(this.eat("fn("))return this.parseFnType(a,c);if(this.eat("[")){var d=this.parseType();if(d==b.ANull&&"[b.]"==this.spec){var e=p("b");console.log(e.props[""].types.length)}return this.eat("]")||this.error(),c&&this.base?(b.Arr.call(this.base,d),this.base):new b.Arr(d)}if(this.eat("+")){var f=this.word(/[\w$<>\.!]/),g=p(f+".prototype");return g instanceof b.Obj||(g=p(f)),g instanceof b.Obj?c&&this.forceNew?new b.Obj(g):b.getInstance(g):g}return this.eat("?")?b.ANull:this.fromWord(this.word(/[\w$<>\.!`]/))},fromWord:function(a){var c=b.cx();switch(a){case"number":return c.num;case"string":return c.str;case"bool":return c.bool;case"":return c.topScope}return c.localDefs&&a in c.localDefs?c.localDefs[a]:p(a)},parseBaseRetType:function(){if(this.eat("[")){var a=this.parseRetType();return this.eat("]")||this.error(),function(c,d){return new b.Arr(a(c,d))}}if(this.eat("+")){var c=this.parseRetType();return function(a,d){return b.getInstance(c(a,d))}}if(this.eat("!")){var d=this.word(/\d/);if(d)return d=Number(d),function(a,c){return c[d]||b.ANull};if(this.eat("this"))return function(a){return a};if(this.eat("custom:")){var e=this.word(/[\w$]/);return q[e]||function(){return b.ANull}}return this.fromWord("!"+d+this.word(/[\w$<>\.!]/))}var f=this.parseType();return function(){return f}},extendRetType:function(a){var c=this.word(/[\w<>$!]/)||this.error();return"!ret"==c?function(c,d){var e=a(c,d);if(e.retval)return e.retval;var f=new b.AVal;return e.propagate(new b.IsCallee(b.ANull,[],null,f)),f}:function(b,d){return a(b,d).getProp(c)}},parseRetType:function(){for(var a=this.parseBaseRetType();this.eat(".");)a=this.extendRetType(a);return a}};var n,o=a.parseEffect=function(a,c){var d;if(0==a.indexOf("propagate ")){var f=new m(a,10),g=f.parseRetType();f.eat(" ")||f.error();var h=f.parseRetType();e(c,function(a,b){g(a,b).propagate(h(a,b))})}else if(0==a.indexOf("call ")){var i=5==a.indexOf("and return ",5),f=new m(a,i?16:5),j=f.parseRetType(),k=null,l=[];for(f.eat(" this=")&&(k=f.parseRetType());f.eat(" ");)l.push(f.parseRetType());e(c,function(a,c){for(var d=j(a,c),e=k?k(a,c):b.ANull,f=[],g=0;g"!=a&&e.propagate(new b.PropHasSubset(a,c))})})}},p=a.parsePath=function(a){var c=b.cx(),d=c.paths[a],e=a;if(null!=d)return d;c.paths[a]=b.ANull;var f=n||c.topScope;if(c.localDefs)for(var g in c.localDefs)if(0==a.indexOf(g)){if(a==g)return c.paths[a]=c.localDefs[a];if("."==a.charAt(g.length)){f=c.localDefs[g],a=a.slice(g.length+1);break}}for(var h=a.split("."),i=0;i"),f=0;fa&&a>8||32===a||160===a}function c(a,c){for(;c>0;--c){var d=a.charCodeAt(c-1);if(10==d)break;if(!b(d))return!1}return!0}a.commentsBefore=function(a,d){var e,f=null,g=0;a:for(;d>0;){var h=a.charCodeAt(d-1);if(10==h)for(var i=--d,j=!1;i>0;--i){if(h=a.charCodeAt(i-1),47==h&&47==a.charCodeAt(i-2)){if(!c(a,i-2))break a;var k=a.slice(i,d);!g&&e?f[0]=k+"\n"+f[0]:(f||(f=[])).unshift(k),e=!0,g=0,d=i-2;break}if(10==h){if(!j&&++g>1)break a;break}j||b(h)||(j=!0)}else if(47==h&&42==a.charCodeAt(d-2)){for(var i=d-2;i>1;--i)if(42==a.charCodeAt(i-1)&&47==a.charCodeAt(i-2)){if(!c(a,i-2))break a;(f||(f=[])).unshift(a.slice(i,d-2)),e=!1,g=0;break}d=i-2}else{if(!b(h))break;--d}}return f},a.commentAfter=function(a,c){for(;ce?a.length:e)}b(d)&&++c}},a.ensureCommentsBefore=function(b,c){return c.hasOwnProperty("commentsBefore")?c.commentsBefore:c.commentsBefore=a.commentsBefore(b,c.start)}}),function(a){return"object"==typeof exports&&"object"==typeof module?a(exports,require("acorn/acorn"),require("acorn/acorn_loose"),require("acorn/util/walk"),require("./def"),require("./signal")):"function"==typeof define&&define.amd?define(["exports","acorn/acorn","acorn/acorn_loose","acorn/util/walk","./def","./signal"],a):(a(self.tern||(self.tern={}),acorn,acorn,acorn.walk,tern.def,tern.signal),void 0)}(function(a,b,c,d,e,f){"use strict";function g(a,b){var c=Object.create(a);if(b)for(var d in b)c[d]=b[d];return c}function h(a){for(var b=0,c=0,d=0,e=null,f=0;f1)return null;if(e)return e;for(var i=0,j=null,f=0;f").isEmpty()?1:2;else if(c){k=1;for(var l=0;l=i&&(i=k,j=g)}return j}function i(){}function j(a,b){fb.disabledComputing={fn:a,prev:fb.disabledComputing};try{return b()}finally{fb.disabledComputing=fb.disabledComputing.prev}}function k(a,b){var c=fb.props[a]||(fb.props[a]=[]);c.push(b)}function l(a){return fb.props[a]}function m(a){if(fb.workList)return a(fb.workList);var b=[],c=0,d=fb.workList=function(a,d,e){c3)&&a.forward)for(var f=0;f"));for(var h=b(c.self,"!this",0),i=0;!h&&i"):d.name}function u(a){switch(a){case"+":case"-":case"~":return fb.num;case"!":return fb.bool;case"typeof":return fb.str;case"void":case"delete":return F}}function v(a){switch(a){case"==":case"!=":case"===":case"!==":case"<":case">":case">=":case"<=":case"in":case"instanceof":return!0}}function w(a){switch(typeof a){case"boolean":return fb.bool;case"number":return fb.num;case"string":return fb.str;case"object":case"function":return a?V(fb.protos.RegExp):F}}function x(a){return function(b,c,d,e,f){var g=a(b,c,d,f);return e&&g.propagate(e),g}}function y(a){return function(b,c,d,e,f){return e||(e=new N),a(b,c,d,e,f),e}}function z(a,b,c,d,e){return lb[a.type](a,b,c,d,e)}function A(a,b){var c=a&&a[b],d=Array.prototype.slice.call(arguments,2);if(c)for(var e=0;e-1}:function(d,e){return e&&e.start>=b&&e.end<=c&&a.indexOf(d.origin)>-1}:null==c?function(b){return b.origin==a}:function(d,e){return e&&e.start>=b&&e.end<=c&&d.origin==a}}function C(a){qb=!0;var b=l(a);if(b)for(var c=0;cb||this.types.indexOf(a)>-1)return;this.signal("addType",a),this.types.push(a);var c=this.forward;c&&m(function(d){for(var e=0;eb&&(a=new _(a,b)),(this.forward||(this.forward=[])).push(a);var c=this.types;c.length&&m(function(d){for(var e=0;e-1},isEmpty:function(){return 0==this.types.length},getFunctionType:function(){for(var a=this.types.length-1;a>=0;--a)if(this.types[a]instanceof db)return this.types[a]},getType:function(a){return 0==this.types.length&&a!==!1?this.makeupType():1==this.types.length?this.types[0]:h(this.types)},computedPropType:function(){if(!this.propertyOf||!this.propertyOf.hasProp(""))return null;var a=this.propertyOf.getProp("");return a==this?null:a.getType()},makeupType:function(){var a=this.computedPropType();if(a)return a;if(!this.forward)return null;for(var b=this.forward.length-1;b>=0;--b){var c=this.forward[b].typeHint();if(c&&!c.isEmpty())return qb=!0,c}for(var d=Object.create(null),e=null,b=0;b"!=f&&"✖"!=f&&(d[f]=!0,e=f)}if(!e)return null;var g=l(e);if(g){var i=[];a:for(var b=0;b8||(a==fb.protos.Array?this.target.addType(new eb):this.target.addType(V(a,this.ctor))))}}),X=O("fn",{addType:function(a){if(a instanceof cb&&!a.hasCtor){a.hasCtor=this.fn;var b=new $(a,this.fn);b.addType(this.fn),a.forAllProps(function(a,c,d){d&&c.propagate(b)})}}}),Y=O("other, target",{addType:function(a,b){a==fb.str?this.target.addType(fb.str,b):a==fb.num&&this.other.hasType(fb.num)&&this.target.addType(fb.num,b)},typeHint:function(){return this.other}}),Z=a.IfObj=O("target",{addType:function(a,b){a instanceof cb&&this.target.addType(a,b)},propagatesTo:function(){return this.target}}),$=O("obj, ctor",{addType:function(a){a instanceof db&&a.self&&a.self.isEmpty()&&a.self.addType(V(this.obj,this.ctor),M)}}),_=O("inner, weight",{addType:function(a,b){this.inner.addType(a,Math.min(b,this.weight))},propagatesTo:function(){return this.inner.propagatesTo()},typeHint:function(){return this.inner.typeHint()},propHint:function(){return this.inner.propHint()}}),ab=a.Type=function(){};ab.prototype=g(F,{constructor:ab,propagate:function(a,b){a.addType(this,b)},hasType:function(a){return a==this},isEmpty:function(){return!1},typeHint:function(){return this},getType:function(){return this}});var bb=a.Prim=function(a,b){this.name=b,this.proto=a};bb.prototype=g(ab.prototype,{constructor:bb,toString:function(){return this.name},getProp:function(a){return this.proto.hasProp(a)||F},gatherProperties:function(a,b){this.proto&&this.proto.gatherProperties(a,b)}});var cb=a.Obj=function(a,b){if(this.props||(this.props=Object.create(null)),this.proto=a===!0?fb.protos.Object:a,a&&!b&&a.name&&!(this instanceof db)){var c=/^(.*)\.prototype$/.exec(this.proto.name);c&&(b=c[1])}this.name=b,this.maybeProps=null,this.origin=fb.curOrigin};cb.prototype=g(ab.prototype,{constructor:cb,toString:function(a){if(!a&&this.name)return this.name;var b=[],c=!1;for(var d in this.props)if(""!=d){if(b.length>5){c=!0;break}a?b.push(d+": "+E(this.props[d].getType(),a-1)):b.push(d)}return b.sort(),c&&b.push("..."),"{"+b.join(", ")+"}"},hasProp:function(a,b){var c=this.props[a];if(b!==!1)for(var d=this.proto;d&&!c;d=d.proto)c=d.props[a];return c},defProp:function(a,b){var c=this.hasProp(a,!1);if(c)return b&&!c.originNode&&(c.originNode=b),c;if("__proto__"==a||"✖"==a)return F;var d=this.maybeProps&&this.maybeProps[a];return d?(delete this.maybeProps[a],this.maybeUnregProtoPropHandler()):(d=new N,d.propertyOf=this),this.props[a]=d,d.originNode=b,d.origin=fb.curOrigin,this.broadcastProp(a,d,!0),d},getProp:function(a){var b=this.hasProp(a,!0)||this.maybeProps&&this.maybeProps[a];if(b)return b;if("__proto__"==a||"✖"==a)return F;var c=this.ensureMaybeProps()[a]=new N;return c.propertyOf=this,c},broadcastProp:function(a,b,c){if(c&&(this.signal("addProp",a,b),this instanceof ib||k(a,this)),this.onNewProp)for(var d=0;d"!=c&&a(c,this,b);this.proto&&this.proto.gatherProperties(a,b+1)}});var db=a.Fn=function(a,b,c,d,e){cb.call(this,fb.protos.Function,a),this.self=b,this.args=c,this.argNames=d,this.retval=e};db.prototype=g(cb.prototype,{constructor:db,toString:function(a){a&&a--;for(var b="fn(",c=0;c");a&&a.propagate(b)};eb.prototype=g(cb.prototype,{constructor:eb,toString:function(a){return"["+E(this.getProp("").getType(),a,this)+"]"}}),a.Context=function(b,c){this.parent=c,this.props=Object.create(null),this.protos=Object.create(null),this.origins=[],this.curOrigin="ecma5",this.paths=Object.create(null),this.definitions=Object.create(null),this.purgeGen=0,this.workList=null,this.disabledComputing=null,a.withContext(this,function(){if(fb.protos.Object=new cb(null,"Object.prototype"),fb.topScope=new ib,fb.topScope.name="",fb.protos.Array=new cb(!0,"Array.prototype"),fb.protos.Function=new cb(!0,"Function.prototype"),fb.protos.RegExp=new cb(!0,"RegExp.prototype"),fb.protos.String=new cb(!0,"String.prototype"),fb.protos.Number=new cb(!0,"Number.prototype"),fb.protos.Boolean=new cb(!0,"Boolean.prototype"),fb.str=new bb(fb.protos.String,"string"),fb.bool=new bb(fb.protos.Boolean,"bool"),fb.num=new bb(fb.protos.Number,"number"),fb.curOrigin=null,b)for(var a=0;ad;++d)z(a.expressions[d],b,c,F);return z(a.expressions[e],b,c)}),UnaryExpression:x(function(a,b,c){return z(a.argument,b,c,F),u(a.operator)}),UpdateExpression:x(function(a,b,c){return z(a.argument,b,c,F),fb.num}),BinaryExpression:x(function(a,b,c){if("+"==a.operator){var d=z(a.left,b,c),e=z(a.right,b,c);if(d.hasType(fb.str)||e.hasType(fb.str))return fb.str;if(d.hasType(fb.num)&&e.hasType(fb.num))return fb.num;var f=new N;return d.propagate(new Y(e,f)),e.propagate(new Y(d,f)),f}return z(a.left,b,c,F),z(a.right,b,c,F),v(a.operator)?fb.bool:fb.num}),AssignmentExpression:x(function(a,b,c){var d,e,f;if("MemberExpression"==a.left.type?(f=t(a.left,b,c),"Identifier"==a.left.object.type&&(e=a.left.object.name+"."+f)):e=a.left.name,"="!=a.operator&&"+="!=a.operator?(z(a.right,b,c,F),d=fb.num):d=z(a.right,b,c,null,e),"MemberExpression"==a.left.type){var g=z(a.left.object,b,c);if("prototype"==f&&n(b,20),""==f){var h=a.left.property.name,i=b.props[h],j=i&&i.iteratesOver;if(j){n(b,20);var k="MemberExpression"==a.right.type&&a.right.computed&&a.right.property.name==h;return j.forAllProps(function(a,b,c){c&&"prototype"!=a&&""!=a&&g.propagate(new Q(a,k?b:F))}),d}}g.propagate(new Q(f,d,a.left.property))}else{var h=b.defVar(a.left.name,a.left);h.maybePurge&&(h.maybePurge=!1),d.propagate(h)}return d}),LogicalExpression:y(function(a,b,c,d){z(a.left,b,c,d),z(a.right,b,c,d)}),ConditionalExpression:y(function(a,b,c,d){z(a.test,b,c,F),z(a.consequent,b,c,d),z(a.alternate,b,c,d)}),NewExpression:y(function(a,b,c,d,e){"Identifier"==a.callee.type&&a.callee.name in b.props&&n(b,20);for(var f=0,g=[];f-1&&n(b,30),g.propagate(new T(h,f,a.arguments,d))}else{var i=z(a.callee,b,c);b.fnType&&b.fnType.args.indexOf(i)>-1&&n(b,30);var j=i.getFunctionType();j&&j.instantiateScore&&b.fnType&&n(b,j.instantiateScore/5),i.propagate(new S(fb.topScope,f,a.arguments,d))}}),MemberExpression:y(function(a,b,c,d){var e=t(a,b),f=z(a.object,b,c),g=f.getProp(e);if(""==e){var h=z(a.property,b,c);if(!h.hasType(fb.num))return g.propagate(d,J)}g.propagate(d)}),Identifier:x(function(a,b){return"arguments"!=a.name||!b.fnType||a.name in b.props||b.defProp(a.name,b.fnType.originNode).addType(new eb(b.fnType.arguments=new N)),b.getProp(a.name)}),ThisExpression:x(function(a,b){return b.fnType?b.fnType.self:fb.topScope}),Literal:x(function(a){return w(a.value)})},mb=d.make({Expression:function(a,b,c){z(a,b,c,F)},FunctionDeclaration:function(a,b,c){var d=a.body.scope,e=d.fnType;c(a.body,b,"ScopeBody"),p(a,d)||r(d);var f=b.getProp(a.id.name);f.addType(e)},VariableDeclaration:function(a,b,c){for(var d=0;d"==c?F:C(c)},Identifier:function(a,b){return b.hasProp(a.name)||F},ThisExpression:function(a,b){return b.fnType?b.fnType.self:fb.topScope +},Literal:function(a){return w(a.value)}},pb=a.searchVisitor=d.make({Function:function(a,b,c){var d=a.body.scope;a.id&&c(a.id,d);for(var e=0;eb?!1:ob.hasOwnProperty(c.type)};return d.findNodeAround(a,c,g,pb,e||fb.topScope)},a.expressionType=function(a){return D(a.node,a.state)};var qb=!1;a.resetGuessing=function(a){qb=a},a.didGuess=function(){return qb},a.forAllPropertiesOf=function(a,b){a.gatherProperties(b,0)};var rb=d.make({},pb);a.findRefs=function(a,b,c,e,f){rb.Identifier=function(a,b){if(a.name==c)for(var d=b;d;d=d.prev)if(d==e&&f(a,b),c in d.props)return},d.recursive(a,b,null,rb)};var sb=d.make({Function:function(a,b,c){c(a.body,a.body.scope,"ScopeBody")}});a.findPropRefs=function(a,b,c,e,f){d.simple(a,{MemberExpression:function(a,b){a.computed||a.property.name!=e||D(a.object,b).getType()==c&&f(a.property)},ObjectExpression:function(a,b){if(D(a,b).getType()==c)for(var d=0;di)return null;var k=b.slice(c,i);if(!/^[\w$]+$/.test(k))return null;e.push(k),c=i+1;var l=j(a,b,c);if(!l)return null;c=l.end,f.push(l.type),c=h(b,c);var m=b.charAt(c);if(++c,m==d)break;if(","!=m)return null}return{labels:e,types:f,end:c}}function j(b,c,d){d=h(c,d);var e;if(c.indexOf("function(",d)==d){var f=i(b,c,d+9,")"),g=a.ANull;if(!f)return null;if(d=h(c,f.end),":"==c.charAt(d)){++d;var k=j(b,c,d+1);if(!k)return null;d=k.end,g=k.type}e=new a.Fn(null,a.ANull,f.types,f.labels,g)}else if("["==c.charAt(d)){var l=j(b,c,d+1);if(!l)return null;if(d=h(c,l.end),"]"!=c.charAt(d))return null;++d,e=new a.Arr(l.type)}else if("{"==c.charAt(d)){var m=i(b,c,d+1,"}");if(!m)return null;e=new a.Obj(!0);for(var n=0;n"!=c.charAt(d++))return null;l=r.type}e=new a.Arr(l)}else if(/^object$/i.test(q)){if(e=new a.Obj(!0),"."==c.charAt(d)&&"<"==c.charAt(d+1)){var s=j(b,c,d+2);if(!s)return null;if(d=h(c,s.end),","!=c.charAt(d++))return null;var t=j(b,c,d);if(!t)return null;if(d=h(c,t.end),">"!=c.charAt(d++))return null;t.type.propagate(e.defProp(""))}}else{var u=b.hasProp(q);if(u&&(u=u.getType()),u)if(u instanceof a.Fn&&/^[A-Z]/.test(q)){var v=u.getProp("prototype").getType();e=v instanceof a.Obj?a.getInstance(v):u}else e=u;else e=a.ANull}}var w=!1;return"="==c.charAt(d)&&(++d,w=!0),{type:e,end:d,isOptional:w}}function k(a,b,c){if(c=h(b,c||0),"{"!=b.charAt(c))return null;var d=j(a,b,c+1);return d&&"}"==b.charAt(d.end)?(++d.end,d):null}function l(a,b,c,d){for(var e,f,g,h,i=0;i ?","!url":"https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Object/getPrototypeOf","!doc":"Returns the prototype (i.e. the internal prototype) of the specified object."},create:{"!type":"fn(proto: ?) -> !custom:Object_create","!url":"https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Object/create","!doc":"Creates a new object with the specified prototype object and properties."},defineProperty:{"!type":"fn(obj: ?, prop: string, desc: ?)","!url":"https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Object/defineProperty","!doc":"Defines a new property directly on an object, or modifies an existing property on an object, and returns the object. If you want to see how to use the Object.defineProperty method with a binary-flags-like syntax, see this article."},defineProperties:{"!type":"fn(obj: ?, props: ?)","!url":"https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Object/defineProperty","!doc":"Defines a new property directly on an object, or modifies an existing property on an object, and returns the object. If you want to see how to use the Object.defineProperty method with a binary-flags-like syntax, see this article."},getOwnPropertyDescriptor:{"!type":"fn(obj: ?, prop: string) -> ?","!url":"https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Object/getOwnPropertyDescriptor","!doc":"Returns a property descriptor for an own property (that is, one directly present on an object, not present by dint of being along an object's prototype chain) of a given object."},keys:{"!type":"fn(obj: ?) -> [string]","!url":"https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Object/keys","!doc":"Returns an array of a given object's own enumerable properties, in the same order as that provided by a for-in loop (the difference being that a for-in loop enumerates properties in the prototype chain as well)."},getOwnPropertyNames:{"!type":"fn(obj: ?) -> [string]","!url":"https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Object/getOwnPropertyNames","!doc":"Returns an array of all properties (enumerable or not) found directly upon a given object."},seal:{"!type":"fn(obj: ?)","!url":"https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Object/seal","!doc":"Seals an object, preventing new properties from being added to it and marking all existing properties as non-configurable. Values of present properties can still be changed as long as they are writable."},isSealed:{"!type":"fn(obj: ?) -> bool","!url":"https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Object/isSealed","!doc":"Determine if an object is sealed."},freeze:{"!type":"fn(obj: ?)","!url":"https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Object/freeze","!doc":"Freezes an object: that is, prevents new properties from being added to it; prevents existing properties from being removed; and prevents existing properties, or their enumerability, configurability, or writability, from being changed. In essence the object is made effectively immutable. The method returns the object being frozen."},isFrozen:{"!type":"fn(obj: ?) -> bool","!url":"https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Object/isFrozen","!doc":"Determine if an object is frozen."},prototype:{"!stdProto":"Object",toString:{"!type":"fn() -> string","!url":"https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Object/toString","!doc":"Returns a string representing the object."},toLocaleString:{"!type":"fn() -> string","!url":"https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Object/toLocaleString","!doc":"Returns a string representing the object. This method is meant to be overriden by derived objects for locale-specific purposes."},valueOf:{"!type":"fn() -> number","!url":"https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Object/valueOf","!doc":"Returns the primitive value of the specified object"},hasOwnProperty:{"!type":"fn(prop: string) -> bool","!url":"https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Object/hasOwnProperty","!doc":"Returns a boolean indicating whether the object has the specified property."},propertyIsEnumerable:{"!type":"fn(prop: string) -> bool","!url":"https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Object/propertyIsEnumerable","!doc":"Returns a Boolean indicating whether the specified property is enumerable."}},"!url":"https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Object","!doc":"Creates an object wrapper."},Function:{"!type":"fn(body: string) -> fn()",prototype:{"!stdProto":"Function",apply:{"!type":"fn(this: ?, args: [?])","!effects":["call and return !this this=!0 !1. !1. !1."],"!url":"https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Function/apply","!doc":"Calls a function with a given this value and arguments provided as an array (or an array like object)."},call:{"!type":"fn(this: ?, args?: ?) -> !this.!ret","!effects":["call and return !this this=!0 !1 !2 !3 !4"],"!url":"https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Function/call","!doc":"Calls a function with a given this value and arguments provided individually."},bind:{"!type":"fn(this: ?, args?: ?) -> !custom:Function_bind","!url":"https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Function/bind","!doc":"Creates a new function that, when called, has its this keyword set to the provided value, with a given sequence of arguments preceding any provided when the new function was called."},prototype:"?"},"!url":"https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Function","!doc":"Every function in JavaScript is actually a Function object."},Array:{"!type":"fn(size: number) -> !custom:Array_ctor",isArray:{"!type":"fn(value: ?) -> bool","!url":"https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array/isArray","!doc":"Returns true if an object is an array, false if it is not."},prototype:{"!stdProto":"Array",length:{"!type":"number","!url":"https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array/length","!doc":"An unsigned, 32-bit integer that specifies the number of elements in an array."},concat:{"!type":"fn(other: [?]) -> !this","!url":"https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array/concat","!doc":"Returns a new array comprised of this array joined with other array(s) and/or value(s)."},join:{"!type":"fn(separator?: string) -> string","!url":"https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array/join","!doc":"Joins all elements of an array into a string."},splice:{"!type":"fn(pos: number, amount: number)","!url":"https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array/splice","!doc":"Changes the content of an array, adding new elements while removing old elements."},pop:{"!type":"fn() -> !this.","!url":"https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array/pop","!doc":"Removes the last element from an array and returns that element."},push:{"!type":"fn(newelt: ?) -> number","!effects":["propagate !0 !this."],"!url":"https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array/push","!doc":"Mutates an array by appending the given elements and returning the new length of the array."},shift:{"!type":"fn() -> !this.","!url":"https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array/shift","!doc":"Removes the first element from an array and returns that element. This method changes the length of the array."},unshift:{"!type":"fn(newelt: ?) -> number","!effects":["propagate !0 !this."],"!url":"https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array/unshift","!doc":"Adds one or more elements to the beginning of an array and returns the new length of the array."},slice:{"!type":"fn(from: number, to?: number) -> !this","!url":"https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array/slice","!doc":"Returns a shallow copy of a portion of an array."},reverse:{"!type":"fn()","!url":"https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array/reverse","!doc":"Reverses an array in place. The first array element becomes the last and the last becomes the first."},sort:{"!type":"fn(compare?: fn(a: ?, b: ?) -> number)","!effects":["call !0 !this. !this."],"!url":"https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array/sort","!doc":"Sorts the elements of an array in place and returns the array."},indexOf:{"!type":"fn(elt: ?, from?: number) -> number","!url":"https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array/indexOf","!doc":"Returns the first index at which a given element can be found in the array, or -1 if it is not present."},lastIndexOf:{"!type":"fn(elt: ?, from?: number) -> number","!url":"https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array/lastIndexOf","!doc":"Returns the last index at which a given element can be found in the array, or -1 if it is not present. The array is searched backwards, starting at fromIndex."},every:{"!type":"fn(test: fn(elt: ?, i: number) -> bool, context?: ?) -> bool","!effects":["call !0 this=!1 !this. number"],"!url":"https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array/every","!doc":"Tests whether all elements in the array pass the test implemented by the provided function."},some:{"!type":"fn(test: fn(elt: ?, i: number) -> bool, context?: ?) -> bool","!effects":["call !0 this=!1 !this. number"],"!url":"https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array/some","!doc":"Tests whether some element in the array passes the test implemented by the provided function."},filter:{"!type":"fn(test: fn(elt: ?, i: number) -> bool, context?: ?) -> !this","!effects":["call !0 this=!1 !this. number"],"!url":"https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array/filter","!doc":"Creates a new array with all elements that pass the test implemented by the provided function."},forEach:{"!type":"fn(f: fn(elt: ?, i: number), context?: ?)","!effects":["call !0 this=!1 !this. number"],"!url":"https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array/forEach","!doc":"Executes a provided function once per array element."},map:{"!type":"fn(f: fn(elt: ?, i: number) -> ?, context?: ?) -> [!0.!ret]","!effects":["call !0 this=!1 !this. number"],"!url":"https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array/map","!doc":"Creates a new array with the results of calling a provided function on every element in this array."},reduce:{"!type":"fn(combine: fn(sum: ?, elt: ?, i: number) -> ?, init?: ?) -> !0.!ret","!effects":["call !0 !1 !this. number"],"!url":"https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array/Reduce","!doc":"Apply a function against an accumulator and each value of the array (from left-to-right) as to reduce it to a single value."},reduceRight:{"!type":"fn(combine: fn(sum: ?, elt: ?, i: number) -> ?, init?: ?) -> !0.!ret","!effects":["call !0 !1 !this. number"],"!url":"https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array/ReduceRight","!doc":"Apply a function simultaneously against two values of the array (from right-to-left) as to reduce it to a single value."}},"!url":"https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array","!doc":"The JavaScript Array global object is a constructor for arrays, which are high-level, list-like objects."},String:{"!type":"fn(value: ?) -> string",fromCharCode:{"!type":"fn(code: number) -> string","!url":"https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/String/fromCharCode","!doc":"Returns a string created by using the specified sequence of Unicode values."},prototype:{"!stdProto":"String",length:{"!type":"number","!url":"https://developer.mozilla.org/en/docs/JavaScript/Reference/Global_Objects/String/length","!doc":"Represents the length of a string."},"":"string",charAt:{"!type":"fn(i: number) -> string","!url":"https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/String/charAt","!doc":"Returns the specified character from a string."},charCodeAt:{"!type":"fn(i: number) -> number","!url":"https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/String/charCodeAt","!doc":"Returns the numeric Unicode value of the character at the given index (except for unicode codepoints > 0x10000)."},indexOf:{"!type":"fn(char: string, from?: number) -> number","!url":"https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/String/indexOf","!doc":"Returns the index within the calling String object of the first occurrence of the specified value, starting the search at fromIndex,\nreturns -1 if the value is not found."},lastIndexOf:{"!type":"fn(char: string, from?: number) -> number","!url":"https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/String/lastIndexOf","!doc":"Returns the index within the calling String object of the last occurrence of the specified value, or -1 if not found. The calling string is searched backward, starting at fromIndex."},substring:{"!type":"fn(from: number, to?: number) -> string","!url":"https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/String/substring","!doc":"Returns a subset of a string between one index and another, or through the end of the string."},substr:{"!type":"fn(from: number, length?: number) -> string","!url":"https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/String/substr","!doc":"Returns the characters in a string beginning at the specified location through the specified number of characters."},slice:{"!type":"fn(from: number, to?: number) -> string","!url":"https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/String/slice","!doc":"Extracts a section of a string and returns a new string."},trim:{"!type":"fn() -> string","!url":"https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/String/Trim","!doc":"Removes whitespace from both ends of the string."},trimLeft:{"!type":"fn() -> string","!url":"https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/String/TrimLeft","!doc":"Removes whitespace from the left end of the string."},trimRight:{"!type":"fn() -> string","!url":"https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/String/TrimRight","!doc":"Removes whitespace from the right end of the string."},toUpperCase:{"!type":"fn() -> string","!url":"https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/String/toUpperCase","!doc":"Returns the calling string value converted to uppercase."},toLowerCase:{"!type":"fn() -> string","!url":"https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/String/toLowerCase","!doc":"Returns the calling string value converted to lowercase."},toLocaleUpperCase:{"!type":"fn() -> string","!url":"https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/String/toLocaleUpperCase","!doc":"Returns the calling string value converted to upper case, according to any locale-specific case mappings."},toLocaleLowerCase:{"!type":"fn() -> string","!url":"https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/String/toLocaleLowerCase","!doc":"Returns the calling string value converted to lower case, according to any locale-specific case mappings."},split:{"!type":"fn(pattern: string) -> [string]","!url":"https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/String/split","!doc":"Splits a String object into an array of strings by separating the string into substrings."},concat:{"!type":"fn(other: string) -> string","!url":"https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/String/concat","!doc":"Combines the text of two or more strings and returns a new string."},localeCompare:{"!type":"fn(other: string) -> number","!url":"https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/String/localeCompare","!doc":"Returns a number indicating whether a reference string comes before or after or is the same as the given string in sort order."},match:{"!type":"fn(pattern: +RegExp) -> [string]","!url":"https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/String/match","!doc":"Used to retrieve the matches when matching a string against a regular expression."},replace:{"!type":"fn(pattern: +RegExp, replacement: string) -> string","!url":"https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/String/replace","!doc":"Returns a new string with some or all matches of a pattern replaced by a replacement. The pattern can be a string or a RegExp, and the replacement can be a string or a function to be called for each match."},search:{"!type":"fn(pattern: +RegExp) -> number","!url":"https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/String/search","!doc":"Executes the search for a match between a regular expression and this String object."}},"!url":"https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/String","!doc":"The String global object is a constructor for strings, or a sequence of characters."},Number:{"!type":"fn(value: ?) -> number",MAX_VALUE:{"!type":"number","!url":"https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Number/MAX_VALUE","!doc":"The maximum numeric value representable in JavaScript."},MIN_VALUE:{"!type":"number","!url":"https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Number/MIN_VALUE","!doc":"The smallest positive numeric value representable in JavaScript."},POSITIVE_INFINITY:{"!type":"number","!url":"https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Number/POSITIVE_INFINITY","!doc":"A value representing the positive Infinity value."},NEGATIVE_INFINITY:{"!type":"number","!url":"https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Number/NEGATIVE_INFINITY","!doc":"A value representing the negative Infinity value."},prototype:{"!stdProto":"Number",toString:{"!type":"fn(radix?: number) -> string","!url":"https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Number/toString","!doc":"Returns a string representing the specified Number object"},toFixed:{"!type":"fn(digits: number) -> string","!url":"https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Number/toFixed","!doc":"Formats a number using fixed-point notation"},toExponential:{"!type":"fn(digits: number) -> string","!url":"https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Number/toExponential","!doc":"Returns a string representing the Number object in exponential notation"}},"!url":"https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Number","!doc":"The Number JavaScript object is a wrapper object allowing you to work with numerical values. A Number object is created using the Number() constructor."},Boolean:{"!type":"fn(value: ?) -> bool",prototype:{"!stdProto":"Boolean"},"!url":"https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Boolean","!doc":"The Boolean object is an object wrapper for a boolean value."},RegExp:{"!type":"fn(source: string, flags?: string)",prototype:{"!stdProto":"RegExp",exec:{"!type":"fn(input: string) -> [string]","!url":"https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/RegExp/exec","!doc":"Executes a search for a match in a specified string. Returns a result array, or null."},compile:{"!type":"fn(source: string, flags?: string)","!url":"https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/RegExp","!doc":"Creates a regular expression object for matching text with a pattern."},test:{"!type":"fn(input: string) -> bool","!url":"https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/RegExp/test","!doc":"Executes the search for a match between a regular expression and a specified string. Returns true or false."},global:{"!type":"bool","!url":"https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/RegExp","!doc":"Creates a regular expression object for matching text with a pattern."},ignoreCase:{"!type":"bool","!url":"https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/RegExp","!doc":"Creates a regular expression object for matching text with a pattern."},multiline:{"!type":"bool","!url":"https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/RegExp/multiline","!doc":"Reflects whether or not to search in strings across multiple lines.\n"},source:{"!type":"string","!url":"https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/RegExp/source","!doc":"A read-only property that contains the text of the pattern, excluding the forward slashes.\n"},lastIndex:{"!type":"number","!url":"https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/RegExp/lastIndex","!doc":"A read/write integer property that specifies the index at which to start the next match."}},"!url":"https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/RegExp","!doc":"Creates a regular expression object for matching text with a pattern."},Date:{"!type":"fn(ms: number)",parse:{"!type":"fn(source: string) -> +Date","!url":"https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Date/parse","!doc":"Parses a string representation of a date, and returns the number of milliseconds since January 1, 1970, 00:00:00 UTC."},UTC:{"!type":"fn(year: number, month: number, date: number, hour?: number, min?: number, sec?: number, ms?: number) -> number","!url":"https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Date/UTC","!doc":"Accepts the same parameters as the longest form of the constructor, and returns the number of milliseconds in a Date object since January 1, 1970, 00:00:00, universal time."},now:{"!type":"fn() -> number","!url":"https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Date/now","!doc":"Returns the number of milliseconds elapsed since 1 January 1970 00:00:00 UTC."},prototype:{toUTCString:{"!type":"fn() -> string","!url":"https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Date/toUTCString","!doc":"Converts a date to a string, using the universal time convention."},toISOString:{"!type":"fn() -> string","!url":"https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Date/toISOString","!doc":"JavaScript provides a direct way to convert a date object into a string in ISO format, the ISO 8601 Extended Format."},toDateString:{"!type":"fn() -> string","!url":"https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Date/toDateString","!doc":"Returns the date portion of a Date object in human readable form in American English."},toTimeString:{"!type":"fn() -> string","!url":"https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Date/toTimeString","!doc":"Returns the time portion of a Date object in human readable form in American English."},toLocaleDateString:{"!type":"fn() -> string","!url":"https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Date/toLocaleDateString","!doc":"Converts a date to a string, returning the \"date\" portion using the operating system's locale's conventions.\n"},toLocaleTimeString:{"!type":"fn() -> string","!url":"https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Date/toLocaleTimeString","!doc":'Converts a date to a string, returning the "time" portion using the current locale\'s conventions.'},getTime:{"!type":"fn() -> number","!url":"https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Date/getTime","!doc":"Returns the numeric value corresponding to the time for the specified date according to universal time."},getFullYear:{"!type":"fn() -> number","!url":"https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Date/getFullYear","!doc":"Returns the year of the specified date according to local time."},getYear:{"!type":"fn() -> number","!url":"https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Date/getYear","!doc":"Returns the year in the specified date according to local time."},getMonth:{"!type":"fn() -> number","!url":"https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Date/getMonth","!doc":"Returns the month in the specified date according to local time."},getUTCMonth:{"!type":"fn() -> number","!url":"https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Date/getUTCMonth","!doc":"Returns the month of the specified date according to universal time.\n"},getDate:{"!type":"fn() -> number","!url":"https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Date/getDate","!doc":"Returns the day of the month for the specified date according to local time."},getUTCDate:{"!type":"fn() -> number","!url":"https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Date/getUTCDate","!doc":"Returns the day (date) of the month in the specified date according to universal time.\n"},getDay:{"!type":"fn() -> number","!url":"https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Date/getDay","!doc":"Returns the day of the week for the specified date according to local time."},getUTCDay:{"!type":"fn() -> number","!url":"https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Date/getUTCDay","!doc":"Returns the day of the week in the specified date according to universal time.\n"},getHours:{"!type":"fn() -> number","!url":"https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Date/getHours","!doc":"Returns the hour for the specified date according to local time."},getUTCHours:{"!type":"fn() -> number","!url":"https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Date/getUTCHours","!doc":"Returns the hours in the specified date according to universal time.\n"},getMinutes:{"!type":"fn() -> number","!url":"https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Date/getMinutes","!doc":"Returns the minutes in the specified date according to local time."},getUTCMinutes:{"!type":"fn() -> number","!url":"https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Date","!doc":"Creates JavaScript Date instances which let you work with dates and times."},getSeconds:{"!type":"fn() -> number","!url":"https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Date/getSeconds","!doc":"Returns the seconds in the specified date according to local time."},getUTCSeconds:{"!type":"fn() -> number","!url":"https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Date/getUTCSeconds","!doc":"Returns the seconds in the specified date according to universal time.\n"},getMilliseconds:{"!type":"fn() -> number","!url":"https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Date/getMilliseconds","!doc":"Returns the milliseconds in the specified date according to local time."},getUTCMilliseconds:{"!type":"fn() -> number","!url":"https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Date/getUTCMilliseconds","!doc":"Returns the milliseconds in the specified date according to universal time.\n"},getTimezoneOffset:{"!type":"fn() -> number","!url":"https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Date/getTimezoneOffset","!doc":"Returns the time-zone offset from UTC, in minutes, for the current locale."},setTime:{"!type":"fn(date: +Date) -> number","!url":"https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Date/setTime","!doc":"Sets the Date object to the time represented by a number of milliseconds since January 1, 1970, 00:00:00 UTC.\n"},setFullYear:{"!type":"fn(year: number) -> number","!url":"https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Date/setFullYear","!doc":"Sets the full year for a specified date according to local time.\n"},setUTCFullYear:{"!type":"fn(year: number) -> number","!url":"https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Date/setUTCFullYear","!doc":"Sets the full year for a specified date according to universal time.\n"},setMonth:{"!type":"fn(month: number) -> number","!url":"https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Date/setMonth","!doc":"Set the month for a specified date according to local time."},setUTCMonth:{"!type":"fn(month: number) -> number","!url":"https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Date/setUTCMonth","!doc":"Sets the month for a specified date according to universal time.\n"},setDate:{"!type":"fn(day: number) -> number","!url":"https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Date/setDate","!doc":"Sets the day of the month for a specified date according to local time."},setUTCDate:{"!type":"fn(day: number) -> number","!url":"https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Date/setUTCDate","!doc":"Sets the day of the month for a specified date according to universal time.\n"},setHours:{"!type":"fn(hour: number) -> number","!url":"https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Date/setHours","!doc":"Sets the hours for a specified date according to local time, and returns the number of milliseconds since 1 January 1970 00:00:00 UTC until the time represented by the updated Date instance."},setUTCHours:{"!type":"fn(hour: number) -> number","!url":"https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Date/setUTCHours","!doc":"Sets the hour for a specified date according to universal time.\n"},setMinutes:{"!type":"fn(min: number) -> number","!url":"https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Date/setMinutes","!doc":"Sets the minutes for a specified date according to local time."},setUTCMinutes:{"!type":"fn(min: number) -> number","!url":"https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Date/setUTCMinutes","!doc":"Sets the minutes for a specified date according to universal time.\n"},setSeconds:{"!type":"fn(sec: number) -> number","!url":"https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Date/setSeconds","!doc":"Sets the seconds for a specified date according to local time."},setUTCSeconds:{"!type":"fn(sec: number) -> number","!url":"https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Date/setUTCSeconds","!doc":"Sets the seconds for a specified date according to universal time.\n"},setMilliseconds:{"!type":"fn(ms: number) -> number","!url":"https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Date/setMilliseconds","!doc":"Sets the milliseconds for a specified date according to local time.\n"},setUTCMilliseconds:{"!type":"fn(ms: number) -> number","!url":"https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Date/setUTCMilliseconds","!doc":"Sets the milliseconds for a specified date according to universal time.\n"}},"!url":"https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Date","!doc":"Creates JavaScript Date instances which let you work with dates and times."},Error:{"!type":"fn(message: string)",prototype:{name:{"!type":"string","!url":"https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Error/name","!doc":"A name for the type of error."},message:{"!type":"string","!url":"https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Error/message","!doc":"A human-readable description of the error."}},"!url":"https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Error","!doc":"Creates an error object."},SyntaxError:{"!type":"fn(message: string)",prototype:"Error.prototype","!url":"https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/SyntaxError","!doc":"Represents an error when trying to interpret syntactically invalid code."},ReferenceError:{"!type":"fn(message: string)",prototype:"Error.prototype","!url":"https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/ReferenceError","!doc":"Represents an error when a non-existent variable is referenced."},URIError:{"!type":"fn(message: string)",prototype:"Error.prototype","!url":"https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/URIError","!doc":"Represents an error when a malformed URI is encountered."},EvalError:{"!type":"fn(message: string)",prototype:"Error.prototype","!url":"https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/EvalError","!doc":"Represents an error regarding the eval function."},RangeError:{"!type":"fn(message: string)",prototype:"Error.prototype","!url":"https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/RangeError","!doc":"Represents an error when a number is not within the correct range allowed."},parseInt:{"!type":"fn(string: string, radix?: number) -> number","!url":"https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/parseInt","!doc":"Parses a string argument and returns an integer of the specified radix or base."},parseFloat:{"!type":"fn(string: string) -> number","!url":"https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/parseFloat","!doc":"Parses a string argument and returns a floating point number."},isNaN:{"!type":"fn(value: number) -> bool","!url":"https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/isNaN","!doc":"Determines whether a value is NaN or not. Be careful, this function is broken. You may be interested in ECMAScript 6 Number.isNaN."},eval:{"!type":"fn(code: string) -> ?","!url":"https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/eval","!doc":"Evaluates JavaScript code represented as a string."},encodeURI:{"!type":"fn(uri: string) -> string","!url":"https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/encodeURI","!doc":'Encodes a Uniform Resource Identifier (URI) by replacing each instance of certain characters by one, two, three, or four escape sequences representing the UTF-8 encoding of the character (will only be four escape sequences for characters composed of two "surrogate" characters).'},encodeURIComponent:{"!type":"fn(uri: string) -> string","!url":"https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/encodeURIComponent","!doc":'Encodes a Uniform Resource Identifier (URI) component by replacing each instance of certain characters by one, two, three, or four escape sequences representing the UTF-8 encoding of the character (will only be four escape sequences for characters composed of two "surrogate" characters).'},decodeURI:{"!type":"fn(uri: string) -> string","!url":"https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/decodeURI","!doc":"Decodes a Uniform Resource Identifier (URI) previously created by encodeURI or by a similar routine."},decodeURIComponent:{"!type":"fn(uri: string) -> string","!url":"https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/decodeURIComponent","!doc":"Decodes a Uniform Resource Identifier (URI) component previously created by encodeURIComponent or by a similar routine."},Math:{E:{"!type":"number","!url":"https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Math/E","!doc":"The base of natural logarithms, e, approximately 2.718."},LN2:{"!type":"number","!url":"https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Math/LN2","!doc":"The natural logarithm of 2, approximately 0.693."},LN10:{"!type":"number","!url":"https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Math/LN10","!doc":"The natural logarithm of 10, approximately 2.302."},LOG2E:{"!type":"number","!url":"https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Math/LOG2E","!doc":"The base 2 logarithm of E (approximately 1.442)."},LOG10E:{"!type":"number","!url":"https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Math/LOG10E","!doc":"The base 10 logarithm of E (approximately 0.434)."},SQRT1_2:{"!type":"number","!url":"https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Math/SQRT1_2","!doc":"The square root of 1/2; equivalently, 1 over the square root of 2, approximately 0.707."},SQRT2:{"!type":"number","!url":"https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Math/SQRT2","!doc":"The square root of 2, approximately 1.414."},PI:{"!type":"number","!url":"https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Math/PI","!doc":"The ratio of the circumference of a circle to its diameter, approximately 3.14159."},abs:{"!type":"fn(number) -> number","!url":"https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Math/abs","!doc":"Returns the absolute value of a number."},cos:{"!type":"fn(number) -> number","!url":"https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Math/cos","!doc":"Returns the cosine of a number."},sin:{"!type":"fn(number) -> number","!url":"https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Math/sin","!doc":"Returns the sine of a number."},tan:{"!type":"fn(number) -> number","!url":"https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Math/tan","!doc":"Returns the tangent of a number."},acos:{"!type":"fn(number) -> number","!url":"https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Math/acos","!doc":"Returns the arccosine (in radians) of a number."},asin:{"!type":"fn(number) -> number","!url":"https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Math/asin","!doc":"Returns the arcsine (in radians) of a number."},atan:{"!type":"fn(number) -> number","!url":"https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Math/atan","!doc":"Returns the arctangent (in radians) of a number."},atan2:{"!type":"fn(number, number) -> number","!url":"https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Math/atan2","!doc":"Returns the arctangent of the quotient of its arguments."},ceil:{"!type":"fn(number) -> number","!url":"https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Math/ceil","!doc":"Returns the smallest integer greater than or equal to a number."},floor:{"!type":"fn(number) -> number","!url":"https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Math/floor","!doc":"Returns the largest integer less than or equal to a number."},round:{"!type":"fn(number) -> number","!url":"https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Math/round","!doc":"Returns the value of a number rounded to the nearest integer."},exp:{"!type":"fn(number) -> number","!url":"https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Math/exp","!doc":"Returns Ex, where x is the argument, and E is Euler's constant, the base of the natural logarithms."},log:{"!type":"fn(number) -> number","!url":"https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Math/log","!doc":"Returns the natural logarithm (base E) of a number."},sqrt:{"!type":"fn(number) -> number","!url":"https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Math/sqrt","!doc":"Returns the square root of a number."},pow:{"!type":"fn(number, number) -> number","!url":"https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Math/pow","!doc":"Returns base to the exponent power, that is, baseexponent."},max:{"!type":"fn(number, number) -> number","!url":"https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Math/max","!doc":"Returns the largest of zero or more numbers."},min:{"!type":"fn(number, number) -> number","!url":"https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Math/min","!doc":"Returns the smallest of zero or more numbers."},random:{"!type":"fn() -> number","!url":"https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Math/random","!doc":"Returns a floating-point, pseudo-random number in the range [0, 1) that is, from 0 (inclusive) up to but not including 1 (exclusive), which you can then scale to your desired range."},"!url":"https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Math","!doc":"A built-in object that has properties and methods for mathematical constants and functions."},JSON:{parse:{"!type":"fn(json: string) -> ?","!url":"https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/JSON/parse","!doc":"Parse a string as JSON, optionally transforming the value produced by parsing."},stringify:{"!type":"fn(value: ?) -> string","!url":"https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/JSON/stringify","!doc":"Convert a value to JSON, optionally replacing values if a replacer function is specified, or optionally including only the specified properties if a replacer array is specified."},"!url":"https://developer.mozilla.org/en-US/docs/JSON","!doc":"JSON (JavaScript Object Notation) is a data-interchange format. It closely resembles a subset of JavaScript syntax, although it is not a strict subset. (See JSON in the JavaScript Reference for full details.) It is useful when writing any kind of JavaScript-based application, including websites and browser extensions. For example, you might store user information in JSON format in a cookie, or you might store extension preferences in JSON in a string-valued browser preference."}},ternBasicDefs[1]={"!name":"browser",location:{assign:{"!type":"fn(url: string)","!url":"https://developer.mozilla.org/en/docs/DOM/window.location","!doc":"Load the document at the provided URL."},replace:{"!type":"fn(url: string)","!url":"https://developer.mozilla.org/en/docs/DOM/window.location","!doc":"Replace the current document with the one at the provided URL. The difference from the assign() method is that after using replace() the current page will not be saved in session history, meaning the user won't be able to use the Back button to navigate to it."},reload:{"!type":"fn()","!url":"https://developer.mozilla.org/en/docs/DOM/window.location","!doc":"Reload the document from the current URL. forceget is a boolean, which, when it is true, causes the page to always be reloaded from the server. If it is false or not specified, the browser may reload the page from its cache."},origin:{"!type":"string","!url":"https://developer.mozilla.org/en/docs/DOM/window.location","!doc":"The origin of the URL."},hash:{"!type":"string","!url":"https://developer.mozilla.org/en/docs/DOM/window.location","!doc":"The part of the URL that follows the # symbol, including the # symbol."},search:{"!type":"string","!url":"https://developer.mozilla.org/en/docs/DOM/window.location","!doc":"The part of the URL that follows the ? symbol, including the ? symbol."},pathname:{"!type":"string","!url":"https://developer.mozilla.org/en/docs/DOM/window.location","!doc":"The path (relative to the host)."},port:{"!type":"string","!url":"https://developer.mozilla.org/en/docs/DOM/window.location","!doc":"The port number of the URL."},hostname:{"!type":"string","!url":"https://developer.mozilla.org/en/docs/DOM/window.location","!doc":"The host name (without the port number or square brackets)."},host:{"!type":"string","!url":"https://developer.mozilla.org/en/docs/DOM/window.location","!doc":"The host name and port number."},protocol:{"!type":"string","!url":"https://developer.mozilla.org/en/docs/DOM/window.location","!doc":"The protocol of the URL."},href:{"!type":"string","!url":"https://developer.mozilla.org/en/docs/DOM/window.location","!doc":"The entire URL."},"!url":"https://developer.mozilla.org/en/docs/DOM/window.location","!doc":"Returns a location object with information about the current location of the document. Assigning to the location property changes the current page to the new address."},Node:{"!type":"fn()",prototype:{parentElement:{"!type":"+Element","!url":"https://developer.mozilla.org/en/docs/DOM/Node.parentElement","!doc":"Returns the DOM node's parent Element, or null if the node either has no parent, or its parent isn't a DOM Element."},textContent:{"!type":"string","!url":"https://developer.mozilla.org/en/docs/DOM/Node.textContent","!doc":"Gets or sets the text content of a node and its descendants."},baseURI:{"!type":"string","!url":"https://developer.mozilla.org/en/docs/DOM/Node.baseURI","!doc":"The absolute base URI of a node or null if unable to obtain an absolute URI."},localName:{"!type":"string","!url":"https://developer.mozilla.org/en/docs/DOM/Node.localName","!doc":"Returns the local part of the qualified name of this node."},prefix:{"!type":"string","!url":"https://developer.mozilla.org/en/docs/DOM/Node.prefix","!doc":"Returns the namespace prefix of the specified node, or null if no prefix is specified. This property is read only."},namespaceURI:{"!type":"string","!url":"https://developer.mozilla.org/en/docs/DOM/Node.namespaceURI","!doc":"The namespace URI of the node, or null if the node is not in a namespace (read-only). When the node is a document, it returns the XML namespace for the current document."},ownerDocument:{"!type":"+Document","!url":"https://developer.mozilla.org/en/docs/DOM/Node.ownerDocument","!doc":"The ownerDocument property returns the top-level document object for this node."},attributes:{"!type":"+NamedNodeMap","!url":"https://developer.mozilla.org/en/docs/DOM/Node.attributes","!doc":"A collection of all attribute nodes registered to the specified node. It is a NamedNodeMap,not an Array, so it has no Array methods and the Attr nodes' indexes may differ among browsers."},nextSibling:{"!type":"+Element","!url":"https://developer.mozilla.org/en/docs/DOM/Node.nextSibling","!doc":"Returns the node immediately following the specified one in its parent's childNodes list, or null if the specified node is the last node in that list."},previousSibling:{"!type":"+Element","!url":"https://developer.mozilla.org/en/docs/DOM/Node.previousSibling","!doc":"Returns the node immediately preceding the specified one in its parent's childNodes list, null if the specified node is the first in that list."},lastChild:{"!type":"+Element","!url":"https://developer.mozilla.org/en/docs/DOM/Node.lastChild","!doc":"Returns the last child of a node."},firstChild:{"!type":"+Element","!url":"https://developer.mozilla.org/en/docs/DOM/Node.firstChild","!doc":"Returns the node's first child in the tree, or null if the node is childless. If the node is a Document, it returns the first node in the list of its direct children."},childNodes:{"!type":"+NodeList","!url":"https://developer.mozilla.org/en/docs/DOM/Node.childNodes","!doc":"Returns a collection of child nodes of the given element."},parentNode:{"!type":"+Element","!url":"https://developer.mozilla.org/en/docs/DOM/Node.parentNode","!doc":"Returns the parent of the specified node in the DOM tree."},nodeType:{"!type":"number","!url":"https://developer.mozilla.org/en/docs/DOM/Node.nodeType","!doc":"Returns an integer code representing the type of the node."},nodeValue:{"!type":"string","!url":"https://developer.mozilla.org/en/docs/DOM/Node.nodeValue","!doc":"Returns or sets the value of the current node."},nodeName:{"!type":"string","!url":"https://developer.mozilla.org/en/docs/DOM/Node.nodeName","!doc":"Returns the name of the current node as a string."},tagName:{"!type":"string","!url":"https://developer.mozilla.org/en/docs/DOM/Node.nodeName","!doc":"Returns the name of the current node as a string."},insertBefore:{"!type":"fn(newElt: +Element, before: +Element) -> +Element","!url":"https://developer.mozilla.org/en/docs/DOM/Node.insertBefore","!doc":"Inserts the specified node before a reference element as a child of the current node."},replaceChild:{"!type":"fn(newElt: +Element, oldElt: +Element) -> +Element","!url":"https://developer.mozilla.org/en/docs/DOM/Node.replaceChild","!doc":"Replaces one child node of the specified element with another."},removeChild:{"!type":"fn(oldElt: +Element) -> +Element","!url":"https://developer.mozilla.org/en/docs/DOM/Node.removeChild","!doc":"Removes a child node from the DOM. Returns removed node."},appendChild:{"!type":"fn(newElt: +Element) -> +Element","!url":"https://developer.mozilla.org/en/docs/DOM/Node.appendChild","!doc":"Adds a node to the end of the list of children of a specified parent node. If the node already exists it is removed from current parent node, then added to new parent node."},hasChildNodes:{"!type":"fn() -> bool","!url":"https://developer.mozilla.org/en/docs/DOM/Node.hasChildNodes","!doc":"Returns a Boolean value indicating whether the current Node has child nodes or not."},cloneNode:{"!type":"fn(deep: bool) -> +Element","!url":"https://developer.mozilla.org/en/docs/DOM/Node.cloneNode","!doc":"Returns a duplicate of the node on which this method was called."},normalize:{"!type":"fn()","!url":"https://developer.mozilla.org/en/docs/DOM/Node.normalize","!doc":'Puts the specified node and all of its subtree into a "normalized" form. In a normalized subtree, no text nodes in the subtree are empty and there are no adjacent text nodes.'},isSupported:{"!type":"fn(features: string, version: number) -> bool","!url":"https://developer.mozilla.org/en/docs/DOM/Node.isSupported","!doc":"Tests whether the DOM implementation implements a specific feature and that feature is supported by this node."},hasAttributes:{"!type":"fn() -> bool","!url":"https://developer.mozilla.org/en/docs/DOM/Node.hasAttributes","!doc":"Returns a boolean value of true or false, indicating if the current element has any attributes or not."},lookupPrefix:{"!type":"fn(uri: string) -> string","!url":"https://developer.mozilla.org/en/docs/DOM/Node.lookupPrefix","!doc":"Returns the prefix for a given namespaceURI if present, and null if not. When multiple prefixes are possible, the result is implementation-dependent."},isDefaultNamespace:{"!type":"fn(uri: string) -> bool","!url":"https://developer.mozilla.org/en/docs/DOM/Node.isDefaultNamespace","!doc":"Accepts a namespace URI as an argument and returns true if the namespace is the default namespace on the given node or false if not."},lookupNamespaceURI:{"!type":"fn(uri: string) -> string","!url":"https://developer.mozilla.org/en/docs/DOM/Node.lookupNamespaceURI","!doc":"Takes a prefix and returns the namespaceURI associated with it on the given node if found (and null if not). Supplying null for the prefix will return the default namespace."},addEventListener:{"!type":"fn(type: string, listener: fn(e: +Event), capture: bool)","!url":"https://developer.mozilla.org/en/docs/DOM/EventTarget.addEventListener","!doc":"Registers a single event listener on a single target. The event target may be a single element in a document, the document itself, a window, or an XMLHttpRequest."},removeEventListener:{"!type":"fn(type: string, listener: fn(), capture: bool)","!url":"https://developer.mozilla.org/en/docs/DOM/EventTarget.removeEventListener","!doc":"Allows the removal of event listeners from the event target."},isSameNode:{"!type":"fn(other: +Node) -> bool","!url":"https://developer.mozilla.org/en/docs/DOM/Node.isSameNode","!doc":"Tests whether two nodes are the same, that is they reference the same object."},isEqualNode:{"!type":"fn(other: +Node) -> bool","!url":"https://developer.mozilla.org/en/docs/DOM/Node.isEqualNode","!doc":"Tests whether two nodes are equal."},compareDocumentPosition:{"!type":"fn(other: +Node) -> number","!url":"https://developer.mozilla.org/en/docs/DOM/Node.compareDocumentPosition","!doc":"Compares the position of the current node against another node in any other document."},contains:{"!type":"fn(other: +Node) -> bool","!url":"https://developer.mozilla.org/en/docs/DOM/Node.contains","!doc":"Indicates whether a node is a descendent of a given node."},dispatchEvent:{"!type":"fn(event: +Event) -> bool","!url":"https://developer.mozilla.org/en/docs/DOM/EventTarget.dispatchEvent","!doc":"Dispatches an event into the event system. The event is subject to the same capturing and bubbling behavior as directly dispatched events."},ELEMENT_NODE:"number",ATTRIBUTE_NODE:"number",TEXT_NODE:"number",CDATA_SECTION_NODE:"number",ENTITY_REFERENCE_NODE:"number",ENTITY_NODE:"number",PROCESSING_INSTRUCTION_NODE:"number",COMMENT_NODE:"number",DOCUMENT_NODE:"number",DOCUMENT_TYPE_NODE:"number",DOCUMENT_FRAGMENT_NODE:"number",NOTATION_NODE:"number",DOCUMENT_POSITION_DISCONNECTED:"number",DOCUMENT_POSITION_PRECEDING:"number",DOCUMENT_POSITION_FOLLOWING:"number",DOCUMENT_POSITION_CONTAINS:"number",DOCUMENT_POSITION_CONTAINED_BY:"number",DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC:"number"},"!url":"https://developer.mozilla.org/en/docs/DOM/Node","!doc":"A Node is an interface from which a number of DOM types inherit, and allows these various types to be treated (or tested) similarly."},Element:{"!type":"fn()",prototype:{"!proto":"Node.prototype",getAttribute:{"!type":"fn(name: string) -> string","!url":"https://developer.mozilla.org/en/docs/DOM/element.getAttribute","!doc":'Returns the value of the named attribute on the specified element. If the named attribute does not exist, the value returned will either be null or "" (the empty string).'},setAttribute:{"!type":"fn(name: string, value: string)","!url":"https://developer.mozilla.org/en/docs/DOM/element.setAttribute","!doc":"Adds a new attribute or changes the value of an existing attribute on the specified element."},removeAttribute:{"!type":"fn(name: string)","!url":"https://developer.mozilla.org/en/docs/DOM/element.removeAttribute","!doc":"Removes an attribute from the specified element."},getAttributeNode:{"!type":"fn(name: string) -> +Attr","!url":"https://developer.mozilla.org/en/docs/DOM/element.getAttributeNode","!doc":"Returns the specified attribute of the specified element, as an Attr node."},getElementsByTagName:{"!type":"fn(tagName: string) -> +NodeList","!url":"https://developer.mozilla.org/en/docs/DOM/element.getElementsByTagName","!doc":"Returns a list of elements with the given tag name. The subtree underneath the specified element is searched, excluding the element itself. The returned list is live, meaning that it updates itself with the DOM tree automatically. Consequently, there is no need to call several times element.getElementsByTagName with the same element and arguments."},getElementsByTagNameNS:{"!type":"fn(ns: string, tagName: string) -> +NodeList","!url":"https://developer.mozilla.org/en/docs/DOM/element.getElementsByTagNameNS","!doc":"Returns a list of elements with the given tag name belonging to the given namespace."},getAttributeNS:{"!type":"fn(ns: string, name: string) -> string","!url":"https://developer.mozilla.org/en/docs/DOM/element.getAttributeNS","!doc":'Returns the string value of the attribute with the specified namespace and name. If the named attribute does not exist, the value returned will either be null or "" (the empty string).'},setAttributeNS:{"!type":"fn(ns: string, name: string, value: string)","!url":"https://developer.mozilla.org/en/docs/DOM/element.setAttributeNS","!doc":"Adds a new attribute or changes the value of an attribute with the given namespace and name."},removeAttributeNS:{"!type":"fn(ns: string, name: string)","!url":"https://developer.mozilla.org/en/docs/DOM/element.removeAttributeNS","!doc":"removeAttributeNS removes the specified attribute from an element."},getAttributeNodeNS:{"!type":"fn(ns: string, name: string) -> +Attr","!url":"https://developer.mozilla.org/en/docs/DOM/element.getAttributeNodeNS","!doc":"Returns the Attr node for the attribute with the given namespace and name."},hasAttribute:{"!type":"fn(name: string) -> bool","!url":"https://developer.mozilla.org/en/docs/DOM/element.hasAttribute","!doc":"hasAttribute returns a boolean value indicating whether the specified element has the specified attribute or not."},hasAttributeNS:{"!type":"fn(ns: string, name: string) -> bool","!url":"https://developer.mozilla.org/en/docs/DOM/element.hasAttributeNS","!doc":"hasAttributeNS returns a boolean value indicating whether the current element has the specified attribute."},focus:{"!type":"fn()","!url":"https://developer.mozilla.org/en/docs/DOM/element.focus","!doc":"Sets focus on the specified element, if it can be focused."},blur:{"!type":"fn()","!url":"https://developer.mozilla.org/en/docs/DOM/element.blur","!doc":"The blur method removes keyboard focus from the current element."},scrollIntoView:{"!type":"fn(top: bool)","!url":"https://developer.mozilla.org/en/docs/DOM/element.scrollIntoView","!doc":"The scrollIntoView() method scrolls the element into view."},scrollByLines:{"!type":"fn(lines: number)","!url":"https://developer.mozilla.org/en/docs/DOM/window.scrollByLines","!doc":"Scrolls the document by the given number of lines."},scrollByPages:{"!type":"fn(pages: number)","!url":"https://developer.mozilla.org/en/docs/DOM/window.scrollByPages","!doc":"Scrolls the current document by the specified number of pages."},getElementsByClassName:{"!type":"fn(name: string) -> +NodeList","!url":"https://developer.mozilla.org/en/docs/DOM/document.getElementsByClassName","!doc":"Returns a set of elements which have all the given class names. When called on the document object, the complete document is searched, including the root node. You may also call getElementsByClassName on any element; it will return only elements which are descendants of the specified root element with the given class names."},querySelector:{"!type":"fn(selectors: string) -> +Node","!url":"https://developer.mozilla.org/en/docs/DOM/Element.querySelector","!doc":"Returns the first element that is a descendent of the element on which it is invoked that matches the specified group of selectors."},querySelectorAll:{"!type":"fn(selectors: string) -> +NodeList","!url":"https://developer.mozilla.org/en/docs/DOM/Element.querySelectorAll","!doc":"Returns a non-live NodeList of all elements descended from the element on which it is invoked that match the specified group of CSS selectors."},getClientRects:{"!type":"fn() -> [+ClientRect]","!url":"https://developer.mozilla.org/en/docs/DOM/element.getClientRects","!doc":"Returns a collection of rectangles that indicate the bounding rectangles for each box in a client."},getBoundingClientRect:{"!type":"fn() -> +ClientRect","!url":"https://developer.mozilla.org/en/docs/DOM/element.getBoundingClientRect","!doc":"Returns a text rectangle object that encloses a group of text rectangles."},setAttributeNode:{"!type":"fn(attr: +Attr) -> +Attr","!url":"https://developer.mozilla.org/en/docs/DOM/element.setAttributeNode","!doc":"Adds a new Attr node to the specified element."},removeAttributeNode:{"!type":"fn(attr: +Attr) -> +Attr","!url":"https://developer.mozilla.org/en/docs/DOM/element.removeAttributeNode","!doc":"Removes the specified attribute from the current element."},setAttributeNodeNS:{"!type":"fn(attr: +Attr) -> +Attr","!url":"https://developer.mozilla.org/en/docs/DOM/element.setAttributeNodeNS","!doc":"Adds a new namespaced attribute node to an element."},insertAdjacentHTML:{"!type":"fn(position: string, text: string)","!url":"https://developer.mozilla.org/en/docs/DOM/element.insertAdjacentHTML","!doc":"Parses the specified text as HTML or XML and inserts the resulting nodes into the DOM tree at a specified position. It does not reparse the element it is being used on and thus it does not corrupt the existing elements inside the element. This, and avoiding the extra step of serialization make it much faster than direct innerHTML manipulation."},children:{"!type":"+HTMLCollection","!url":"https://developer.mozilla.org/en/docs/DOM/Element.children","!doc":"Returns a collection of child elements of the given element."},childElementCount:{"!type":"number","!url":"https://developer.mozilla.org/en/docs/DOM/Element.childElementCount","!doc":"Returns the number of child elements of the given element."},className:{"!type":"string","!url":"https://developer.mozilla.org/en/docs/DOM/element.className","!doc":"Gets and sets the value of the class attribute of the specified element."},style:{cssText:"string",alignmentBaseline:"string",background:"string",backgroundAttachment:"string",backgroundClip:"string",backgroundColor:"string",backgroundImage:"string",backgroundOrigin:"string",backgroundPosition:"string",backgroundPositionX:"string",backgroundPositionY:"string",backgroundRepeat:"string",backgroundRepeatX:"string",backgroundRepeatY:"string",backgroundSize:"string",baselineShift:"string",border:"string",borderBottom:"string",borderBottomColor:"string",borderBottomLeftRadius:"string",borderBottomRightRadius:"string",borderBottomStyle:"string",borderBottomWidth:"string",borderCollapse:"string",borderColor:"string",borderImage:"string",borderImageOutset:"string",borderImageRepeat:"string",borderImageSlice:"string",borderImageSource:"string",borderImageWidth:"string",borderLeft:"string",borderLeftColor:"string",borderLeftStyle:"string",borderLeftWidth:"string",borderRadius:"string",borderRight:"string",borderRightColor:"string",borderRightStyle:"string",borderRightWidth:"string",borderSpacing:"string",borderStyle:"string",borderTop:"string",borderTopColor:"string",borderTopLeftRadius:"string",borderTopRightRadius:"string",borderTopStyle:"string",borderTopWidth:"string",borderWidth:"string",bottom:"string",boxShadow:"string",boxSizing:"string",captionSide:"string",clear:"string",clip:"string",clipPath:"string",clipRule:"string",color:"string",colorInterpolation:"string",colorInterpolationFilters:"string",colorProfile:"string",colorRendering:"string",content:"string",counterIncrement:"string",counterReset:"string",cursor:"string",direction:"string",display:"string",dominantBaseline:"string",emptyCells:"string",enableBackground:"string",fill:"string",fillOpacity:"string",fillRule:"string",filter:"string","float":"string",floodColor:"string",floodOpacity:"string",font:"string",fontFamily:"string",fontSize:"string",fontStretch:"string",fontStyle:"string",fontVariant:"string",fontWeight:"string",glyphOrientationHorizontal:"string",glyphOrientationVertical:"string",height:"string",imageRendering:"string",kerning:"string",left:"string",letterSpacing:"string",lightingColor:"string",lineHeight:"string",listStyle:"string",listStyleImage:"string",listStylePosition:"string",listStyleType:"string",margin:"string",marginBottom:"string",marginLeft:"string",marginRight:"string",marginTop:"string",marker:"string",markerEnd:"string",markerMid:"string",markerStart:"string",mask:"string",maxHeight:"string",maxWidth:"string",minHeight:"string",minWidth:"string",opacity:"string",orphans:"string",outline:"string",outlineColor:"string",outlineOffset:"string",outlineStyle:"string",outlineWidth:"string",overflow:"string",overflowWrap:"string",overflowX:"string",overflowY:"string",padding:"string",paddingBottom:"string",paddingLeft:"string",paddingRight:"string",paddingTop:"string",page:"string",pageBreakAfter:"string",pageBreakBefore:"string",pageBreakInside:"string",pointerEvents:"string",position:"string",quotes:"string",resize:"string",right:"string",shapeRendering:"string",size:"string",speak:"string",src:"string",stopColor:"string",stopOpacity:"string",stroke:"string",strokeDasharray:"string",strokeDashoffset:"string",strokeLinecap:"string",strokeLinejoin:"string",strokeMiterlimit:"string",strokeOpacity:"string",strokeWidth:"string",tabSize:"string",tableLayout:"string",textAlign:"string",textAnchor:"string",textDecoration:"string",textIndent:"string",textLineThrough:"string",textLineThroughColor:"string",textLineThroughMode:"string",textLineThroughStyle:"string",textLineThroughWidth:"string",textOverflow:"string",textOverline:"string",textOverlineColor:"string",textOverlineMode:"string",textOverlineStyle:"string",textOverlineWidth:"string",textRendering:"string",textShadow:"string",textTransform:"string",textUnderline:"string",textUnderlineColor:"string",textUnderlineMode:"string",textUnderlineStyle:"string",textUnderlineWidth:"string",top:"string",unicodeBidi:"string",unicodeRange:"string",vectorEffect:"string",verticalAlign:"string",visibility:"string",whiteSpace:"string",width:"string",wordBreak:"string",wordSpacing:"string",wordWrap:"string",writingMode:"string",zIndex:"string",zoom:"string","!url":"https://developer.mozilla.org/en/docs/DOM/element.style","!doc":"Returns an object that represents the element's style attribute."},classList:{"!type":"+DOMTokenList","!url":"https://developer.mozilla.org/en/docs/DOM/element.classList","!doc":"Returns a token list of the class attribute of the element."},contentEditable:{"!type":"bool","!url":"https://developer.mozilla.org/en/docs/DOM/Element.contentEditable","!doc":"Indicates whether or not the element is editable."},firstElementChild:{"!type":"+Element","!url":"https://developer.mozilla.org/en/docs/DOM/Element.firstElementChild","!doc":"Returns the element's first child element or null if there are no child elements."},lastElementChild:{"!type":"+Element","!url":"https://developer.mozilla.org/en/docs/DOM/Element.lastElementChild","!doc":"Returns the element's last child element or null if there are no child elements."},nextElementSibling:{"!type":"+Element","!url":"https://developer.mozilla.org/en/docs/DOM/Element.nextElementSibling","!doc":"Returns the element immediately following the specified one in its parent's children list, or null if the specified element is the last one in the list."},previousElementSibling:{"!type":"+Element","!url":"https://developer.mozilla.org/en/docs/DOM/Element.previousElementSibling","!doc":"Returns the element immediately prior to the specified one in its parent's children list, or null if the specified element is the first one in the list."},tabIndex:{"!type":"number","!url":"https://developer.mozilla.org/en/docs/DOM/element.tabIndex","!doc":"Gets/sets the tab order of the current element."},title:{"!type":"string","!url":"https://developer.mozilla.org/en/docs/DOM/element.title","!doc":"Establishes the text to be displayed in a 'tool tip' popup when the mouse is over the displayed node."},width:{"!type":"number","!url":"https://developer.mozilla.org/en/docs/DOM/element.offsetWidth","!doc":"Returns the layout width of an element."},height:{"!type":"number","!url":"https://developer.mozilla.org/en/docs/DOM/element.offsetHeight","!doc":"Height of an element relative to the element's offsetParent."},getContext:{"!type":"fn(id: string) -> CanvasRenderingContext2D","!url":"https://developer.mozilla.org/en/docs/DOM/HTMLCanvasElement","!doc":"DOM canvas elements expose the HTMLCanvasElement interface, which provides properties and methods for manipulating the layout and presentation of canvas elements. The HTMLCanvasElement interface inherits the properties and methods of the element object interface."},supportsContext:"fn(id: string) -> bool",oncopy:{"!type":"?","!url":"https://developer.mozilla.org/en/docs/DOM/element.oncopy","!doc":"The oncopy property returns the onCopy event handler code on the current element."},oncut:{"!type":"?","!url":"https://developer.mozilla.org/en/docs/DOM/element.oncut","!doc":"The oncut property returns the onCut event handler code on the current element."},onpaste:{"!type":"?","!url":"https://developer.mozilla.org/en/docs/DOM/element.onpaste","!doc":"The onpaste property returns the onPaste event handler code on the current element."},onbeforeunload:{"!type":"?","!url":"https://developer.mozilla.org/en/docs/HTML/Element/body","!doc":"The HTML element represents the main content of an HTML document. There is only one element in a document."},onfocus:{"!type":"?","!url":"https://developer.mozilla.org/en/docs/DOM/element.onfocus","!doc":"The onfocus property returns the onFocus event handler code on the current element."},onblur:{"!type":"?","!url":"https://developer.mozilla.org/en/docs/DOM/element.onblur","!doc":"The onblur property returns the onBlur event handler code, if any, that exists on the current element."},onchange:{"!type":"?","!url":"https://developer.mozilla.org/en/docs/DOM/element.onchange","!doc":"The onchange property sets and returns the onChange event handler code for the current element."},onclick:{"!type":"?","!url":"https://developer.mozilla.org/en/docs/DOM/element.onclick","!doc":"The onclick property returns the onClick event handler code on the current element."},ondblclick:{"!type":"?","!url":"https://developer.mozilla.org/en/docs/DOM/element.ondblclick","!doc":"The ondblclick property returns the onDblClick event handler code on the current element."},onmousedown:{"!type":"?","!url":"https://developer.mozilla.org/en/docs/DOM/element.onmousedown","!doc":"The onmousedown property returns the onMouseDown event handler code on the current element."},onmouseup:{"!type":"?","!url":"https://developer.mozilla.org/en/docs/DOM/element.onmouseup","!doc":"The onmouseup property returns the onMouseUp event handler code on the current element."},onmousewheel:{"!type":"?","!url":"https://developer.mozilla.org/en/docs/DOM/Mozilla_event_reference/wheel","!doc":"The wheel event is fired when a wheel button of a pointing device (usually a mouse) is rotated. This event deprecates the legacy mousewheel event."},onmouseover:{"!type":"?","!url":"https://developer.mozilla.org/en/docs/DOM/element.onmouseover","!doc":"The onmouseover property returns the onMouseOver event handler code on the current element."},onmouseout:{"!type":"?","!url":"https://developer.mozilla.org/en/docs/DOM/element.onmouseout","!doc":"The onmouseout property returns the onMouseOut event handler code on the current element."},onmousemove:{"!type":"?","!url":"https://developer.mozilla.org/en/docs/DOM/element.onmousemove","!doc":"The onmousemove property returns the mousemove event handler code on the current element."},oncontextmenu:{"!type":"?","!url":"https://developer.mozilla.org/en/docs/DOM/window.oncontextmenu","!doc":'An event handler property for right-click events on the window. Unless the default behavior is prevented, the browser context menu will activate. Note that this event will occur with any non-disabled right-click event and does not depend on an element possessing the "contextmenu" attribute.'},onkeydown:{"!type":"?","!url":"https://developer.mozilla.org/en/docs/DOM/element.onkeydown","!doc":"The onkeydown property returns the onKeyDown event handler code on the current element."},onkeyup:{"!type":"?","!url":"https://developer.mozilla.org/en/docs/DOM/element.onkeyup","!doc":"The onkeyup property returns the onKeyUp event handler code for the current element."},onkeypress:{"!type":"?","!url":"https://developer.mozilla.org/en/docs/DOM/element.onkeypress","!doc":"The onkeypress property sets and returns the onKeyPress event handler code for the current element."},onresize:{"!type":"?","!url":"https://developer.mozilla.org/en/docs/DOM/element.onresize","!doc":"onresize returns the element's onresize event handler code. It can also be used to set the code to be executed when the resize event occurs."},onscroll:{"!type":"?","!url":"https://developer.mozilla.org/en/docs/DOM/element.onscroll","!doc":"The onscroll property returns the onScroll event handler code on the current element."},ondragstart:{"!type":"?","!url":"https://developer.mozilla.org/en/docs/DragDrop/Drag_Operations","!doc":"The following describes the steps that occur during a drag and drop operation."},ondragover:{"!type":"?","!url":"https://developer.mozilla.org/en/docs/DOM/Mozilla_event_reference/dragover","!doc":"The dragover event is fired when an element or text selection is being dragged over a valid drop target (every few hundred milliseconds)."},ondragleave:{"!type":"?","!url":"https://developer.mozilla.org/en/docs/DOM/Mozilla_event_reference/dragleave","!doc":"The dragleave event is fired when a dragged element or text selection leaves a valid drop target."},ondragenter:{"!type":"?","!url":"https://developer.mozilla.org/en/docs/DOM/Mozilla_event_reference/dragenter","!doc":"The dragenter event is fired when a dragged element or text selection enters a valid drop target."},ondragend:{"!type":"?","!url":"https://developer.mozilla.org/en/docs/DOM/Mozilla_event_reference/dragend","!doc":"The dragend event is fired when a drag operation is being ended (by releasing a mouse button or hitting the escape key)."},ondrag:{"!type":"?","!url":"https://developer.mozilla.org/en/docs/DOM/Mozilla_event_reference/drag","!doc":"The drag event is fired when an element or text selection is being dragged (every few hundred milliseconds)."},offsetTop:{"!type":"number","!url":"https://developer.mozilla.org/en/docs/DOM/element.offsetTop","!doc":"Returns the distance of the current element relative to the top of the offsetParent node."},offsetLeft:{"!type":"number","!url":"https://developer.mozilla.org/en/docs/DOM/element.offsetLeft","!doc":"Returns the number of pixels that the upper left corner of the current element is offset to the left within the offsetParent node."},offsetHeight:{"!type":"number","!url":"https://developer.mozilla.org/en/docs/DOM/element.offsetHeight","!doc":"Height of an element relative to the element's offsetParent."},offsetWidth:{"!type":"number","!url":"https://developer.mozilla.org/en/docs/DOM/element.offsetWidth","!doc":"Returns the layout width of an element."},scrollTop:{"!type":"number","!url":"https://developer.mozilla.org/en/docs/DOM/element.scrollTop","!doc":"Gets or sets the number of pixels that the content of an element is scrolled upward."},scrollLeft:{"!type":"number","!url":"https://developer.mozilla.org/en/docs/DOM/element.scrollLeft","!doc":"Gets or sets the number of pixels that an element's content is scrolled to the left."},scrollHeight:{"!type":"number","!url":"https://developer.mozilla.org/en/docs/DOM/element.scrollHeight","!doc":"Height of the scroll view of an element; it includes the element padding but not its margin."},scrollWidth:{"!type":"number","!url":"https://developer.mozilla.org/en/docs/DOM/element.scrollWidth","!doc":"Read-only property that returns either the width in pixels of the content of an element or the width of the element itself, whichever is greater."},clientTop:{"!type":"number","!url":"https://developer.mozilla.org/en/docs/DOM/element.clientTop","!doc":"The width of the top border of an element in pixels. It does not include the top margin or padding. clientTop is read-only."},clientLeft:{"!type":"number","!url":"https://developer.mozilla.org/en/docs/DOM/element.clientLeft","!doc":"The width of the left border of an element in pixels. It includes the width of the vertical scrollbar if the text direction of the element is right-to-left and if there is an overflow causing a left vertical scrollbar to be rendered. clientLeft does not include the left margin or the left padding. clientLeft is read-only."},clientHeight:{"!type":"number","!url":"https://developer.mozilla.org/en/docs/DOM/element.clientHeight","!doc":"Returns the inner height of an element in pixels, including padding but not the horizontal scrollbar height, border, or margin."},clientWidth:{"!type":"number","!url":"https://developer.mozilla.org/en/docs/DOM/element.clientWidth","!doc":"The inner width of an element in pixels. It includes padding but not the vertical scrollbar (if present, if rendered), border or margin."},innerHTML:{"!type":"string","!url":"https://developer.mozilla.org/en/docs/DOM/element.innerHTML","!doc":"Sets or gets the HTML syntax describing the element's descendants."},createdCallback:{"!type":"fn()","!url":"http://w3c.github.io/webcomponents/spec/custom/index.html#dfn-created-callback","!doc":"This callback is invoked after custom element instance is created and its definition is registered. The actual timing of this callback is defined further in this specification."},attachedCallback:{"!type":"fn()","!url":"http://w3c.github.io/webcomponents/spec/custom/index.html#dfn-entered-view-callback","!doc":"Unless specified otherwise, this callback must be enqueued whenever custom element is inserted into a document and this document has a browsing context."},detachedCallback:{"!type":"fn()","!url":"http://w3c.github.io/webcomponents/spec/custom/index.html#dfn-left-view-callback","!doc":"Unless specified otherwise, this callback must be enqueued whenever custom element is removed from the document and this document has a browsing context."},attributeChangedCallback:{"!type":"fn()","!url":"http://w3c.github.io/webcomponents/spec/custom/index.html#dfn-attribute-changed-callback","!doc":"Unless specified otherwise, this callback must be enqueued whenever custom element's attribute is added, changed or removed."}},"!url":"https://developer.mozilla.org/en/docs/DOM/Element","!doc":"Represents an element in an HTML or XML document."},Text:{"!type":"fn()",prototype:{"!proto":"Node.prototype",wholeText:{"!type":"string","!url":"https://developer.mozilla.org/en/docs/DOM/Text.wholeText","!doc":"Returns all text of all Text nodes logically adjacent to the node. The text is concatenated in document order. This allows you to specify any text node and obtain all adjacent text as a single string."},splitText:{"!type":"fn(offset: number) -> +Text","!url":"https://developer.mozilla.org/en/docs/DOM/Text.splitText","!doc":"Breaks the Text node into two nodes at the specified offset, keeping both nodes in the tree as siblings."}},"!url":"https://developer.mozilla.org/en/docs/DOM/Text","!doc":"In the DOM, the Text interface represents the textual content of an Element or Attr. If an element has no markup within its content, it has a single child implementing Text that contains the element's text. However, if the element contains markup, it is parsed into information items and Text nodes that form its children."},Document:{"!type":"fn()",prototype:{"!proto":"Node.prototype",activeElement:{"!type":"+Element","!url":"https://developer.mozilla.org/en/docs/DOM/document.activeElement","!doc":"Returns the currently focused element, that is, the element that will get keystroke events if the user types any. This attribute is read only."},compatMode:{"!type":"string","!url":"https://developer.mozilla.org/en/docs/DOM/document.compatMode","!doc":"Indicates whether the document is rendered in Quirks mode or Strict mode."},designMode:{"!type":"string","!url":"https://developer.mozilla.org/en/docs/DOM/document.designMode","!doc":"Can be used to make any document editable, for example in a