From e6a9501d9a219d546ecb64d719272eb6ea24f21c Mon Sep 17 00:00:00 2001 From: Ben Croker <57572400+bencroker@users.noreply.github.com> Date: Tue, 30 Jun 2020 11:34:06 +0200 Subject: [PATCH 01/10] Made indicator and request classes customisable --- src/htmx.js | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/src/htmx.js b/src/htmx.js index 1c598ff9..dc675b4b 100644 --- a/src/htmx.js +++ b/src/htmx.js @@ -1149,7 +1149,7 @@ return (function () { indicators = [elt]; } forEach(indicators, function(ic) { - ic.classList[action].call(ic.classList, "htmx-request"); + ic.classList[action].call(ic.classList, htmx.config.requestClass); }); } @@ -1668,18 +1668,16 @@ return (function () { } } - // insert htmx-indicator css rules immediate, if not configured otherwise - (function() { - var metaConfig = getMetaConfig(); - if (metaConfig === null || metaConfig.includeIndicatorStyles !== false) { + function insertIndicatorStyles() { + if (htmx.config.includeIndicatorStyles !== false) { getDocument().head.insertAdjacentHTML("beforeend", ""); } - })(); + } function getMetaConfig() { var element = getDocument().querySelector('meta[name="htmx-config"]'); @@ -1700,6 +1698,7 @@ return (function () { // initialize the document ready(function () { mergeMetaConfig(); + insertIndicatorStyles(); var body = getDocument().body; processNode(body, true); triggerEvent(body, 'load.htmx', {}); @@ -1733,7 +1732,9 @@ return (function () { defaultSwapStyle:'innerHTML', defaultSwapDelay:0, defaultSettleDelay:100, - includeIndicatorStyles:true + includeIndicatorStyles:true, + indicatorClass:'htmx-indicator', + requestClass:'htmx-request' }, parseInterval:parseInterval, _:internalEval, From 9ed66d5130c6a19e37f47c76f90ce657ad00f63b Mon Sep 17 00:00:00 2001 From: Ben Croker <57572400+bencroker@users.noreply.github.com> Date: Tue, 30 Jun 2020 11:54:01 +0200 Subject: [PATCH 02/10] Added indicator and request class config variables --- www/docs.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/www/docs.md b/www/docs.md index e0bffa70..245c1fab 100644 --- a/www/docs.md +++ b/www/docs.md @@ -681,7 +681,9 @@ Htmx allows you to configure a few defaults: | `htmx.config.defaultSwapStyle` | defaults to `innerHTML` | `htmx.config.defaultSwapDelay` | defaults to 0 | `htmx.config.defaultSettleDelay` | defaults to 100 -| `htmx.config.includeIndicatorStyles` | defaults to `true` (determines if the `htmx-indicator` default styles are loaded, must be set in a `meta` tag before the htmx js is included) +| `htmx.config.includeIndicatorStyles` | defaults to `true` (determines if the indicator styles are loaded) +| `htmx.config.indicatorClass` | defaults to `htmx-indicator` +| `htmx.config.requestClass` | defaults to `htmx-request` From 3fd502af73d2cdeab8f43e6844ac07afd7558c56 Mon Sep 17 00:00:00 2001 From: Ben Croker <57572400+bencroker@users.noreply.github.com> Date: Tue, 30 Jun 2020 23:24:17 +0200 Subject: [PATCH 03/10] Added settlingClass and swappingClass to config variables --- src/htmx.js | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/htmx.js b/src/htmx.js index dc675b4b..ab3c08ff 100644 --- a/src/htmx.js +++ b/src/htmx.js @@ -1522,7 +1522,7 @@ return (function () { var swapSpec = getSwapSpecification(elt); - target.classList.add("htmx-swapping"); + target.classList.add(htmx.config.swappingClass); var doSwap = function () { try { @@ -1544,10 +1544,10 @@ return (function () { newActiveElt.focus(); } - target.classList.remove("htmx-swapping"); + target.classList.remove(htmx.config.swappingClass); forEach(settleInfo.elts, function (elt) { if (elt.classList) { - elt.classList.add("htmx-settling"); + elt.classList.add(htmx.config.settlingClass); } triggerEvent(elt, 'afterSwap.htmx', eventDetail); }); @@ -1560,7 +1560,7 @@ return (function () { }); forEach(settleInfo.elts, function (elt) { if (elt.classList) { - elt.classList.remove("htmx-settling"); + elt.classList.remove(htmx.config.settlingClass); } triggerEvent(elt, 'afterSettle.htmx', eventDetail); }); @@ -1734,7 +1734,9 @@ return (function () { defaultSettleDelay:100, includeIndicatorStyles:true, indicatorClass:'htmx-indicator', - requestClass:'htmx-request' + requestClass:'htmx-request', + settlingClass:'htmx-settling', + swappingClass:'htmx-swapping', }, parseInterval:parseInterval, _:internalEval, From 4e2b57634b737e5712a22c68597a3dd57a827b2d Mon Sep 17 00:00:00 2001 From: Ben Croker <57572400+bencroker@users.noreply.github.com> Date: Tue, 30 Jun 2020 23:27:49 +0200 Subject: [PATCH 04/10] Added settlingClass and swappingClass to docs --- www/docs.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/www/docs.md b/www/docs.md index 245c1fab..76f239a9 100644 --- a/www/docs.md +++ b/www/docs.md @@ -684,6 +684,8 @@ Htmx allows you to configure a few defaults: | `htmx.config.includeIndicatorStyles` | defaults to `true` (determines if the indicator styles are loaded) | `htmx.config.indicatorClass` | defaults to `htmx-indicator` | `htmx.config.requestClass` | defaults to `htmx-request` +| `htmx.config.settlingClass` | defaults to `htmx-settling` +| `htmx.config.swappingClass` | defaults to `htmx-swapping` From 947a4470de7cca21479ed6f9a761d4bf56e451d9 Mon Sep 17 00:00:00 2001 From: carson Date: Sat, 4 Jul 2020 15:27:39 -0700 Subject: [PATCH 05/10] Experimental fix for https://github.com/bigskysoftware/htmx/issues/131 --- www/js/htmx.js | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/www/js/htmx.js b/www/js/htmx.js index 2c311130..249c924c 100644 --- a/www/js/htmx.js +++ b/www/js/htmx.js @@ -1071,7 +1071,7 @@ return (function () { } function pushUrlIntoHistory(path) { - if(htmx.config.historyEnabled) history.pushState({}, "", path); + if(htmx.config.historyEnabled) history.pushState({htmx:true}, "", path); currentPathForHistory = path; } @@ -1703,8 +1703,10 @@ return (function () { var body = getDocument().body; processNode(body, true); triggerEvent(body, 'htmx:load', {}); - window.onpopstate = function () { - restoreHistory(); + window.onpopstate = function (event) { + if (event.state && event.state.htmx) { + restoreHistory(); + } }; }) From aaae399308e22cc0542eb065262618ef1da379a6 Mon Sep 17 00:00:00 2001 From: carson Date: Sat, 4 Jul 2020 15:46:25 -0700 Subject: [PATCH 06/10] Lets try that again Experimental fix for https://github.com/bigskysoftware/htmx/issues/131 --- src/htmx.js | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/htmx.js b/src/htmx.js index 2c311130..98116357 100644 --- a/src/htmx.js +++ b/src/htmx.js @@ -1066,12 +1066,12 @@ return (function () { var elt = getHistoryElement(); var path = currentPathForHistory || location.pathname+location.search; triggerEvent(getDocument().body, "htmx:beforeHistorySave", {path:path, historyElt:elt}); - if(htmx.config.historyEnabled) history.replaceState({}, getDocument().title, window.location.href); + if(htmx.config.historyEnabled) history.replaceState({htmx:true}, getDocument().title, window.location.href); saveToHistoryCache(path, elt.innerHTML, getDocument().title, window.scrollY); } function pushUrlIntoHistory(path) { - if(htmx.config.historyEnabled) history.pushState({}, "", path); + if(htmx.config.historyEnabled) history.pushState({htmx:true}, "", path); currentPathForHistory = path; } @@ -1703,8 +1703,10 @@ return (function () { var body = getDocument().body; processNode(body, true); triggerEvent(body, 'htmx:load', {}); - window.onpopstate = function () { - restoreHistory(); + window.onpopstate = function (event) { + if (event.state && event.state.htmx) { + restoreHistory(); + } }; }) From 5202de55247fa83e3dff5637a78e34df482481eb Mon Sep 17 00:00:00 2001 From: Ben Croker <57572400+bencroker@users.noreply.github.com> Date: Mon, 6 Jul 2020 18:23:00 +0200 Subject: [PATCH 07/10] Fixed `swapSpec` when `view` --- src/htmx.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/htmx.js b/src/htmx.js index 98116357..80b5a7b4 100644 --- a/src/htmx.js +++ b/src/htmx.js @@ -1338,7 +1338,7 @@ return (function () { swapSpec["scroll"] = modifier.substr(7); } if (modifier.indexOf("view:") === 0) { - swapSpec["view"] = modifier.substr(7); + swapSpec["view"] = modifier.substr(5); } } } @@ -1374,10 +1374,10 @@ return (function () { } } if (swapSpec.view) { - if (swapSpec.scroll === "top") { + if (swapSpec.view === "top") { target.scrollIntoView(true); } - if (swapSpec.scroll === "bottom") { + if (swapSpec.view === "bottom") { target.scrollIntoView(false); } } From 38d587ef62c7e843d45b2f95d3e47834a1a7f4b5 Mon Sep 17 00:00:00 2001 From: carson Date: Mon, 6 Jul 2020 09:36:03 -0700 Subject: [PATCH 08/10] Move `view` modifier to `show` --- src/htmx.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/htmx.js b/src/htmx.js index 17cc504c..7a5478b5 100644 --- a/src/htmx.js +++ b/src/htmx.js @@ -1337,8 +1337,8 @@ return (function () { if (modifier.indexOf("scroll:") === 0) { swapSpec["scroll"] = modifier.substr(7); } - if (modifier.indexOf("view:") === 0) { - swapSpec["view"] = modifier.substr(5); + if (modifier.indexOf("show:") === 0) { + swapSpec["show"] = modifier.substr(5); } } } @@ -1373,11 +1373,11 @@ return (function () { target.scrollTop = target.scrollHeight; } } - if (swapSpec.view) { - if (swapSpec.view === "top") { + if (swapSpec.show) { + if (swapSpec.show === "top") { target.scrollIntoView(true); } - if (swapSpec.view === "bottom") { + if (swapSpec.show === "bottom") { target.scrollIntoView(false); } } From 1162c4a6f426bda6aa87153973b576d19f992858 Mon Sep 17 00:00:00 2001 From: carson Date: Mon, 6 Jul 2020 09:37:01 -0700 Subject: [PATCH 09/10] 0.0.8 release prep --- README.md | 2 +- dist/htmx.js | 51 +- dist/htmx.min.js | 2 +- dist/htmx.min.js.gz | Bin 7449 -> 7515 bytes package.json | 2 +- www/attributes/hx-swap.md | 10 +- www/docs.md | 2 +- www/extensions.md | 2 +- www/index.md | 2 +- www/js/htmx.js | 43 +- www/test/0.0.8/node_modules/chai/chai.js | 10854 +++++++++ www/test/0.0.8/node_modules/mocha/mocha.css | 325 + www/test/0.0.8/node_modules/mocha/mocha.js | 18178 ++++++++++++++++ .../0.0.8/node_modules/sinon/pkg/sinon.js | 16430 ++++++++++++++ www/test/0.0.8/src/ext/ajax-header.js | 7 + www/test/0.0.8/src/ext/class-tools.js | 84 + .../0.0.8/src/ext/client-side-templates.js | 37 + www/test/0.0.8/src/ext/debug.js | 11 + www/test/0.0.8/src/ext/include-vals.js | 24 + www/test/0.0.8/src/ext/json-enc.js | 12 + www/test/0.0.8/src/ext/method-override.js | 11 + www/test/0.0.8/src/ext/morphdom-swap.js | 11 + www/test/0.0.8/src/ext/path-deps.js | 35 + www/test/0.0.8/src/ext/remove-me.js | 27 + www/test/0.0.8/src/htmx.js | 1754 ++ www/test/0.0.8/test/attributes/hx-boost.js | 61 + www/test/0.0.8/test/attributes/hx-delete.js | 34 + www/test/0.0.8/test/attributes/hx-ext.js | 98 + www/test/0.0.8/test/attributes/hx-get.js | 76 + www/test/0.0.8/test/attributes/hx-include.js | 153 + .../0.0.8/test/attributes/hx-indicator.js | 52 + www/test/0.0.8/test/attributes/hx-params.js | 101 + www/test/0.0.8/test/attributes/hx-patch.js | 34 + www/test/0.0.8/test/attributes/hx-post.js | 36 + www/test/0.0.8/test/attributes/hx-push-url.js | 170 + www/test/0.0.8/test/attributes/hx-put.js | 34 + www/test/0.0.8/test/attributes/hx-select.js | 40 + www/test/0.0.8/test/attributes/hx-sse.js | 120 + www/test/0.0.8/test/attributes/hx-swap-oob.js | 75 + www/test/0.0.8/test/attributes/hx-swap.js | 274 + www/test/0.0.8/test/attributes/hx-target.js | 83 + www/test/0.0.8/test/attributes/hx-trigger.js | 160 + www/test/0.0.8/test/attributes/hx-vars.js | 75 + www/test/0.0.8/test/attributes/hx-ws.js | 73 + www/test/0.0.8/test/core/ajax.js | 475 + www/test/0.0.8/test/core/api.js | 167 + www/test/0.0.8/test/core/events.js | 122 + www/test/0.0.8/test/core/headers.js | 118 + www/test/0.0.8/test/core/internals.js | 23 + www/test/0.0.8/test/core/parameters.js | 121 + www/test/0.0.8/test/core/perf.js | 70 + www/test/0.0.8/test/core/regressions.js | 68 + www/test/0.0.8/test/core/verbs.js | 44 + www/test/0.0.8/test/ext/ajax-header.js | 21 + www/test/0.0.8/test/ext/bad-extension.js | 27 + www/test/0.0.8/test/ext/class-tools.js | 55 + .../0.0.8/test/ext/client-side-templates.js | 30 + www/test/0.0.8/test/ext/debug.js | 19 + www/test/0.0.8/test/ext/extension-swap.js | 60 + www/test/0.0.8/test/ext/hyperscript.js | 37 + www/test/0.0.8/test/ext/include-vals.js | 23 + www/test/0.0.8/test/ext/json-enc.js | 136 + www/test/0.0.8/test/ext/method-override.js | 53 + www/test/0.0.8/test/ext/morphdom-swap.js | 31 + www/test/0.0.8/test/ext/path-deps.js | 142 + www/test/0.0.8/test/ext/remove-me.js | 43 + www/test/0.0.8/test/img/bars.svg | 52 + www/test/0.0.8/test/index.html | 147 + www/test/0.0.8/test/lib/_hyperscript.js | 1689 ++ www/test/0.0.8/test/lib/handlebars-v4.7.6.js | 5210 +++++ www/test/0.0.8/test/lib/morphdom-umd.js | 763 + www/test/0.0.8/test/lib/mustache.js | 740 + .../0.0.8/test/manual/browser-only-tests.html | 110 + .../0.0.8/test/manual/confirm-and-prompt.html | 28 + .../0.0.8/test/manual/no-indicator-css.html | 16 + www/test/0.0.8/test/manual/scroll-tests.html | 29 + .../0.0.8/test/manual/yes-indicator-css.html | 11 + www/test/0.0.8/test/scratch.html | 56 + www/test/0.0.8/test/util/scratch_server.js | 17 + www/test/0.0.8/test/util/util.js | 101 + www/test/index.html | 1 + 81 files changed, 60470 insertions(+), 50 deletions(-) create mode 100644 www/test/0.0.8/node_modules/chai/chai.js create mode 100644 www/test/0.0.8/node_modules/mocha/mocha.css create mode 100644 www/test/0.0.8/node_modules/mocha/mocha.js create mode 100644 www/test/0.0.8/node_modules/sinon/pkg/sinon.js create mode 100644 www/test/0.0.8/src/ext/ajax-header.js create mode 100644 www/test/0.0.8/src/ext/class-tools.js create mode 100644 www/test/0.0.8/src/ext/client-side-templates.js create mode 100644 www/test/0.0.8/src/ext/debug.js create mode 100644 www/test/0.0.8/src/ext/include-vals.js create mode 100644 www/test/0.0.8/src/ext/json-enc.js create mode 100644 www/test/0.0.8/src/ext/method-override.js create mode 100644 www/test/0.0.8/src/ext/morphdom-swap.js create mode 100644 www/test/0.0.8/src/ext/path-deps.js create mode 100644 www/test/0.0.8/src/ext/remove-me.js create mode 100644 www/test/0.0.8/src/htmx.js create mode 100644 www/test/0.0.8/test/attributes/hx-boost.js create mode 100644 www/test/0.0.8/test/attributes/hx-delete.js create mode 100644 www/test/0.0.8/test/attributes/hx-ext.js create mode 100644 www/test/0.0.8/test/attributes/hx-get.js create mode 100644 www/test/0.0.8/test/attributes/hx-include.js create mode 100644 www/test/0.0.8/test/attributes/hx-indicator.js create mode 100644 www/test/0.0.8/test/attributes/hx-params.js create mode 100644 www/test/0.0.8/test/attributes/hx-patch.js create mode 100644 www/test/0.0.8/test/attributes/hx-post.js create mode 100644 www/test/0.0.8/test/attributes/hx-push-url.js create mode 100644 www/test/0.0.8/test/attributes/hx-put.js create mode 100644 www/test/0.0.8/test/attributes/hx-select.js create mode 100644 www/test/0.0.8/test/attributes/hx-sse.js create mode 100644 www/test/0.0.8/test/attributes/hx-swap-oob.js create mode 100644 www/test/0.0.8/test/attributes/hx-swap.js create mode 100644 www/test/0.0.8/test/attributes/hx-target.js create mode 100644 www/test/0.0.8/test/attributes/hx-trigger.js create mode 100644 www/test/0.0.8/test/attributes/hx-vars.js create mode 100644 www/test/0.0.8/test/attributes/hx-ws.js create mode 100644 www/test/0.0.8/test/core/ajax.js create mode 100644 www/test/0.0.8/test/core/api.js create mode 100644 www/test/0.0.8/test/core/events.js create mode 100644 www/test/0.0.8/test/core/headers.js create mode 100644 www/test/0.0.8/test/core/internals.js create mode 100644 www/test/0.0.8/test/core/parameters.js create mode 100644 www/test/0.0.8/test/core/perf.js create mode 100644 www/test/0.0.8/test/core/regressions.js create mode 100644 www/test/0.0.8/test/core/verbs.js create mode 100644 www/test/0.0.8/test/ext/ajax-header.js create mode 100644 www/test/0.0.8/test/ext/bad-extension.js create mode 100644 www/test/0.0.8/test/ext/class-tools.js create mode 100644 www/test/0.0.8/test/ext/client-side-templates.js create mode 100644 www/test/0.0.8/test/ext/debug.js create mode 100644 www/test/0.0.8/test/ext/extension-swap.js create mode 100644 www/test/0.0.8/test/ext/hyperscript.js create mode 100644 www/test/0.0.8/test/ext/include-vals.js create mode 100644 www/test/0.0.8/test/ext/json-enc.js create mode 100644 www/test/0.0.8/test/ext/method-override.js create mode 100644 www/test/0.0.8/test/ext/morphdom-swap.js create mode 100644 www/test/0.0.8/test/ext/path-deps.js create mode 100644 www/test/0.0.8/test/ext/remove-me.js create mode 100644 www/test/0.0.8/test/img/bars.svg create mode 100644 www/test/0.0.8/test/index.html create mode 100644 www/test/0.0.8/test/lib/_hyperscript.js create mode 100644 www/test/0.0.8/test/lib/handlebars-v4.7.6.js create mode 100644 www/test/0.0.8/test/lib/morphdom-umd.js create mode 100644 www/test/0.0.8/test/lib/mustache.js create mode 100644 www/test/0.0.8/test/manual/browser-only-tests.html create mode 100644 www/test/0.0.8/test/manual/confirm-and-prompt.html create mode 100644 www/test/0.0.8/test/manual/no-indicator-css.html create mode 100644 www/test/0.0.8/test/manual/scroll-tests.html create mode 100644 www/test/0.0.8/test/manual/yes-indicator-css.html create mode 100644 www/test/0.0.8/test/scratch.html create mode 100644 www/test/0.0.8/test/util/scratch_server.js create mode 100644 www/test/0.0.8/test/util/util.js diff --git a/README.md b/README.md index 80c970f9..a4644363 100644 --- a/README.md +++ b/README.md @@ -23,7 +23,7 @@ IE11 compatible ```html - + ``` diff --git a/www/index.md b/www/index.md index 5b50c03f..b26a4e0e 100644 --- a/www/index.md +++ b/www/index.md @@ -26,7 +26,7 @@ IE11 compatible ```html - + '); + var btn = byId('b1'); + btn.click(); + this.server.respond(); + div.innerHTML.should.equal("Boosted"); + }) + + it('handles basic form get properly', function () { + this.server.respondWith("GET", "/test", "Boosted"); + var div = make('
'); + var btn = byId('b1'); + btn.click(); + this.server.respond(); + div.innerHTML.should.equal("Boosted"); + }) + + it('handles basic form with no explicit method property', function () { + this.server.respondWith("GET", "/test", "Boosted"); + var div = make('
'); + var btn = byId('b1'); + btn.click(); + this.server.respond(); + div.innerHTML.should.equal("Boosted"); + }) + + it('handles basic anchor properly w/ data-* prefix', function () { + this.server.respondWith("GET", "/test", "Boosted"); + var div = make('
Foo
'); + var a = byId('a1'); + a.click(); + this.server.respond(); + div.innerHTML.should.equal("Boosted"); + }) + + +}); + diff --git a/www/test/0.0.8/test/attributes/hx-delete.js b/www/test/0.0.8/test/attributes/hx-delete.js new file mode 100644 index 00000000..22b0f760 --- /dev/null +++ b/www/test/0.0.8/test/attributes/hx-delete.js @@ -0,0 +1,34 @@ +describe("hx-delete attribute", function(){ + beforeEach(function() { + this.server = makeServer(); + clearWorkArea(); + }); + afterEach(function() { + this.server.restore(); + clearWorkArea(); + }); + + it('issues a DELETE request', function() + { + this.server.respondWith("DELETE", "/test", function(xhr){ + xhr.respond(200, {}, "Deleted!"); + }); + + var btn = make('') + btn.click(); + this.server.respond(); + btn.innerHTML.should.equal("Deleted!"); + }); + + it('issues a DELETE request w/ data-* prefix', function() + { + this.server.respondWith("DELETE", "/test", function(xhr){ + xhr.respond(200, {}, "Deleted!"); + }); + + var btn = make('') + btn.click(); + this.server.respond(); + btn.innerHTML.should.equal("Deleted!"); + }); +}) diff --git a/www/test/0.0.8/test/attributes/hx-ext.js b/www/test/0.0.8/test/attributes/hx-ext.js new file mode 100644 index 00000000..1211e722 --- /dev/null +++ b/www/test/0.0.8/test/attributes/hx-ext.js @@ -0,0 +1,98 @@ +describe("hx-ext attribute", function() { + + var ext1Calls, ext2Calls, ext3Calls; + + beforeEach(function () { + ext1Calls = ext2Calls = ext3Calls = 0; + this.server = makeServer(); + clearWorkArea(); + htmx.defineExtension("ext-1", { + onEvent : function(name, evt) { + if(name === "htmx:afterRequest"){ + ext1Calls++; + } + } + }); + htmx.defineExtension("ext-2", { + onEvent : function(name, evt) { + if(name === "htmx:afterRequest"){ + ext2Calls++; + } + } + }); + htmx.defineExtension("ext-3", { + onEvent : function(name, evt) { + if(name === "htmx:afterRequest"){ + ext3Calls++; + } + } + }); + }); + + afterEach(function () { + this.server.restore(); + clearWorkArea(); + htmx.removeExtension("ext-1"); + htmx.removeExtension("ext-2"); + htmx.removeExtension("ext-3"); + }); + + it('A simple extension is invoked properly', function () { + this.server.respondWith("GET", "/test", "Clicked!"); + + var btn = make('') + btn.click(); + this.server.respond(); + ext1Calls.should.equal(1); + ext2Calls.should.equal(0); + ext3Calls.should.equal(0); + }); + + it('Extensions are merged properly', function () { + this.server.respondWith("GET", "/test", "Clicked!"); + + make('
' + + '
') + var btn1 = byId("btn-1"); + var btn2 = byId("btn-2"); + + btn1.click(); + this.server.respond(); + ext1Calls.should.equal(1); + ext2Calls.should.equal(1); + ext3Calls.should.equal(0); + + btn2.click(); + this.server.respond(); + ext1Calls.should.equal(2); + ext2Calls.should.equal(1); + ext3Calls.should.equal(1); + }); + + it('supports comma separated lists', function () { + this.server.respondWith("GET", "/test", "Clicked!"); + + make('
') + var btn1 = byId("btn-1"); + var btn2 = byId("btn-2"); + + btn1.click(); + this.server.respond(); + ext1Calls.should.equal(1); + ext2Calls.should.equal(1); + ext3Calls.should.equal(1); + }); + + it('A simple extension is invoked properly w/ data-* prefix', function () { + this.server.respondWith("GET", "/test", "Clicked!"); + + var btn = make('') + btn.click(); + this.server.respond(); + ext1Calls.should.equal(1); + ext2Calls.should.equal(0); + ext3Calls.should.equal(0); + }); + + +}); \ No newline at end of file diff --git a/www/test/0.0.8/test/attributes/hx-get.js b/www/test/0.0.8/test/attributes/hx-get.js new file mode 100644 index 00000000..7326c39e --- /dev/null +++ b/www/test/0.0.8/test/attributes/hx-get.js @@ -0,0 +1,76 @@ +describe("hx-get attribute", function() { + beforeEach(function () { + this.server = makeServer(); + clearWorkArea(); + }); + afterEach(function () { + this.server.restore(); + clearWorkArea(); + }); + + it('issues a GET request on click and swaps content', function () { + this.server.respondWith("GET", "/test", "Clicked!"); + + var btn = make('') + btn.click(); + this.server.respond(); + btn.innerHTML.should.equal("Clicked!"); + }); + + it('GET does not include surrounding data by default', function () { + this.server.respondWith("GET", "/test", function (xhr) { + should.equal(getParameters(xhr)["i1"], undefined); + xhr.respond(200, {}, "Clicked!"); + }); + make('
') + var btn = byId("b1"); + btn.click(); + this.server.respond(); + btn.innerHTML.should.equal("Clicked!"); + }); + + it('GET on form includes its own data by default', function () { + this.server.respondWith("GET", /\/test.*/, function (xhr) { + getParameters(xhr)["i1"].should.equal("value"); + xhr.respond(200, {}, "Clicked!"); + }); + var form = make('
'); + form.click(); + this.server.respond(); + form.innerHTML.should.equal("Clicked!"); + }); + + it('GET on form with existing parameters works properly', function () { + this.server.respondWith("GET", /\/test.*/, function (xhr) { + getParameters(xhr)["foo"].should.equal("bar"); + getParameters(xhr)["i1"].should.equal("value"); + xhr.respond(200, {}, "Clicked!"); + }); + var form = make('
'); + form.click(); + this.server.respond(); + form.innerHTML.should.equal("Clicked!"); + }); + + it('GET on form with anchor works properly', function () { + this.server.respondWith("GET", /\/test.*/, function (xhr) { + getParameters(xhr)["foo"].should.equal("bar"); + getParameters(xhr)["i1"].should.equal("value"); + xhr.respond(200, {}, "Clicked!"); + }); + var form = make('
'); + form.click(); + this.server.respond(); + form.innerHTML.should.equal("Clicked!"); + }); + + + it('issues a GET request on click and swaps content w/ data-* prefix', function () { + this.server.respondWith("GET", "/test", "Clicked!"); + + var btn = make('') + btn.click(); + this.server.respond(); + btn.innerHTML.should.equal("Clicked!"); + }); +}); \ No newline at end of file diff --git a/www/test/0.0.8/test/attributes/hx-include.js b/www/test/0.0.8/test/attributes/hx-include.js new file mode 100644 index 00000000..1d00f25d --- /dev/null +++ b/www/test/0.0.8/test/attributes/hx-include.js @@ -0,0 +1,153 @@ +describe("hx-include attribute", function() { + beforeEach(function () { + this.server = makeServer(); + clearWorkArea(); + }); + afterEach(function () { + this.server.restore(); + clearWorkArea(); + }); + + it('By default an input includes itself', function () { + this.server.respondWith("POST", "/include", function (xhr) { + var params = getParameters(xhr); + params['i1'].should.equal("test"); + xhr.respond(200, {}, "Clicked!") + }); + var div = make('
') + var input = byId("i1") + input.click(); + this.server.respond(); + div.innerHTML.should.equal("Clicked!"); + }); + + it('non-GET includes closest form', function () { + this.server.respondWith("POST", "/include", function (xhr) { + var params = getParameters(xhr); + params['i1'].should.equal("test"); + xhr.respond(200, {}, "Clicked!") + }); + var div = make('
') + var input = byId("d1") + input.click(); + this.server.respond(); + div.innerHTML.should.equal("Clicked!"); + }); + + it('GET does not include closest form by default', function () { + this.server.respondWith("GET", "/include", function (xhr) { + var params = getParameters(xhr); + should.equal(params['i1'], undefined); + xhr.respond(200, {}, "Clicked!") + }); + var div = make('
') + var input = byId("d1") + input.click(); + this.server.respond(); + div.innerHTML.should.equal("Clicked!"); + }); + + it('Input not included twice when in form', function () { + this.server.respondWith("POST", "/include", function (xhr) { + var params = getParameters(xhr); + params['i1'].should.equal("test"); + xhr.respond(200, {}, "Clicked!") + }); + var div = make('
') + var input = byId("i1") + input.click(); + this.server.respond(); + div.innerHTML.should.equal("Clicked!"); + }); + + it('Two inputs are included twice when they have the same name', function () { + this.server.respondWith("POST", "/include", function (xhr) { + var params = getParameters(xhr); + params['i1'].should.deep.equal(["test", "test2"]); + xhr.respond(200, {}, "Clicked!") + }); + var div = make('
' + + '' + + '' + + '
') + var input = byId("i1") + input.click(); + this.server.respond(); + div.innerHTML.should.equal("Clicked!"); + }); + + it('Input not included twice when it explicitly refers to parent form', function () { + this.server.respondWith("POST", "/include", function (xhr) { + var params = getParameters(xhr); + params['i1'].should.equal("test"); + xhr.respond(200, {}, "Clicked!") + }); + var div = make('
' + + '' + + '
') + var input = byId("i1") + input.click(); + this.server.respond(); + div.innerHTML.should.equal("Clicked!"); + }); + + it('Input can be referred to externally', function () { + this.server.respondWith("POST", "/include", function (xhr) { + var params = getParameters(xhr); + params['i1'].should.equal("test"); + xhr.respond(200, {}, "Clicked!") + }); + make(''); + var div = make('
') + div.click(); + this.server.respond(); + div.innerHTML.should.equal("Clicked!"); + }); + + it('Two inputs can be referred to externally', function () { + this.server.respondWith("POST", "/include", function (xhr) { + var params = getParameters(xhr); + params['i1'].should.equal("test"); + params['i2'].should.equal("test"); + xhr.respond(200, {}, "Clicked!") + }); + make(''); + make(''); + var div = make('
') + div.click(); + this.server.respond(); + div.innerHTML.should.equal("Clicked!"); + }); + + it('A form can be referred to externally', function () { + this.server.respondWith("POST", "/include", function (xhr) { + var params = getParameters(xhr); + params['i1'].should.equal("test"); + params['i2'].should.equal("test"); + xhr.respond(200, {}, "Clicked!") + }); + make('
' + + '' + + '' + + '
'); + var div = make('
') + div.click(); + this.server.respond(); + div.innerHTML.should.equal("Clicked!"); + }); + + it('By default an input includes itself w/ data-* prefix', function () { + this.server.respondWith("POST", "/include", function (xhr) { + var params = getParameters(xhr); + params['i1'].should.equal("test"); + xhr.respond(200, {}, "Clicked!") + }); + var div = make('
') + var input = byId("i1") + input.click(); + this.server.respond(); + div.innerHTML.should.equal("Clicked!"); + }); + + +}); \ No newline at end of file diff --git a/www/test/0.0.8/test/attributes/hx-indicator.js b/www/test/0.0.8/test/attributes/hx-indicator.js new file mode 100644 index 00000000..1385eb42 --- /dev/null +++ b/www/test/0.0.8/test/attributes/hx-indicator.js @@ -0,0 +1,52 @@ +describe("hx-indicator attribute", function(){ + beforeEach(function() { + this.server = sinon.fakeServer.create(); + clearWorkArea(); + }); + afterEach(function() { + this.server.restore(); + clearWorkArea(); + }); + + it('Indicator classes are properly put on element with no explicit indicator', function() + { + this.server.respondWith("GET", "/test", "Clicked!"); + var btn = make('') + btn.click(); + btn.classList.contains("htmx-request").should.equal(true); + this.server.respond(); + btn.classList.contains("htmx-request").should.equal(false); + }); + + it('Indicator classes are properly put on element with explicit indicator', function() + { + this.server.respondWith("GET", "/test", "Clicked!"); + var btn = make('') + var a1 = make('') + var a2 = make('') + btn.click(); + btn.classList.contains("htmx-request").should.equal(false); + a1.classList.contains("htmx-request").should.equal(true); + a2.classList.contains("htmx-request").should.equal(true); + this.server.respond(); + btn.classList.contains("htmx-request").should.equal(false); + a1.classList.contains("htmx-request").should.equal(false); + a2.classList.contains("htmx-request").should.equal(false); + }); + + it('Indicator classes are properly put on element with explicit indicator w/ data-* prefix', function() + { + this.server.respondWith("GET", "/test", "Clicked!"); + var btn = make('') + var a1 = make('') + var a2 = make('') + btn.click(); + btn.classList.contains("htmx-request").should.equal(false); + a1.classList.contains("htmx-request").should.equal(true); + a2.classList.contains("htmx-request").should.equal(true); + this.server.respond(); + btn.classList.contains("htmx-request").should.equal(false); + a1.classList.contains("htmx-request").should.equal(false); + a2.classList.contains("htmx-request").should.equal(false); + }); +}) diff --git a/www/test/0.0.8/test/attributes/hx-params.js b/www/test/0.0.8/test/attributes/hx-params.js new file mode 100644 index 00000000..b2b19ca2 --- /dev/null +++ b/www/test/0.0.8/test/attributes/hx-params.js @@ -0,0 +1,101 @@ +describe("hx-params attribute", function() { + beforeEach(function () { + this.server = makeServer(); + clearWorkArea(); + }); + afterEach(function () { + this.server.restore(); + clearWorkArea(); + }); + + it('none excludes all params', function () { + this.server.respondWith("POST", "/params", function (xhr) { + var params = getParameters(xhr); + should.equal(params['i1'], undefined); + should.equal(params['i2'], undefined); + should.equal(params['i3'], undefined); + xhr.respond(200, {}, "Clicked!") + }); + var form = make('
' + + '' + + '' + + '' + + '
'); + form.click(); + this.server.respond(); + form.innerHTML.should.equal("Clicked!"); + }); + + it('"*" includes all params', function () { + this.server.respondWith("POST", "/params", function (xhr) { + var params = getParameters(xhr); + should.equal(params['i1'], "test"); + should.equal(params['i2'], "test"); + should.equal(params['i3'], "test"); + xhr.respond(200, {}, "Clicked!") + }); + var form = make('
' + + '' + + '' + + '' + + '
'); + form.click(); + this.server.respond(); + form.innerHTML.should.equal("Clicked!"); + }); + + it('named includes works', function () { + this.server.respondWith("POST", "/params", function (xhr) { + var params = getParameters(xhr); + should.equal(params['i1'], "test"); + should.equal(params['i2'], undefined); + should.equal(params['i3'], "test"); + xhr.respond(200, {}, "Clicked!") + }); + var form = make('
' + + '' + + '' + + '' + + '
'); + form.click(); + this.server.respond(); + form.innerHTML.should.equal("Clicked!"); + }); + + it('named exclude works', function () { + this.server.respondWith("POST", "/params", function (xhr) { + var params = getParameters(xhr); + should.equal(params['i1'], undefined); + should.equal(params['i2'], "test"); + should.equal(params['i3'], undefined); + xhr.respond(200, {}, "Clicked!") + }); + var form = make('
' + + '' + + '' + + '' + + '
'); + form.click(); + this.server.respond(); + form.innerHTML.should.equal("Clicked!"); + }); + + it('named exclude works w/ data-* prefix', function () { + this.server.respondWith("POST", "/params", function (xhr) { + var params = getParameters(xhr); + should.equal(params['i1'], undefined); + should.equal(params['i2'], "test"); + should.equal(params['i3'], undefined); + xhr.respond(200, {}, "Clicked!") + }); + var form = make('
' + + '' + + '' + + '' + + '
'); + form.click(); + this.server.respond(); + form.innerHTML.should.equal("Clicked!"); + }); + +}); \ No newline at end of file diff --git a/www/test/0.0.8/test/attributes/hx-patch.js b/www/test/0.0.8/test/attributes/hx-patch.js new file mode 100644 index 00000000..a3c51984 --- /dev/null +++ b/www/test/0.0.8/test/attributes/hx-patch.js @@ -0,0 +1,34 @@ +describe("hx-patch attribute", function(){ + beforeEach(function() { + this.server = makeServer(); + clearWorkArea(); + }); + afterEach(function() { + this.server.restore(); + clearWorkArea(); + }); + + it('issues a PATCH request', function() + { + this.server.respondWith("PATCH", "/test", function(xhr){ + xhr.respond(200, {}, "Patched!"); + }); + + var btn = make('') + btn.click(); + this.server.respond(); + btn.innerHTML.should.equal("Patched!"); + }); + + it('issues a PATCH request w/ data-* prefix', function() + { + this.server.respondWith("PATCH", "/test", function(xhr){ + xhr.respond(200, {}, "Patched!"); + }); + + var btn = make('') + btn.click(); + this.server.respond(); + btn.innerHTML.should.equal("Patched!"); + }); +}) diff --git a/www/test/0.0.8/test/attributes/hx-post.js b/www/test/0.0.8/test/attributes/hx-post.js new file mode 100644 index 00000000..6734e30d --- /dev/null +++ b/www/test/0.0.8/test/attributes/hx-post.js @@ -0,0 +1,36 @@ +describe("hx-post attribute", function(){ + beforeEach(function() { + this.server = makeServer(); + clearWorkArea(); + }); + afterEach(function() { + this.server.restore(); + clearWorkArea(); + }); + + it('issues a POST request with proper headers', function() + { + this.server.respondWith("POST", "/test", function(xhr){ + should.equal(xhr.requestHeaders['X-HTTP-Method-Override'], undefined); + xhr.respond(200, {}, "Posted!"); + }); + + var btn = make('') + btn.click(); + this.server.respond(); + btn.innerHTML.should.equal("Posted!"); + }); + + it('issues a POST request with proper headers w/ data-* prefix', function() + { + this.server.respondWith("POST", "/test", function(xhr){ + should.equal(xhr.requestHeaders['X-HTTP-Method-Override'], undefined); + xhr.respond(200, {}, "Posted!"); + }); + + var btn = make('') + btn.click(); + this.server.respond(); + btn.innerHTML.should.equal("Posted!"); + }); +}) diff --git a/www/test/0.0.8/test/attributes/hx-push-url.js b/www/test/0.0.8/test/attributes/hx-push-url.js new file mode 100644 index 00000000..206fe934 --- /dev/null +++ b/www/test/0.0.8/test/attributes/hx-push-url.js @@ -0,0 +1,170 @@ +describe("hx-push-url attribute", function() { + + var HTMX_HISTORY_CACHE_NAME = "htmx-history-cache"; + + beforeEach(function () { + this.server = makeServer(); + clearWorkArea(); + localStorage.removeItem(HTMX_HISTORY_CACHE_NAME); + }); + afterEach(function () { + this.server.restore(); + clearWorkArea(); + localStorage.removeItem(HTMX_HISTORY_CACHE_NAME); + }); + + it("navigation should push an element into the cache when true", function () { + this.server.respondWith("GET", "/test", "second"); + getWorkArea().innerHTML.should.be.equal(""); + var div = make('
first
'); + div.click(); + this.server.respond(); + div.click(); + this.server.respond(); + getWorkArea().textContent.should.equal("second") + var cache = JSON.parse(localStorage.getItem(HTMX_HISTORY_CACHE_NAME)); + cache.length.should.equal(2); + cache[1].url.should.equal("/test"); + }); + + it("navigation should push an element into the cache when string", function () { + this.server.respondWith("GET", "/test", "second"); + getWorkArea().innerHTML.should.be.equal(""); + var div = make('
first
'); + div.click(); + this.server.respond(); + div.click(); + this.server.respond(); + getWorkArea().textContent.should.equal("second") + var cache = JSON.parse(localStorage.getItem(HTMX_HISTORY_CACHE_NAME)); + console.log(cache); + cache.length.should.equal(2); + cache[1].url.should.equal("/abc123"); + }); + + it("restore should return old value", function () { + this.server.respondWith("GET", "/test1", '
test1
'); + this.server.respondWith("GET", "/test2", '
test2
'); + + make('
init
'); + + byId("d1").click(); + this.server.respond(); + var workArea = getWorkArea(); + workArea.textContent.should.equal("test1") + + byId("d2").click(); + this.server.respond(); + workArea.textContent.should.equal("test2") + + var cache = JSON.parse(localStorage.getItem(HTMX_HISTORY_CACHE_NAME)); + + cache.length.should.equal(2); + htmx._('restoreHistory')("/test1") + this.server.respond(); + getWorkArea().textContent.should.equal("test1") + }); + + it("cache should only store 10 entries", function () { + var x = 0; + this.server.respondWith("GET", /test.*/, function(xhr){ + x++; + xhr.respond(200, {}, '
') + }); + getWorkArea().innerHTML.should.be.equal(""); + make('
'); + for (var i = 0; i < 20; i++) { // issue 20 requests + byId("d1").click(); + this.server.respond(); + } + var cache = JSON.parse(localStorage.getItem(HTMX_HISTORY_CACHE_NAME)); + cache.length.should.equal(10); // should only be 10 elements + }); + + it("cache miss should issue another GET", function () { + this.server.respondWith("GET", "/test1", '
test1
'); + this.server.respondWith("GET", "/test2", '
test2
'); + + make('
init
'); + + byId("d1").click(); + this.server.respond(); + var workArea = getWorkArea(); + workArea.textContent.should.equal("test1") + + byId("d2").click(); + this.server.respond(); + workArea.textContent.should.equal("test2") + + var cache = JSON.parse(localStorage.getItem(HTMX_HISTORY_CACHE_NAME)); + + cache.length.should.equal(2); + localStorage.removeItem(HTMX_HISTORY_CACHE_NAME); // clear cache + htmx._('restoreHistory')("/test1") + this.server.respond(); + getWorkArea().textContent.should.equal("test1") + }); + + it("navigation should push an element into the cache w/ data-* prefix", function () { + this.server.respondWith("GET", "/test", "second"); + getWorkArea().innerHTML.should.be.equal(""); + var div = make('
first
'); + div.click(); + this.server.respond(); + getWorkArea().textContent.should.equal("second") + var cache = JSON.parse(localStorage.getItem(HTMX_HISTORY_CACHE_NAME)); + cache.length.should.equal(1); + }); + + it("deals with malformed JSON in history cache when getting", function () { + localStorage.setItem(HTMX_HISTORY_CACHE_NAME, "Invalid JSON"); + var history = htmx._('getCachedHistory')('url'); + should.equal(history, null); + }); + + it("deals with malformed JSON in history cache when saving", function () { + localStorage.setItem(HTMX_HISTORY_CACHE_NAME, "Invalid JSON"); + htmx._('saveToHistoryCache')('url', 'content', 'title', 'scroll'); + var cache = JSON.parse(localStorage.getItem(HTMX_HISTORY_CACHE_NAME)); + cache.length.should.equal(1); + }); + + + it("htmx:afterSettle is called when replacing outerHTML", function () { + var called = false; + var handler = htmx.on("htmx:afterSettle", function (evt) { + called = true; + }); + try { + this.server.respondWith("POST", "/test", function (xhr) { + xhr.respond(200, {}, ""); + }); + var div = make(""); + div.click(); + this.server.respond(); + should.equal(called, true); + } finally { + htmx.off("htmx:afterSettle", handler); + } + }); + + it("should include parameters on a get", function () { + var path = ""; + var handler = htmx.on("htmx:pushedIntoHistory", function (evt) { + path = evt.detail.path; + }); + try { + this.server.respondWith("GET", /test.*/, function (xhr) { + xhr.respond(200, {}, "second") + }); + var form = make('
first
'); + form.click(); + this.server.respond(); + form.textContent.should.equal("second") + path.should.equal("/test?foo=bar") + } finally { + htmx.off("htmx:pushedIntoHistory", handler); + } + }); + +}); diff --git a/www/test/0.0.8/test/attributes/hx-put.js b/www/test/0.0.8/test/attributes/hx-put.js new file mode 100644 index 00000000..589ec199 --- /dev/null +++ b/www/test/0.0.8/test/attributes/hx-put.js @@ -0,0 +1,34 @@ +describe("hx-put attribute", function(){ + beforeEach(function() { + this.server = makeServer(); + clearWorkArea(); + }); + afterEach(function() { + this.server.restore(); + clearWorkArea(); + }); + + it('issues a PUT request', function() + { + this.server.respondWith("PUT", "/test", function(xhr){ + xhr.respond(200, {}, "Putted!"); + }); + + var btn = make('') + btn.click(); + this.server.respond(); + btn.innerHTML.should.equal("Putted!"); + }); + + it('issues a PUT request w/ data-* prefix', function() + { + this.server.respondWith("PUT", "/test", function(xhr){ + xhr.respond(200, {}, "Putted!"); + }); + + var btn = make('') + btn.click(); + this.server.respond(); + btn.innerHTML.should.equal("Putted!"); + }); +}) diff --git a/www/test/0.0.8/test/attributes/hx-select.js b/www/test/0.0.8/test/attributes/hx-select.js new file mode 100644 index 00000000..c5868430 --- /dev/null +++ b/www/test/0.0.8/test/attributes/hx-select.js @@ -0,0 +1,40 @@ +describe("BOOTSTRAP - htmx AJAX Tests", function(){ + beforeEach(function() { + this.server = makeServer(); + clearWorkArea(); + }); + afterEach(function() { + this.server.restore(); + clearWorkArea(); + }); + + it('properly handles a partial of HTML', function() + { + var i = 1; + this.server.respondWith("GET", "/test", "
foo
bar
"); + var div = make('
'); + div.click(); + this.server.respond(); + div.innerHTML.should.equal("
foo
"); + }); + + it('properly handles a full HTML document', function() + { + var i = 1; + this.server.respondWith("GET", "/test", "
foo
bar
"); + var div = make('
'); + div.click(); + this.server.respond(); + div.innerHTML.should.equal("
foo
"); + }); + + it('properly handles a full HTML document w/ data-* prefix', function() + { + var i = 1; + this.server.respondWith("GET", "/test", "
foo
bar
"); + var div = make('
'); + div.click(); + this.server.respond(); + div.innerHTML.should.equal("
foo
"); + }); +}) diff --git a/www/test/0.0.8/test/attributes/hx-sse.js b/www/test/0.0.8/test/attributes/hx-sse.js new file mode 100644 index 00000000..84c1ece5 --- /dev/null +++ b/www/test/0.0.8/test/attributes/hx-sse.js @@ -0,0 +1,120 @@ +describe("hx-sse attribute", function() { + + function mockEventSource() { + var listeners = {}; + var wasClosed = false; + var mockEventSource = { + addEventListener: function (message, l) { + listeners[message] = l; + }, + sendEvent: function (event) { + var listener = listeners[event]; + if (listener) { + listener(); + } + }, + close: function () { + wasClosed = true; + }, + wasClosed: function () { + return wasClosed; + } + }; + return mockEventSource; + } + + beforeEach(function () { + this.server = makeServer(); + var eventSource = mockEventSource(); + this.eventSource = eventSource; + clearWorkArea(); + htmx.createEventSource = function(){ return eventSource }; + }); + afterEach(function () { + this.server.restore(); + clearWorkArea(); + }); + + it('handles basic sse triggering', function () { + + this.server.respondWith("GET", "/d1", "div1 updated"); + this.server.respondWith("GET", "/d2", "div2 updated"); + + var div = make('
' + + '
div1
' + + '
div2
' + + '
'); + + this.eventSource.sendEvent("e1"); + this.server.respond(); + byId("d1").innerHTML.should.equal("div1 updated"); + byId("d2").innerHTML.should.equal("div2"); + + this.eventSource.sendEvent("e2"); + this.server.respond(); + byId("d1").innerHTML.should.equal("div1 updated"); + byId("d2").innerHTML.should.equal("div2 updated"); + }) + + it('does not trigger events that arent named', function () { + + this.server.respondWith("GET", "/d1", "div1 updated"); + + var div = make('
' + + '
div1
' + + '
'); + + this.eventSource.sendEvent("foo"); + this.server.respond(); + byId("d1").innerHTML.should.equal("div1"); + + this.eventSource.sendEvent("e2"); + this.server.respond(); + byId("d1").innerHTML.should.equal("div1"); + + this.eventSource.sendEvent("e1"); + this.server.respond(); + byId("d1").innerHTML.should.equal("div1 updated"); + }) + + it('does not trigger events not on decendents', function () { + + this.server.respondWith("GET", "/d1", "div1 updated"); + + var div = make('
' + + '
div1
'); + + this.eventSource.sendEvent("foo"); + this.server.respond(); + byId("d1").innerHTML.should.equal("div1"); + + this.eventSource.sendEvent("e2"); + this.server.respond(); + byId("d1").innerHTML.should.equal("div1"); + + this.eventSource.sendEvent("e1"); + this.server.respond(); + byId("d1").innerHTML.should.equal("div1"); + }) + + it('is closed after removal', function () { + this.server.respondWith("GET", "/test", "Clicked!"); + var div = make('
' + + '
div1
' + + '
'); + div.click(); + this.server.respond(); + this.eventSource.wasClosed().should.equal(true) + }) + + it('is closed after removal with no close and activity', function () { + var div = make('
' + + '
div1
' + + '
'); + div.parentElement.removeChild(div); + this.eventSource.sendEvent("e1") + this.eventSource.wasClosed().should.equal(true) + }) + +}); + diff --git a/www/test/0.0.8/test/attributes/hx-swap-oob.js b/www/test/0.0.8/test/attributes/hx-swap-oob.js new file mode 100644 index 00000000..513159c5 --- /dev/null +++ b/www/test/0.0.8/test/attributes/hx-swap-oob.js @@ -0,0 +1,75 @@ +describe("hx-swap-oob attribute", function () { + beforeEach(function () { + this.server = makeServer(); + clearWorkArea(); + }); + afterEach(function () { + this.server.restore(); + clearWorkArea(); + }); + + it('handles basic response properly', function () { + this.server.respondWith("GET", "/test", "Clicked
Swapped
"); + var div = make('
click me
'); + make('
'); + div.click(); + this.server.respond(); + div.innerHTML.should.equal("Clicked"); + byId("d1").innerHTML.should.equal("Swapped"); + }) + + it('handles more than one oob swap properly', function () { + this.server.respondWith("GET", "/test", "Clicked
Swapped1
Swapped2
"); + var div = make('
click me
'); + make('
'); + make('
'); + div.click(); + this.server.respond(); + div.innerHTML.should.equal("Clicked"); + byId("d1").innerHTML.should.equal("Swapped1"); + byId("d2").innerHTML.should.equal("Swapped2"); + }) + + it('handles no id match properly', function () { + this.server.respondWith("GET", "/test", "Clicked
Swapped
"); + var div = make('
click me
'); + div.click(); + this.server.respond(); + div.innerText.should.equal("Clicked"); + }) + + it('handles basic response properly w/ data-* prefix', function () { + this.server.respondWith("GET", "/test", "Clicked
Swapped
"); + var div = make('
click me
'); + make('
'); + div.click(); + this.server.respond(); + div.innerHTML.should.equal("Clicked"); + byId("d1").innerHTML.should.equal("Swapped"); + }) + + it('handles outerHTML response properly', function () { + this.server.respondWith("GET", "/test", "Clicked
Swapped
"); + var div = make('
click me
'); + make('
'); + div.click(); + this.server.respond(); + byId("d1").getAttribute("foo").should.equal("bar"); + div.innerHTML.should.equal("Clicked"); + byId("d1").innerHTML.should.equal("Swapped"); + }) + + it('handles innerHTML response properly', function () { + this.server.respondWith("GET", "/test", "Clicked
Swapped
"); + var div = make('
click me
'); + make('
'); + div.click(); + this.server.respond(); + should.equal(byId("d1").getAttribute("foo"), null); + div.innerHTML.should.equal("Clicked"); + byId("d1").innerHTML.should.equal("Swapped"); + }) + + +}); + diff --git a/www/test/0.0.8/test/attributes/hx-swap.js b/www/test/0.0.8/test/attributes/hx-swap.js new file mode 100644 index 00000000..e8a4ae74 --- /dev/null +++ b/www/test/0.0.8/test/attributes/hx-swap.js @@ -0,0 +1,274 @@ +describe("hx-swap attribute", function(){ + beforeEach(function() { + this.server = makeServer(); + clearWorkArea(); + }); + afterEach(function() { + this.server.restore(); + clearWorkArea(); + }); + + it('swap innerHTML properly', function() + { + this.server.respondWith("GET", "/test", 'Click Me'); + this.server.respondWith("GET", "/test2", "Clicked!"); + + var div = make('
') + div.click(); + this.server.respond(); + div.innerHTML.should.equal('Click Me'); + var a = div.querySelector('a'); + a.click(); + this.server.respond(); + a.innerHTML.should.equal('Clicked!'); + }); + + it('swap outerHTML properly', function() + { + this.server.respondWith("GET", "/test", 'Click Me'); + this.server.respondWith("GET", "/test2", "Clicked!"); + + var div = make('
') + div.click(); + should.equal(byId("d1"), div); + this.server.respond(); + should.equal(byId("d1"), null); + byId("a1").click(); + this.server.respond(); + byId("a1").innerHTML.should.equal('Clicked!'); + }); + + it('swap beforebegin properly', function() + { + var i = 0; + this.server.respondWith("GET", "/test", function(xhr){ + i++; + xhr.respond(200, {}, '' + i + ''); + }); + this.server.respondWith("GET", "/test2", "*"); + + var div = make('
*
') + var parent = div.parentElement; + div.click(); + this.server.respond(); + div.innerText.should.equal("*"); + removeWhiteSpace(parent.innerText).should.equal("1*"); + + byId("a1").click(); + this.server.respond(); + removeWhiteSpace(parent.innerText).should.equal("**"); + + div.click(); + this.server.respond(); + div.innerText.should.equal("*"); + removeWhiteSpace(parent.innerText).should.equal("*2*"); + + byId("a2").click(); + this.server.respond(); + removeWhiteSpace(parent.innerText).should.equal("***"); + }); + + it('swap afterbegin properly', function() + { + var i = 0; + this.server.respondWith("GET", "/test", function(xhr){ + i++; + xhr.respond(200, {}, '' + i + ''); + }); + this.server.respondWith("GET", "/test2", "*"); + + var div = make('
*
') + div.click(); + this.server.respond(); + div.innerText.should.equal("1*"); + + byId("a1").click(); + this.server.respond(); + div.innerText.should.equal("**"); + + div.click(); + this.server.respond(); + div.innerText.should.equal("2**"); + + byId("a2").click(); + this.server.respond(); + div.innerText.should.equal("***"); + }); + + it('swap afterbegin properly with no initial content', function() + { + var i = 0; + this.server.respondWith("GET", "/test", function(xhr){ + i++; + xhr.respond(200, {}, '' + i + ''); + }); + this.server.respondWith("GET", "/test2", "*"); + + var div = make('
') + div.click(); + this.server.respond(); + div.innerText.should.equal("1"); + + byId("a1").click(); + this.server.respond(); + div.innerText.should.equal("*"); + + div.click(); + this.server.respond(); + div.innerText.should.equal("2*"); + + byId("a2").click(); + this.server.respond(); + div.innerText.should.equal("**"); + }); + + it('swap afterend properly', function() + { + var i = 0; + this.server.respondWith("GET", "/test", function(xhr){ + i++; + xhr.respond(200, {}, '' + i + ''); + }); + this.server.respondWith("GET", "/test2", "*"); + + var div = make('
*
') + var parent = div.parentElement; + div.click(); + this.server.respond(); + div.innerText.should.equal("*"); + removeWhiteSpace(parent.innerText).should.equal("*1"); + + byId("a1").click(); + this.server.respond(); + removeWhiteSpace(parent.innerText).should.equal("**"); + + div.click(); + this.server.respond(); + div.innerText.should.equal("*"); + removeWhiteSpace(parent.innerText).should.equal("*2*"); + + byId("a2").click(); + this.server.respond(); + removeWhiteSpace(parent.innerText).should.equal("***"); + }); + + it('swap beforeend properly', function() + { + var i = 0; + this.server.respondWith("GET", "/test", function(xhr){ + i++; + xhr.respond(200, {}, '' + i + ''); + }); + this.server.respondWith("GET", "/test2", "*"); + + var div = make('
*
') + div.click(); + this.server.respond(); + div.innerText.should.equal("*1"); + + byId("a1").click(); + this.server.respond(); + div.innerText.should.equal("**"); + + div.click(); + this.server.respond(); + div.innerText.should.equal("**2"); + + byId("a2").click(); + this.server.respond(); + div.innerText.should.equal("***"); + }); + + it('swap beforeend properly with no initial content', function() + { + var i = 0; + this.server.respondWith("GET", "/test", function(xhr){ + i++; + xhr.respond(200, {}, '' + i + ''); + }); + this.server.respondWith("GET", "/test2", "*"); + + var div = make('
') + div.click(); + this.server.respond(); + div.innerText.should.equal("1"); + + byId("a1").click(); + this.server.respond(); + div.innerText.should.equal("*"); + + div.click(); + this.server.respond(); + div.innerText.should.equal("*2"); + + byId("a2").click(); + this.server.respond(); + div.innerText.should.equal("**"); + }); + + it('properly parses various swap specifications', function(){ + var swapSpec = htmx._("getSwapSpecification"); // internal function for swap spec + swapSpec(make("
")).swapStyle.should.equal("innerHTML") + swapSpec(make("
")).swapStyle.should.equal("innerHTML") + swapSpec(make("
")).swapDelay.should.equal(0) + swapSpec(make("
")).settleDelay.should.equal(0) // set to 0 in tests + swapSpec(make("
")).swapDelay.should.equal(10) + swapSpec(make("
")).settleDelay.should.equal(10) + swapSpec(make("
")).swapDelay.should.equal(10) + swapSpec(make("
")).settleDelay.should.equal(11) + swapSpec(make("
")).swapDelay.should.equal(10) + swapSpec(make("
")).settleDelay.should.equal(11) + swapSpec(make("
")).settleDelay.should.equal(11) + swapSpec(make("
")).settleDelay.should.equal(11) + }) + + it('works with a swap delay', function(done) { + this.server.respondWith("GET", "/test", "Clicked!"); + var div = make("
"); + div.click(); + this.server.respond(); + div.innerText.should.equal(""); + setTimeout(function () { + div.innerText.should.equal("Clicked!"); + done(); + }, 30); + }); + + it('works with a settle delay', function(done) { + this.server.respondWith("GET", "/test", "
"); + var div = make("
"); + div.click(); + this.server.respond(); + div.classList.contains('foo').should.equal(false); + setTimeout(function () { + byId('d1').classList.contains('foo').should.equal(true); + done(); + }, 30); + }); + + it('swap outerHTML properly w/ data-* prefix', function() + { + this.server.respondWith("GET", "/test", 'Click Me'); + this.server.respondWith("GET", "/test2", "Clicked!"); + + var div = make('
') + div.click(); + should.equal(byId("d1"), div); + this.server.respond(); + should.equal(byId("d1"), null); + byId("a1").click(); + this.server.respond(); + byId("a1").innerHTML.should.equal('Clicked!'); + }); + + it('swap none works properly', function() + { + this.server.respondWith("GET", "/test", 'Ooops, swapped'); + + var div = make('
Foo
') + div.click(); + this.server.respond(); + div.innerHTML.should.equal('Foo'); + }); + +}) diff --git a/www/test/0.0.8/test/attributes/hx-target.js b/www/test/0.0.8/test/attributes/hx-target.js new file mode 100644 index 00000000..d90c2db3 --- /dev/null +++ b/www/test/0.0.8/test/attributes/hx-target.js @@ -0,0 +1,83 @@ +describe("hx-target attribute", function(){ + beforeEach(function() { + this.server = sinon.fakeServer.create(); + clearWorkArea(); + }); + afterEach(function() { + this.server.restore(); + clearWorkArea(); + }); + + it('targets an adjacent element properly', function() + { + this.server.respondWith("GET", "/test", "Clicked!"); + var btn = make('') + var div1 = make('
') + btn.click(); + this.server.respond(); + div1.innerHTML.should.equal("Clicked!"); + }); + + it('targets a parent element properly', function() + { + this.server.respondWith("GET", "/test", "Clicked!"); + var div1 = make('
') + var btn = byId("b1") + btn.click(); + this.server.respond(); + div1.innerHTML.should.equal("Clicked!"); + }); + + it('targets a `this` element properly', function() + { + this.server.respondWith("GET", "/test", "Clicked!"); + var div1 = make('
') + var btn = byId("b1") + btn.click(); + this.server.respond(); + div1.innerHTML.should.equal("Clicked!"); + }); + + it('targets a `closest` element properly', function() + { + this.server.respondWith("GET", "/test", "Clicked!"); + var div1 = make('

') + var btn = byId("b1") + btn.click(); + this.server.respond(); + div1.innerHTML.should.equal("Clicked!"); + }); + + it('targets an inner element properly', function() + { + this.server.respondWith("GET", "/test", "Clicked!"); + var btn = make('') + var div1 = byId("d1") + btn.click(); + this.server.respond(); + div1.innerHTML.should.equal("Clicked!"); + }); + + + it('handles bad target gracefully', function() + { + this.server.respondWith("GET", "/test", "Clicked!"); + var btn = make('') + btn.click(); + this.server.respond(); + btn.innerHTML.should.equal("Click Me!"); + }); + + + it('targets an adjacent element properly w/ data-* prefix', function() + { + this.server.respondWith("GET", "/test", "Clicked!"); + var btn = make('') + var div1 = make('
') + btn.click(); + this.server.respond(); + div1.innerHTML.should.equal("Clicked!"); + }); + + +}) diff --git a/www/test/0.0.8/test/attributes/hx-trigger.js b/www/test/0.0.8/test/attributes/hx-trigger.js new file mode 100644 index 00000000..7c764947 --- /dev/null +++ b/www/test/0.0.8/test/attributes/hx-trigger.js @@ -0,0 +1,160 @@ +describe("hx-trigger attribute", function(){ + beforeEach(function() { + this.server = sinon.fakeServer.create(); + clearWorkArea(); + }); + afterEach(function() { + this.server.restore(); + clearWorkArea(); + }); + + it('non-default value works', function() + { + this.server.respondWith("GET", "/test", "Clicked!"); + + var form = make('
Click Me!
'); + form.click(); + form.innerHTML.should.equal("Click Me!"); + this.server.respond(); + form.innerHTML.should.equal("Clicked!"); + }); + + it('changed modifier works', function() + { + var requests = 0; + this.server.respondWith("GET", "/test", function (xhr) { + requests++; + xhr.respond(200, {}, "Requests: " + requests); + }); + var input = make(''); + var div = make('
'); + input.click(); + this.server.respond(); + div.innerHTML.should.equal(""); + input.click(); + this.server.respond(); + div.innerHTML.should.equal(""); + input.value = "bar"; + input.click(); + this.server.respond(); + div.innerHTML.should.equal("Requests: 1"); + input.click(); + this.server.respond(); + div.innerHTML.should.equal("Requests: 1"); + }); + + it('once modifier works', function() + { + var requests = 0; + this.server.respondWith("GET", "/test", function (xhr) { + requests++; + xhr.respond(200, {}, "Requests: " + requests); + }); + var input = make(''); + var div = make('
'); + input.click(); + this.server.respond(); + div.innerHTML.should.equal("Requests: 1"); + input.click(); + this.server.respond(); + div.innerHTML.should.equal("Requests: 1"); + input.value = "bar"; + input.click(); + this.server.respond(); + div.innerHTML.should.equal("Requests: 1"); + input.click(); + this.server.respond(); + div.innerHTML.should.equal("Requests: 1"); + }); + + it('polling works', function(complete) + { + var requests = 0; + this.server.respondWith("GET", "/test", function (xhr) { + requests++; + if (requests > 5) { + complete(); + // cancel polling with a + xhr.respond(286, {}, "Requests: " + requests); + } else { + xhr.respond(200, {}, "Requests: " + requests); + } + }); + this.server.autoRespond = true; + this.server.autoRespondAfter = 0; + make('
'); + }); + + + it('non-default value works w/ data-* prefix', function() + { + this.server.respondWith("GET", "/test", "Clicked!"); + + var form = make('
Click Me!
'); + form.click(); + form.innerHTML.should.equal("Click Me!"); + this.server.respond(); + form.innerHTML.should.equal("Clicked!"); + }); + + it('works with multiple events', function() + { + var requests = 0; + this.server.respondWith("GET", "/test", function (xhr) { + requests++; + xhr.respond(200, {}, "Requests: " + requests); + }); + var div = make('
Requests: 0
'); + div.innerHTML.should.equal("Requests: 0"); + this.server.respond(); + div.innerHTML.should.equal("Requests: 1"); + div.click(); + this.server.respond(); + div.innerHTML.should.equal("Requests: 2"); + }); + + + + it("parses spec strings", function() + { + var specExamples = { + "": [{trigger: 'click'}], + "every 1s": [{trigger: 'every', pollInterval: 1000}], + "click": [{trigger: 'click'}], + "customEvent": [{trigger: 'customEvent'}], + "event changed": [{trigger: 'event', changed: true}], + "event once": [{trigger: 'event', once: true}], + "event delay:1s": [{trigger: 'event', delay: 1000}], + "event throttle:1s": [{trigger: 'event', throttle: 1000}], + "event changed once delay:1s": [{trigger: 'event', changed: true, once: true, delay: 1000}], + "event1,event2": [{trigger: 'event1'}, {trigger: 'event2'}], + "event1, event2": [{trigger: 'event1'}, {trigger: 'event2'}], + "event1 once, event2 changed": [{trigger: 'event1', once: true}, {trigger: 'event2', changed: true}], + "event1,": [{trigger: 'event1'}], + ",event1": [{trigger: 'event1'}], + " ": [{trigger: 'click'}], + ",": [{trigger: 'click'}] + } + + for (var specString in specExamples) { + var div = make("
"); + var spec = htmx._('getTriggerSpecs')(div); + spec.should.deep.equal(specExamples[specString], "Found : " + JSON.stringify(spec) + ", expected : " + JSON.stringify(specExamples[specString]) + " for spec: " + specString); + } + }); + + it('sets default trigger for forms', function() + { + var form = make('
'); + var spec = htmx._('getTriggerSpecs')(form); + spec.should.deep.equal([{trigger: 'submit'}]); + }) + + it('sets default trigger for form elements', function() + { + var form = make(''); + var spec = htmx._('getTriggerSpecs')(form); + spec.should.deep.equal([{trigger: 'change'}]); + }) + +}) diff --git a/www/test/0.0.8/test/attributes/hx-vars.js b/www/test/0.0.8/test/attributes/hx-vars.js new file mode 100644 index 00000000..ab169b4c --- /dev/null +++ b/www/test/0.0.8/test/attributes/hx-vars.js @@ -0,0 +1,75 @@ +describe("hx-vars attribute", function() { + beforeEach(function () { + this.server = makeServer(); + clearWorkArea(); + }); + afterEach(function () { + this.server.restore(); + clearWorkArea(); + }); + + it('basic hx-vars works', function () { + this.server.respondWith("POST", "/vars", function (xhr) { + var params = getParameters(xhr); + params['i1'].should.equal("test"); + xhr.respond(200, {}, "Clicked!") + }); + var div = make('
') + div.click(); + this.server.respond(); + div.innerHTML.should.equal("Clicked!"); + }); + + it('multiple hx-vars works', function () { + this.server.respondWith("POST", "/vars", function (xhr) { + var params = getParameters(xhr); + params['v1'].should.equal("test"); + params['v2'].should.equal("42"); + xhr.respond(200, {}, "Clicked!") + }); + var div = make('
') + div.click(); + this.server.respond(); + div.innerHTML.should.equal("Clicked!"); + }); + + it('hx-vars can be on parents', function () { + this.server.respondWith("POST", "/vars", function (xhr) { + var params = getParameters(xhr); + params['i1'].should.equal("test"); + xhr.respond(200, {}, "Clicked!") + }); + make('
') + var div = byId("d1"); + div.click(); + this.server.respond(); + div.innerHTML.should.equal("Clicked!"); + }); + + it('hx-vars can override parents', function () { + this.server.respondWith("POST", "/vars", function (xhr) { + var params = getParameters(xhr); + params['i1'].should.equal("best"); + xhr.respond(200, {}, "Clicked!") + }); + make('
') + var div = byId("d1"); + div.click(); + this.server.respond(); + div.innerHTML.should.equal("Clicked!"); + }); + + it('hx-vars do not override inputs', function () { + this.server.respondWith("POST", "/include", function (xhr) { + var params = getParameters(xhr); + params['i1'].should.equal("test"); + xhr.respond(200, {}, "Clicked!") + }); + var div = make('
') + var input = byId("i1") + input.click(); + this.server.respond(); + div.innerHTML.should.equal("Clicked!"); + }); + +}); \ No newline at end of file diff --git a/www/test/0.0.8/test/attributes/hx-ws.js b/www/test/0.0.8/test/attributes/hx-ws.js new file mode 100644 index 00000000..3dc1c327 --- /dev/null +++ b/www/test/0.0.8/test/attributes/hx-ws.js @@ -0,0 +1,73 @@ +describe("hx-ws attribute", function() { + + function mockWebsocket() { + var listener; + var lastSent; + var wasClosed = false; + var mockSocket = { + addEventListener : function(message, l) { + listener = l; + }, + write : function(content) { + return listener({data:content}); + }, + send : function(data) { + lastSent = data; + }, + getLastSent : function() { + return lastSent; + }, + close : function() { + wasClosed = true; + }, + wasClosed : function () { + return wasClosed; + } + }; + return mockSocket; + } + + beforeEach(function () { + this.server = makeServer(); + var socket = mockWebsocket(); + this.socket = socket; + clearWorkArea(); + htmx.createWebSocket = function(){ return socket }; + }); + afterEach(function () { + this.server.restore(); + clearWorkArea(); + }); + + it('handles a basic call back', function () { + var div = make('
div1
div2
'); + this.socket.write("
replaced
") + byId("d1").innerHTML.should.equal("replaced"); + byId("d2").innerHTML.should.equal("div2"); + }) + + it('handles a basic send', function () { + var div = make('
div1
'); + byId("d1").click(); + var lastSent = this.socket.getLastSent(); + var data = JSON.parse(lastSent); + data.HEADERS["HX-Request"].should.equal("true"); + }) + + it('is closed after removal', function () { + this.server.respondWith("GET", "/test", "Clicked!"); + var div = make('
'); + div.click(); + this.server.respond(); + this.socket.wasClosed().should.equal(true) + }) + + it('is closed after removal with no close and activity', function () { + var div = make('
'); + div.parentElement.removeChild(div); + this.socket.write("
replaced
") + this.socket.wasClosed().should.equal(true) + }) + +}); + diff --git a/www/test/0.0.8/test/core/ajax.js b/www/test/0.0.8/test/core/ajax.js new file mode 100644 index 00000000..efdb738c --- /dev/null +++ b/www/test/0.0.8/test/core/ajax.js @@ -0,0 +1,475 @@ +describe("Core htmx AJAX Tests", function(){ + beforeEach(function() { + this.server = makeServer(); + clearWorkArea(); + }); + afterEach(function() { + this.server.restore(); + clearWorkArea(); + }); + + // bootstrap test + it('issues a GET request on click and swaps content', function() + { + this.server.respondWith("GET", "/test", "Clicked!"); + + var btn = make('') + btn.click(); + this.server.respond(); + btn.innerHTML.should.equal("Clicked!"); + }); + + it('processes inner content properly', function() + { + this.server.respondWith("GET", "/test", 'Click Me'); + this.server.respondWith("GET", "/test2", "Clicked!"); + + var div = make('
') + div.click(); + this.server.respond(); + div.innerHTML.should.equal('Click Me'); + var a = div.querySelector('a'); + a.click(); + this.server.respond(); + a.innerHTML.should.equal('Clicked!'); + }); + + it('handles swap outerHTML properly', function() + { + this.server.respondWith("GET", "/test", 'Click Me'); + this.server.respondWith("GET", "/test2", "Clicked!"); + + var div = make('
') + div.click(); + should.equal(byId("d1"), div); + this.server.respond(); + should.equal(byId("d1"), null); + byId("a1").click(); + this.server.respond(); + byId("a1").innerHTML.should.equal('Clicked!'); + }); + + it('handles beforebegin properly', function() + { + var i = 0; + this.server.respondWith("GET", "/test", function(xhr){ + i++; + xhr.respond(200, {}, '' + i + ''); + }); + this.server.respondWith("GET", "/test2", "*"); + + var div = make('
*
') + var parent = div.parentElement; + div.click(); + this.server.respond(); + div.innerText.should.equal("*"); + removeWhiteSpace(parent.innerText).should.equal("1*"); + + byId("a1").click(); + this.server.respond(); + removeWhiteSpace(parent.innerText).should.equal("**"); + + div.click(); + this.server.respond(); + div.innerText.should.equal("*"); + removeWhiteSpace(parent.innerText).should.equal("*2*"); + + byId("a2").click(); + this.server.respond(); + removeWhiteSpace(parent.innerText).should.equal("***"); + }); + + it('handles afterbegin properly', function() + { + var i = 0; + this.server.respondWith("GET", "/test", function(xhr){ + i++; + xhr.respond(200, {}, '' + i + ''); + }); + this.server.respondWith("GET", "/test2", "*"); + + var div = make('
*
') + div.click(); + this.server.respond(); + div.innerText.should.equal("1*"); + + byId("a1").click(); + this.server.respond(); + div.innerText.should.equal("**"); + + div.click(); + this.server.respond(); + div.innerText.should.equal("2**"); + + byId("a2").click(); + this.server.respond(); + div.innerText.should.equal("***"); + }); + + it('handles afterbegin properly with no initial content', function() + { + var i = 0; + this.server.respondWith("GET", "/test", function(xhr){ + i++; + xhr.respond(200, {}, '' + i + ''); + }); + this.server.respondWith("GET", "/test2", "*"); + + var div = make('
') + div.click(); + this.server.respond(); + div.innerText.should.equal("1"); + + byId("a1").click(); + this.server.respond(); + div.innerText.should.equal("*"); + + div.click(); + this.server.respond(); + div.innerText.should.equal("2*"); + + byId("a2").click(); + this.server.respond(); + div.innerText.should.equal("**"); + }); + + it('handles afterend properly', function() + { + var i = 0; + this.server.respondWith("GET", "/test", function(xhr){ + i++; + xhr.respond(200, {}, '' + i + ''); + }); + this.server.respondWith("GET", "/test2", "*"); + + var div = make('
*
') + var parent = div.parentElement; + div.click(); + this.server.respond(); + div.innerText.should.equal("*"); + removeWhiteSpace(parent.innerText).should.equal("*1"); + + byId("a1").click(); + this.server.respond(); + removeWhiteSpace(parent.innerText).should.equal("**"); + + div.click(); + this.server.respond(); + div.innerText.should.equal("*"); + removeWhiteSpace(parent.innerText).should.equal("*2*"); + + byId("a2").click(); + this.server.respond(); + removeWhiteSpace(parent.innerText).should.equal("***"); + }); + + it('handles beforeend properly', function() + { + var i = 0; + this.server.respondWith("GET", "/test", function(xhr){ + i++; + xhr.respond(200, {}, '' + i + ''); + }); + this.server.respondWith("GET", "/test2", "*"); + + var div = make('
*
') + div.click(); + this.server.respond(); + div.innerText.should.equal("*1"); + + byId("a1").click(); + this.server.respond(); + div.innerText.should.equal("**"); + + div.click(); + this.server.respond(); + div.innerText.should.equal("**2"); + + byId("a2").click(); + this.server.respond(); + div.innerText.should.equal("***"); + }); + + it('handles beforeend properly with no initial content', function() + { + var i = 0; + this.server.respondWith("GET", "/test", function(xhr){ + i++; + xhr.respond(200, {}, '' + i + ''); + }); + this.server.respondWith("GET", "/test2", "*"); + + var div = make('
') + div.click(); + this.server.respond(); + div.innerText.should.equal("1"); + + byId("a1").click(); + this.server.respond(); + div.innerText.should.equal("*"); + + div.click(); + this.server.respond(); + div.innerText.should.equal("*2"); + + byId("a2").click(); + this.server.respond(); + div.innerText.should.equal("**"); + }); + + it('handles hx-target properly', function() + { + this.server.respondWith("GET", "/test", "Clicked!"); + + var btn = make(''); + var target = make('Initial'); + btn.click(); + target.innerHTML.should.equal("Initial"); + this.server.respond(); + target.innerHTML.should.equal("Clicked!"); + }); + + it('handles 204 NO CONTENT responses properly', function() + { + this.server.respondWith("GET", "/test", [204, {}, "No Content!"]); + + var btn = make(''); + btn.click(); + btn.innerHTML.should.equal("Click Me!"); + this.server.respond(); + btn.innerHTML.should.equal("Click Me!"); + }); + + it('handles hx-trigger with non-default value', function() + { + this.server.respondWith("GET", "/test", "Clicked!"); + + var form = make('
Click Me!
'); + form.click(); + form.innerHTML.should.equal("Click Me!"); + this.server.respond(); + form.innerHTML.should.equal("Clicked!"); + }); + + it('handles hx-trigger with load event', function() + { + this.server.respondWith("GET", "/test", "Loaded!"); + var div = make('
Load Me!
'); + div.innerHTML.should.equal("Load Me!"); + this.server.respond(); + div.innerHTML.should.equal("Loaded!"); + }); + + it('sets the content type of the request properly', function (done) { + this.server.respondWith("GET", "/test", function(xhr){ + xhr.respond(200, {}, "done"); + xhr.overriddenMimeType.should.equal("text/html"); + done(); + }); + var div = make('
Click Me!
'); + div.click(); + this.server.respond(); + }); + + it('doesnt issue two requests when clicked twice before response', function() + { + var i = 1; + this.server.respondWith("GET", "/test", function (xhr) { + xhr.respond(200, {}, "click " + i); + i++ + }); + var div = make('
'); + div.click(); + div.click(); + this.server.respond(); + div.innerHTML.should.equal("click 1"); + }); + + it('properly handles hx-select for basic situation', function() + { + var i = 1; + this.server.respondWith("GET", "/test", "
foo
bar
"); + var div = make('
'); + div.click(); + this.server.respond(); + div.innerHTML.should.equal("
foo
"); + }); + + it('properly handles hx-select for full html document situation', function() + { + var i = 1; + this.server.respondWith("GET", "/test", "
foo
bar
"); + var div = make('
'); + div.click(); + this.server.respond(); + div.innerHTML.should.equal("
foo
"); + }); + + it('properly settles attributes on interior elements', function(done) + { + this.server.respondWith("GET", "/test", "
"); + var div = make("
"); + div.click(); + this.server.respond(); + should.equal(byId("d1").getAttribute("foo"), null); + setTimeout(function () { + should.equal(byId("d1").getAttribute("foo"), "bar"); + done(); + }, 20); + }); + + it('properly handles checkbox inputs', function() + { + var values; + this.server.respondWith("Post", "/test", function (xhr) { + values = getParameters(xhr); + xhr.respond(204, {}, ""); + }); + + var form = make('
' + + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + '
'); + + form.click(); + this.server.respond(); + values.should.deep.equal({}); + + byId("cb1").checked = true; + form.click(); + this.server.respond(); + values.should.deep.equal({c1:"cb1"}); + + byId("cb1").checked = true; + byId("cb2").checked = true; + form.click(); + this.server.respond(); + values.should.deep.equal({c1:["cb1", "cb2"]}); + + byId("cb1").checked = true; + byId("cb2").checked = true; + byId("cb3").checked = true; + form.click(); + this.server.respond(); + values.should.deep.equal({c1:["cb1", "cb2", "cb3"]}); + + byId("cb1").checked = true; + byId("cb2").checked = true; + byId("cb3").checked = true; + byId("cb4").checked = true; + form.click(); + this.server.respond(); + values.should.deep.equal({c1:["cb1", "cb2", "cb3"], c2:"cb4"}); + + byId("cb1").checked = true; + byId("cb2").checked = true; + byId("cb3").checked = true; + byId("cb4").checked = true; + byId("cb5").checked = true; + form.click(); + this.server.respond(); + values.should.deep.equal({c1:["cb1", "cb2", "cb3"], c2:["cb4", "cb5"]}); + + byId("cb1").checked = true; + byId("cb2").checked = true; + byId("cb3").checked = true; + byId("cb4").checked = true; + byId("cb5").checked = true; + byId("cb6").checked = true; + form.click(); + this.server.respond(); + values.should.deep.equal({c1:["cb1", "cb2", "cb3"], c2:["cb4", "cb5"], c3:"cb6"}); + + byId("cb1").checked = true; + byId("cb2").checked = false; + byId("cb3").checked = true; + byId("cb4").checked = false; + byId("cb5").checked = true; + byId("cb6").checked = true; + form.click(); + this.server.respond(); + values.should.deep.equal({c1:["cb1", "cb3"], c2:"cb5", c3:"cb6"}); + + }); + + it('text nodes dont screw up settling via variable capture', function() + { + this.server.respondWith("GET", "/test", "
fooo"); + this.server.respondWith("GET", "/test2", "clicked"); + var div = make("
"); + div.click(); + this.server.respond(); + byId("d1").click(); + this.server.respond(); + byId("d1").innerHTML.should.equal("clicked"); + }); + + var globalWasCalled = false; + window.callGlobal = function() { + globalWasCalled = true; + } + + it('script nodes evaluate', function() + { + try { + this.server.respondWith("GET", "/test", "
"); + var div = make("
"); + div.click(); + this.server.respond(); + globalWasCalled.should.equal(true); + } finally { + delete window.callGlobal; + } + }); + + it('script node exceptions do not break rendering', function() + { + this.server.respondWith("GET", "/test", "clicked"); + var div = make("
"); + div.click(); + this.server.respond(); + div.innerText.should.equal("clicked"); + }); + + it('allows empty verb values', function() + { + var path = null; + var div = make("
"); + htmx.on(div, "htmx:configRequest", function (evt) { + path = evt.detail.path; + return false; + }); + div.click(); + this.server.respond(); + path.should.not.be.null; + }); + + it('allows blank verb values', function() + { + var path = null; + var div = make("
"); + htmx.on(div, "htmx:configRequest", function (evt) { + path = evt.detail.path; + return false; + }); + div.click(); + this.server.respond(); + path.should.not.be.null; + }); + + it('input values are not settle swapped (causes flicker)', function() + { + this.server.respondWith("GET", "/test", ""); + var input = make(""); + input.click(); + this.server.respond(); + input = byId('i1'); + input.value.should.equal('bar'); + }); + + +}) diff --git a/www/test/0.0.8/test/core/api.js b/www/test/0.0.8/test/core/api.js new file mode 100644 index 00000000..10c84ad2 --- /dev/null +++ b/www/test/0.0.8/test/core/api.js @@ -0,0 +1,167 @@ +describe("Core htmx API test", function(){ + beforeEach(function() { + this.server = makeServer(); + clearWorkArea(); + }); + afterEach(function() { + this.server.restore(); + clearWorkArea(); + }); + + it('onLoad is called... onLoad', function(){ + // also tests on/off + this.server.respondWith("GET", "/test", "
") + var helper = htmx.onLoad(function (elt) { + elt.setAttribute("foo", "bar"); + }); + try { + var div = make("
"); + div.click(); + this.server.respond(); + byId("d1").getAttribute("foo").should.equal("bar"); + } finally { + htmx.off("htmx:load", helper); + } + }); + + it('triggers properly', function () { + var div = make("
"); + var myEventCalled = false; + var detailStr = ""; + htmx.on("myEvent", function(evt){ + myEventCalled = true; + detailStr = evt.detail.str; + }) + htmx.trigger(div, "myEvent", {str:"foo"}) + + myEventCalled.should.equal(true); + detailStr.should.equal("foo"); + }); + + it('triggers with no details properly', function () { + var div = make("
"); + var myEventCalled = false; + htmx.on("myEvent", function(evt){ + myEventCalled = true; + }) + htmx.trigger(div, "myEvent") + myEventCalled.should.equal(true); + }); + + it('should find properly', function(){ + var div = make("
"); + div.should.equal(htmx.find("#d1")); + div.should.equal(htmx.find(".c1")); + div.should.equal(htmx.find(".c2")); + div.should.equal(htmx.find(".c1.c2")); + }); + + it('should find properly from elt', function(){ + var div = make("
"); + htmx.find(div, "a").id.should.equal('a1'); + }); + + it('should find all properly', function(){ + var div = make("
"); + htmx.findAll(".c1").length.should.equal(3); + htmx.findAll(".c2").length.should.equal(2); + htmx.findAll(".c3").length.should.equal(1); + }); + + it('should find all properly from elt', function(){ + var div = make("
"); + htmx.findAll(div, ".c1").length.should.equal(3); + htmx.findAll(div, ".c2").length.should.equal(2); + htmx.findAll(div,".c3").length.should.equal(1); + }); + + it('should find closest element properly', function () { + var div = make("
"); + var a = htmx.find(div, "a"); + htmx.closest(a, "div").should.equal(div); + }); + + it('should remove element properly', function () { + var div = make("
"); + var a = htmx.find(div, "a"); + htmx.remove(a); + div.innerHTML.should.equal(""); + }); + + it('should add class properly', function () { + var div = make("
"); + div.classList.contains("foo").should.equal(false); + htmx.addClass(div, "foo"); + div.classList.contains("foo").should.equal(true); + }); + + it('should add class properly after delay', function (done) { + var div = make("
"); + div.classList.contains("foo").should.equal(false); + htmx.addClass(div, "foo", 10); + div.classList.contains("foo").should.equal(false); + setTimeout(function () { + div.classList.contains("foo").should.equal(true); + done(); + }, 20); + }); + + it('should remove class properly', function () { + var div = make("
"); + htmx.addClass(div, "foo"); + div.classList.contains("foo").should.equal(true); + htmx.removeClass(div, "foo"); + div.classList.contains("foo").should.equal(false); + }); + + it('should add class properly after delay', function (done) { + var div = make("
"); + htmx.addClass(div, "foo"); + div.classList.contains("foo").should.equal(true); + htmx.removeClass(div, "foo", 10); + div.classList.contains("foo").should.equal(true); + setTimeout(function () { + div.classList.contains("foo").should.equal(false); + done(); + }, 20); + }); + + it('should toggle class properly', function () { + var div = make("
"); + div.classList.contains("foo").should.equal(false); + htmx.toggleClass(div, "foo"); + div.classList.contains("foo").should.equal(true); + htmx.toggleClass(div, "foo"); + div.classList.contains("foo").should.equal(false); + }); + + it('should take class properly', function () { + var div1 = make("
"); + var div2 = make("
"); + var div3 = make("
"); + + div1.classList.contains("foo").should.equal(false); + div2.classList.contains("foo").should.equal(false); + div3.classList.contains("foo").should.equal(false); + + htmx.takeClass(div1, "foo"); + + div1.classList.contains("foo").should.equal(true); + div2.classList.contains("foo").should.equal(false); + div3.classList.contains("foo").should.equal(false); + + htmx.takeClass(div2, "foo"); + + div1.classList.contains("foo").should.equal(false); + div2.classList.contains("foo").should.equal(true); + div3.classList.contains("foo").should.equal(false); + + htmx.takeClass(div3, "foo"); + + div1.classList.contains("foo").should.equal(false); + div2.classList.contains("foo").should.equal(false); + div3.classList.contains("foo").should.equal(true); + }); + + +}) diff --git a/www/test/0.0.8/test/core/events.js b/www/test/0.0.8/test/core/events.js new file mode 100644 index 00000000..c7db8fa1 --- /dev/null +++ b/www/test/0.0.8/test/core/events.js @@ -0,0 +1,122 @@ +describe("Core htmx Events", function() { + beforeEach(function () { + this.server = makeServer(); + clearWorkArea(); + }); + afterEach(function () { + this.server.restore(); + clearWorkArea(); + }); + + it("load.htmx fires properly", function () { + var called = false; + var handler = htmx.on("htmx:load", function (evt) { + called = true; + }); + try { + this.server.respondWith("GET", "/test", ""); + this.server.respondWith("GET", "/test", "
"); + var div = make("
"); + div.click(); + this.server.respond(); + should.equal(called, true); + } finally { + htmx.off("htmx:load", handler); + } + }); + + it("configRequest.htmx allows attribute addition", function () { + var handler = htmx.on("htmx:configRequest", function (evt) { + evt.detail.parameters['param'] = "true"; + }); + try { + var param = null; + this.server.respondWith("POST", "/test", function (xhr) { + param = getParameters(xhr)['param']; + xhr.respond(200, {}, ""); + }); + var div = make("
"); + div.click(); + this.server.respond(); + param.should.equal("true"); + } finally { + htmx.off("htmx:configRequest", handler); + } + }); + + it("configRequest.htmx allows attribute removal", function () { + var param = "foo"; + var handler = htmx.on("htmx:configRequest", function (evt) { + delete evt.detail.parameters['param']; + }); + try { + this.server.respondWith("POST", "/test", function (xhr) { + param = getParameters(xhr)['param']; + xhr.respond(200, {}, ""); + }); + var div = make("
"); + div.click(); + this.server.respond(); + should.equal(param, undefined); + } finally { + htmx.off("htmx:configRequest", handler); + } + }); + + it("configRequest.htmx allows header tweaking", function () { + var header = "foo"; + var handler = htmx.on("htmx:configRequest", function (evt) { + evt.detail.headers['X-My-Header'] = "bar"; + }); + try { + this.server.respondWith("POST", "/test", function (xhr) { + header = xhr.requestHeaders['X-My-Header']; + xhr.respond(200, {}, ""); + }); + var div = make("
"); + div.click(); + this.server.respond(); + should.equal(header, "bar"); + } finally { + htmx.off("htmx:configRequest", handler); + } + }); + + it("afterSwap.htmx is called when replacing outerHTML", function () { + var called = false; + var handler = htmx.on("htmx:afterSwap", function (evt) { + called = true; + }); + try { + this.server.respondWith("POST", "/test", function (xhr) { + xhr.respond(200, {}, ""); + }); + var div = make(""); + div.click(); + this.server.respond(); + should.equal(called, true); + } finally { + htmx.off("htmx:afterSwap", handler); + } + }); + + it("afterSettle.htmx is called when replacing outerHTML", function () { + var called = false; + var handler = htmx.on("htmx:afterSettle", function (evt) { + called = true; + }); + try { + this.server.respondWith("POST", "/test", function (xhr) { + xhr.respond(200, {}, ""); + }); + var div = make(""); + div.click(); + this.server.respond(); + should.equal(called, true); + } finally { + htmx.off("htmx:afterSettle", handler); + } + }); + +}); + diff --git a/www/test/0.0.8/test/core/headers.js b/www/test/0.0.8/test/core/headers.js new file mode 100644 index 00000000..ab59f992 --- /dev/null +++ b/www/test/0.0.8/test/core/headers.js @@ -0,0 +1,118 @@ +describe("Core htmx AJAX headers", function() { + beforeEach(function () { + this.server = makeServer(); + clearWorkArea(); + }); + afterEach(function () { + this.server.restore(); + clearWorkArea(); + }); + + it("should include the HX-Request header", function(){ + this.server.respondWith("GET", "/test", function(xhr){ + xhr.requestHeaders['HX-Request'].should.be.equal('true'); + xhr.respond(200, {}, ""); + }); + var div = make('
'); + div.click(); + this.server.respond(); + }) + + it("should include the HX-Trigger header", function(){ + this.server.respondWith("GET", "/test", function(xhr){ + xhr.requestHeaders['HX-Trigger'].should.equal('d1'); + xhr.respond(200, {}, ""); + }); + var div = make('
'); + div.click(); + this.server.respond(); + }) + + it("should include the HX-Trigger-Name header", function(){ + this.server.respondWith("GET", "/test", function(xhr){ + xhr.requestHeaders['HX-Trigger-Name'].should.equal('n1'); + xhr.respond(200, {}, ""); + }); + var div = make(''); + div.click(); + this.server.respond(); + }) + + it("should include the HX-Target header", function(){ + this.server.respondWith("GET", "/test", function(xhr){ + xhr.requestHeaders['HX-Target'].should.equal('d1'); + xhr.respond(200, {}, ""); + }); + var div = make('
'); + div.click(); + this.server.respond(); + }) + + it("should handle simple string HX-Trigger response header properly", function(){ + this.server.respondWith("GET", "/test", [200, {"HX-Trigger" : "foo"}, ""]); + + var div = make('
'); + var invokedEvent = false; + div.addEventListener("foo", function (evt) { + invokedEvent = true; + }); + div.click(); + this.server.respond(); + invokedEvent.should.equal(true); + }) + + it("should handle basic JSON HX-Trigger response header properly", function(){ + this.server.respondWith("GET", "/test", [200, {"HX-Trigger" : "{\"foo\":null}"}, ""]); + + var div = make('
'); + var invokedEvent = false; + div.addEventListener("foo", function (evt) { + invokedEvent = true; + should.equal(null, evt.detail.value); + evt.detail.elt.should.equal(div); + }); + div.click(); + this.server.respond(); + invokedEvent.should.equal(true); + }) + + it("should handle JSON with array arg HX-Trigger response header properly", function(){ + this.server.respondWith("GET", "/test", [200, {"HX-Trigger" : "{\"foo\":[1, 2, 3]}"}, ""]); + + var div = make('
'); + var invokedEvent = false; + div.addEventListener("foo", function (evt) { + invokedEvent = true; + evt.detail.elt.should.equal(div); + evt.detail.value.should.deep.equal([1, 2, 3]); + }); + div.click(); + this.server.respond(); + invokedEvent.should.equal(true); + }) + + it("should handle JSON with array arg HX-Trigger response header properly", function(){ + this.server.respondWith("GET", "/test", [200, {"HX-Trigger" : "{\"foo\":{\"a\":1, \"b\":2}}"}, ""]); + + var div = make('
'); + var invokedEvent = false; + div.addEventListener("foo", function (evt) { + invokedEvent = true; + evt.detail.elt.should.equal(div); + evt.detail.a.should.equal(1); + evt.detail.b.should.equal(2); + }); + div.click(); + this.server.respond(); + invokedEvent.should.equal(true); + }) + + it("should survive malformed JSON in HX-Trigger response header", function(){ + this.server.respondWith("GET", "/test", [200, {"HX-Trigger" : "{not: valid}"}, ""]); + + var div = make('
'); + div.click(); + this.server.respond(); + }) + +}); diff --git a/www/test/0.0.8/test/core/internals.js b/www/test/0.0.8/test/core/internals.js new file mode 100644 index 00000000..9e6f139e --- /dev/null +++ b/www/test/0.0.8/test/core/internals.js @@ -0,0 +1,23 @@ +describe("Core htmx internals Tests", function() { + beforeEach(function () { + this.server = makeServer(); + clearWorkArea(); + }); + afterEach(function () { + this.server.restore(); + clearWorkArea(); + }); + + it("makeFragment works with janky stuff", function(){ + htmx._("makeFragment")("").tagName.should.equal("BODY"); + htmx._("makeFragment")("").tagName.should.equal("BODY"); + + //NB - the tag name should be the *parent* element hosting the HTML since we use the fragment children + // for the swap + htmx._("makeFragment")("").tagName.should.equal("TR"); + htmx._("makeFragment")("").tagName.should.equal("TABLE"); + htmx._("makeFragment")("").tagName.should.equal("COLGROUP"); + htmx._("makeFragment")("").tagName.should.equal("TBODY"); + }) + +}); \ No newline at end of file diff --git a/www/test/0.0.8/test/core/parameters.js b/www/test/0.0.8/test/core/parameters.js new file mode 100644 index 00000000..f6b71a35 --- /dev/null +++ b/www/test/0.0.8/test/core/parameters.js @@ -0,0 +1,121 @@ +describe("Core htmx Parameter Handling", function() { + beforeEach(function () { + this.server = makeServer(); + clearWorkArea(); + }); + afterEach(function () { + this.server.restore(); + clearWorkArea(); + }); + + it('Input includes value', function () { + var input = make(''); + var vals = htmx._('getInputValues')(input); + vals['foo'].should.equal('bar'); + }) + + it('Input includes value on get', function () { + var input = make(''); + var vals = htmx._('getInputValues')(input, "get"); + vals['foo'].should.equal('bar'); + }) + + it('Input includes form', function () { + var form = make('
'); + var input = byId('i1'); + var vals = htmx._('getInputValues')(input); + vals['foo'].should.equal('bar'); + vals['do'].should.equal('rey'); + }) + + it('Input doesnt include form on get', function () { + var form = make('
'); + var input = byId('i1'); + var vals = htmx._('getInputValues')(input, 'get'); + vals['foo'].should.equal('bar'); + should.equal(vals['do'], undefined); + }) + + it('non-input includes form', function () { + var form = make('
'); + var div = byId('d1'); + var vals = htmx._('getInputValues')(div, "post"); + vals['do'].should.equal('rey'); + }) + + it('non-input doesnt include form on get', function () { + var form = make('
'); + var div = byId('d1'); + var vals = htmx._('getInputValues')(div, "get"); + should.equal(vals['do'], undefined); + }) + + it('Basic form works on get', function () { + var form = make('
'); + var vals = htmx._('getInputValues')(form, 'get'); + vals['foo'].should.equal('bar'); + vals['do'].should.equal('rey'); + }) + + it('Basic form works on non-get', function () { + var form = make('
'); + var vals = htmx._('getInputValues')(form, 'post'); + vals['foo'].should.equal('bar'); + vals['do'].should.equal('rey'); + }) + + it('Double values are included as array', function () { + var form = make('
'); + var vals = htmx._('getInputValues')(form); + vals['foo'].should.equal('bar'); + vals['do'].should.deep.equal(['rey', 'rey']); + }) + + it('Double values are included as array in correct order', function () { + var form = make('
'); + var vals = htmx._('getInputValues')(byId("i3")); + vals['foo'].should.equal('bar'); + vals['do'].should.deep.equal(['rey1', 'rey2']); + }) + + it('hx-include works with form', function () { + var form = make('
'); + var div = make('
'); + var vals = htmx._('getInputValues')(div); + vals['foo'].should.equal('bar'); + vals['do'].should.deep.equal(['rey', 'rey']); + }) + + it('hx-include works with input', function () { + var form = make('
'); + var div = make('
'); + var vals = htmx._('getInputValues')(div); + vals['foo'].should.equal('bar'); + should.equal(vals['do'], undefined); + }) + + it('hx-include works with two inputs', function () { + var form = make('
'); + var div = make('
'); + var vals = htmx._('getInputValues')(div); + vals['foo'].should.equal('bar'); + vals['do'].should.deep.equal(['rey', 'rey']); + }) + + it('hx-include works with two inputs, plus form', function () { + var form = make('
'); + var div = make('
'); + var vals = htmx._('getInputValues')(div); + vals['foo'].should.equal('bar'); + vals['do'].should.deep.equal(['rey', 'rey']); + }) + + it('correctly URL escapes values', function () { + htmx._("urlEncode")({}).should.equal(""); + htmx._("urlEncode")({"foo": "bar"}).should.equal("foo=bar"); + htmx._("urlEncode")({"foo": "bar", "do" : "rey"}).should.equal("foo=bar&do=rey"); + htmx._("urlEncode")({"foo": "bar", "do" : ["rey", "blah"]}).should.equal("foo=bar&do=rey&do=blah"); + }); + +}); + diff --git a/www/test/0.0.8/test/core/perf.js b/www/test/0.0.8/test/core/perf.js new file mode 100644 index 00000000..6fdbbbea --- /dev/null +++ b/www/test/0.0.8/test/core/perf.js @@ -0,0 +1,70 @@ +describe("Core htmx perf Tests", function() { + + var HTMX_HISTORY_CACHE_NAME = "htmx-history-cache"; + + beforeEach(function () { + this.server = makeServer(); + clearWorkArea(); + localStorage.removeItem(HTMX_HISTORY_CACHE_NAME); + }); + afterEach(function () { + this.server.restore(); + clearWorkArea(); + localStorage.removeItem(HTMX_HISTORY_CACHE_NAME); + }); + + function stringRepeat(str, num) { + num = Number(num); + + var result = ''; + while (true) { + if (num & 1) { // (1) + result += str; + } + num >>>= 1; // (2) + if (num <= 0) break; + str += str; + } + + return result; + } + + it("DOM processing should be fast", function(){ + this.server.respondWith("GET", "/test", "Clicked!"); + + // create an entry with a large content string (256k) and see how fast we can write and read it + // to local storage as a single entry + var str = stringRepeat("
", 30) + stringRepeat("
\n", 1000) + stringRepeat("
", 30); + var start = performance.now(); + var stuff = make(str); + var end = performance.now(); + var timeInMs = end - start; + + // make sure the DOM actually processed + var firstBtn = stuff.querySelector("button"); + firstBtn.click(); + this.server.respond(); + firstBtn.innerHTML.should.equal("Clicked!"); + + chai.assert(timeInMs < 100, "Should take less than 100ms on most platforms, took: " + timeInMs + "ms"); + }) + + it("history implementation should be fast", function(){ + // create an entry with a large content string (256k) and see how fast we can write and read it + // to local storage as a single entry + var entry = {url: stringRepeat("x", 32), content:stringRepeat("x", 256*1024)} + var array = []; + for (var i = 0; i < 10; i++) { + array.push(entry); + } + var start = performance.now(); + var string = JSON.stringify(array); + localStorage.setItem(HTMX_HISTORY_CACHE_NAME, string); + var reReadString = localStorage.getItem(HTMX_HISTORY_CACHE_NAME); + var finalJson = JSON.parse(reReadString); + var end = performance.now(); + var timeInMs = end - start; + chai.assert(timeInMs < 300, "Should take less than 300ms on most platforms"); + }) + +}) \ No newline at end of file diff --git a/www/test/0.0.8/test/core/regressions.js b/www/test/0.0.8/test/core/regressions.js new file mode 100644 index 00000000..bc819029 --- /dev/null +++ b/www/test/0.0.8/test/core/regressions.js @@ -0,0 +1,68 @@ +describe("Core htmx Regression Tests", function(){ + + beforeEach(function() { + this.server = makeServer(); + clearWorkArea(); + }); + afterEach(function() { + this.server.restore(); + clearWorkArea(); + }); + + it('SVGs process properly in IE11', function() + { + var btn = make('\n' + + '\n' + + '\n' + + '\n' + + '') + }); + + it ('Handles https://github.com/bigskysoftware/htmx/issues/4 properly', function() { + this.server.respondWith("GET", "/index2a.php", + "
I came from message oob swap I should be second
" + + "
I came from a message2 oob swap I should be third but I am in the wrong spot
" + + "I'm page2 content (non-swap) I should be first") + + var h1 = make("

Kutty CLICK ME

" + + "
" + + "
" + + "
") + h1.click(); + this.server.respond(); + htmx.find("#page2").innerHTML.should.equal("I'm page2 content (non-swap) I should be first") + htmx.find("#message").innerHTML.should.equal("I came from message oob swap I should be second") + htmx.find("#message2").innerHTML.should.equal("I came from a message2 oob swap I should be third but I am in the wrong spot") + }); + + it ('Handles https://github.com/bigskysoftware/htmx/issues/33 "empty values" properly', function() { + this.server.respondWith("POST", "/htmx.php", function (xhr) { + xhr.respond(200, {}, xhr.requestBody); + }); + + var form = make('
\n' + + '\n' + + '\n' + + '
') + form.click(); + this.server.respond(); + form.innerHTML.should.equal("variable=") + }); + + it ('name=id doesnt cause an error', function(){ + this.server.respondWith("GET", "/test", "Foo
") + var div = make('
Get It
') + div.click(); + this.server.respond(); + div.innerText.should.contain("Foo") + }); + + it ('empty id doesnt cause an error', function(){ + this.server.respondWith("GET", "/test", "Foo\n
") + var div = make('
Get It
') + div.click(); + this.server.respond(); + div.innerText.should.contain("Foo") + }); + +}) diff --git a/www/test/0.0.8/test/core/verbs.js b/www/test/0.0.8/test/core/verbs.js new file mode 100644 index 00000000..1d0711c2 --- /dev/null +++ b/www/test/0.0.8/test/core/verbs.js @@ -0,0 +1,44 @@ +describe("Core htmx AJAX Verbs", function() { + beforeEach(function () { + this.server = makeServer(); + clearWorkArea(); + }); + afterEach(function () { + this.server.restore(); + clearWorkArea(); + }); + + it('handles basic posts properly', function () { + this.server.respondWith("POST", "/test", "post"); + var div = make('
click me
'); + div.click(); + this.server.respond(); + div.innerHTML.should.equal("post"); + }) + + it('handles basic put properly', function () { + this.server.respondWith("PUT", "/test", "put"); + var div = make('
click me
'); + div.click(); + this.server.respond(); + div.innerHTML.should.equal("put"); + }) + + it('handles basic patch properly', function () { + this.server.respondWith("PATCH", "/test", "patch"); + var div = make('
click me
'); + div.click(); + this.server.respond(); + div.innerHTML.should.equal("patch"); + }) + + it('handles basic delete properly', function () { + this.server.respondWith("DELETE", "/test", "delete"); + var div = make('
click me
'); + div.click(); + this.server.respond(); + div.innerHTML.should.equal("delete"); + }) + +}); + diff --git a/www/test/0.0.8/test/ext/ajax-header.js b/www/test/0.0.8/test/ext/ajax-header.js new file mode 100644 index 00000000..0888ef3b --- /dev/null +++ b/www/test/0.0.8/test/ext/ajax-header.js @@ -0,0 +1,21 @@ +describe("ajax-header extension", function() { + beforeEach(function () { + this.server = makeServer(); + clearWorkArea(); + }); + afterEach(function () { + this.server.restore(); + clearWorkArea(); + }); + + it('Sends the X-Requested-With header', function () { + this.server.respondWith("GET", "/test", function (xhr) { + xhr.respond(200, {}, xhr.requestHeaders['X-Requested-With']) + }); + var btn = make('') + btn.click(); + this.server.respond(); + btn.innerHTML.should.equal("XMLHttpRequest"); + }); + +}); \ No newline at end of file diff --git a/www/test/0.0.8/test/ext/bad-extension.js b/www/test/0.0.8/test/ext/bad-extension.js new file mode 100644 index 00000000..fcf6a438 --- /dev/null +++ b/www/test/0.0.8/test/ext/bad-extension.js @@ -0,0 +1,27 @@ +describe("bad extension", function() { + htmx.defineExtension("bad-extension", { + onEvent : function(name, evt) {throw "onEvent"}, + transformResponse : function(text, xhr, elt) {throw "transformRequest"}, + isInlineSwap : function(swapStyle) {throw "isInlineSwap"}, + handleSwap : function(swapStyle, target, fragment, settleInfo) {throw "handleSwap"}, + encodeParameters : function(xhr, parameters, elt) {throw "encodeParmeters"} + } + ) + beforeEach(function () { + this.server = makeServer(); + clearWorkArea(); + }); + afterEach(function () { + this.server.restore(); + clearWorkArea(); + }); + + it('does not blow up rendering', function () { + this.server.respondWith("GET", "/test", "clicked!"); + var div = make('
Click Me!
') + div.click(); + this.server.respond(); + div.innerHTML.should.equal("clicked!"); + }); + +}); \ No newline at end of file diff --git a/www/test/0.0.8/test/ext/class-tools.js b/www/test/0.0.8/test/ext/class-tools.js new file mode 100644 index 00000000..0c5004b5 --- /dev/null +++ b/www/test/0.0.8/test/ext/class-tools.js @@ -0,0 +1,55 @@ +describe("class-tools extension", function(){ + beforeEach(function() { + this.server = makeServer(); + clearWorkArea(); + }); + afterEach(function() { + this.server.restore(); + clearWorkArea(); + }); + + it('adds classes properly', function(done) + { + var div = make('
Click Me!
') + should.equal(div.classList.length, 0); + setTimeout(function(){ + should.equal(div.classList.contains("c1"), true); + done(); + }, 100); + }); + + it('removes classes properly', function(done) + { + var div = make('
Click Me!
') + should.equal(div.classList.contains("foo"), true); + should.equal(div.classList.contains("bar"), true); + setTimeout(function(){ + should.equal(div.classList.contains("foo"), true); + should.equal(div.classList.contains("bar"), false); + done(); + }, 100); + }); + + it('adds classes properly w/ data-* prefix', function(done) + { + var div = make('
Click Me!
') + should.equal(div.classList.length, 0); + setTimeout(function(){ + should.equal(div.classList.contains("c1"), true); + done(); + }, 100); + }); + + it('extension can be on parent', function(done) + { + var div = make('
Click Me!
') + should.equal(div.classList.length, 0); + setTimeout(function(){ + should.equal(div.classList.contains("c1"), false); + should.equal(byId("d1").classList.contains("c1"), true); + done(); + }, 100); + }); + + +}) diff --git a/www/test/0.0.8/test/ext/client-side-templates.js b/www/test/0.0.8/test/ext/client-side-templates.js new file mode 100644 index 00000000..29206d21 --- /dev/null +++ b/www/test/0.0.8/test/ext/client-side-templates.js @@ -0,0 +1,30 @@ +describe("client-side-templates extension", function() { + beforeEach(function () { + this.server = makeServer(); + clearWorkArea(); + }); + afterEach(function () { + this.server.restore(); + clearWorkArea(); + }); + + it('works on basic mustache template', function () { + this.server.respondWith("GET", "/test", '{"foo":"bar"}'); + var btn = make('') + make('') + btn.click(); + this.server.respond(); + btn.innerHTML.should.equal("*bar*"); + }); + + it('works on basic handlebars template', function () { + this.server.respondWith("GET", "/test", '{"foo":"bar"}'); + var btn = make('') + Handlebars.partials["hb1"] = Handlebars.compile("*{{foo}}*"); + btn.click(); + this.server.respond(); + btn.innerHTML.should.equal("*bar*"); + }); + + +}); \ No newline at end of file diff --git a/www/test/0.0.8/test/ext/debug.js b/www/test/0.0.8/test/ext/debug.js new file mode 100644 index 00000000..4eeca295 --- /dev/null +++ b/www/test/0.0.8/test/ext/debug.js @@ -0,0 +1,19 @@ +describe("debug extension", function() { + beforeEach(function () { + this.server = makeServer(); + clearWorkArea(); + }); + afterEach(function () { + this.server.restore(); + clearWorkArea(); + }); + + it('works on basic request', function () { + this.server.respondWith("GET", "/test", "Clicked!"); + var btn = make('') + btn.click(); + this.server.respond(); + btn.innerHTML.should.equal("Clicked!"); + }); + +}); \ No newline at end of file diff --git a/www/test/0.0.8/test/ext/extension-swap.js b/www/test/0.0.8/test/ext/extension-swap.js new file mode 100644 index 00000000..0186b525 --- /dev/null +++ b/www/test/0.0.8/test/ext/extension-swap.js @@ -0,0 +1,60 @@ +describe("default extensions behavior", function() { + + var loadCalls, afterSwapCalls, afterSettleCalls; + + beforeEach(function () { + loadCalls = []; + this.server = makeServer(); + clearWorkArea(); + + htmx.defineExtension("ext-testswap", { + onEvent : function(name, evt) { + if (name === "htmx:load") { + loadCalls.push(evt.detail.elt); + } + }, + handleSwap: function (swapStyle, target, fragment, settleInfo) { + // simple outerHTML replacement for tests + var parentEl = target.parentElement; + parentEl.removeChild(target); + return [parentEl.appendChild(fragment)]; // return the newly added element + } + + }); + + }); + + afterEach(function () { + this.server.restore(); + clearWorkArea(); + htmx.removeExtension("ext-testswap"); + }); + + it('handleSwap: afterSwap and afterSettle triggered if extension defined on parent', function () { + this.server.respondWith("GET", "/test", ''); + var div = make('
'); + var btn = div.firstChild; + btn.click() + this.server.respond(); + loadCalls.length.should.equal(1); + loadCalls[0].textContent.should.equal('Clicked!'); // the new button is loaded + }); + + it('handleSwap: new content is handled by htmx', function() { + this.server.respondWith("GET", "/test", ''); + this.server.respondWith("GET", "/test-inner", 'Loaded!'); + make('
').querySelector('button').click(); + + this.server.respond(); // call /test via button trigger=click + var btn = byId('test-ext-testswap'); + btn.textContent.should.equal('Clicked!'); + loadCalls.length.should.equal(1); + loadCalls[0].textContent.should.equal('Clicked!'); // the new button is loaded + + this.server.respond(); // call /test-inner via span trigger=load + btn.textContent.should.equal("Clicked!Loaded!"); + loadCalls.length.should.equal(2); + loadCalls[1].textContent.should.equal('Loaded!'); // the new span is loaded + }); + +}); diff --git a/www/test/0.0.8/test/ext/hyperscript.js b/www/test/0.0.8/test/ext/hyperscript.js new file mode 100644 index 00000000..07b93bfd --- /dev/null +++ b/www/test/0.0.8/test/ext/hyperscript.js @@ -0,0 +1,37 @@ +describe("hyperscript integration", function() { + beforeEach(function () { + this.server = makeServer(); + clearWorkArea(); + }); + afterEach(function () { + this.server.restore(); + clearWorkArea(); + }); + + it('can trigger with a custom event', function () { + this.server.respondWith("GET", "/test", "Custom Event Sent!"); + var btn = make('') + btn.click(); + this.server.respond(); + btn.innerHTML.should.equal("Custom Event Sent!"); + }); + + it('can handle htmx driven events', function () { + this.server.respondWith("GET", "/test", "Clicked!"); + var btn = make('') + btn.classList.contains("afterSettle").should.equal(false); + btn.click(); + this.server.respond(); + btn.classList.contains("afterSettle").should.equal(true); + }); + + it('can handle htmx error events', function () { + this.server.respondWith("GET", "/test", [404, {}, "Bad request"]); + var div = make('
') + var btn = make('') + btn.click(); + this.server.respond(); + div.innerHTML.should.equal("Response Status Error Code 404 from /test"); + }); + +}); \ No newline at end of file diff --git a/www/test/0.0.8/test/ext/include-vals.js b/www/test/0.0.8/test/ext/include-vals.js new file mode 100644 index 00000000..fc05a067 --- /dev/null +++ b/www/test/0.0.8/test/ext/include-vals.js @@ -0,0 +1,23 @@ +describe("include-vals extension", function() { + beforeEach(function () { + this.server = makeServer(); + clearWorkArea(); + }); + afterEach(function () { + this.server.restore(); + clearWorkArea(); + }); + + it('Includes values properly', function () { + var params = {}; + this.server.respondWith("POST", "/test", function (xhr) { + params = getParameters(xhr); + xhr.respond(200, {}, "clicked"); + }); + var btn = make('') + btn.click(); + this.server.respond(); + params['foo'].should.equal("bar"); + }); + +}); \ No newline at end of file diff --git a/www/test/0.0.8/test/ext/json-enc.js b/www/test/0.0.8/test/ext/json-enc.js new file mode 100644 index 00000000..ed805a17 --- /dev/null +++ b/www/test/0.0.8/test/ext/json-enc.js @@ -0,0 +1,136 @@ +// +describe("json-enc extension", function() { + beforeEach(function () { + this.server = makeServer(); + clearWorkArea(); + }); + afterEach(function () { + this.server.restore(); + clearWorkArea(); + }); + + it('handles basic post properly', function () { + var jsonResponseBody = JSON.stringify({}); + this.server.respondWith("POST", "/test", jsonResponseBody); + var div = make("
click me
"); + div.click(); + this.server.respond(); + this.server.lastRequest.response.should.equal("{}"); + }) + + it('handles basic put properly', function () { + var jsonResponseBody = JSON.stringify({}); + this.server.respondWith("PUT", "/test", jsonResponseBody); + var div = make('
click me
'); + div.click(); + this.server.respond(); + this.server.lastRequest.response.should.equal("{}"); + }) + + it('handles basic patch properly', function () { + var jsonResponseBody = JSON.stringify({}); + this.server.respondWith("PATCH", "/test", jsonResponseBody); + var div = make('
click me
'); + div.click(); + this.server.respond(); + this.server.lastRequest.response.should.equal("{}"); + }) + + it('handles basic delete properly', function () { + var jsonResponseBody = JSON.stringify({}); + this.server.respondWith("DELETE", "/test", jsonResponseBody); + var div = make('
click me
'); + div.click(); + this.server.respond(); + this.server.lastRequest.response.should.equal("{}"); + }) + + it('handles post with form parameters', function () { + + this.server.respondWith("POST", "/test", function (xhr) { + var values = JSON.parse(xhr.requestBody); + values.should.have.keys("username","password"); + values["username"].should.be.equal("joe"); + values["password"].should.be.equal("123456"); + var ans = { "passwordok": values["password"] == "123456"}; + xhr.respond(200, {}, JSON.stringify(ans)); + }); + + var html = make('
' + + ' ' + + ' ' + + ' '); + + byId("btnSubmit").click(); + this.server.respond(); + this.server.lastRequest.response.should.equal('{"passwordok":true}'); + }) + + it('handles put with form parameters', function () { + + this.server.respondWith("PUT", "/test", function (xhr) { + var values = JSON.parse(xhr.requestBody); + values.should.have.keys("username","password"); + values["username"].should.be.equal("joe"); + values["password"].should.be.equal("123456"); + var ans = { "passwordok": values["password"] == "123456"}; + xhr.respond(200, {}, JSON.stringify(ans)); + }); + + var html = make(' ' + + ' ' + + ' ' + + ' '); + + byId("btnSubmit").click(); + this.server.respond(); + this.server.lastRequest.response.should.equal('{"passwordok":true}'); + }) + + + it('handles patch with form parameters', function () { + + this.server.respondWith("PATCH", "/test", function (xhr) { + var values = JSON.parse(xhr.requestBody); + values.should.have.keys("username","password"); + values["username"].should.be.equal("joe"); + values["password"].should.be.equal("123456"); + var ans = { "passwordok": values["password"] == "123456"}; + xhr.respond(200, {}, JSON.stringify(ans)); + }); + + var html = make(' ' + + ' ' + + ' ' + + ' '); + + byId("btnSubmit").click(); + this.server.respond(); + this.server.lastRequest.response.should.equal('{"passwordok":true}'); + }) + + it('handles delete with form parameters', function () { + + this.server.respondWith("DELETE", "/test", function (xhr) { + var values = JSON.parse(xhr.requestBody); + values.should.have.keys("username","password"); + values["username"].should.be.equal("joe"); + values["password"].should.be.equal("123456"); + var ans = { "passwordok": values["password"] == "123456"}; + xhr.respond(200, {}, JSON.stringify(ans)); + }); + + var html = make(' ' + + ' ' + + ' ' + + ' '); + + byId("btnSubmit").click(); + this.server.respond(); + this.server.lastRequest.response.should.equal('{"passwordok":true}'); + }) + + + +}); + diff --git a/www/test/0.0.8/test/ext/method-override.js b/www/test/0.0.8/test/ext/method-override.js new file mode 100644 index 00000000..b0a21ea1 --- /dev/null +++ b/www/test/0.0.8/test/ext/method-override.js @@ -0,0 +1,53 @@ +describe("method-override extension", function(){ + beforeEach(function() { + this.server = makeServer(); + clearWorkArea(); + }); + afterEach(function() { + this.server.restore(); + clearWorkArea(); + }); + + it('issues a DELETE request with proper headers', function() + { + this.server.respondWith("DELETE", "/test", function(xhr){ + xhr.requestHeaders['X-HTTP-Method-Override'].should.equal('DELETE'); + xhr.method.should.equal("POST") + xhr.respond(200, {}, "Deleted!"); + }); + + var btn = make('') + btn.click(); + this.server.respond(); + btn.innerHTML.should.equal("Deleted!"); + }); + + it('issues a PATCH request with proper headers', function() + { + this.server.respondWith("PATCH", "/test", function(xhr){ + xhr.requestHeaders['X-HTTP-Method-Override'].should.equal('PATCH'); + xhr.method.should.equal("POST") + xhr.respond(200, {}, "Patched!"); + }); + + var btn = make('') + btn.click(); + this.server.respond(); + btn.innerHTML.should.equal("Patched!"); + }); + + it('issues a PUT request with proper headers', function() + { + this.server.respondWith("PUT", "/test", function(xhr){ + xhr.requestHeaders['X-HTTP-Method-Override'].should.equal('PUT'); + xhr.method.should.equal("POST") + xhr.respond(200, {}, "Putted!"); + }); + + var btn = make('') + btn.click(); + this.server.respond(); + btn.innerHTML.should.equal("Putted!"); + }); + +}) diff --git a/www/test/0.0.8/test/ext/morphdom-swap.js b/www/test/0.0.8/test/ext/morphdom-swap.js new file mode 100644 index 00000000..c394c909 --- /dev/null +++ b/www/test/0.0.8/test/ext/morphdom-swap.js @@ -0,0 +1,31 @@ +describe("morphdom-swap extension", function() { + beforeEach(function () { + this.server = makeServer(); + clearWorkArea(); + }); + afterEach(function () { + this.server.restore(); + clearWorkArea(); + }); + + it('works on basic request', function () { + this.server.respondWith("GET", "/test", "!"); + var btn = make('') + btn.click(); + should.equal(btn.getAttribute("hx-get"), "/test"); + this.server.respond(); + should.equal(btn.getAttribute("hx-get"), null); + btn.innerHTML.should.equal("Clicked!"); + }); + + it('works with htmx elements in new content', function () { + this.server.respondWith("GET", "/test", ''); + this.server.respondWith("GET", "/test-inner", 'Loaded!'); + var btn = make('
').querySelector('button'); + btn.click(); + this.server.respond(); // call /test via button trigger=click + this.server.respond(); // call /test-inner via span trigger=load + btn.innerHTML.should.equal("Clicked!Loaded!"); + }); + +}); diff --git a/www/test/0.0.8/test/ext/path-deps.js b/www/test/0.0.8/test/ext/path-deps.js new file mode 100644 index 00000000..8dea9f70 --- /dev/null +++ b/www/test/0.0.8/test/ext/path-deps.js @@ -0,0 +1,142 @@ +describe("path-deps extension", function() { + beforeEach(function () { + this.server = makeServer(); + clearWorkArea(); + }); + afterEach(function () { + this.server.restore(); + clearWorkArea(); + }); + + it('path-deps basic case works', function () { + this.server.respondWith("POST", "/test", "Clicked!"); + this.server.respondWith("GET", "/test2", "Deps fired!"); + var btn = make('') + var div = make('
FOO
') + btn.click(); + this.server.respond(); + btn.innerHTML.should.equal("Clicked!"); + div.innerHTML.should.equal("FOO"); + this.server.respond(); + div.innerHTML.should.equal("Deps fired!"); + }); + + it('path-deps works with trailing slash', function () { + this.server.respondWith("POST", "/test", "Clicked!"); + this.server.respondWith("GET", "/test2", "Deps fired!"); + var btn = make('') + var div = make('
FOO
') + btn.click(); + this.server.respond(); + btn.innerHTML.should.equal("Clicked!"); + div.innerHTML.should.equal("FOO"); + this.server.respond(); + div.innerHTML.should.equal("Deps fired!"); + }); + + it('path-deps GET does not trigger', function () { + this.server.respondWith("GET", "/test", "Clicked!"); + this.server.respondWith("GET", "/test2", "Deps fired!"); + var btn = make('') + var div = make('
FOO
') + btn.click(); + this.server.respond(); + btn.innerHTML.should.equal("Clicked!"); + div.innerHTML.should.equal("FOO"); + this.server.respond(); + div.innerHTML.should.equal("FOO"); + }); + + it('path-deps dont trigger on path mismatch', function () { + this.server.respondWith("POST", "/test", "Clicked!"); + this.server.respondWith("GET", "/test2", "Deps fired!"); + var btn = make('') + var div = make('
FOO
') + btn.click(); + this.server.respond(); + btn.innerHTML.should.equal("Clicked!"); + div.innerHTML.should.equal("FOO"); + this.server.respond(); + div.innerHTML.should.equal("FOO"); + }); + + it('path-deps dont trigger on path longer than request', function () { + this.server.respondWith("POST", "/test", "Clicked!"); + this.server.respondWith("GET", "/test2", "Deps fired!"); + var btn = make('') + var div = make('
FOO
') + btn.click(); + this.server.respond(); + btn.innerHTML.should.equal("Clicked!"); + div.innerHTML.should.equal("FOO"); + this.server.respond(); + div.innerHTML.should.equal("FOO"); + }); + + it('path-deps trigger on path shorter than request', function () { + this.server.respondWith("POST", "/test/child", "Clicked!"); + this.server.respondWith("GET", "/test2", "Deps fired!"); + var btn = make('') + var div = make('
FOO
') + btn.click(); + this.server.respond(); + btn.innerHTML.should.equal("Clicked!"); + div.innerHTML.should.equal("FOO"); + this.server.respond(); + div.innerHTML.should.equal("Deps fired!"); + }); + + it('path-deps trigger on *-at-start path', function () { + this.server.respondWith("POST", "/test/child/test", "Clicked!"); + this.server.respondWith("GET", "/test2", "Deps fired!"); + var btn = make('') + var div = make('
FOO
') + btn.click(); + this.server.respond(); + btn.innerHTML.should.equal("Clicked!"); + div.innerHTML.should.equal("FOO"); + this.server.respond(); + div.innerHTML.should.equal("Deps fired!"); + }); + + it('path-deps trigger on *-in-middle path', function () { + this.server.respondWith("POST", "/test/child/test", "Clicked!"); + this.server.respondWith("GET", "/test2", "Deps fired!"); + var btn = make('') + var div = make('
FOO
') + btn.click(); + this.server.respond(); + btn.innerHTML.should.equal("Clicked!"); + div.innerHTML.should.equal("FOO"); + this.server.respond(); + div.innerHTML.should.equal("Deps fired!"); + }); + + it('path-deps trigger on *-at-end path', function () { + this.server.respondWith("POST", "/test/child/test", "Clicked!"); + this.server.respondWith("GET", "/test2", "Deps fired!"); + var btn = make('') + var div = make('
FOO
') + btn.click(); + this.server.respond(); + btn.innerHTML.should.equal("Clicked!"); + div.innerHTML.should.equal("FOO"); + this.server.respond(); + div.innerHTML.should.equal("Deps fired!"); + }); + + it('path-deps trigger all *s path', function () { + this.server.respondWith("POST", "/test/child/test", "Clicked!"); + this.server.respondWith("GET", "/test2", "Deps fired!"); + var btn = make('') + var div = make('
FOO
') + btn.click(); + this.server.respond(); + btn.innerHTML.should.equal("Clicked!"); + div.innerHTML.should.equal("FOO"); + this.server.respond(); + div.innerHTML.should.equal("Deps fired!"); + }); + + +}); \ No newline at end of file diff --git a/www/test/0.0.8/test/ext/remove-me.js b/www/test/0.0.8/test/ext/remove-me.js new file mode 100644 index 00000000..1d710944 --- /dev/null +++ b/www/test/0.0.8/test/ext/remove-me.js @@ -0,0 +1,43 @@ +describe("remove-me extension", function(){ + beforeEach(function() { + this.server = makeServer(); + clearWorkArea(); + }); + afterEach(function() { + this.server.restore(); + clearWorkArea(); + }); + + it('removes elements properly', function(done) + { + var div = make('
Click Me!
') + byId("d1").should.equal(div) + setTimeout(function(){ + should.equal(byId("d1"), null); + done(); + }, 40); + }); + + + it('removes properly w/ data-* prefix', function(done) + { + var div = make('
Click Me!
') + should.equal(div.classList.length, 0); + setTimeout(function(){ + should.equal(div.parentElement, null); + done(); + }, 100); + }); + + it('extension can be on parent', function(done) + { + var div = make('
Click Me!
') + should.equal(div.classList.length, 0); + setTimeout(function(){ + should.equal(byId("d1"), null); + done(); + }, 100); + }); + + +}) diff --git a/www/test/0.0.8/test/img/bars.svg b/www/test/0.0.8/test/img/bars.svg new file mode 100644 index 00000000..7cb07e65 --- /dev/null +++ b/www/test/0.0.8/test/img/bars.svg @@ -0,0 +1,52 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/www/test/0.0.8/test/index.html b/www/test/0.0.8/test/index.html new file mode 100644 index 00000000..06102a59 --- /dev/null +++ b/www/test/0.0.8/test/index.html @@ -0,0 +1,147 @@ + + + + Mocha Tests + + + + + + + + + + + +

htmx.js test suite

+ +

Scratch Page

+ + +

Manual Tests

+ + +

Mocha Test Suite

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +Work Area +
+
+
+ + diff --git a/www/test/0.0.8/test/lib/_hyperscript.js b/www/test/0.0.8/test/lib/_hyperscript.js new file mode 100644 index 00000000..0638762f --- /dev/null +++ b/www/test/0.0.8/test/lib/_hyperscript.js @@ -0,0 +1,1689 @@ +//AMD insanity +(function (root, factory) { + if (typeof define === 'function' && define.amd) { + // AMD. Register as an anonymous module. + define([], factory); + } else { + // Browser globals + root._hyperscript = factory(); + } +}(typeof self !== 'undefined' ? self : this, function () { + return (function () { + 'use strict'; + + //----------------------------------------------- + // Lexer + //----------------------------------------------- + var _lexer = function () { + var OP_TABLE = { + '+': 'PLUS', + '-': 'MINUS', + '*': 'MULTIPLY', + '/': 'DIVIDE', + '.': 'PERIOD', + '\\': 'BACKSLASH', + ':': 'COLON', + '%': 'PERCENT', + '|': 'PIPE', + '!': 'EXCLAMATION', + '?': 'QUESTION', + '#': 'POUND', + '&': 'AMPERSAND', + ';': 'SEMI', + ',': 'COMMA', + '(': 'L_PAREN', + ')': 'R_PAREN', + '<': 'L_ANG', + '>': 'R_ANG', + '<=': 'LTE_ANG', + '>=': 'GTE_ANG', + '==': 'EQ', + '===': 'EQQ', + '!=': 'NEQ', + '!==': 'NEQQ', + '{': 'L_BRACE', + '}': 'R_BRACE', + '[': 'L_BRACKET', + ']': 'R_BRACKET', + '=': 'EQUALS' + }; + + function isValidCSSClassChar(c) { + return isAlpha(c) || isNumeric(c) || c === "-" || c === "_"; + } + + function isValidCSSIDChar(c) { + return isAlpha(c) || isNumeric(c) || c === "-" || c === "_" || c === ":"; + } + + function isWhitespace(c) { + return c === " " || c === "\t" || isNewline(c); + } + + function positionString(token) { + return "[Line: " + token.line + ", Column: " + token.col + "]" + } + + function isNewline(c) { + return c === '\r' || c === '\n'; + } + + function isNumeric(c) { + return c >= '0' && c <= '9'; + } + + function isAlpha(c) { + return (c >= 'a' && c <= 'z') || + (c >= 'A' && c <= 'Z'); + } + + + function makeTokensObject(tokens, consumed, source) { + + var ignoreWhiteSpace = true; + matchTokenType("WHITESPACE"); // consume any initial whitespace + + function raiseError(tokens, error) { + _parser.raiseParseError(tokens, error); + } + + function requireOpToken(value) { + var token = matchOpToken(value); + if (token) { + return token; + } else { + raiseError(this, "Expected '" + value + "' but found '" + currentToken().value + "'"); + } + } + + function matchAnyOpToken(op1, op2, op3) { + for (var i = 0; i < arguments.length; i++) { + var opToken = arguments[i]; + var match = matchOpToken(opToken); + if (match) { + return match; + } + } + } + + function matchOpToken(value) { + if (currentToken() && currentToken().op && currentToken().value === value) { + return consumeToken(); + } + } + + function requireTokenType(type1, type2, type3, type4) { + var token = matchTokenType(type1, type2, type3, type4); + if (token) { + return token; + } else { + raiseError(this, "Expected one of " + JSON.stringify([type1, type2, type3])); + } + } + + function matchTokenType(type1, type2, type3, type4) { + if (currentToken() && currentToken().type && [type1, type2, type3, type4].indexOf(currentToken().type) >= 0) { + return consumeToken(); + } + } + + function requireToken(value, type) { + var token = matchToken(value, type); + if (token) { + return token; + } else { + raiseError(this, "Expected '" + value + "' but found '" + currentToken().value + "'"); + } + } + + function matchToken(value, type) { + var type = type || "IDENTIFIER"; + if (currentToken() && currentToken().value === value && currentToken().type === type) { + return consumeToken(); + } + } + + function consumeToken() { + var match = tokens.shift(); + consumed.push(match); + if(ignoreWhiteSpace) { + matchTokenType("WHITESPACE"); // consume any whitespace until the next token + } + return match; + } + + function consumeUntilWhitespace() { + var tokenList = []; + ignoreWhiteSpace = false; + while (currentToken() && currentToken().type !== "WHITESPACE") { + tokenList.push(consumeToken()); + } + ignoreWhiteSpace = true; + return tokenList; + } + + function hasMore() { + return tokens.length > 0; + } + + function currentToken() { + return tokens[0]; + } + + return { + matchAnyOpToken: matchAnyOpToken, + matchOpToken: matchOpToken, + requireOpToken: requireOpToken, + matchTokenType: matchTokenType, + requireTokenType: requireTokenType, + consumeToken: consumeToken, + matchToken: matchToken, + requireToken: requireToken, + list: tokens, + source: source, + hasMore: hasMore, + currentToken: currentToken, + consumeUntilWhitespace: consumeUntilWhitespace + } + } + + function tokenize(string) { + var source = string; + var tokens = []; + var position = 0; + var column = 0; + var line = 1; + var lastToken = ""; + + while (position < source.length) { + if (currentChar() === "-" && nextChar() === "-") { + consumeComment(); + } else { + if (isWhitespace(currentChar())) { + tokens.push(consumeWhitespace()); + } else if (!possiblePrecedingSymbol() && currentChar() === "." && isAlpha(nextChar())) { + tokens.push(consumeClassReference()); + } else if (!possiblePrecedingSymbol() && currentChar() === "#" && isAlpha(nextChar())) { + tokens.push(consumeIdReference()); + } else if (isAlpha(currentChar())) { + tokens.push(consumeIdentifier()); + } else if (isNumeric(currentChar())) { + tokens.push(consumeNumber()); + } else if (currentChar() === '"' || currentChar() === "'") { + tokens.push(consumeString()); + } else if (OP_TABLE[currentChar()]) { + tokens.push(consumeOp()); + } else { + if (position < source.length) { + throw Error("Unknown token: " + currentChar() + " "); + } + } + } + } + + return makeTokensObject(tokens, [], source); + + function makeOpToken(type, value) { + var token = makeToken(type, value); + token.op = true; + return token; + } + + function makeToken(type, value) { + return { + type: type, + value: value, + start: position, + end: position + 1, + column: column, + line: line + }; + } + + function consumeComment() { + while (currentChar() && !isNewline(currentChar())) { + consumeChar(); + } + consumeChar(); + } + + function consumeClassReference() { + var classRef = makeToken("CLASS_REF"); + var value = consumeChar(); + while (isValidCSSClassChar(currentChar())) { + value += consumeChar(); + } + classRef.value = value; + classRef.end = position; + return classRef; + } + + + function consumeIdReference() { + var idRef = makeToken("ID_REF"); + var value = consumeChar(); + while (isValidCSSIDChar(currentChar())) { + value += consumeChar(); + } + idRef.value = value; + idRef.end = position; + return idRef; + } + + function consumeIdentifier() { + var identifier = makeToken("IDENTIFIER"); + var value = consumeChar(); + while (isAlpha(currentChar())) { + value += consumeChar(); + } + identifier.value = value; + identifier.end = position; + return identifier; + } + + function consumeNumber() { + var number = makeToken("NUMBER"); + var value = consumeChar(); + while (isNumeric(currentChar())) { + value += consumeChar(); + } + if (currentChar() === ".") { + value += consumeChar(); + } + while (isNumeric(currentChar())) { + value += consumeChar(); + } + number.value = value; + number.end = position; + return number; + } + + function consumeOp() { + var value = consumeChar(); // consume leading char + while (currentChar() && OP_TABLE[value + currentChar()]) { + value += consumeChar(); + } + var op = makeOpToken(OP_TABLE[value], value); + op.value = value; + op.end = position; + return op; + } + + function consumeString() { + var string = makeToken("STRING"); + var startChar = consumeChar(); // consume leading quote + var value = ""; + while (currentChar() && currentChar() !== startChar) { + if (currentChar() === "\\") { + consumeChar(); // consume escape char and move on + } + value += consumeChar(); + } + if (currentChar() !== startChar) { + throw Error("Unterminated string at " + positionString(string)); + } else { + consumeChar(); // consume final quote + } + string.value = value; + string.end = position; + return string; + } + + function currentChar() { + return source.charAt(position); + } + + function nextChar() { + return source.charAt(position + 1); + } + + function consumeChar() { + lastToken = currentChar(); + position++; + column++; + return lastToken; + } + + function possiblePrecedingSymbol() { + return isAlpha(lastToken) || isNumeric(lastToken) || lastToken === ")" || lastToken === "}" || lastToken === "]" + } + + function consumeWhitespace() { + var whitespace = makeToken("WHITESPACE"); + var value = ""; + while (currentChar() && isWhitespace(currentChar())) { + if (isNewline(currentChar())) { + column = 0; + line++; + } + value += consumeChar(); + } + whitespace.value = value; + whitespace.end = position; + return whitespace; + } + } + + return { + tokenize: tokenize + } + }(); + + //----------------------------------------------- + // Parser + //----------------------------------------------- + var _parser = function () { + + var GRAMMAR = {} + + function addGrammarElement(name, definition) { + GRAMMAR[name] = definition; + } + + function createParserContext(tokens) { + var currentToken = tokens.currentToken(); + var source = tokens.source; + var lines = source.split("\n"); + var line = currentToken ? currentToken.line - 1 : lines.length - 1; + var contextLine = lines[line]; + var offset = currentToken ? currentToken.column : contextLine.length - 1; + return contextLine + "\n" + " ".repeat(offset) + "^^\n\n"; + } + + function raiseParseError(tokens, message) { + message = (message || "Unexpected Token : " + tokens.currentToken().value) + "\n\n" + + createParserContext(tokens); + var error = new Error(message); + error.tokens = tokens; + throw error + } + + function parseElement(type, tokens, root) { + var expressionDef = GRAMMAR[type]; + if (expressionDef) return expressionDef(_parser, tokens, root); + } + + function parseAnyOf(types, tokens) { + for (var i = 0; i < types.length; i++) { + var type = types[i]; + var expression = parseElement(type, tokens); + if (expression) { + return expression; + } + } + } + + function parseHyperScript(tokens) { + return parseElement("hyperscript", tokens) + } + + function transpile(node, defaultVal) { + if (node == null) { + return defaultVal; + } + var src = node.transpile(); + if (node.next) { + return src + "\n" + transpile(node.next) + } else { + return src; + } + } + + return { + // parser API + parseElement: parseElement, + parseAnyOf: parseAnyOf, + parseHyperScript: parseHyperScript, + raiseParseError: raiseParseError, + addGrammarElement: addGrammarElement, + transpile: transpile + } + }(); + + //----------------------------------------------- + // Runtime + //----------------------------------------------- + var _runtime = function () { + var SCRIPT_ATTRIBUTES = ["_", "script", "data-script"]; + + function matchesSelector(elt, selector) { + // noinspection JSUnresolvedVariable + var matchesFunction = elt.matches || + elt.matchesSelector || elt.msMatchesSelector || elt.mozMatchesSelector + || elt.webkitMatchesSelector || elt.oMatchesSelector; + return matchesFunction && matchesFunction.call(elt, selector); + } + + function makeEvent(eventName, detail) { + var evt; + if (window.CustomEvent && typeof window.CustomEvent === 'function') { + evt = new CustomEvent(eventName, {bubbles: true, cancelable: true, detail: detail}); + } else { + evt = document.createEvent('CustomEvent'); + evt.initCustomEvent(eventName, true, true, detail); + } + return evt; + } + + function triggerEvent(elt, eventName, detail) { + var detail = detail || {}; + detail["sentBy"] = elt; + var event = makeEvent(eventName, detail); + var eventResult = elt.dispatchEvent(event); + return eventResult; + } + + function forEach(arr, func) { + if (arr.length) { + for (var i = 0; i < arr.length; i++) { + func(arr[i]); + } + } else { + func(arr); + } + } + + function evalTarget(root, path) { + if (root.length) { + var last = root; + } else { + var last = [root]; + } + + while (path.length > 0) { + var prop = path.shift(); + var next = [] + // flat map + for (var i = 0; i < last.length; i++) { + var element = last[i]; + var nextVal = element[prop]; + if (nextVal && nextVal.length) { + next = next.concat(nextVal); + } else { + next.push(nextVal); + } + } + last = next; + } + + return last; + } + + function getScript(elt) { + for (var i = 0; i < SCRIPT_ATTRIBUTES.length; i++) { + var scriptAttribute = SCRIPT_ATTRIBUTES[i]; + if (elt.hasAttribute && elt.hasAttribute(scriptAttribute)) { + return elt.getAttribute(scriptAttribute) + } + } + return null; + } + + function applyEventListeners(hypeScript, elt) { + forEach(hypeScript.eventListeners, function (eventListener) { + eventListener(elt); + }); + } + + function setScriptAttrs(values) { + SCRIPT_ATTRIBUTES = values; + } + + function getScriptSelector() { + return SCRIPT_ATTRIBUTES.map(function (attribute) { + return "[" + attribute + "]"; + }).join(", "); + } + + function isType(o, type) { + return Object.prototype.toString.call(o) === "[object " + type + "]"; + } + + function evaluate(typeOrSrc, srcOrCtx, ctxArg) { + if (isType(srcOrCtx, "Object")) { + var src = typeOrSrc; + var ctx = srcOrCtx; + var type = "expression" + } else if (isType(srcOrCtx, "String")) { + var src = srcOrCtx; + var type = typeOrSrc + var ctx = ctxArg; + } else { + var src = typeOrSrc; + var ctx = {}; + var type = "expression"; + } + ctx = ctx || {}; + var compiled = _parser.parseElement(type, _lexer.tokenize(src) ).transpile(); + var evalString = "(function(" + Object.keys(ctx).join(",") + "){return " + compiled + "})"; + var args = Object.keys(ctx).map(function (key) { + return ctx[key] + }); + return eval(evalString).apply(null, args); + } + + function initElement(elt) { + var src = getScript(elt); + if (src) { + var tokens = _lexer.tokenize(src); + var hyperScript = _parser.parseHyperScript(tokens); + var transpiled = _parser.transpile(hyperScript); + if (elt.getAttribute('debug') === "true") { + console.log(transpiled); + } + var hyperscriptObj = eval(transpiled); + hyperscriptObj.applyEventListenersTo(elt); + } + } + + function ajax(method, url, callback, data) { + var xhr = new XMLHttpRequest(); + xhr.onload = function() { + callback(this.response, xhr); + }; + xhr.open(method, url); + xhr.send(JSON.stringify(data)); + } + + function typeCheck(value, typeString, nullOk) { + if (value == null && nullOk) { + return value; + } + var typeName = Object.prototype.toString.call(value).slice(8, -1); + var typeCheckValue = value && typeName === typeString; + if (typeCheckValue) { + return value; + } else { + throw new Error("Typecheck failed! Expected: " + typeString + ", Found: " + typeName); + } + } + + return { + typeCheck: typeCheck, + forEach: forEach, + evalTarget: evalTarget, + triggerEvent: triggerEvent, + matchesSelector: matchesSelector, + getScript: getScript, + applyEventListeners: applyEventListeners, + setScriptAttrs: setScriptAttrs, + initElement: initElement, + evaluate: evaluate, + getScriptSelector: getScriptSelector, + ajax: ajax, + } + }(); + + //----------------------------------------------- + // Expressions + //----------------------------------------------- + + _parser.addGrammarElement("parenthesized", function (parser, tokens) { + if (tokens.matchOpToken('(')) { + var expr = parser.parseElement("expression", tokens); + tokens.requireOpToken(")"); + return { + type: "parenthesized", + expr: expr, + transpile: function () { + return "(" + parser.transpile(expr) + ")"; + } + } + } + }) + + _parser.addGrammarElement("string", function (parser, tokens) { + var stringToken = tokens.matchTokenType('STRING'); + if (stringToken) { + return { + type: "string", + token: stringToken, + transpile: function () { + if (stringToken.value.indexOf("'") === 0) { + return "'" + stringToken.value + "'"; + } else { + return '"' + stringToken.value + '"'; + } + } + } + } + }) + + _parser.addGrammarElement("nakedString", function (parser, tokens) { + if (tokens.hasMore()) { + var tokenArr = tokens.consumeUntilWhitespace(); + tokens.matchTokenType("WHITESPACE"); + return { + type: "nakedString", + tokens: tokenArr, + transpile: function () { + return "'" + tokenArr.map(function(t){return t.value}).join("") + "'"; + } + } + } + }) + + _parser.addGrammarElement("number", function (parser, tokens) { + var number = tokens.matchTokenType('NUMBER'); + if (number) { + var numberToken = number; + var value = parseFloat(number.value) + return { + type: "number", + value: value, + numberToken: numberToken, + transpile: function () { + return numberToken.value; + } + } + } + }) + + _parser.addGrammarElement("idRef", function (parser, tokens) { + var elementId = tokens.matchTokenType('ID_REF'); + if (elementId) { + return { + type: "idRef", + value: elementId.value.substr(1), + transpile: function () { + return "document.getElementById('" + this.value + "')" + } + }; + } + }) + + _parser.addGrammarElement("classRef", function (parser, tokens) { + var classRef = tokens.matchTokenType('CLASS_REF'); + if (classRef) { + return { + type: "classRef", + value: classRef.value, + className: function () { + return this.value.substr(1); + }, + transpile: function () { + return "document.querySelectorAll('" + this.value + "')" + } + }; + } + }) + + _parser.addGrammarElement("attributeRef", function (parser, tokens) { + if (tokens.matchOpToken("[")) { + var name = tokens.matchTokenType("IDENTIFIER"); + var value = null; + if (tokens.matchOpToken("=")) { + value = parser.parseElement("expression", tokens); + } + tokens.requireOpToken("]"); + return { + type: "attribute_expression", + name: name.value, + value: value, + transpile: function () { + if (this.value) { + return "({name: '" + this.name + "', value: " + parser.transpile(this.value) + "})"; + } else { + return "({name: '" + this.name + "'})"; + } + } + } + } + }) + + _parser.addGrammarElement("objectLiteral", function (parser, tokens) { + if (tokens.matchOpToken("{")) { + var fields = [] + if (!tokens.matchOpToken("}")) { + do { + var name = tokens.requireTokenType("IDENTIFIER"); + tokens.requireOpToken(":"); + var value = parser.parseElement("expression", tokens); + fields.push({name: name, value: value}); + } while (tokens.matchOpToken(",")) + tokens.requireOpToken("}"); + } + return { + type: "objectLiteral", + fields: fields, + transpile: function () { + return "({" + fields.map(function (field) { + return field.name.value + ":" + parser.transpile(field.value) + }).join(", ") + "})"; + } + } + } + + + }) + + _parser.addGrammarElement("namedArgumentList", function (parser, tokens) { + if (tokens.matchOpToken("(")) { + var fields = [] + if (!tokens.matchOpToken(")")) { + do { + var name = tokens.requireTokenType("IDENTIFIER"); + tokens.requireOpToken(":"); + var value = parser.parseElement("expression", tokens); + fields.push({name: name, value: value}); + } while (tokens.matchOpToken(",")) + tokens.requireOpToken(")"); + } + return { + type: "namedArgumentList", + fields: fields, + transpile: function () { + return "({_namedArgList_:true, " + fields.map(function (field) { + return field.name.value + ":" + parser.transpile(field.value) + }).join(", ") + "})"; + } + } + } + + + }) + + _parser.addGrammarElement("symbol", function (parser, tokens) { + var identifier = tokens.matchTokenType('IDENTIFIER'); + if (identifier) { + return { + type: "symbol", + name: identifier.value, + transpile: function () { + return identifier.value; + } + }; + } + }); + + _parser.addGrammarElement("implicitMeTarget", function (parser, tokens) { + return { + type: "implicitMeTarget", + transpile: function () { + return "[me]" + } + }; + }); + + _parser.addGrammarElement("implicitAllTarget", function (parser, tokens) { + return { + type: "implicitAllTarget", + transpile: function () { + return 'document.querySelectorAll("*")'; + } + }; + }); + + _parser.addGrammarElement("millisecondLiteral", function (parser, tokens) { + var number = tokens.requireTokenType(tokens, "NUMBER"); + var factor = 1; + if (tokens.matchToken("s")) { + factor = 1000; + } else if (tokens.matchToken("ms")) { + // do nothing + } + return { + type: "millisecondLiteral", + number: number, + factor: factor, + transpile: function () { + return factor * parseFloat(this.number.value); + } + }; + }); + + _parser.addGrammarElement("boolean", function (parser, tokens) { + var booleanLiteral = tokens.matchToken("true") || tokens.matchToken("false"); + if (booleanLiteral) { + return { + type: "boolean", + transpile: function () { + return booleanLiteral.value; + } + } + } + }); + + _parser.addGrammarElement("null", function (parser, tokens) { + if (tokens.matchToken('null')) { + return { + type: "null", + transpile: function () { + return "null"; + } + } + } + }); + + _parser.addGrammarElement("arrayLiteral", function (parser, tokens) { + if (tokens.matchOpToken('[')) { + var values = []; + if (!tokens.matchOpToken(']')) { + do { + var expr = parser.parseElement("expression", tokens); + if (expr == null) { + parser.raiseParseError(tokens, "Expected an expression"); + } + values.push(expr); + } while(tokens.matchOpToken(",")) + tokens.requireOpToken("]"); + } + return { + type: "arrayLiteral", + values:values, + transpile: function () { + return "[" + values.map(function(v){ return parser.transpile(v) }).join(", ") + "]"; + } + } + } + }); + + _parser.addGrammarElement("blockLiteral", function (parser, tokens) { + if (tokens.matchOpToken('\\')) { + var args = [] + var arg1 = tokens.matchTokenType("IDENTIFIER"); + if (arg1) { + args.push(arg1); + while (tokens.matchOpToken(",")) { + args.push(tokens.requireTokenType("IDENTIFIER")); + } + } + // TODO compound op token + tokens.requireOpToken("-"); + tokens.requireOpToken(">"); + var expr = parser.parseElement("expression", tokens); + if (expr == null) { + parser.raiseParseError(tokens, "Expected an expression"); + } + return { + type: "blockLiteral", + args: args, + expr: expr, + transpile: function () { + return "function(" + args.map(function (arg) { + return arg.value + }).join(", ") + "){ return " + + parser.transpile(expr) + " }"; + } + } + } + }); + + _parser.addGrammarElement("leaf", function (parser, tokens) { + return parser.parseAnyOf(["parenthesized", "boolean", "null", "string", "number", "idRef", "classRef", "symbol", "propertyRef", "objectLiteral", "arrayLiteral", "blockLiteral"], tokens) + }); + + _parser.addGrammarElement("propertyAccess", function (parser, tokens, root) { + if (tokens.matchOpToken(".")) { + var prop = tokens.requireTokenType("IDENTIFIER"); + var propertyAccess = { + type: "propertyAccess", + root: root, + prop: prop, + transpile: function () { + return parser.transpile(root) + "." + prop.value; + } + }; + return _parser.parseElement("indirectExpression", tokens, propertyAccess); + } + }); + + _parser.addGrammarElement("functionCall", function (parser, tokens, root) { + if (tokens.matchOpToken("(")) { + var args = []; + do { + args.push(parser.parseElement("expression", tokens)); + } while (tokens.matchOpToken(",")) + tokens.requireOpToken(")"); + var functionCall = { + type: "functionCall", + root: root, + args: args, + transpile: function () { + return parser.transpile(root) + "(" + args.map(function (arg) { + return parser.transpile(arg) + }).join(",") + ")" + } + }; + return _parser.parseElement("indirectExpression", tokens, functionCall); + } + }); + + _parser.addGrammarElement("indirectExpression", function (parser, tokens, root) { + var propAccess = parser.parseElement("propertyAccess", tokens, root); + if (propAccess) { + return propAccess; + } + + var functionCall = parser.parseElement("functionCall", tokens, root); + if (functionCall) { + return functionCall; + } + + return root; + }); + + _parser.addGrammarElement("primaryExpression", function (parser, tokens) { + var leaf = parser.parseElement("leaf", tokens); + if (leaf) { + return parser.parseElement("indirectExpression", tokens, leaf); + } + parser.raiseParseError(tokens, "Unexpected value: " + tokens.currentToken().value); + }); + + _parser.addGrammarElement("postfixExpression", function (parser, tokens) { + var root = parser.parseElement("primaryExpression", tokens); + if (tokens.matchOpToken(":")) { + var typeName = tokens.requireTokenType("IDENTIFIER"); + var nullOk = !tokens.matchOpToken("!"); + return { + type: "typeCheck", + typeName: typeName, + root: root, + nullOk: nullOk, + transpile: function () { + return "_hyperscript.runtime.typeCheck(" + parser.transpile(root) + ", '" + typeName.value + "', " + nullOk + ")"; + } + } + } else { + return root; + } + }); + + _parser.addGrammarElement("logicalNot", function (parser, tokens) { + if (tokens.matchToken("not")) { + var root = parser.parseElement("unaryExpression", tokens); + return { + type: "logicalNot", + root: root, + transpile: function () { + return "!" + parser.transpile(root); + } + }; + } + }); + + _parser.addGrammarElement("negativeNumber", function (parser, tokens) { + if (tokens.matchOpToken("-")) { + var root = parser.parseElement("unaryExpression", tokens); + return { + type: "negativeNumber", + root: root, + transpile: function () { + return "-" + parser.transpile(root); + } + }; + } + }); + + _parser.addGrammarElement("unaryExpression", function (parser, tokens) { + return parser.parseAnyOf(["logicalNot", "negativeNumber", "postfixExpression"], tokens); + }); + + _parser.addGrammarElement("mathOperator", function (parser, tokens) { + var expr = parser.parseElement("unaryExpression", tokens); + var mathOp, initialMathOp = null; + mathOp = tokens.matchAnyOpToken("+", "-", "*", "/", "%") + while (mathOp) { + initialMathOp = initialMathOp || mathOp; + if(initialMathOp.value !== mathOp.value) { + parser.raiseParseError(tokens, "You must parenthesize math operations with different operators") + } + var rhs = parser.parseElement("unaryExpression", tokens); + expr = { + type: "mathOperator", + operator: mathOp.value, + lhs: expr, + rhs: rhs, + transpile: function () { + return parser.transpile(this.lhs) + " " + this.operator + " " + parser.transpile(this.rhs); + } + } + mathOp = tokens.matchAnyOpToken("+", "-", "*", "/", "%") + } + return expr; + }); + + _parser.addGrammarElement("mathExpression", function (parser, tokens) { + return parser.parseAnyOf(["mathOperator", "unaryExpression"], tokens); + }); + + _parser.addGrammarElement("comparisonOperator", function (parser, tokens) { + var expr = parser.parseElement("mathExpression", tokens); + var comparisonOp, initialComparisonOp = null; + comparisonOp = tokens.matchAnyOpToken("<", ">", "<=", ">=", "==", "===", "!=", "!==") + while (comparisonOp) { + initialComparisonOp = initialComparisonOp || comparisonOp; + if(initialComparisonOp.value !== comparisonOp.value) { + parser.raiseParseError(tokens, "You must parenthesize comparison operations with different operators") + } + var rhs = parser.parseElement("mathExpression", tokens); + expr = { + type: "comparisonOperator", + operator: comparisonOp.value, + lhs: expr, + rhs: rhs, + transpile: function () { + return parser.transpile(this.lhs) + " " + this.operator + " " + parser.transpile(this.rhs); + } + } + comparisonOp = tokens.matchAnyOpToken("<", ">", "<=", ">=", "==", "===", "!=", "!==") + } + return expr; + }); + + _parser.addGrammarElement("comparisonExpression", function (parser, tokens) { + return parser.parseAnyOf(["comparisonOperator", "mathExpression"], tokens); + }); + + _parser.addGrammarElement("logicalOperator", function (parser, tokens) { + var expr = parser.parseElement("comparisonExpression", tokens); + var logicalOp, initialLogicalOp = null; + logicalOp = tokens.matchToken("and") || tokens.matchToken("or"); + while (logicalOp) { + initialLogicalOp = initialLogicalOp || logicalOp; + if(initialLogicalOp.value !== logicalOp.value) { + parser.raiseParseError(tokens, "You must parenthesize logical operations with different operators") + } + var rhs = parser.parseElement("comparisonExpression", tokens); + expr = { + type: "logicalOperator", + operator: logicalOp.value, + lhs: expr, + rhs: rhs, + transpile: function () { + return parser.transpile(this.lhs) + " " + (this.operator === "and" ? " && " : " || ") + " " + parser.transpile(this.rhs); + } + } + logicalOp = tokens.matchToken("and") || tokens.matchToken("or"); + } + return expr; + }); + + _parser.addGrammarElement("logicalExpression", function (parser, tokens) { + return parser.parseAnyOf(["logicalOperator", "mathExpression"], tokens); + }); + + _parser.addGrammarElement("expression", function (parser, tokens) { + return parser.parseElement("logicalExpression", tokens); + }); + + _parser.addGrammarElement("target", function (parser, tokens) { + var root = parser.parseAnyOf(["symbol", "classRef", "idRef"], tokens); + if (root == null) { + parser.raiseParseError(tokens, "Expected a valid target expression"); + } + + var propPath = [] + while (tokens.matchOpToken(".")) { + propPath.push(tokens.requireTokenType("IDENTIFIER").value) + } + + return { + type: "target", + propPath: propPath, + root: root, + transpile: function () { + return "_hyperscript.runtime.evalTarget(" + parser.transpile(root) + ", [" + propPath.map(function (prop) { + return "\"" + prop + "\"" + }).join(", ") + "])"; + } + }; + }); + + _parser.addGrammarElement("command", function (parser, tokens) { + return parser.parseAnyOf(["onCmd", "addCmd", "removeCmd", "toggleCmd", "waitCmd", "sendCmd", "triggerCmd", + "takeCmd", "logCmd", "callCmd", "putCmd", "setCmd", "ifCmd", "ajaxCmd"], tokens); + }) + + _parser.addGrammarElement("commandList", function (parser, tokens) { + var cmd = parser.parseElement("command", tokens); + if (cmd) { + tokens.matchToken("then"); + cmd.next = parser.parseElement("commandList", tokens); + return cmd; + } + }) + + _parser.addGrammarElement("hyperscript", function (parser, tokens) { + var eventListeners = [] + do { + eventListeners.push(parser.parseElement("eventListener", tokens)); + } while (tokens.matchToken("end") && tokens.hasMore()) + if (tokens.hasMore()) { + parser.raiseParseError(tokens); + } + return { + type: "hyperscript", + eventListeners: eventListeners, + transpile: function () { + return "(function(){\n" + + "var eventListeners = []\n" + + eventListeners.map(function (el) { + return " eventListeners.push(" + parser.transpile(el) + ");\n" + }).join("") + + " function applyEventListenersTo(elt) { _hyperscript.runtime.applyEventListeners(this, elt) }\n" + + " return {eventListeners:eventListeners, applyEventListenersTo:applyEventListenersTo}\n" + + "})()" + } + }; + }) + + + _parser.addGrammarElement("eventListener", function (parser, tokens) { + tokens.requireToken("on"); + var on = parser.parseElement("dotOrColonPath", tokens); + if (on == null) { + parser.raiseParseError(tokens, "Expected event name") + } + if (tokens.matchToken("from")) { + var from = parser.parseElement("target", tokens); + if (from == null) { + parser.raiseParseError(tokens, "Expected target value") + } + } else { + var from = parser.parseElement("implicitMeTarget", tokens); + } + + var args = []; + if (tokens.matchOpToken("(")) { + do { + args.push(tokens.requireTokenType('IDENTIFIER')); + } while (tokens.matchOpToken(",")) + tokens.requireOpToken(')') + } + + var start = parser.parseElement("commandList", tokens); + var eventListener = { + type: "eventListener", + on: on, + from: from, + start: start, + transpile: function () { + return "(function(me){" + + "var my = me;\n" + + "_hyperscript.runtime.forEach( " + parser.transpile(from) + ", function(target){\n" + + " target.addEventListener('" + parser.transpile(on) + "', function(event){\n" + + args.map(function(arg){return "var " + arg.value + " = event.detail." + arg.value + ";"}).join("\n") + "\n" + + parser.transpile(start) + + " })\n" + + "})\n" + + "})" + } + }; + return eventListener; + }); + + _parser.addGrammarElement("addCmd", function (parser, tokens) { + if (tokens.matchToken("add")) { + var classRef = parser.parseElement("classRef", tokens); + var attributeRef = null; + if (classRef == null) { + attributeRef = parser.parseElement("attributeRef", tokens); + if (attributeRef == null) { + parser.raiseParseError(tokens, "Expected either a class reference or attribute expression") + } + } + + if (tokens.matchToken("to")) { + var to = parser.parseElement("target", tokens); + } else { + var to = parser.parseElement("implicitMeTarget"); + } + + return { + type: "addCmd", + classRef: classRef, + attributeRef: attributeRef, + to: to, + transpile: function () { + if (this.classRef) { + return "_hyperscript.runtime.forEach( " + parser.transpile(to) + ", function (target) {" + + " target.classList.add('" + classRef.className() + "')" + + "})"; + } else { + return "_hyperscript.runtime.forEach( " + parser.transpile(to) + ", function (target) {" + + " target.setAttribute('" + attributeRef.name + "', " + parser.transpile(attributeRef) + ".value)" + + "})"; + } + } + } + } + }); + + _parser.addGrammarElement("removeCmd", function (parser, tokens) { + if (tokens.matchToken("remove")) { + var classRef = parser.parseElement("classRef", tokens); + var attributeRef = null; + var elementExpr = null; + if (classRef == null) { + attributeRef = parser.parseElement("attributeRef", tokens); + if (attributeRef == null) { + elementExpr = parser.parseElement("expression", tokens) + if (elementExpr == null) { + parser.raiseParseError(tokens, "Expected either a class reference, attribute expression or value expression"); + } + } + } + if (tokens.matchToken("from")) { + var from = parser.parseElement("target", tokens); + } else { + var from = parser.parseElement("implicitMeTarget"); + } + + return { + type: "removeCmd", + classRef: classRef, + attributeRef: attributeRef, + elementExpr: elementExpr, + from: from, + transpile: function () { + if (this.elementExpr) { + return "_hyperscript.runtime.forEach( " + parser.transpile(elementExpr) + ", function (target) {" + + " target.parentElement.removeChild(target)" + + "})"; + } else { + if (this.classRef) { + return "_hyperscript.runtime.forEach( " + parser.transpile(from) + ", function (target) {" + + " target.classList.remove('" + classRef.className() + "')" + + "})"; + } else { + return "_hyperscript.runtime.forEach( " + parser.transpile(from) + ", function (target) {" + + " target.removeAttribute('" + attributeRef.name + "')" + + "})"; + } + } + } + } + } + }); + + _parser.addGrammarElement("toggleCmd", function (parser, tokens) { + if (tokens.matchToken("toggle")) { + var classRef = parser.parseElement("classRef", tokens); + var attributeRef = null; + if (classRef == null) { + attributeRef = parser.parseElement("attributeRef", tokens); + if (attributeRef == null) { + parser.raiseParseError(tokens, "Expected either a class reference or attribute expression") + } + } + if (tokens.matchToken("on")) { + var on = parser.parseElement("target", tokens); + } else { + var on = parser.parseElement("implicitMeTarget"); + } + return { + type: "toggleCmd", + classRef: classRef, + attributeRef: attributeRef, + on: on, + transpile: function () { + if (this.classRef) { + return "_hyperscript.runtime.forEach( " + parser.transpile(on) + ", function (target) {" + + " target.classList.toggle('" + classRef.className() + "')" + + "})"; + } else { + return "_hyperscript.runtime.forEach( " + parser.transpile(on) + ", function (target) {" + + " if(target.hasAttribute('" + attributeRef.name + "')) {\n" + + " target.removeAttribute('" + attributeRef.name + "');\n" + + " } else { \n" + + " target.setAttribute('" + attributeRef.name + "', " + parser.transpile(attributeRef) + ".value)" + + " }" + + "})"; + } + } + } + } + }) + + _parser.addGrammarElement("waitCmd", function (parser, tokens) { + if (tokens.matchToken("wait")) { + var time = parser.parseElement('millisecondLiteral', tokens); + return { + type: "waitCmd", + time: time, + transpile: function () { + var capturedNext = this.next; + delete this.next; + return "setTimeout(function () { " + parser.transpile(capturedNext) + " }, " + parser.transpile(this.time) + ")"; + } + } + } + }) + + // TODO - colon path needs to eventually become part of ruby-style symbols + _parser.addGrammarElement("dotOrColonPath", function (parser, tokens) { + var root = tokens.matchTokenType("IDENTIFIER"); + if (root) { + var path = [root.value]; + + var separator = tokens.matchOpToken(".") || tokens.matchOpToken(":"); + if (separator) { + do { + path.push(tokens.requireTokenType("IDENTIFIER").value); + } while (tokens.matchOpToken(separator.value)) + } + + return { + type: "dotOrColonPath", + path: path, + transpile: function () { + return path.join(separator ? separator.value : ""); + } + } + } + }); + + _parser.addGrammarElement("sendCmd", function (parser, tokens) { + if (tokens.matchToken("send")) { + + var eventName = parser.parseElement("dotOrColonPath", tokens); + + var details = parser.parseElement("namedArgumentList", tokens); + if (tokens.matchToken("to")) { + var to = parser.parseElement("target", tokens); + } else { + var to = parser.parseElement("implicitMeTarget"); + } + + return { + type: "sendCmd", + eventName: eventName, + details: details, + to: to, + transpile: function () { + return "_hyperscript.runtime.forEach( " + parser.transpile(to) + ", function (target) {" + + " _hyperscript.runtime.triggerEvent(target, '" + parser.transpile(eventName) + "'," + parser.transpile(details, "{}") + ")" + + "})"; + } + } + } + }) + + _parser.addGrammarElement("triggerCmd", function (parser, tokens) { + if (tokens.matchToken("trigger")) { + + var eventName = parser.parseElement("dotOrColonPath", tokens); + var details = parser.parseElement("namedArgumentList", tokens); + + return { + type: "triggerCmd", + eventName: eventName, + details: details, + transpile: function () { + return "_hyperscript.runtime.triggerEvent(me, '" + parser.transpile(eventName) + "'," + parser.transpile(details, "{}") + ");"; + } + } + } + }) + + _parser.addGrammarElement("takeCmd", function (parser, tokens) { + if (tokens.matchToken("take")) { + var classRef = tokens.requireTokenType(tokens, "CLASS_REF"); + + if (tokens.matchToken("from")) { + var from = parser.parseElement("target", tokens); + } else { + var from = parser.parseElement("implicitAllTarget") + } + + if (tokens.matchToken("for")) { + var forElt = parser.parseElement("target", tokens); + } else { + var forElt = parser.parseElement("implicitMeTarget") + } + + return { + type: "takeCmd", + classRef: classRef, + from: from, + forElt: forElt, + transpile: function () { + var clazz = this.classRef.value.substr(1); + return " _hyperscript.runtime.forEach(" + parser.transpile(from) + ", function (target) { target.classList.remove('" + clazz + "') }); " + + "_hyperscript.runtime.forEach( " + parser.transpile(forElt) + ", function (target) {" + + " target.classList.add('" + clazz + "')" + + "})"; + } + } + } + }) + + _parser.addGrammarElement("logCmd", function (parser, tokens) { + if (tokens.matchToken("log")) { + var exprs = [parser.parseElement("expression", tokens)]; + while (tokens.matchOpToken(",")) { + exprs.push(parser.parseElement("expression", tokens)); + } + if (tokens.matchToken("with")) { + var withExpr = parser.parseElement("expression", tokens); + } + return { + type: "logCmd", + exprs: exprs, + withExpr: withExpr, + transpile: function () { + if (withExpr) { + return parser.transpile(withExpr) + "(" + exprs.map(function (expr) { + return parser.transpile(expr) + }).join(", ") + ")"; + } else { + return "console.log(" + exprs.map(function (expr) { + return parser.transpile(expr) + }).join(", ") + ")"; + } + } + }; + } + }) + + _parser.addGrammarElement("callCmd", function (parser, tokens) { + if (tokens.matchToken("call") || tokens.matchToken("get")) { + return { + type: "callCmd", + expr: parser.parseElement("expression", tokens), + transpile: function () { + return "var it = " + parser.transpile(this.expr); + } + } + } + }) + + _parser.addGrammarElement("putCmd", function (parser, tokens) { + if (tokens.matchToken("put")) { + + var value = parser.parseElement("expression", tokens); + + var operation = tokens.matchToken("into") || + tokens.matchToken("before") || + tokens.matchToken("after"); + + if (operation == null && tokens.matchToken("at")) { + operation = tokens.matchToken("start") || + tokens.matchToken("end"); + tokens.requireToken("of"); + } + + if (operation == null) { + parser.raiseParseError(tokens, "Expected one of 'into', 'before', 'at start of', 'at end of', 'after'"); + } + var target = parser.parseElement("target", tokens); + + var directWrite = target.propPath.length === 0 && operation.value === "into"; + var symbolWrite = directWrite && target.root.type === "symbol"; + if (directWrite && !symbolWrite) { + parser.raiseParseError(tokens, "Can only put directly into symbols, not references") + } + + return { + type: "putCmd", + target: target, + op: operation.value, + symbolWrite: symbolWrite, + value: value, + transpile: function () { + if (this.symbolWrite) { + return "var " + target.root.name + " = " + parser.transpile(value); + } else { + if (this.op === "into") { + var lastProperty = target.propPath.pop(); // steal last property for assignment + return "_hyperscript.runtime.forEach( " + parser.transpile(target) + ", function (target) {" + + " target." + lastProperty + "=" + parser.transpile(value) + + "})"; + } else if (this.op === "before") { + return "_hyperscript.runtime.forEach( " + parser.transpile(target) + ", function (target) {" + + " target.insertAdjacentHTML('beforebegin', " + parser.transpile(value) + ")" + + "})"; + } else if (this.op === "start") { + return "_hyperscript.runtime.forEach( " + parser.transpile(target) + ", function (target) {" + + " target.insertAdjacentHTML('afterbegin', " + parser.transpile(value) + ")" + + "})"; + } else if (this.op === "end") { + return "_hyperscript.runtime.forEach( " + parser.transpile(target) + ", function (target) {" + + " target.insertAdjacentHTML('beforeend', " + parser.transpile(value) + ")" + + "})"; + } else if (this.op === "after") { + return "_hyperscript.runtime.forEach( " + parser.transpile(target) + ", function (target) {" + + " target.insertAdjacentHTML('afterend', " + parser.transpile(value) + ")" + + "})"; + } + } + } + } + } + }) + + _parser.addGrammarElement("setCmd", function (parser, tokens) { + if (tokens.matchToken("set")) { + + var target = parser.parseElement("target", tokens); + + tokens.requireToken("to"); + + var value = parser.parseElement("expression", tokens); + + var directWrite = target.propPath.length === 0; + var symbolWrite = directWrite && target.root.type === "symbol"; + if (directWrite && !symbolWrite) { + parser.raiseParseError(tokens, "Can only put directly into symbols, not references") + } + + return { + type: "setCmd", + target: target, + symbolWrite: symbolWrite, + value: value, + transpile: function () { + if (this.symbolWrite) { + return "var " + target.root.name + " = " + parser.transpile(value); + } else { + var lastProperty = target.propPath.pop(); // steal last property for assignment + return "_hyperscript.runtime.forEach( " + parser.transpile(target) + ", function (target) {" + + " target." + lastProperty + "=" + parser.transpile(value) + + "})"; + } + } + } + } + }) + + _parser.addGrammarElement("ifCmd", function (parser, tokens) { + if (tokens.matchToken("if")) { + var expr = parser.parseElement("expression", tokens); + tokens.matchToken("then"); // optional 'then' + var trueBranch = parser.parseElement("commandList", tokens); + if (tokens.matchToken("else")) { + var falseBranch = parser.parseElement("commandList", tokens); + } + if (tokens.hasMore()) { + tokens.requireToken("end"); + } + return { + type: "ifCmd", + expr: expr, + trueBranch: trueBranch, + falseBranch: falseBranch, + transpile: function () { + return "if(" + parser.transpile(expr) + "){" + "" + parser.transpile(trueBranch) + "}" + + " else {" + parser.transpile(falseBranch, "") + "}" + + } + } + } + }) + + _parser.addGrammarElement("ajaxCmd", function (parser, tokens) { + if (tokens.matchToken("ajax")) { + var method = tokens.matchToken("GET") || tokens.matchToken("POST"); + if (method == null) { + parser.raiseParseError(tokens, "Requires either GET or POST"); + } + if (method.value !== "GET") { + if (!tokens.matchToken("to")) { + var data = parser.parseElement("expression", tokens); + tokens.requireToken("to"); + } + } + + var url = parser.parseElement("string", tokens); + if (url == null) { + var url = parser.parseElement("nakedString", tokens); + } + + return { + type: "requestCommand", + method: method, + transpile: function () { + var capturedNext = this.next; + delete this.next; + return "_hyperscript.runtime.ajax('" + method.value + "', " + + parser.transpile(url) + ", " + + "function(response, xhr){ " + parser.transpile(capturedNext) + " }," + + parser.transpile(data, "null") + ")"; + } + }; + } + }) + + //----------------------------------------------- + // API + //----------------------------------------------- + + function start(scriptAttrs) { + if (scriptAttrs) { + _runtime.setScriptAttrs(scriptAttrs); + } + var fn = function () { + var elements = document.querySelectorAll(_runtime.getScriptSelector()); + _runtime.forEach(elements, function (elt) { + init(elt); + }) + }; + if (document.readyState !== 'loading') { + fn(); + } else { + document.addEventListener('DOMContentLoaded', fn); + } + return true; + } + + function init(elt) { + _runtime.initElement(elt); + } + + function evaluate(str) { + return _runtime.evaluate(str); + } + + return { + lexer: _lexer, + parser: _parser, + runtime: _runtime, + evaluate: evaluate, + init: init, + start: start + } + } + )() +})); \ No newline at end of file diff --git a/www/test/0.0.8/test/lib/handlebars-v4.7.6.js b/www/test/0.0.8/test/lib/handlebars-v4.7.6.js new file mode 100644 index 00000000..05d9f614 --- /dev/null +++ b/www/test/0.0.8/test/lib/handlebars-v4.7.6.js @@ -0,0 +1,5210 @@ +/**! + + @license + handlebars v4.7.6 + +Copyright (C) 2011-2019 by Yehuda Katz + +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. + +*/ +(function webpackUniversalModuleDefinition(root, factory) { + if(typeof exports === 'object' && typeof module === 'object') + module.exports = factory(); + else if(typeof define === 'function' && define.amd) + define([], factory); + else if(typeof exports === 'object') + exports["Handlebars"] = factory(); + else + root["Handlebars"] = factory(); +})(this, function() { +return /******/ (function(modules) { // webpackBootstrap +/******/ // The module cache +/******/ var installedModules = {}; + +/******/ // The require function +/******/ function __webpack_require__(moduleId) { + +/******/ // Check if module is in cache +/******/ if(installedModules[moduleId]) +/******/ return installedModules[moduleId].exports; + +/******/ // Create a new module (and put it into the cache) +/******/ var module = installedModules[moduleId] = { +/******/ exports: {}, +/******/ id: moduleId, +/******/ loaded: false +/******/ }; + +/******/ // Execute the module function +/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); + +/******/ // Flag the module as loaded +/******/ module.loaded = true; + +/******/ // Return the exports of the module +/******/ return module.exports; +/******/ } + + +/******/ // expose the modules object (__webpack_modules__) +/******/ __webpack_require__.m = modules; + +/******/ // expose the module cache +/******/ __webpack_require__.c = installedModules; + +/******/ // __webpack_public_path__ +/******/ __webpack_require__.p = ""; + +/******/ // Load entry module and return exports +/******/ return __webpack_require__(0); +/******/ }) +/************************************************************************/ +/******/ ([ +/* 0 */ +/***/ (function(module, exports, __webpack_require__) { + + 'use strict'; + + var _interopRequireDefault = __webpack_require__(1)['default']; + + exports.__esModule = true; + + var _handlebarsRuntime = __webpack_require__(2); + + var _handlebarsRuntime2 = _interopRequireDefault(_handlebarsRuntime); + + // Compiler imports + + var _handlebarsCompilerAst = __webpack_require__(45); + + var _handlebarsCompilerAst2 = _interopRequireDefault(_handlebarsCompilerAst); + + var _handlebarsCompilerBase = __webpack_require__(46); + + var _handlebarsCompilerCompiler = __webpack_require__(51); + + var _handlebarsCompilerJavascriptCompiler = __webpack_require__(52); + + var _handlebarsCompilerJavascriptCompiler2 = _interopRequireDefault(_handlebarsCompilerJavascriptCompiler); + + var _handlebarsCompilerVisitor = __webpack_require__(49); + + var _handlebarsCompilerVisitor2 = _interopRequireDefault(_handlebarsCompilerVisitor); + + var _handlebarsNoConflict = __webpack_require__(44); + + var _handlebarsNoConflict2 = _interopRequireDefault(_handlebarsNoConflict); + + var _create = _handlebarsRuntime2['default'].create; + function create() { + var hb = _create(); + + hb.compile = function (input, options) { + return _handlebarsCompilerCompiler.compile(input, options, hb); + }; + hb.precompile = function (input, options) { + return _handlebarsCompilerCompiler.precompile(input, options, hb); + }; + + hb.AST = _handlebarsCompilerAst2['default']; + hb.Compiler = _handlebarsCompilerCompiler.Compiler; + hb.JavaScriptCompiler = _handlebarsCompilerJavascriptCompiler2['default']; + hb.Parser = _handlebarsCompilerBase.parser; + hb.parse = _handlebarsCompilerBase.parse; + hb.parseWithoutProcessing = _handlebarsCompilerBase.parseWithoutProcessing; + + return hb; + } + + var inst = create(); + inst.create = create; + + _handlebarsNoConflict2['default'](inst); + + inst.Visitor = _handlebarsCompilerVisitor2['default']; + + inst['default'] = inst; + + exports['default'] = inst; + module.exports = exports['default']; + +/***/ }), +/* 1 */ +/***/ (function(module, exports) { + + "use strict"; + + exports["default"] = function (obj) { + return obj && obj.__esModule ? obj : { + "default": obj + }; + }; + + exports.__esModule = true; + +/***/ }), +/* 2 */ +/***/ (function(module, exports, __webpack_require__) { + + 'use strict'; + + var _interopRequireWildcard = __webpack_require__(3)['default']; + + var _interopRequireDefault = __webpack_require__(1)['default']; + + exports.__esModule = true; + + var _handlebarsBase = __webpack_require__(4); + + var base = _interopRequireWildcard(_handlebarsBase); + + // Each of these augment the Handlebars object. No need to setup here. + // (This is done to easily share code between commonjs and browse envs) + + var _handlebarsSafeString = __webpack_require__(37); + + var _handlebarsSafeString2 = _interopRequireDefault(_handlebarsSafeString); + + var _handlebarsException = __webpack_require__(6); + + var _handlebarsException2 = _interopRequireDefault(_handlebarsException); + + var _handlebarsUtils = __webpack_require__(5); + + var Utils = _interopRequireWildcard(_handlebarsUtils); + + var _handlebarsRuntime = __webpack_require__(38); + + var runtime = _interopRequireWildcard(_handlebarsRuntime); + + var _handlebarsNoConflict = __webpack_require__(44); + + var _handlebarsNoConflict2 = _interopRequireDefault(_handlebarsNoConflict); + + // For compatibility and usage outside of module systems, make the Handlebars object a namespace + function create() { + var hb = new base.HandlebarsEnvironment(); + + Utils.extend(hb, base); + hb.SafeString = _handlebarsSafeString2['default']; + hb.Exception = _handlebarsException2['default']; + hb.Utils = Utils; + hb.escapeExpression = Utils.escapeExpression; + + hb.VM = runtime; + hb.template = function (spec) { + return runtime.template(spec, hb); + }; + + return hb; + } + + var inst = create(); + inst.create = create; + + _handlebarsNoConflict2['default'](inst); + + inst['default'] = inst; + + exports['default'] = inst; + module.exports = exports['default']; + +/***/ }), +/* 3 */ +/***/ (function(module, exports) { + + "use strict"; + + exports["default"] = function (obj) { + if (obj && obj.__esModule) { + return obj; + } else { + var newObj = {}; + + if (obj != null) { + for (var key in obj) { + if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; + } + } + + newObj["default"] = obj; + return newObj; + } + }; + + exports.__esModule = true; + +/***/ }), +/* 4 */ +/***/ (function(module, exports, __webpack_require__) { + + 'use strict'; + + var _interopRequireDefault = __webpack_require__(1)['default']; + + exports.__esModule = true; + exports.HandlebarsEnvironment = HandlebarsEnvironment; + + var _utils = __webpack_require__(5); + + var _exception = __webpack_require__(6); + + var _exception2 = _interopRequireDefault(_exception); + + var _helpers = __webpack_require__(10); + + var _decorators = __webpack_require__(30); + + var _logger = __webpack_require__(32); + + var _logger2 = _interopRequireDefault(_logger); + + var _internalProtoAccess = __webpack_require__(33); + + var VERSION = '4.7.6'; + exports.VERSION = VERSION; + var COMPILER_REVISION = 8; + exports.COMPILER_REVISION = COMPILER_REVISION; + var LAST_COMPATIBLE_COMPILER_REVISION = 7; + + exports.LAST_COMPATIBLE_COMPILER_REVISION = LAST_COMPATIBLE_COMPILER_REVISION; + var REVISION_CHANGES = { + 1: '<= 1.0.rc.2', // 1.0.rc.2 is actually rev2 but doesn't report it + 2: '== 1.0.0-rc.3', + 3: '== 1.0.0-rc.4', + 4: '== 1.x.x', + 5: '== 2.0.0-alpha.x', + 6: '>= 2.0.0-beta.1', + 7: '>= 4.0.0 <4.3.0', + 8: '>= 4.3.0' + }; + + exports.REVISION_CHANGES = REVISION_CHANGES; + var objectType = '[object Object]'; + + function HandlebarsEnvironment(helpers, partials, decorators) { + this.helpers = helpers || {}; + this.partials = partials || {}; + this.decorators = decorators || {}; + + _helpers.registerDefaultHelpers(this); + _decorators.registerDefaultDecorators(this); + } + + HandlebarsEnvironment.prototype = { + constructor: HandlebarsEnvironment, + + logger: _logger2['default'], + log: _logger2['default'].log, + + registerHelper: function registerHelper(name, fn) { + if (_utils.toString.call(name) === objectType) { + if (fn) { + throw new _exception2['default']('Arg not supported with multiple helpers'); + } + _utils.extend(this.helpers, name); + } else { + this.helpers[name] = fn; + } + }, + unregisterHelper: function unregisterHelper(name) { + delete this.helpers[name]; + }, + + registerPartial: function registerPartial(name, partial) { + if (_utils.toString.call(name) === objectType) { + _utils.extend(this.partials, name); + } else { + if (typeof partial === 'undefined') { + throw new _exception2['default']('Attempting to register a partial called "' + name + '" as undefined'); + } + this.partials[name] = partial; + } + }, + unregisterPartial: function unregisterPartial(name) { + delete this.partials[name]; + }, + + registerDecorator: function registerDecorator(name, fn) { + if (_utils.toString.call(name) === objectType) { + if (fn) { + throw new _exception2['default']('Arg not supported with multiple decorators'); + } + _utils.extend(this.decorators, name); + } else { + this.decorators[name] = fn; + } + }, + unregisterDecorator: function unregisterDecorator(name) { + delete this.decorators[name]; + }, + /** + * Reset the memory of illegal property accesses that have already been logged. + * @deprecated should only be used in handlebars test-cases + */ + resetLoggedPropertyAccesses: function resetLoggedPropertyAccesses() { + _internalProtoAccess.resetLoggedProperties(); + } + }; + + var log = _logger2['default'].log; + + exports.log = log; + exports.createFrame = _utils.createFrame; + exports.logger = _logger2['default']; + +/***/ }), +/* 5 */ +/***/ (function(module, exports) { + + 'use strict'; + + exports.__esModule = true; + exports.extend = extend; + exports.indexOf = indexOf; + exports.escapeExpression = escapeExpression; + exports.isEmpty = isEmpty; + exports.createFrame = createFrame; + exports.blockParams = blockParams; + exports.appendContextPath = appendContextPath; + var escape = { + '&': '&', + '<': '<', + '>': '>', + '"': '"', + "'": ''', + '`': '`', + '=': '=' + }; + + var badChars = /[&<>"'`=]/g, + possible = /[&<>"'`=]/; + + function escapeChar(chr) { + return escape[chr]; + } + + function extend(obj /* , ...source */) { + for (var i = 1; i < arguments.length; i++) { + for (var key in arguments[i]) { + if (Object.prototype.hasOwnProperty.call(arguments[i], key)) { + obj[key] = arguments[i][key]; + } + } + } + + return obj; + } + + var toString = Object.prototype.toString; + + exports.toString = toString; + // Sourced from lodash + // https://github.com/bestiejs/lodash/blob/master/LICENSE.txt + /* eslint-disable func-style */ + var isFunction = function isFunction(value) { + return typeof value === 'function'; + }; + // fallback for older versions of Chrome and Safari + /* istanbul ignore next */ + if (isFunction(/x/)) { + exports.isFunction = isFunction = function (value) { + return typeof value === 'function' && toString.call(value) === '[object Function]'; + }; + } + exports.isFunction = isFunction; + + /* eslint-enable func-style */ + + /* istanbul ignore next */ + var isArray = Array.isArray || function (value) { + return value && typeof value === 'object' ? toString.call(value) === '[object Array]' : false; + }; + + exports.isArray = isArray; + // Older IE versions do not directly support indexOf so we must implement our own, sadly. + + function indexOf(array, value) { + for (var i = 0, len = array.length; i < len; i++) { + if (array[i] === value) { + return i; + } + } + return -1; + } + + function escapeExpression(string) { + if (typeof string !== 'string') { + // don't escape SafeStrings, since they're already safe + if (string && string.toHTML) { + return string.toHTML(); + } else if (string == null) { + return ''; + } else if (!string) { + return string + ''; + } + + // Force a string conversion as this will be done by the append regardless and + // the regex test will do this transparently behind the scenes, causing issues if + // an object's to string has escaped characters in it. + string = '' + string; + } + + if (!possible.test(string)) { + return string; + } + return string.replace(badChars, escapeChar); + } + + function isEmpty(value) { + if (!value && value !== 0) { + return true; + } else if (isArray(value) && value.length === 0) { + return true; + } else { + return false; + } + } + + function createFrame(object) { + var frame = extend({}, object); + frame._parent = object; + return frame; + } + + function blockParams(params, ids) { + params.path = ids; + return params; + } + + function appendContextPath(contextPath, id) { + return (contextPath ? contextPath + '.' : '') + id; + } + +/***/ }), +/* 6 */ +/***/ (function(module, exports, __webpack_require__) { + + 'use strict'; + + var _Object$defineProperty = __webpack_require__(7)['default']; + + exports.__esModule = true; + var errorProps = ['description', 'fileName', 'lineNumber', 'endLineNumber', 'message', 'name', 'number', 'stack']; + + function Exception(message, node) { + var loc = node && node.loc, + line = undefined, + endLineNumber = undefined, + column = undefined, + endColumn = undefined; + + if (loc) { + line = loc.start.line; + endLineNumber = loc.end.line; + column = loc.start.column; + endColumn = loc.end.column; + + message += ' - ' + line + ':' + column; + } + + var tmp = Error.prototype.constructor.call(this, message); + + // Unfortunately errors are not enumerable in Chrome (at least), so `for prop in tmp` doesn't work. + for (var idx = 0; idx < errorProps.length; idx++) { + this[errorProps[idx]] = tmp[errorProps[idx]]; + } + + /* istanbul ignore else */ + if (Error.captureStackTrace) { + Error.captureStackTrace(this, Exception); + } + + try { + if (loc) { + this.lineNumber = line; + this.endLineNumber = endLineNumber; + + // Work around issue under safari where we can't directly set the column value + /* istanbul ignore next */ + if (_Object$defineProperty) { + Object.defineProperty(this, 'column', { + value: column, + enumerable: true + }); + Object.defineProperty(this, 'endColumn', { + value: endColumn, + enumerable: true + }); + } else { + this.column = column; + this.endColumn = endColumn; + } + } + } catch (nop) { + /* Ignore if the browser is very particular */ + } + } + + Exception.prototype = new Error(); + + exports['default'] = Exception; + module.exports = exports['default']; + +/***/ }), +/* 7 */ +/***/ (function(module, exports, __webpack_require__) { + + module.exports = { "default": __webpack_require__(8), __esModule: true }; + +/***/ }), +/* 8 */ +/***/ (function(module, exports, __webpack_require__) { + + var $ = __webpack_require__(9); + module.exports = function defineProperty(it, key, desc){ + return $.setDesc(it, key, desc); + }; + +/***/ }), +/* 9 */ +/***/ (function(module, exports) { + + var $Object = Object; + module.exports = { + create: $Object.create, + getProto: $Object.getPrototypeOf, + isEnum: {}.propertyIsEnumerable, + getDesc: $Object.getOwnPropertyDescriptor, + setDesc: $Object.defineProperty, + setDescs: $Object.defineProperties, + getKeys: $Object.keys, + getNames: $Object.getOwnPropertyNames, + getSymbols: $Object.getOwnPropertySymbols, + each: [].forEach + }; + +/***/ }), +/* 10 */ +/***/ (function(module, exports, __webpack_require__) { + + 'use strict'; + + var _interopRequireDefault = __webpack_require__(1)['default']; + + exports.__esModule = true; + exports.registerDefaultHelpers = registerDefaultHelpers; + exports.moveHelperToHooks = moveHelperToHooks; + + var _helpersBlockHelperMissing = __webpack_require__(11); + + var _helpersBlockHelperMissing2 = _interopRequireDefault(_helpersBlockHelperMissing); + + var _helpersEach = __webpack_require__(12); + + var _helpersEach2 = _interopRequireDefault(_helpersEach); + + var _helpersHelperMissing = __webpack_require__(25); + + var _helpersHelperMissing2 = _interopRequireDefault(_helpersHelperMissing); + + var _helpersIf = __webpack_require__(26); + + var _helpersIf2 = _interopRequireDefault(_helpersIf); + + var _helpersLog = __webpack_require__(27); + + var _helpersLog2 = _interopRequireDefault(_helpersLog); + + var _helpersLookup = __webpack_require__(28); + + var _helpersLookup2 = _interopRequireDefault(_helpersLookup); + + var _helpersWith = __webpack_require__(29); + + var _helpersWith2 = _interopRequireDefault(_helpersWith); + + function registerDefaultHelpers(instance) { + _helpersBlockHelperMissing2['default'](instance); + _helpersEach2['default'](instance); + _helpersHelperMissing2['default'](instance); + _helpersIf2['default'](instance); + _helpersLog2['default'](instance); + _helpersLookup2['default'](instance); + _helpersWith2['default'](instance); + } + + function moveHelperToHooks(instance, helperName, keepHelper) { + if (instance.helpers[helperName]) { + instance.hooks[helperName] = instance.helpers[helperName]; + if (!keepHelper) { + delete instance.helpers[helperName]; + } + } + } + +/***/ }), +/* 11 */ +/***/ (function(module, exports, __webpack_require__) { + + 'use strict'; + + exports.__esModule = true; + + var _utils = __webpack_require__(5); + + exports['default'] = function (instance) { + instance.registerHelper('blockHelperMissing', function (context, options) { + var inverse = options.inverse, + fn = options.fn; + + if (context === true) { + return fn(this); + } else if (context === false || context == null) { + return inverse(this); + } else if (_utils.isArray(context)) { + if (context.length > 0) { + if (options.ids) { + options.ids = [options.name]; + } + + return instance.helpers.each(context, options); + } else { + return inverse(this); + } + } else { + if (options.data && options.ids) { + var data = _utils.createFrame(options.data); + data.contextPath = _utils.appendContextPath(options.data.contextPath, options.name); + options = { data: data }; + } + + return fn(context, options); + } + }); + }; + + module.exports = exports['default']; + +/***/ }), +/* 12 */ +/***/ (function(module, exports, __webpack_require__) { + + /* WEBPACK VAR INJECTION */(function(global) {'use strict'; + + var _Object$keys = __webpack_require__(13)['default']; + + var _interopRequireDefault = __webpack_require__(1)['default']; + + exports.__esModule = true; + + var _utils = __webpack_require__(5); + + var _exception = __webpack_require__(6); + + var _exception2 = _interopRequireDefault(_exception); + + exports['default'] = function (instance) { + instance.registerHelper('each', function (context, options) { + if (!options) { + throw new _exception2['default']('Must pass iterator to #each'); + } + + var fn = options.fn, + inverse = options.inverse, + i = 0, + ret = '', + data = undefined, + contextPath = undefined; + + if (options.data && options.ids) { + contextPath = _utils.appendContextPath(options.data.contextPath, options.ids[0]) + '.'; + } + + if (_utils.isFunction(context)) { + context = context.call(this); + } + + if (options.data) { + data = _utils.createFrame(options.data); + } + + function execIteration(field, index, last) { + if (data) { + data.key = field; + data.index = index; + data.first = index === 0; + data.last = !!last; + + if (contextPath) { + data.contextPath = contextPath + field; + } + } + + ret = ret + fn(context[field], { + data: data, + blockParams: _utils.blockParams([context[field], field], [contextPath + field, null]) + }); + } + + if (context && typeof context === 'object') { + if (_utils.isArray(context)) { + for (var j = context.length; i < j; i++) { + if (i in context) { + execIteration(i, i, i === context.length - 1); + } + } + } else if (global.Symbol && context[global.Symbol.iterator]) { + var newContext = []; + var iterator = context[global.Symbol.iterator](); + for (var it = iterator.next(); !it.done; it = iterator.next()) { + newContext.push(it.value); + } + context = newContext; + for (var j = context.length; i < j; i++) { + execIteration(i, i, i === context.length - 1); + } + } else { + (function () { + var priorKey = undefined; + + _Object$keys(context).forEach(function (key) { + // We're running the iterations one step out of sync so we can detect + // the last iteration without have to scan the object twice and create + // an itermediate keys array. + if (priorKey !== undefined) { + execIteration(priorKey, i - 1); + } + priorKey = key; + i++; + }); + if (priorKey !== undefined) { + execIteration(priorKey, i - 1, true); + } + })(); + } + } + + if (i === 0) { + ret = inverse(this); + } + + return ret; + }); + }; + + module.exports = exports['default']; + /* WEBPACK VAR INJECTION */}.call(exports, (function() { return this; }()))) + +/***/ }), +/* 13 */ +/***/ (function(module, exports, __webpack_require__) { + + module.exports = { "default": __webpack_require__(14), __esModule: true }; + +/***/ }), +/* 14 */ +/***/ (function(module, exports, __webpack_require__) { + + __webpack_require__(15); + module.exports = __webpack_require__(21).Object.keys; + +/***/ }), +/* 15 */ +/***/ (function(module, exports, __webpack_require__) { + + // 19.1.2.14 Object.keys(O) + var toObject = __webpack_require__(16); + + __webpack_require__(18)('keys', function($keys){ + return function keys(it){ + return $keys(toObject(it)); + }; + }); + +/***/ }), +/* 16 */ +/***/ (function(module, exports, __webpack_require__) { + + // 7.1.13 ToObject(argument) + var defined = __webpack_require__(17); + module.exports = function(it){ + return Object(defined(it)); + }; + +/***/ }), +/* 17 */ +/***/ (function(module, exports) { + + // 7.2.1 RequireObjectCoercible(argument) + module.exports = function(it){ + if(it == undefined)throw TypeError("Can't call method on " + it); + return it; + }; + +/***/ }), +/* 18 */ +/***/ (function(module, exports, __webpack_require__) { + + // most Object methods by ES6 should accept primitives + var $export = __webpack_require__(19) + , core = __webpack_require__(21) + , fails = __webpack_require__(24); + module.exports = function(KEY, exec){ + var fn = (core.Object || {})[KEY] || Object[KEY] + , exp = {}; + exp[KEY] = exec(fn); + $export($export.S + $export.F * fails(function(){ fn(1); }), 'Object', exp); + }; + +/***/ }), +/* 19 */ +/***/ (function(module, exports, __webpack_require__) { + + var global = __webpack_require__(20) + , core = __webpack_require__(21) + , ctx = __webpack_require__(22) + , PROTOTYPE = 'prototype'; + + var $export = function(type, name, source){ + var IS_FORCED = type & $export.F + , IS_GLOBAL = type & $export.G + , IS_STATIC = type & $export.S + , IS_PROTO = type & $export.P + , IS_BIND = type & $export.B + , IS_WRAP = type & $export.W + , exports = IS_GLOBAL ? core : core[name] || (core[name] = {}) + , target = IS_GLOBAL ? global : IS_STATIC ? global[name] : (global[name] || {})[PROTOTYPE] + , key, own, out; + if(IS_GLOBAL)source = name; + for(key in source){ + // contains in native + own = !IS_FORCED && target && key in target; + if(own && key in exports)continue; + // export native or passed + out = own ? target[key] : source[key]; + // prevent global pollution for namespaces + exports[key] = IS_GLOBAL && typeof target[key] != 'function' ? source[key] + // bind timers to global for call from export context + : IS_BIND && own ? ctx(out, global) + // wrap global constructors for prevent change them in library + : IS_WRAP && target[key] == out ? (function(C){ + var F = function(param){ + return this instanceof C ? new C(param) : C(param); + }; + F[PROTOTYPE] = C[PROTOTYPE]; + return F; + // make static versions for prototype methods + })(out) : IS_PROTO && typeof out == 'function' ? ctx(Function.call, out) : out; + if(IS_PROTO)(exports[PROTOTYPE] || (exports[PROTOTYPE] = {}))[key] = out; + } + }; + // type bitmap + $export.F = 1; // forced + $export.G = 2; // global + $export.S = 4; // static + $export.P = 8; // proto + $export.B = 16; // bind + $export.W = 32; // wrap + module.exports = $export; + +/***/ }), +/* 20 */ +/***/ (function(module, exports) { + + // https://github.com/zloirock/core-js/issues/86#issuecomment-115759028 + var global = module.exports = typeof window != 'undefined' && window.Math == Math + ? window : typeof self != 'undefined' && self.Math == Math ? self : Function('return this')(); + if(typeof __g == 'number')__g = global; // eslint-disable-line no-undef + +/***/ }), +/* 21 */ +/***/ (function(module, exports) { + + var core = module.exports = {version: '1.2.6'}; + if(typeof __e == 'number')__e = core; // eslint-disable-line no-undef + +/***/ }), +/* 22 */ +/***/ (function(module, exports, __webpack_require__) { + + // optional / simple context binding + var aFunction = __webpack_require__(23); + module.exports = function(fn, that, length){ + aFunction(fn); + if(that === undefined)return fn; + switch(length){ + case 1: return function(a){ + return fn.call(that, a); + }; + case 2: return function(a, b){ + return fn.call(that, a, b); + }; + case 3: return function(a, b, c){ + return fn.call(that, a, b, c); + }; + } + return function(/* ...args */){ + return fn.apply(that, arguments); + }; + }; + +/***/ }), +/* 23 */ +/***/ (function(module, exports) { + + module.exports = function(it){ + if(typeof it != 'function')throw TypeError(it + ' is not a function!'); + return it; + }; + +/***/ }), +/* 24 */ +/***/ (function(module, exports) { + + module.exports = function(exec){ + try { + return !!exec(); + } catch(e){ + return true; + } + }; + +/***/ }), +/* 25 */ +/***/ (function(module, exports, __webpack_require__) { + + 'use strict'; + + var _interopRequireDefault = __webpack_require__(1)['default']; + + exports.__esModule = true; + + var _exception = __webpack_require__(6); + + var _exception2 = _interopRequireDefault(_exception); + + exports['default'] = function (instance) { + instance.registerHelper('helperMissing', function () /* [args, ]options */{ + if (arguments.length === 1) { + // A missing field in a {{foo}} construct. + return undefined; + } else { + // Someone is actually trying to call something, blow up. + throw new _exception2['default']('Missing helper: "' + arguments[arguments.length - 1].name + '"'); + } + }); + }; + + module.exports = exports['default']; + +/***/ }), +/* 26 */ +/***/ (function(module, exports, __webpack_require__) { + + 'use strict'; + + var _interopRequireDefault = __webpack_require__(1)['default']; + + exports.__esModule = true; + + var _utils = __webpack_require__(5); + + var _exception = __webpack_require__(6); + + var _exception2 = _interopRequireDefault(_exception); + + exports['default'] = function (instance) { + instance.registerHelper('if', function (conditional, options) { + if (arguments.length != 2) { + throw new _exception2['default']('#if requires exactly one argument'); + } + if (_utils.isFunction(conditional)) { + conditional = conditional.call(this); + } + + // Default behavior is to render the positive path if the value is truthy and not empty. + // The `includeZero` option may be set to treat the condtional as purely not empty based on the + // behavior of isEmpty. Effectively this determines if 0 is handled by the positive path or negative. + if (!options.hash.includeZero && !conditional || _utils.isEmpty(conditional)) { + return options.inverse(this); + } else { + return options.fn(this); + } + }); + + instance.registerHelper('unless', function (conditional, options) { + if (arguments.length != 2) { + throw new _exception2['default']('#unless requires exactly one argument'); + } + return instance.helpers['if'].call(this, conditional, { + fn: options.inverse, + inverse: options.fn, + hash: options.hash + }); + }); + }; + + module.exports = exports['default']; + +/***/ }), +/* 27 */ +/***/ (function(module, exports) { + + 'use strict'; + + exports.__esModule = true; + + exports['default'] = function (instance) { + instance.registerHelper('log', function () /* message, options */{ + var args = [undefined], + options = arguments[arguments.length - 1]; + for (var i = 0; i < arguments.length - 1; i++) { + args.push(arguments[i]); + } + + var level = 1; + if (options.hash.level != null) { + level = options.hash.level; + } else if (options.data && options.data.level != null) { + level = options.data.level; + } + args[0] = level; + + instance.log.apply(instance, args); + }); + }; + + module.exports = exports['default']; + +/***/ }), +/* 28 */ +/***/ (function(module, exports) { + + 'use strict'; + + exports.__esModule = true; + + exports['default'] = function (instance) { + instance.registerHelper('lookup', function (obj, field, options) { + if (!obj) { + // Note for 5.0: Change to "obj == null" in 5.0 + return obj; + } + return options.lookupProperty(obj, field); + }); + }; + + module.exports = exports['default']; + +/***/ }), +/* 29 */ +/***/ (function(module, exports, __webpack_require__) { + + 'use strict'; + + var _interopRequireDefault = __webpack_require__(1)['default']; + + exports.__esModule = true; + + var _utils = __webpack_require__(5); + + var _exception = __webpack_require__(6); + + var _exception2 = _interopRequireDefault(_exception); + + exports['default'] = function (instance) { + instance.registerHelper('with', function (context, options) { + if (arguments.length != 2) { + throw new _exception2['default']('#with requires exactly one argument'); + } + if (_utils.isFunction(context)) { + context = context.call(this); + } + + var fn = options.fn; + + if (!_utils.isEmpty(context)) { + var data = options.data; + if (options.data && options.ids) { + data = _utils.createFrame(options.data); + data.contextPath = _utils.appendContextPath(options.data.contextPath, options.ids[0]); + } + + return fn(context, { + data: data, + blockParams: _utils.blockParams([context], [data && data.contextPath]) + }); + } else { + return options.inverse(this); + } + }); + }; + + module.exports = exports['default']; + +/***/ }), +/* 30 */ +/***/ (function(module, exports, __webpack_require__) { + + 'use strict'; + + var _interopRequireDefault = __webpack_require__(1)['default']; + + exports.__esModule = true; + exports.registerDefaultDecorators = registerDefaultDecorators; + + var _decoratorsInline = __webpack_require__(31); + + var _decoratorsInline2 = _interopRequireDefault(_decoratorsInline); + + function registerDefaultDecorators(instance) { + _decoratorsInline2['default'](instance); + } + +/***/ }), +/* 31 */ +/***/ (function(module, exports, __webpack_require__) { + + 'use strict'; + + exports.__esModule = true; + + var _utils = __webpack_require__(5); + + exports['default'] = function (instance) { + instance.registerDecorator('inline', function (fn, props, container, options) { + var ret = fn; + if (!props.partials) { + props.partials = {}; + ret = function (context, options) { + // Create a new partials stack frame prior to exec. + var original = container.partials; + container.partials = _utils.extend({}, original, props.partials); + var ret = fn(context, options); + container.partials = original; + return ret; + }; + } + + props.partials[options.args[0]] = options.fn; + + return ret; + }); + }; + + module.exports = exports['default']; + +/***/ }), +/* 32 */ +/***/ (function(module, exports, __webpack_require__) { + + 'use strict'; + + exports.__esModule = true; + + var _utils = __webpack_require__(5); + + var logger = { + methodMap: ['debug', 'info', 'warn', 'error'], + level: 'info', + + // Maps a given level value to the `methodMap` indexes above. + lookupLevel: function lookupLevel(level) { + if (typeof level === 'string') { + var levelMap = _utils.indexOf(logger.methodMap, level.toLowerCase()); + if (levelMap >= 0) { + level = levelMap; + } else { + level = parseInt(level, 10); + } + } + + return level; + }, + + // Can be overridden in the host environment + log: function log(level) { + level = logger.lookupLevel(level); + + if (typeof console !== 'undefined' && logger.lookupLevel(logger.level) <= level) { + var method = logger.methodMap[level]; + // eslint-disable-next-line no-console + if (!console[method]) { + method = 'log'; + } + + for (var _len = arguments.length, message = Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) { + message[_key - 1] = arguments[_key]; + } + + console[method].apply(console, message); // eslint-disable-line no-console + } + } + }; + + exports['default'] = logger; + module.exports = exports['default']; + +/***/ }), +/* 33 */ +/***/ (function(module, exports, __webpack_require__) { + + 'use strict'; + + var _Object$create = __webpack_require__(34)['default']; + + var _Object$keys = __webpack_require__(13)['default']; + + var _interopRequireWildcard = __webpack_require__(3)['default']; + + exports.__esModule = true; + exports.createProtoAccessControl = createProtoAccessControl; + exports.resultIsAllowed = resultIsAllowed; + exports.resetLoggedProperties = resetLoggedProperties; + + var _createNewLookupObject = __webpack_require__(36); + + var _logger = __webpack_require__(32); + + var logger = _interopRequireWildcard(_logger); + + var loggedProperties = _Object$create(null); + + function createProtoAccessControl(runtimeOptions) { + var defaultMethodWhiteList = _Object$create(null); + defaultMethodWhiteList['constructor'] = false; + defaultMethodWhiteList['__defineGetter__'] = false; + defaultMethodWhiteList['__defineSetter__'] = false; + defaultMethodWhiteList['__lookupGetter__'] = false; + + var defaultPropertyWhiteList = _Object$create(null); + // eslint-disable-next-line no-proto + defaultPropertyWhiteList['__proto__'] = false; + + return { + properties: { + whitelist: _createNewLookupObject.createNewLookupObject(defaultPropertyWhiteList, runtimeOptions.allowedProtoProperties), + defaultValue: runtimeOptions.allowProtoPropertiesByDefault + }, + methods: { + whitelist: _createNewLookupObject.createNewLookupObject(defaultMethodWhiteList, runtimeOptions.allowedProtoMethods), + defaultValue: runtimeOptions.allowProtoMethodsByDefault + } + }; + } + + function resultIsAllowed(result, protoAccessControl, propertyName) { + if (typeof result === 'function') { + return checkWhiteList(protoAccessControl.methods, propertyName); + } else { + return checkWhiteList(protoAccessControl.properties, propertyName); + } + } + + function checkWhiteList(protoAccessControlForType, propertyName) { + if (protoAccessControlForType.whitelist[propertyName] !== undefined) { + return protoAccessControlForType.whitelist[propertyName] === true; + } + if (protoAccessControlForType.defaultValue !== undefined) { + return protoAccessControlForType.defaultValue; + } + logUnexpecedPropertyAccessOnce(propertyName); + return false; + } + + function logUnexpecedPropertyAccessOnce(propertyName) { + if (loggedProperties[propertyName] !== true) { + loggedProperties[propertyName] = true; + logger.log('error', 'Handlebars: Access has been denied to resolve the property "' + propertyName + '" because it is not an "own property" of its parent.\n' + 'You can add a runtime option to disable the check or this warning:\n' + 'See https://handlebarsjs.com/api-reference/runtime-options.html#options-to-control-prototype-access for details'); + } + } + + function resetLoggedProperties() { + _Object$keys(loggedProperties).forEach(function (propertyName) { + delete loggedProperties[propertyName]; + }); + } + +/***/ }), +/* 34 */ +/***/ (function(module, exports, __webpack_require__) { + + module.exports = { "default": __webpack_require__(35), __esModule: true }; + +/***/ }), +/* 35 */ +/***/ (function(module, exports, __webpack_require__) { + + var $ = __webpack_require__(9); + module.exports = function create(P, D){ + return $.create(P, D); + }; + +/***/ }), +/* 36 */ +/***/ (function(module, exports, __webpack_require__) { + + 'use strict'; + + var _Object$create = __webpack_require__(34)['default']; + + exports.__esModule = true; + exports.createNewLookupObject = createNewLookupObject; + + var _utils = __webpack_require__(5); + + /** + * Create a new object with "null"-prototype to avoid truthy results on prototype properties. + * The resulting object can be used with "object[property]" to check if a property exists + * @param {...object} sources a varargs parameter of source objects that will be merged + * @returns {object} + */ + + function createNewLookupObject() { + for (var _len = arguments.length, sources = Array(_len), _key = 0; _key < _len; _key++) { + sources[_key] = arguments[_key]; + } + + return _utils.extend.apply(undefined, [_Object$create(null)].concat(sources)); + } + +/***/ }), +/* 37 */ +/***/ (function(module, exports) { + + // Build out our basic SafeString type + 'use strict'; + + exports.__esModule = true; + function SafeString(string) { + this.string = string; + } + + SafeString.prototype.toString = SafeString.prototype.toHTML = function () { + return '' + this.string; + }; + + exports['default'] = SafeString; + module.exports = exports['default']; + +/***/ }), +/* 38 */ +/***/ (function(module, exports, __webpack_require__) { + + 'use strict'; + + var _Object$seal = __webpack_require__(39)['default']; + + var _Object$keys = __webpack_require__(13)['default']; + + var _interopRequireWildcard = __webpack_require__(3)['default']; + + var _interopRequireDefault = __webpack_require__(1)['default']; + + exports.__esModule = true; + exports.checkRevision = checkRevision; + exports.template = template; + exports.wrapProgram = wrapProgram; + exports.resolvePartial = resolvePartial; + exports.invokePartial = invokePartial; + exports.noop = noop; + + var _utils = __webpack_require__(5); + + var Utils = _interopRequireWildcard(_utils); + + var _exception = __webpack_require__(6); + + var _exception2 = _interopRequireDefault(_exception); + + var _base = __webpack_require__(4); + + var _helpers = __webpack_require__(10); + + var _internalWrapHelper = __webpack_require__(43); + + var _internalProtoAccess = __webpack_require__(33); + + function checkRevision(compilerInfo) { + var compilerRevision = compilerInfo && compilerInfo[0] || 1, + currentRevision = _base.COMPILER_REVISION; + + if (compilerRevision >= _base.LAST_COMPATIBLE_COMPILER_REVISION && compilerRevision <= _base.COMPILER_REVISION) { + return; + } + + if (compilerRevision < _base.LAST_COMPATIBLE_COMPILER_REVISION) { + var runtimeVersions = _base.REVISION_CHANGES[currentRevision], + compilerVersions = _base.REVISION_CHANGES[compilerRevision]; + throw new _exception2['default']('Template was precompiled with an older version of Handlebars than the current runtime. ' + 'Please update your precompiler to a newer version (' + runtimeVersions + ') or downgrade your runtime to an older version (' + compilerVersions + ').'); + } else { + // Use the embedded version info since the runtime doesn't know about this revision yet + throw new _exception2['default']('Template was precompiled with a newer version of Handlebars than the current runtime. ' + 'Please update your runtime to a newer version (' + compilerInfo[1] + ').'); + } + } + + function template(templateSpec, env) { + /* istanbul ignore next */ + if (!env) { + throw new _exception2['default']('No environment passed to template'); + } + if (!templateSpec || !templateSpec.main) { + throw new _exception2['default']('Unknown template object: ' + typeof templateSpec); + } + + templateSpec.main.decorator = templateSpec.main_d; + + // Note: Using env.VM references rather than local var references throughout this section to allow + // for external users to override these as pseudo-supported APIs. + env.VM.checkRevision(templateSpec.compiler); + + // backwards compatibility for precompiled templates with compiler-version 7 (<4.3.0) + var templateWasPrecompiledWithCompilerV7 = templateSpec.compiler && templateSpec.compiler[0] === 7; + + function invokePartialWrapper(partial, context, options) { + if (options.hash) { + context = Utils.extend({}, context, options.hash); + if (options.ids) { + options.ids[0] = true; + } + } + partial = env.VM.resolvePartial.call(this, partial, context, options); + + var extendedOptions = Utils.extend({}, options, { + hooks: this.hooks, + protoAccessControl: this.protoAccessControl + }); + + var result = env.VM.invokePartial.call(this, partial, context, extendedOptions); + + if (result == null && env.compile) { + options.partials[options.name] = env.compile(partial, templateSpec.compilerOptions, env); + result = options.partials[options.name](context, extendedOptions); + } + if (result != null) { + if (options.indent) { + var lines = result.split('\n'); + for (var i = 0, l = lines.length; i < l; i++) { + if (!lines[i] && i + 1 === l) { + break; + } + + lines[i] = options.indent + lines[i]; + } + result = lines.join('\n'); + } + return result; + } else { + throw new _exception2['default']('The partial ' + options.name + ' could not be compiled when running in runtime-only mode'); + } + } + + // Just add water + var container = { + strict: function strict(obj, name, loc) { + if (!obj || !(name in obj)) { + throw new _exception2['default']('"' + name + '" not defined in ' + obj, { + loc: loc + }); + } + return obj[name]; + }, + lookupProperty: function lookupProperty(parent, propertyName) { + var result = parent[propertyName]; + if (result == null) { + return result; + } + if (Object.prototype.hasOwnProperty.call(parent, propertyName)) { + return result; + } + + if (_internalProtoAccess.resultIsAllowed(result, container.protoAccessControl, propertyName)) { + return result; + } + return undefined; + }, + lookup: function lookup(depths, name) { + var len = depths.length; + for (var i = 0; i < len; i++) { + var result = depths[i] && container.lookupProperty(depths[i], name); + if (result != null) { + return depths[i][name]; + } + } + }, + lambda: function lambda(current, context) { + return typeof current === 'function' ? current.call(context) : current; + }, + + escapeExpression: Utils.escapeExpression, + invokePartial: invokePartialWrapper, + + fn: function fn(i) { + var ret = templateSpec[i]; + ret.decorator = templateSpec[i + '_d']; + return ret; + }, + + programs: [], + program: function program(i, data, declaredBlockParams, blockParams, depths) { + var programWrapper = this.programs[i], + fn = this.fn(i); + if (data || depths || blockParams || declaredBlockParams) { + programWrapper = wrapProgram(this, i, fn, data, declaredBlockParams, blockParams, depths); + } else if (!programWrapper) { + programWrapper = this.programs[i] = wrapProgram(this, i, fn); + } + return programWrapper; + }, + + data: function data(value, depth) { + while (value && depth--) { + value = value._parent; + } + return value; + }, + mergeIfNeeded: function mergeIfNeeded(param, common) { + var obj = param || common; + + if (param && common && param !== common) { + obj = Utils.extend({}, common, param); + } + + return obj; + }, + // An empty object to use as replacement for null-contexts + nullContext: _Object$seal({}), + + noop: env.VM.noop, + compilerInfo: templateSpec.compiler + }; + + function ret(context) { + var options = arguments.length <= 1 || arguments[1] === undefined ? {} : arguments[1]; + + var data = options.data; + + ret._setup(options); + if (!options.partial && templateSpec.useData) { + data = initData(context, data); + } + var depths = undefined, + blockParams = templateSpec.useBlockParams ? [] : undefined; + if (templateSpec.useDepths) { + if (options.depths) { + depths = context != options.depths[0] ? [context].concat(options.depths) : options.depths; + } else { + depths = [context]; + } + } + + function main(context /*, options*/) { + return '' + templateSpec.main(container, context, container.helpers, container.partials, data, blockParams, depths); + } + + main = executeDecorators(templateSpec.main, main, container, options.depths || [], data, blockParams); + return main(context, options); + } + + ret.isTop = true; + + ret._setup = function (options) { + if (!options.partial) { + var mergedHelpers = Utils.extend({}, env.helpers, options.helpers); + wrapHelpersToPassLookupProperty(mergedHelpers, container); + container.helpers = mergedHelpers; + + if (templateSpec.usePartial) { + // Use mergeIfNeeded here to prevent compiling global partials multiple times + container.partials = container.mergeIfNeeded(options.partials, env.partials); + } + if (templateSpec.usePartial || templateSpec.useDecorators) { + container.decorators = Utils.extend({}, env.decorators, options.decorators); + } + + container.hooks = {}; + container.protoAccessControl = _internalProtoAccess.createProtoAccessControl(options); + + var keepHelperInHelpers = options.allowCallsToHelperMissing || templateWasPrecompiledWithCompilerV7; + _helpers.moveHelperToHooks(container, 'helperMissing', keepHelperInHelpers); + _helpers.moveHelperToHooks(container, 'blockHelperMissing', keepHelperInHelpers); + } else { + container.protoAccessControl = options.protoAccessControl; // internal option + container.helpers = options.helpers; + container.partials = options.partials; + container.decorators = options.decorators; + container.hooks = options.hooks; + } + }; + + ret._child = function (i, data, blockParams, depths) { + if (templateSpec.useBlockParams && !blockParams) { + throw new _exception2['default']('must pass block params'); + } + if (templateSpec.useDepths && !depths) { + throw new _exception2['default']('must pass parent depths'); + } + + return wrapProgram(container, i, templateSpec[i], data, 0, blockParams, depths); + }; + return ret; + } + + function wrapProgram(container, i, fn, data, declaredBlockParams, blockParams, depths) { + function prog(context) { + var options = arguments.length <= 1 || arguments[1] === undefined ? {} : arguments[1]; + + var currentDepths = depths; + if (depths && context != depths[0] && !(context === container.nullContext && depths[0] === null)) { + currentDepths = [context].concat(depths); + } + + return fn(container, context, container.helpers, container.partials, options.data || data, blockParams && [options.blockParams].concat(blockParams), currentDepths); + } + + prog = executeDecorators(fn, prog, container, depths, data, blockParams); + + prog.program = i; + prog.depth = depths ? depths.length : 0; + prog.blockParams = declaredBlockParams || 0; + return prog; + } + + /** + * This is currently part of the official API, therefore implementation details should not be changed. + */ + + function resolvePartial(partial, context, options) { + if (!partial) { + if (options.name === '@partial-block') { + partial = options.data['partial-block']; + } else { + partial = options.partials[options.name]; + } + } else if (!partial.call && !options.name) { + // This is a dynamic partial that returned a string + options.name = partial; + partial = options.partials[partial]; + } + return partial; + } + + function invokePartial(partial, context, options) { + // Use the current closure context to save the partial-block if this partial + var currentPartialBlock = options.data && options.data['partial-block']; + options.partial = true; + if (options.ids) { + options.data.contextPath = options.ids[0] || options.data.contextPath; + } + + var partialBlock = undefined; + if (options.fn && options.fn !== noop) { + (function () { + options.data = _base.createFrame(options.data); + // Wrapper function to get access to currentPartialBlock from the closure + var fn = options.fn; + partialBlock = options.data['partial-block'] = function partialBlockWrapper(context) { + var options = arguments.length <= 1 || arguments[1] === undefined ? {} : arguments[1]; + + // Restore the partial-block from the closure for the execution of the block + // i.e. the part inside the block of the partial call. + options.data = _base.createFrame(options.data); + options.data['partial-block'] = currentPartialBlock; + return fn(context, options); + }; + if (fn.partials) { + options.partials = Utils.extend({}, options.partials, fn.partials); + } + })(); + } + + if (partial === undefined && partialBlock) { + partial = partialBlock; + } + + if (partial === undefined) { + throw new _exception2['default']('The partial ' + options.name + ' could not be found'); + } else if (partial instanceof Function) { + return partial(context, options); + } + } + + function noop() { + return ''; + } + + function initData(context, data) { + if (!data || !('root' in data)) { + data = data ? _base.createFrame(data) : {}; + data.root = context; + } + return data; + } + + function executeDecorators(fn, prog, container, depths, data, blockParams) { + if (fn.decorator) { + var props = {}; + prog = fn.decorator(prog, props, container, depths && depths[0], data, blockParams, depths); + Utils.extend(prog, props); + } + return prog; + } + + function wrapHelpersToPassLookupProperty(mergedHelpers, container) { + _Object$keys(mergedHelpers).forEach(function (helperName) { + var helper = mergedHelpers[helperName]; + mergedHelpers[helperName] = passLookupPropertyOption(helper, container); + }); + } + + function passLookupPropertyOption(helper, container) { + var lookupProperty = container.lookupProperty; + return _internalWrapHelper.wrapHelper(helper, function (options) { + return Utils.extend({ lookupProperty: lookupProperty }, options); + }); + } + +/***/ }), +/* 39 */ +/***/ (function(module, exports, __webpack_require__) { + + module.exports = { "default": __webpack_require__(40), __esModule: true }; + +/***/ }), +/* 40 */ +/***/ (function(module, exports, __webpack_require__) { + + __webpack_require__(41); + module.exports = __webpack_require__(21).Object.seal; + +/***/ }), +/* 41 */ +/***/ (function(module, exports, __webpack_require__) { + + // 19.1.2.17 Object.seal(O) + var isObject = __webpack_require__(42); + + __webpack_require__(18)('seal', function($seal){ + return function seal(it){ + return $seal && isObject(it) ? $seal(it) : it; + }; + }); + +/***/ }), +/* 42 */ +/***/ (function(module, exports) { + + module.exports = function(it){ + return typeof it === 'object' ? it !== null : typeof it === 'function'; + }; + +/***/ }), +/* 43 */ +/***/ (function(module, exports) { + + 'use strict'; + + exports.__esModule = true; + exports.wrapHelper = wrapHelper; + + function wrapHelper(helper, transformOptionsFn) { + if (typeof helper !== 'function') { + // This should not happen, but apparently it does in https://github.com/wycats/handlebars.js/issues/1639 + // We try to make the wrapper least-invasive by not wrapping it, if the helper is not a function. + return helper; + } + var wrapper = function wrapper() /* dynamic arguments */{ + var options = arguments[arguments.length - 1]; + arguments[arguments.length - 1] = transformOptionsFn(options); + return helper.apply(this, arguments); + }; + return wrapper; + } + +/***/ }), +/* 44 */ +/***/ (function(module, exports) { + + /* WEBPACK VAR INJECTION */(function(global) {'use strict'; + + exports.__esModule = true; + + exports['default'] = function (Handlebars) { + /* istanbul ignore next */ + var root = typeof global !== 'undefined' ? global : window, + $Handlebars = root.Handlebars; + /* istanbul ignore next */ + Handlebars.noConflict = function () { + if (root.Handlebars === Handlebars) { + root.Handlebars = $Handlebars; + } + return Handlebars; + }; + }; + + module.exports = exports['default']; + /* WEBPACK VAR INJECTION */}.call(exports, (function() { return this; }()))) + +/***/ }), +/* 45 */ +/***/ (function(module, exports) { + + 'use strict'; + + exports.__esModule = true; + var AST = { + // Public API used to evaluate derived attributes regarding AST nodes + helpers: { + // a mustache is definitely a helper if: + // * it is an eligible helper, and + // * it has at least one parameter or hash segment + helperExpression: function helperExpression(node) { + return node.type === 'SubExpression' || (node.type === 'MustacheStatement' || node.type === 'BlockStatement') && !!(node.params && node.params.length || node.hash); + }, + + scopedId: function scopedId(path) { + return (/^\.|this\b/.test(path.original) + ); + }, + + // an ID is simple if it only has one part, and that part is not + // `..` or `this`. + simpleId: function simpleId(path) { + return path.parts.length === 1 && !AST.helpers.scopedId(path) && !path.depth; + } + } + }; + + // Must be exported as an object rather than the root of the module as the jison lexer + // must modify the object to operate properly. + exports['default'] = AST; + module.exports = exports['default']; + +/***/ }), +/* 46 */ +/***/ (function(module, exports, __webpack_require__) { + + 'use strict'; + + var _interopRequireDefault = __webpack_require__(1)['default']; + + var _interopRequireWildcard = __webpack_require__(3)['default']; + + exports.__esModule = true; + exports.parseWithoutProcessing = parseWithoutProcessing; + exports.parse = parse; + + var _parser = __webpack_require__(47); + + var _parser2 = _interopRequireDefault(_parser); + + var _whitespaceControl = __webpack_require__(48); + + var _whitespaceControl2 = _interopRequireDefault(_whitespaceControl); + + var _helpers = __webpack_require__(50); + + var Helpers = _interopRequireWildcard(_helpers); + + var _utils = __webpack_require__(5); + + exports.parser = _parser2['default']; + + var yy = {}; + _utils.extend(yy, Helpers); + + function parseWithoutProcessing(input, options) { + // Just return if an already-compiled AST was passed in. + if (input.type === 'Program') { + return input; + } + + _parser2['default'].yy = yy; + + // Altering the shared object here, but this is ok as parser is a sync operation + yy.locInfo = function (locInfo) { + return new yy.SourceLocation(options && options.srcName, locInfo); + }; + + var ast = _parser2['default'].parse(input); + + return ast; + } + + function parse(input, options) { + var ast = parseWithoutProcessing(input, options); + var strip = new _whitespaceControl2['default'](options); + + return strip.accept(ast); + } + +/***/ }), +/* 47 */ +/***/ (function(module, exports) { + + // File ignored in coverage tests via setting in .istanbul.yml + /* Jison generated parser */ + "use strict"; + + exports.__esModule = true; + var handlebars = (function () { + var parser = { trace: function trace() {}, + yy: {}, + symbols_: { "error": 2, "root": 3, "program": 4, "EOF": 5, "program_repetition0": 6, "statement": 7, "mustache": 8, "block": 9, "rawBlock": 10, "partial": 11, "partialBlock": 12, "content": 13, "COMMENT": 14, "CONTENT": 15, "openRawBlock": 16, "rawBlock_repetition0": 17, "END_RAW_BLOCK": 18, "OPEN_RAW_BLOCK": 19, "helperName": 20, "openRawBlock_repetition0": 21, "openRawBlock_option0": 22, "CLOSE_RAW_BLOCK": 23, "openBlock": 24, "block_option0": 25, "closeBlock": 26, "openInverse": 27, "block_option1": 28, "OPEN_BLOCK": 29, "openBlock_repetition0": 30, "openBlock_option0": 31, "openBlock_option1": 32, "CLOSE": 33, "OPEN_INVERSE": 34, "openInverse_repetition0": 35, "openInverse_option0": 36, "openInverse_option1": 37, "openInverseChain": 38, "OPEN_INVERSE_CHAIN": 39, "openInverseChain_repetition0": 40, "openInverseChain_option0": 41, "openInverseChain_option1": 42, "inverseAndProgram": 43, "INVERSE": 44, "inverseChain": 45, "inverseChain_option0": 46, "OPEN_ENDBLOCK": 47, "OPEN": 48, "mustache_repetition0": 49, "mustache_option0": 50, "OPEN_UNESCAPED": 51, "mustache_repetition1": 52, "mustache_option1": 53, "CLOSE_UNESCAPED": 54, "OPEN_PARTIAL": 55, "partialName": 56, "partial_repetition0": 57, "partial_option0": 58, "openPartialBlock": 59, "OPEN_PARTIAL_BLOCK": 60, "openPartialBlock_repetition0": 61, "openPartialBlock_option0": 62, "param": 63, "sexpr": 64, "OPEN_SEXPR": 65, "sexpr_repetition0": 66, "sexpr_option0": 67, "CLOSE_SEXPR": 68, "hash": 69, "hash_repetition_plus0": 70, "hashSegment": 71, "ID": 72, "EQUALS": 73, "blockParams": 74, "OPEN_BLOCK_PARAMS": 75, "blockParams_repetition_plus0": 76, "CLOSE_BLOCK_PARAMS": 77, "path": 78, "dataName": 79, "STRING": 80, "NUMBER": 81, "BOOLEAN": 82, "UNDEFINED": 83, "NULL": 84, "DATA": 85, "pathSegments": 86, "SEP": 87, "$accept": 0, "$end": 1 }, + terminals_: { 2: "error", 5: "EOF", 14: "COMMENT", 15: "CONTENT", 18: "END_RAW_BLOCK", 19: "OPEN_RAW_BLOCK", 23: "CLOSE_RAW_BLOCK", 29: "OPEN_BLOCK", 33: "CLOSE", 34: "OPEN_INVERSE", 39: "OPEN_INVERSE_CHAIN", 44: "INVERSE", 47: "OPEN_ENDBLOCK", 48: "OPEN", 51: "OPEN_UNESCAPED", 54: "CLOSE_UNESCAPED", 55: "OPEN_PARTIAL", 60: "OPEN_PARTIAL_BLOCK", 65: "OPEN_SEXPR", 68: "CLOSE_SEXPR", 72: "ID", 73: "EQUALS", 75: "OPEN_BLOCK_PARAMS", 77: "CLOSE_BLOCK_PARAMS", 80: "STRING", 81: "NUMBER", 82: "BOOLEAN", 83: "UNDEFINED", 84: "NULL", 85: "DATA", 87: "SEP" }, + productions_: [0, [3, 2], [4, 1], [7, 1], [7, 1], [7, 1], [7, 1], [7, 1], [7, 1], [7, 1], [13, 1], [10, 3], [16, 5], [9, 4], [9, 4], [24, 6], [27, 6], [38, 6], [43, 2], [45, 3], [45, 1], [26, 3], [8, 5], [8, 5], [11, 5], [12, 3], [59, 5], [63, 1], [63, 1], [64, 5], [69, 1], [71, 3], [74, 3], [20, 1], [20, 1], [20, 1], [20, 1], [20, 1], [20, 1], [20, 1], [56, 1], [56, 1], [79, 2], [78, 1], [86, 3], [86, 1], [6, 0], [6, 2], [17, 0], [17, 2], [21, 0], [21, 2], [22, 0], [22, 1], [25, 0], [25, 1], [28, 0], [28, 1], [30, 0], [30, 2], [31, 0], [31, 1], [32, 0], [32, 1], [35, 0], [35, 2], [36, 0], [36, 1], [37, 0], [37, 1], [40, 0], [40, 2], [41, 0], [41, 1], [42, 0], [42, 1], [46, 0], [46, 1], [49, 0], [49, 2], [50, 0], [50, 1], [52, 0], [52, 2], [53, 0], [53, 1], [57, 0], [57, 2], [58, 0], [58, 1], [61, 0], [61, 2], [62, 0], [62, 1], [66, 0], [66, 2], [67, 0], [67, 1], [70, 1], [70, 2], [76, 1], [76, 2]], + performAction: function anonymous(yytext, yyleng, yylineno, yy, yystate, $$, _$) { + + var $0 = $$.length - 1; + switch (yystate) { + case 1: + return $$[$0 - 1]; + break; + case 2: + this.$ = yy.prepareProgram($$[$0]); + break; + case 3: + this.$ = $$[$0]; + break; + case 4: + this.$ = $$[$0]; + break; + case 5: + this.$ = $$[$0]; + break; + case 6: + this.$ = $$[$0]; + break; + case 7: + this.$ = $$[$0]; + break; + case 8: + this.$ = $$[$0]; + break; + case 9: + this.$ = { + type: 'CommentStatement', + value: yy.stripComment($$[$0]), + strip: yy.stripFlags($$[$0], $$[$0]), + loc: yy.locInfo(this._$) + }; + + break; + case 10: + this.$ = { + type: 'ContentStatement', + original: $$[$0], + value: $$[$0], + loc: yy.locInfo(this._$) + }; + + break; + case 11: + this.$ = yy.prepareRawBlock($$[$0 - 2], $$[$0 - 1], $$[$0], this._$); + break; + case 12: + this.$ = { path: $$[$0 - 3], params: $$[$0 - 2], hash: $$[$0 - 1] }; + break; + case 13: + this.$ = yy.prepareBlock($$[$0 - 3], $$[$0 - 2], $$[$0 - 1], $$[$0], false, this._$); + break; + case 14: + this.$ = yy.prepareBlock($$[$0 - 3], $$[$0 - 2], $$[$0 - 1], $$[$0], true, this._$); + break; + case 15: + this.$ = { open: $$[$0 - 5], path: $$[$0 - 4], params: $$[$0 - 3], hash: $$[$0 - 2], blockParams: $$[$0 - 1], strip: yy.stripFlags($$[$0 - 5], $$[$0]) }; + break; + case 16: + this.$ = { path: $$[$0 - 4], params: $$[$0 - 3], hash: $$[$0 - 2], blockParams: $$[$0 - 1], strip: yy.stripFlags($$[$0 - 5], $$[$0]) }; + break; + case 17: + this.$ = { path: $$[$0 - 4], params: $$[$0 - 3], hash: $$[$0 - 2], blockParams: $$[$0 - 1], strip: yy.stripFlags($$[$0 - 5], $$[$0]) }; + break; + case 18: + this.$ = { strip: yy.stripFlags($$[$0 - 1], $$[$0 - 1]), program: $$[$0] }; + break; + case 19: + var inverse = yy.prepareBlock($$[$0 - 2], $$[$0 - 1], $$[$0], $$[$0], false, this._$), + program = yy.prepareProgram([inverse], $$[$0 - 1].loc); + program.chained = true; + + this.$ = { strip: $$[$0 - 2].strip, program: program, chain: true }; + + break; + case 20: + this.$ = $$[$0]; + break; + case 21: + this.$ = { path: $$[$0 - 1], strip: yy.stripFlags($$[$0 - 2], $$[$0]) }; + break; + case 22: + this.$ = yy.prepareMustache($$[$0 - 3], $$[$0 - 2], $$[$0 - 1], $$[$0 - 4], yy.stripFlags($$[$0 - 4], $$[$0]), this._$); + break; + case 23: + this.$ = yy.prepareMustache($$[$0 - 3], $$[$0 - 2], $$[$0 - 1], $$[$0 - 4], yy.stripFlags($$[$0 - 4], $$[$0]), this._$); + break; + case 24: + this.$ = { + type: 'PartialStatement', + name: $$[$0 - 3], + params: $$[$0 - 2], + hash: $$[$0 - 1], + indent: '', + strip: yy.stripFlags($$[$0 - 4], $$[$0]), + loc: yy.locInfo(this._$) + }; + + break; + case 25: + this.$ = yy.preparePartialBlock($$[$0 - 2], $$[$0 - 1], $$[$0], this._$); + break; + case 26: + this.$ = { path: $$[$0 - 3], params: $$[$0 - 2], hash: $$[$0 - 1], strip: yy.stripFlags($$[$0 - 4], $$[$0]) }; + break; + case 27: + this.$ = $$[$0]; + break; + case 28: + this.$ = $$[$0]; + break; + case 29: + this.$ = { + type: 'SubExpression', + path: $$[$0 - 3], + params: $$[$0 - 2], + hash: $$[$0 - 1], + loc: yy.locInfo(this._$) + }; + + break; + case 30: + this.$ = { type: 'Hash', pairs: $$[$0], loc: yy.locInfo(this._$) }; + break; + case 31: + this.$ = { type: 'HashPair', key: yy.id($$[$0 - 2]), value: $$[$0], loc: yy.locInfo(this._$) }; + break; + case 32: + this.$ = yy.id($$[$0 - 1]); + break; + case 33: + this.$ = $$[$0]; + break; + case 34: + this.$ = $$[$0]; + break; + case 35: + this.$ = { type: 'StringLiteral', value: $$[$0], original: $$[$0], loc: yy.locInfo(this._$) }; + break; + case 36: + this.$ = { type: 'NumberLiteral', value: Number($$[$0]), original: Number($$[$0]), loc: yy.locInfo(this._$) }; + break; + case 37: + this.$ = { type: 'BooleanLiteral', value: $$[$0] === 'true', original: $$[$0] === 'true', loc: yy.locInfo(this._$) }; + break; + case 38: + this.$ = { type: 'UndefinedLiteral', original: undefined, value: undefined, loc: yy.locInfo(this._$) }; + break; + case 39: + this.$ = { type: 'NullLiteral', original: null, value: null, loc: yy.locInfo(this._$) }; + break; + case 40: + this.$ = $$[$0]; + break; + case 41: + this.$ = $$[$0]; + break; + case 42: + this.$ = yy.preparePath(true, $$[$0], this._$); + break; + case 43: + this.$ = yy.preparePath(false, $$[$0], this._$); + break; + case 44: + $$[$0 - 2].push({ part: yy.id($$[$0]), original: $$[$0], separator: $$[$0 - 1] });this.$ = $$[$0 - 2]; + break; + case 45: + this.$ = [{ part: yy.id($$[$0]), original: $$[$0] }]; + break; + case 46: + this.$ = []; + break; + case 47: + $$[$0 - 1].push($$[$0]); + break; + case 48: + this.$ = []; + break; + case 49: + $$[$0 - 1].push($$[$0]); + break; + case 50: + this.$ = []; + break; + case 51: + $$[$0 - 1].push($$[$0]); + break; + case 58: + this.$ = []; + break; + case 59: + $$[$0 - 1].push($$[$0]); + break; + case 64: + this.$ = []; + break; + case 65: + $$[$0 - 1].push($$[$0]); + break; + case 70: + this.$ = []; + break; + case 71: + $$[$0 - 1].push($$[$0]); + break; + case 78: + this.$ = []; + break; + case 79: + $$[$0 - 1].push($$[$0]); + break; + case 82: + this.$ = []; + break; + case 83: + $$[$0 - 1].push($$[$0]); + break; + case 86: + this.$ = []; + break; + case 87: + $$[$0 - 1].push($$[$0]); + break; + case 90: + this.$ = []; + break; + case 91: + $$[$0 - 1].push($$[$0]); + break; + case 94: + this.$ = []; + break; + case 95: + $$[$0 - 1].push($$[$0]); + break; + case 98: + this.$ = [$$[$0]]; + break; + case 99: + $$[$0 - 1].push($$[$0]); + break; + case 100: + this.$ = [$$[$0]]; + break; + case 101: + $$[$0 - 1].push($$[$0]); + break; + } + }, + table: [{ 3: 1, 4: 2, 5: [2, 46], 6: 3, 14: [2, 46], 15: [2, 46], 19: [2, 46], 29: [2, 46], 34: [2, 46], 48: [2, 46], 51: [2, 46], 55: [2, 46], 60: [2, 46] }, { 1: [3] }, { 5: [1, 4] }, { 5: [2, 2], 7: 5, 8: 6, 9: 7, 10: 8, 11: 9, 12: 10, 13: 11, 14: [1, 12], 15: [1, 20], 16: 17, 19: [1, 23], 24: 15, 27: 16, 29: [1, 21], 34: [1, 22], 39: [2, 2], 44: [2, 2], 47: [2, 2], 48: [1, 13], 51: [1, 14], 55: [1, 18], 59: 19, 60: [1, 24] }, { 1: [2, 1] }, { 5: [2, 47], 14: [2, 47], 15: [2, 47], 19: [2, 47], 29: [2, 47], 34: [2, 47], 39: [2, 47], 44: [2, 47], 47: [2, 47], 48: [2, 47], 51: [2, 47], 55: [2, 47], 60: [2, 47] }, { 5: [2, 3], 14: [2, 3], 15: [2, 3], 19: [2, 3], 29: [2, 3], 34: [2, 3], 39: [2, 3], 44: [2, 3], 47: [2, 3], 48: [2, 3], 51: [2, 3], 55: [2, 3], 60: [2, 3] }, { 5: [2, 4], 14: [2, 4], 15: [2, 4], 19: [2, 4], 29: [2, 4], 34: [2, 4], 39: [2, 4], 44: [2, 4], 47: [2, 4], 48: [2, 4], 51: [2, 4], 55: [2, 4], 60: [2, 4] }, { 5: [2, 5], 14: [2, 5], 15: [2, 5], 19: [2, 5], 29: [2, 5], 34: [2, 5], 39: [2, 5], 44: [2, 5], 47: [2, 5], 48: [2, 5], 51: [2, 5], 55: [2, 5], 60: [2, 5] }, { 5: [2, 6], 14: [2, 6], 15: [2, 6], 19: [2, 6], 29: [2, 6], 34: [2, 6], 39: [2, 6], 44: [2, 6], 47: [2, 6], 48: [2, 6], 51: [2, 6], 55: [2, 6], 60: [2, 6] }, { 5: [2, 7], 14: [2, 7], 15: [2, 7], 19: [2, 7], 29: [2, 7], 34: [2, 7], 39: [2, 7], 44: [2, 7], 47: [2, 7], 48: [2, 7], 51: [2, 7], 55: [2, 7], 60: [2, 7] }, { 5: [2, 8], 14: [2, 8], 15: [2, 8], 19: [2, 8], 29: [2, 8], 34: [2, 8], 39: [2, 8], 44: [2, 8], 47: [2, 8], 48: [2, 8], 51: [2, 8], 55: [2, 8], 60: [2, 8] }, { 5: [2, 9], 14: [2, 9], 15: [2, 9], 19: [2, 9], 29: [2, 9], 34: [2, 9], 39: [2, 9], 44: [2, 9], 47: [2, 9], 48: [2, 9], 51: [2, 9], 55: [2, 9], 60: [2, 9] }, { 20: 25, 72: [1, 35], 78: 26, 79: 27, 80: [1, 28], 81: [1, 29], 82: [1, 30], 83: [1, 31], 84: [1, 32], 85: [1, 34], 86: 33 }, { 20: 36, 72: [1, 35], 78: 26, 79: 27, 80: [1, 28], 81: [1, 29], 82: [1, 30], 83: [1, 31], 84: [1, 32], 85: [1, 34], 86: 33 }, { 4: 37, 6: 3, 14: [2, 46], 15: [2, 46], 19: [2, 46], 29: [2, 46], 34: [2, 46], 39: [2, 46], 44: [2, 46], 47: [2, 46], 48: [2, 46], 51: [2, 46], 55: [2, 46], 60: [2, 46] }, { 4: 38, 6: 3, 14: [2, 46], 15: [2, 46], 19: [2, 46], 29: [2, 46], 34: [2, 46], 44: [2, 46], 47: [2, 46], 48: [2, 46], 51: [2, 46], 55: [2, 46], 60: [2, 46] }, { 15: [2, 48], 17: 39, 18: [2, 48] }, { 20: 41, 56: 40, 64: 42, 65: [1, 43], 72: [1, 35], 78: 26, 79: 27, 80: [1, 28], 81: [1, 29], 82: [1, 30], 83: [1, 31], 84: [1, 32], 85: [1, 34], 86: 33 }, { 4: 44, 6: 3, 14: [2, 46], 15: [2, 46], 19: [2, 46], 29: [2, 46], 34: [2, 46], 47: [2, 46], 48: [2, 46], 51: [2, 46], 55: [2, 46], 60: [2, 46] }, { 5: [2, 10], 14: [2, 10], 15: [2, 10], 18: [2, 10], 19: [2, 10], 29: [2, 10], 34: [2, 10], 39: [2, 10], 44: [2, 10], 47: [2, 10], 48: [2, 10], 51: [2, 10], 55: [2, 10], 60: [2, 10] }, { 20: 45, 72: [1, 35], 78: 26, 79: 27, 80: [1, 28], 81: [1, 29], 82: [1, 30], 83: [1, 31], 84: [1, 32], 85: [1, 34], 86: 33 }, { 20: 46, 72: [1, 35], 78: 26, 79: 27, 80: [1, 28], 81: [1, 29], 82: [1, 30], 83: [1, 31], 84: [1, 32], 85: [1, 34], 86: 33 }, { 20: 47, 72: [1, 35], 78: 26, 79: 27, 80: [1, 28], 81: [1, 29], 82: [1, 30], 83: [1, 31], 84: [1, 32], 85: [1, 34], 86: 33 }, { 20: 41, 56: 48, 64: 42, 65: [1, 43], 72: [1, 35], 78: 26, 79: 27, 80: [1, 28], 81: [1, 29], 82: [1, 30], 83: [1, 31], 84: [1, 32], 85: [1, 34], 86: 33 }, { 33: [2, 78], 49: 49, 65: [2, 78], 72: [2, 78], 80: [2, 78], 81: [2, 78], 82: [2, 78], 83: [2, 78], 84: [2, 78], 85: [2, 78] }, { 23: [2, 33], 33: [2, 33], 54: [2, 33], 65: [2, 33], 68: [2, 33], 72: [2, 33], 75: [2, 33], 80: [2, 33], 81: [2, 33], 82: [2, 33], 83: [2, 33], 84: [2, 33], 85: [2, 33] }, { 23: [2, 34], 33: [2, 34], 54: [2, 34], 65: [2, 34], 68: [2, 34], 72: [2, 34], 75: [2, 34], 80: [2, 34], 81: [2, 34], 82: [2, 34], 83: [2, 34], 84: [2, 34], 85: [2, 34] }, { 23: [2, 35], 33: [2, 35], 54: [2, 35], 65: [2, 35], 68: [2, 35], 72: [2, 35], 75: [2, 35], 80: [2, 35], 81: [2, 35], 82: [2, 35], 83: [2, 35], 84: [2, 35], 85: [2, 35] }, { 23: [2, 36], 33: [2, 36], 54: [2, 36], 65: [2, 36], 68: [2, 36], 72: [2, 36], 75: [2, 36], 80: [2, 36], 81: [2, 36], 82: [2, 36], 83: [2, 36], 84: [2, 36], 85: [2, 36] }, { 23: [2, 37], 33: [2, 37], 54: [2, 37], 65: [2, 37], 68: [2, 37], 72: [2, 37], 75: [2, 37], 80: [2, 37], 81: [2, 37], 82: [2, 37], 83: [2, 37], 84: [2, 37], 85: [2, 37] }, { 23: [2, 38], 33: [2, 38], 54: [2, 38], 65: [2, 38], 68: [2, 38], 72: [2, 38], 75: [2, 38], 80: [2, 38], 81: [2, 38], 82: [2, 38], 83: [2, 38], 84: [2, 38], 85: [2, 38] }, { 23: [2, 39], 33: [2, 39], 54: [2, 39], 65: [2, 39], 68: [2, 39], 72: [2, 39], 75: [2, 39], 80: [2, 39], 81: [2, 39], 82: [2, 39], 83: [2, 39], 84: [2, 39], 85: [2, 39] }, { 23: [2, 43], 33: [2, 43], 54: [2, 43], 65: [2, 43], 68: [2, 43], 72: [2, 43], 75: [2, 43], 80: [2, 43], 81: [2, 43], 82: [2, 43], 83: [2, 43], 84: [2, 43], 85: [2, 43], 87: [1, 50] }, { 72: [1, 35], 86: 51 }, { 23: [2, 45], 33: [2, 45], 54: [2, 45], 65: [2, 45], 68: [2, 45], 72: [2, 45], 75: [2, 45], 80: [2, 45], 81: [2, 45], 82: [2, 45], 83: [2, 45], 84: [2, 45], 85: [2, 45], 87: [2, 45] }, { 52: 52, 54: [2, 82], 65: [2, 82], 72: [2, 82], 80: [2, 82], 81: [2, 82], 82: [2, 82], 83: [2, 82], 84: [2, 82], 85: [2, 82] }, { 25: 53, 38: 55, 39: [1, 57], 43: 56, 44: [1, 58], 45: 54, 47: [2, 54] }, { 28: 59, 43: 60, 44: [1, 58], 47: [2, 56] }, { 13: 62, 15: [1, 20], 18: [1, 61] }, { 33: [2, 86], 57: 63, 65: [2, 86], 72: [2, 86], 80: [2, 86], 81: [2, 86], 82: [2, 86], 83: [2, 86], 84: [2, 86], 85: [2, 86] }, { 33: [2, 40], 65: [2, 40], 72: [2, 40], 80: [2, 40], 81: [2, 40], 82: [2, 40], 83: [2, 40], 84: [2, 40], 85: [2, 40] }, { 33: [2, 41], 65: [2, 41], 72: [2, 41], 80: [2, 41], 81: [2, 41], 82: [2, 41], 83: [2, 41], 84: [2, 41], 85: [2, 41] }, { 20: 64, 72: [1, 35], 78: 26, 79: 27, 80: [1, 28], 81: [1, 29], 82: [1, 30], 83: [1, 31], 84: [1, 32], 85: [1, 34], 86: 33 }, { 26: 65, 47: [1, 66] }, { 30: 67, 33: [2, 58], 65: [2, 58], 72: [2, 58], 75: [2, 58], 80: [2, 58], 81: [2, 58], 82: [2, 58], 83: [2, 58], 84: [2, 58], 85: [2, 58] }, { 33: [2, 64], 35: 68, 65: [2, 64], 72: [2, 64], 75: [2, 64], 80: [2, 64], 81: [2, 64], 82: [2, 64], 83: [2, 64], 84: [2, 64], 85: [2, 64] }, { 21: 69, 23: [2, 50], 65: [2, 50], 72: [2, 50], 80: [2, 50], 81: [2, 50], 82: [2, 50], 83: [2, 50], 84: [2, 50], 85: [2, 50] }, { 33: [2, 90], 61: 70, 65: [2, 90], 72: [2, 90], 80: [2, 90], 81: [2, 90], 82: [2, 90], 83: [2, 90], 84: [2, 90], 85: [2, 90] }, { 20: 74, 33: [2, 80], 50: 71, 63: 72, 64: 75, 65: [1, 43], 69: 73, 70: 76, 71: 77, 72: [1, 78], 78: 26, 79: 27, 80: [1, 28], 81: [1, 29], 82: [1, 30], 83: [1, 31], 84: [1, 32], 85: [1, 34], 86: 33 }, { 72: [1, 79] }, { 23: [2, 42], 33: [2, 42], 54: [2, 42], 65: [2, 42], 68: [2, 42], 72: [2, 42], 75: [2, 42], 80: [2, 42], 81: [2, 42], 82: [2, 42], 83: [2, 42], 84: [2, 42], 85: [2, 42], 87: [1, 50] }, { 20: 74, 53: 80, 54: [2, 84], 63: 81, 64: 75, 65: [1, 43], 69: 82, 70: 76, 71: 77, 72: [1, 78], 78: 26, 79: 27, 80: [1, 28], 81: [1, 29], 82: [1, 30], 83: [1, 31], 84: [1, 32], 85: [1, 34], 86: 33 }, { 26: 83, 47: [1, 66] }, { 47: [2, 55] }, { 4: 84, 6: 3, 14: [2, 46], 15: [2, 46], 19: [2, 46], 29: [2, 46], 34: [2, 46], 39: [2, 46], 44: [2, 46], 47: [2, 46], 48: [2, 46], 51: [2, 46], 55: [2, 46], 60: [2, 46] }, { 47: [2, 20] }, { 20: 85, 72: [1, 35], 78: 26, 79: 27, 80: [1, 28], 81: [1, 29], 82: [1, 30], 83: [1, 31], 84: [1, 32], 85: [1, 34], 86: 33 }, { 4: 86, 6: 3, 14: [2, 46], 15: [2, 46], 19: [2, 46], 29: [2, 46], 34: [2, 46], 47: [2, 46], 48: [2, 46], 51: [2, 46], 55: [2, 46], 60: [2, 46] }, { 26: 87, 47: [1, 66] }, { 47: [2, 57] }, { 5: [2, 11], 14: [2, 11], 15: [2, 11], 19: [2, 11], 29: [2, 11], 34: [2, 11], 39: [2, 11], 44: [2, 11], 47: [2, 11], 48: [2, 11], 51: [2, 11], 55: [2, 11], 60: [2, 11] }, { 15: [2, 49], 18: [2, 49] }, { 20: 74, 33: [2, 88], 58: 88, 63: 89, 64: 75, 65: [1, 43], 69: 90, 70: 76, 71: 77, 72: [1, 78], 78: 26, 79: 27, 80: [1, 28], 81: [1, 29], 82: [1, 30], 83: [1, 31], 84: [1, 32], 85: [1, 34], 86: 33 }, { 65: [2, 94], 66: 91, 68: [2, 94], 72: [2, 94], 80: [2, 94], 81: [2, 94], 82: [2, 94], 83: [2, 94], 84: [2, 94], 85: [2, 94] }, { 5: [2, 25], 14: [2, 25], 15: [2, 25], 19: [2, 25], 29: [2, 25], 34: [2, 25], 39: [2, 25], 44: [2, 25], 47: [2, 25], 48: [2, 25], 51: [2, 25], 55: [2, 25], 60: [2, 25] }, { 20: 92, 72: [1, 35], 78: 26, 79: 27, 80: [1, 28], 81: [1, 29], 82: [1, 30], 83: [1, 31], 84: [1, 32], 85: [1, 34], 86: 33 }, { 20: 74, 31: 93, 33: [2, 60], 63: 94, 64: 75, 65: [1, 43], 69: 95, 70: 76, 71: 77, 72: [1, 78], 75: [2, 60], 78: 26, 79: 27, 80: [1, 28], 81: [1, 29], 82: [1, 30], 83: [1, 31], 84: [1, 32], 85: [1, 34], 86: 33 }, { 20: 74, 33: [2, 66], 36: 96, 63: 97, 64: 75, 65: [1, 43], 69: 98, 70: 76, 71: 77, 72: [1, 78], 75: [2, 66], 78: 26, 79: 27, 80: [1, 28], 81: [1, 29], 82: [1, 30], 83: [1, 31], 84: [1, 32], 85: [1, 34], 86: 33 }, { 20: 74, 22: 99, 23: [2, 52], 63: 100, 64: 75, 65: [1, 43], 69: 101, 70: 76, 71: 77, 72: [1, 78], 78: 26, 79: 27, 80: [1, 28], 81: [1, 29], 82: [1, 30], 83: [1, 31], 84: [1, 32], 85: [1, 34], 86: 33 }, { 20: 74, 33: [2, 92], 62: 102, 63: 103, 64: 75, 65: [1, 43], 69: 104, 70: 76, 71: 77, 72: [1, 78], 78: 26, 79: 27, 80: [1, 28], 81: [1, 29], 82: [1, 30], 83: [1, 31], 84: [1, 32], 85: [1, 34], 86: 33 }, { 33: [1, 105] }, { 33: [2, 79], 65: [2, 79], 72: [2, 79], 80: [2, 79], 81: [2, 79], 82: [2, 79], 83: [2, 79], 84: [2, 79], 85: [2, 79] }, { 33: [2, 81] }, { 23: [2, 27], 33: [2, 27], 54: [2, 27], 65: [2, 27], 68: [2, 27], 72: [2, 27], 75: [2, 27], 80: [2, 27], 81: [2, 27], 82: [2, 27], 83: [2, 27], 84: [2, 27], 85: [2, 27] }, { 23: [2, 28], 33: [2, 28], 54: [2, 28], 65: [2, 28], 68: [2, 28], 72: [2, 28], 75: [2, 28], 80: [2, 28], 81: [2, 28], 82: [2, 28], 83: [2, 28], 84: [2, 28], 85: [2, 28] }, { 23: [2, 30], 33: [2, 30], 54: [2, 30], 68: [2, 30], 71: 106, 72: [1, 107], 75: [2, 30] }, { 23: [2, 98], 33: [2, 98], 54: [2, 98], 68: [2, 98], 72: [2, 98], 75: [2, 98] }, { 23: [2, 45], 33: [2, 45], 54: [2, 45], 65: [2, 45], 68: [2, 45], 72: [2, 45], 73: [1, 108], 75: [2, 45], 80: [2, 45], 81: [2, 45], 82: [2, 45], 83: [2, 45], 84: [2, 45], 85: [2, 45], 87: [2, 45] }, { 23: [2, 44], 33: [2, 44], 54: [2, 44], 65: [2, 44], 68: [2, 44], 72: [2, 44], 75: [2, 44], 80: [2, 44], 81: [2, 44], 82: [2, 44], 83: [2, 44], 84: [2, 44], 85: [2, 44], 87: [2, 44] }, { 54: [1, 109] }, { 54: [2, 83], 65: [2, 83], 72: [2, 83], 80: [2, 83], 81: [2, 83], 82: [2, 83], 83: [2, 83], 84: [2, 83], 85: [2, 83] }, { 54: [2, 85] }, { 5: [2, 13], 14: [2, 13], 15: [2, 13], 19: [2, 13], 29: [2, 13], 34: [2, 13], 39: [2, 13], 44: [2, 13], 47: [2, 13], 48: [2, 13], 51: [2, 13], 55: [2, 13], 60: [2, 13] }, { 38: 55, 39: [1, 57], 43: 56, 44: [1, 58], 45: 111, 46: 110, 47: [2, 76] }, { 33: [2, 70], 40: 112, 65: [2, 70], 72: [2, 70], 75: [2, 70], 80: [2, 70], 81: [2, 70], 82: [2, 70], 83: [2, 70], 84: [2, 70], 85: [2, 70] }, { 47: [2, 18] }, { 5: [2, 14], 14: [2, 14], 15: [2, 14], 19: [2, 14], 29: [2, 14], 34: [2, 14], 39: [2, 14], 44: [2, 14], 47: [2, 14], 48: [2, 14], 51: [2, 14], 55: [2, 14], 60: [2, 14] }, { 33: [1, 113] }, { 33: [2, 87], 65: [2, 87], 72: [2, 87], 80: [2, 87], 81: [2, 87], 82: [2, 87], 83: [2, 87], 84: [2, 87], 85: [2, 87] }, { 33: [2, 89] }, { 20: 74, 63: 115, 64: 75, 65: [1, 43], 67: 114, 68: [2, 96], 69: 116, 70: 76, 71: 77, 72: [1, 78], 78: 26, 79: 27, 80: [1, 28], 81: [1, 29], 82: [1, 30], 83: [1, 31], 84: [1, 32], 85: [1, 34], 86: 33 }, { 33: [1, 117] }, { 32: 118, 33: [2, 62], 74: 119, 75: [1, 120] }, { 33: [2, 59], 65: [2, 59], 72: [2, 59], 75: [2, 59], 80: [2, 59], 81: [2, 59], 82: [2, 59], 83: [2, 59], 84: [2, 59], 85: [2, 59] }, { 33: [2, 61], 75: [2, 61] }, { 33: [2, 68], 37: 121, 74: 122, 75: [1, 120] }, { 33: [2, 65], 65: [2, 65], 72: [2, 65], 75: [2, 65], 80: [2, 65], 81: [2, 65], 82: [2, 65], 83: [2, 65], 84: [2, 65], 85: [2, 65] }, { 33: [2, 67], 75: [2, 67] }, { 23: [1, 123] }, { 23: [2, 51], 65: [2, 51], 72: [2, 51], 80: [2, 51], 81: [2, 51], 82: [2, 51], 83: [2, 51], 84: [2, 51], 85: [2, 51] }, { 23: [2, 53] }, { 33: [1, 124] }, { 33: [2, 91], 65: [2, 91], 72: [2, 91], 80: [2, 91], 81: [2, 91], 82: [2, 91], 83: [2, 91], 84: [2, 91], 85: [2, 91] }, { 33: [2, 93] }, { 5: [2, 22], 14: [2, 22], 15: [2, 22], 19: [2, 22], 29: [2, 22], 34: [2, 22], 39: [2, 22], 44: [2, 22], 47: [2, 22], 48: [2, 22], 51: [2, 22], 55: [2, 22], 60: [2, 22] }, { 23: [2, 99], 33: [2, 99], 54: [2, 99], 68: [2, 99], 72: [2, 99], 75: [2, 99] }, { 73: [1, 108] }, { 20: 74, 63: 125, 64: 75, 65: [1, 43], 72: [1, 35], 78: 26, 79: 27, 80: [1, 28], 81: [1, 29], 82: [1, 30], 83: [1, 31], 84: [1, 32], 85: [1, 34], 86: 33 }, { 5: [2, 23], 14: [2, 23], 15: [2, 23], 19: [2, 23], 29: [2, 23], 34: [2, 23], 39: [2, 23], 44: [2, 23], 47: [2, 23], 48: [2, 23], 51: [2, 23], 55: [2, 23], 60: [2, 23] }, { 47: [2, 19] }, { 47: [2, 77] }, { 20: 74, 33: [2, 72], 41: 126, 63: 127, 64: 75, 65: [1, 43], 69: 128, 70: 76, 71: 77, 72: [1, 78], 75: [2, 72], 78: 26, 79: 27, 80: [1, 28], 81: [1, 29], 82: [1, 30], 83: [1, 31], 84: [1, 32], 85: [1, 34], 86: 33 }, { 5: [2, 24], 14: [2, 24], 15: [2, 24], 19: [2, 24], 29: [2, 24], 34: [2, 24], 39: [2, 24], 44: [2, 24], 47: [2, 24], 48: [2, 24], 51: [2, 24], 55: [2, 24], 60: [2, 24] }, { 68: [1, 129] }, { 65: [2, 95], 68: [2, 95], 72: [2, 95], 80: [2, 95], 81: [2, 95], 82: [2, 95], 83: [2, 95], 84: [2, 95], 85: [2, 95] }, { 68: [2, 97] }, { 5: [2, 21], 14: [2, 21], 15: [2, 21], 19: [2, 21], 29: [2, 21], 34: [2, 21], 39: [2, 21], 44: [2, 21], 47: [2, 21], 48: [2, 21], 51: [2, 21], 55: [2, 21], 60: [2, 21] }, { 33: [1, 130] }, { 33: [2, 63] }, { 72: [1, 132], 76: 131 }, { 33: [1, 133] }, { 33: [2, 69] }, { 15: [2, 12], 18: [2, 12] }, { 14: [2, 26], 15: [2, 26], 19: [2, 26], 29: [2, 26], 34: [2, 26], 47: [2, 26], 48: [2, 26], 51: [2, 26], 55: [2, 26], 60: [2, 26] }, { 23: [2, 31], 33: [2, 31], 54: [2, 31], 68: [2, 31], 72: [2, 31], 75: [2, 31] }, { 33: [2, 74], 42: 134, 74: 135, 75: [1, 120] }, { 33: [2, 71], 65: [2, 71], 72: [2, 71], 75: [2, 71], 80: [2, 71], 81: [2, 71], 82: [2, 71], 83: [2, 71], 84: [2, 71], 85: [2, 71] }, { 33: [2, 73], 75: [2, 73] }, { 23: [2, 29], 33: [2, 29], 54: [2, 29], 65: [2, 29], 68: [2, 29], 72: [2, 29], 75: [2, 29], 80: [2, 29], 81: [2, 29], 82: [2, 29], 83: [2, 29], 84: [2, 29], 85: [2, 29] }, { 14: [2, 15], 15: [2, 15], 19: [2, 15], 29: [2, 15], 34: [2, 15], 39: [2, 15], 44: [2, 15], 47: [2, 15], 48: [2, 15], 51: [2, 15], 55: [2, 15], 60: [2, 15] }, { 72: [1, 137], 77: [1, 136] }, { 72: [2, 100], 77: [2, 100] }, { 14: [2, 16], 15: [2, 16], 19: [2, 16], 29: [2, 16], 34: [2, 16], 44: [2, 16], 47: [2, 16], 48: [2, 16], 51: [2, 16], 55: [2, 16], 60: [2, 16] }, { 33: [1, 138] }, { 33: [2, 75] }, { 33: [2, 32] }, { 72: [2, 101], 77: [2, 101] }, { 14: [2, 17], 15: [2, 17], 19: [2, 17], 29: [2, 17], 34: [2, 17], 39: [2, 17], 44: [2, 17], 47: [2, 17], 48: [2, 17], 51: [2, 17], 55: [2, 17], 60: [2, 17] }], + defaultActions: { 4: [2, 1], 54: [2, 55], 56: [2, 20], 60: [2, 57], 73: [2, 81], 82: [2, 85], 86: [2, 18], 90: [2, 89], 101: [2, 53], 104: [2, 93], 110: [2, 19], 111: [2, 77], 116: [2, 97], 119: [2, 63], 122: [2, 69], 135: [2, 75], 136: [2, 32] }, + parseError: function parseError(str, hash) { + throw new Error(str); + }, + parse: function parse(input) { + var self = this, + stack = [0], + vstack = [null], + lstack = [], + table = this.table, + yytext = "", + yylineno = 0, + yyleng = 0, + recovering = 0, + TERROR = 2, + EOF = 1; + this.lexer.setInput(input); + this.lexer.yy = this.yy; + this.yy.lexer = this.lexer; + this.yy.parser = this; + if (typeof this.lexer.yylloc == "undefined") this.lexer.yylloc = {}; + var yyloc = this.lexer.yylloc; + lstack.push(yyloc); + var ranges = this.lexer.options && this.lexer.options.ranges; + if (typeof this.yy.parseError === "function") this.parseError = this.yy.parseError; + function popStack(n) { + stack.length = stack.length - 2 * n; + vstack.length = vstack.length - n; + lstack.length = lstack.length - n; + } + function lex() { + var token; + token = self.lexer.lex() || 1; + if (typeof token !== "number") { + token = self.symbols_[token] || token; + } + return token; + } + var symbol, + preErrorSymbol, + state, + action, + a, + r, + yyval = {}, + p, + len, + newState, + expected; + while (true) { + state = stack[stack.length - 1]; + if (this.defaultActions[state]) { + action = this.defaultActions[state]; + } else { + if (symbol === null || typeof symbol == "undefined") { + symbol = lex(); + } + action = table[state] && table[state][symbol]; + } + if (typeof action === "undefined" || !action.length || !action[0]) { + var errStr = ""; + if (!recovering) { + expected = []; + for (p in table[state]) if (this.terminals_[p] && p > 2) { + expected.push("'" + this.terminals_[p] + "'"); + } + if (this.lexer.showPosition) { + errStr = "Parse error on line " + (yylineno + 1) + ":\n" + this.lexer.showPosition() + "\nExpecting " + expected.join(", ") + ", got '" + (this.terminals_[symbol] || symbol) + "'"; + } else { + errStr = "Parse error on line " + (yylineno + 1) + ": Unexpected " + (symbol == 1 ? "end of input" : "'" + (this.terminals_[symbol] || symbol) + "'"); + } + this.parseError(errStr, { text: this.lexer.match, token: this.terminals_[symbol] || symbol, line: this.lexer.yylineno, loc: yyloc, expected: expected }); + } + } + if (action[0] instanceof Array && action.length > 1) { + throw new Error("Parse Error: multiple actions possible at state: " + state + ", token: " + symbol); + } + switch (action[0]) { + case 1: + stack.push(symbol); + vstack.push(this.lexer.yytext); + lstack.push(this.lexer.yylloc); + stack.push(action[1]); + symbol = null; + if (!preErrorSymbol) { + yyleng = this.lexer.yyleng; + yytext = this.lexer.yytext; + yylineno = this.lexer.yylineno; + yyloc = this.lexer.yylloc; + if (recovering > 0) recovering--; + } else { + symbol = preErrorSymbol; + preErrorSymbol = null; + } + break; + case 2: + len = this.productions_[action[1]][1]; + yyval.$ = vstack[vstack.length - len]; + yyval._$ = { first_line: lstack[lstack.length - (len || 1)].first_line, last_line: lstack[lstack.length - 1].last_line, first_column: lstack[lstack.length - (len || 1)].first_column, last_column: lstack[lstack.length - 1].last_column }; + if (ranges) { + yyval._$.range = [lstack[lstack.length - (len || 1)].range[0], lstack[lstack.length - 1].range[1]]; + } + r = this.performAction.call(yyval, yytext, yyleng, yylineno, this.yy, action[1], vstack, lstack); + if (typeof r !== "undefined") { + return r; + } + if (len) { + stack = stack.slice(0, -1 * len * 2); + vstack = vstack.slice(0, -1 * len); + lstack = lstack.slice(0, -1 * len); + } + stack.push(this.productions_[action[1]][0]); + vstack.push(yyval.$); + lstack.push(yyval._$); + newState = table[stack[stack.length - 2]][stack[stack.length - 1]]; + stack.push(newState); + break; + case 3: + return true; + } + } + return true; + } + }; + /* Jison generated lexer */ + var lexer = (function () { + var lexer = { EOF: 1, + parseError: function parseError(str, hash) { + if (this.yy.parser) { + this.yy.parser.parseError(str, hash); + } else { + throw new Error(str); + } + }, + setInput: function setInput(input) { + this._input = input; + this._more = this._less = this.done = false; + this.yylineno = this.yyleng = 0; + this.yytext = this.matched = this.match = ''; + this.conditionStack = ['INITIAL']; + this.yylloc = { first_line: 1, first_column: 0, last_line: 1, last_column: 0 }; + if (this.options.ranges) this.yylloc.range = [0, 0]; + this.offset = 0; + return this; + }, + input: function input() { + var ch = this._input[0]; + this.yytext += ch; + this.yyleng++; + this.offset++; + this.match += ch; + this.matched += ch; + var lines = ch.match(/(?:\r\n?|\n).*/g); + if (lines) { + this.yylineno++; + this.yylloc.last_line++; + } else { + this.yylloc.last_column++; + } + if (this.options.ranges) this.yylloc.range[1]++; + + this._input = this._input.slice(1); + return ch; + }, + unput: function unput(ch) { + var len = ch.length; + var lines = ch.split(/(?:\r\n?|\n)/g); + + this._input = ch + this._input; + this.yytext = this.yytext.substr(0, this.yytext.length - len - 1); + //this.yyleng -= len; + this.offset -= len; + var oldLines = this.match.split(/(?:\r\n?|\n)/g); + this.match = this.match.substr(0, this.match.length - 1); + this.matched = this.matched.substr(0, this.matched.length - 1); + + if (lines.length - 1) this.yylineno -= lines.length - 1; + var r = this.yylloc.range; + + this.yylloc = { first_line: this.yylloc.first_line, + last_line: this.yylineno + 1, + first_column: this.yylloc.first_column, + last_column: lines ? (lines.length === oldLines.length ? this.yylloc.first_column : 0) + oldLines[oldLines.length - lines.length].length - lines[0].length : this.yylloc.first_column - len + }; + + if (this.options.ranges) { + this.yylloc.range = [r[0], r[0] + this.yyleng - len]; + } + return this; + }, + more: function more() { + this._more = true; + return this; + }, + less: function less(n) { + this.unput(this.match.slice(n)); + }, + pastInput: function pastInput() { + var past = this.matched.substr(0, this.matched.length - this.match.length); + return (past.length > 20 ? '...' : '') + past.substr(-20).replace(/\n/g, ""); + }, + upcomingInput: function upcomingInput() { + var next = this.match; + if (next.length < 20) { + next += this._input.substr(0, 20 - next.length); + } + return (next.substr(0, 20) + (next.length > 20 ? '...' : '')).replace(/\n/g, ""); + }, + showPosition: function showPosition() { + var pre = this.pastInput(); + var c = new Array(pre.length + 1).join("-"); + return pre + this.upcomingInput() + "\n" + c + "^"; + }, + next: function next() { + if (this.done) { + return this.EOF; + } + if (!this._input) this.done = true; + + var token, match, tempMatch, index, col, lines; + if (!this._more) { + this.yytext = ''; + this.match = ''; + } + var rules = this._currentRules(); + for (var i = 0; i < rules.length; i++) { + tempMatch = this._input.match(this.rules[rules[i]]); + if (tempMatch && (!match || tempMatch[0].length > match[0].length)) { + match = tempMatch; + index = i; + if (!this.options.flex) break; + } + } + if (match) { + lines = match[0].match(/(?:\r\n?|\n).*/g); + if (lines) this.yylineno += lines.length; + this.yylloc = { first_line: this.yylloc.last_line, + last_line: this.yylineno + 1, + first_column: this.yylloc.last_column, + last_column: lines ? lines[lines.length - 1].length - lines[lines.length - 1].match(/\r?\n?/)[0].length : this.yylloc.last_column + match[0].length }; + this.yytext += match[0]; + this.match += match[0]; + this.matches = match; + this.yyleng = this.yytext.length; + if (this.options.ranges) { + this.yylloc.range = [this.offset, this.offset += this.yyleng]; + } + this._more = false; + this._input = this._input.slice(match[0].length); + this.matched += match[0]; + token = this.performAction.call(this, this.yy, this, rules[index], this.conditionStack[this.conditionStack.length - 1]); + if (this.done && this._input) this.done = false; + if (token) return token;else return; + } + if (this._input === "") { + return this.EOF; + } else { + return this.parseError('Lexical error on line ' + (this.yylineno + 1) + '. Unrecognized text.\n' + this.showPosition(), { text: "", token: null, line: this.yylineno }); + } + }, + lex: function lex() { + var r = this.next(); + if (typeof r !== 'undefined') { + return r; + } else { + return this.lex(); + } + }, + begin: function begin(condition) { + this.conditionStack.push(condition); + }, + popState: function popState() { + return this.conditionStack.pop(); + }, + _currentRules: function _currentRules() { + return this.conditions[this.conditionStack[this.conditionStack.length - 1]].rules; + }, + topState: function topState() { + return this.conditionStack[this.conditionStack.length - 2]; + }, + pushState: function begin(condition) { + this.begin(condition); + } }; + lexer.options = {}; + lexer.performAction = function anonymous(yy, yy_, $avoiding_name_collisions, YY_START) { + + function strip(start, end) { + return yy_.yytext = yy_.yytext.substring(start, yy_.yyleng - end + start); + } + + var YYSTATE = YY_START; + switch ($avoiding_name_collisions) { + case 0: + if (yy_.yytext.slice(-2) === "\\\\") { + strip(0, 1); + this.begin("mu"); + } else if (yy_.yytext.slice(-1) === "\\") { + strip(0, 1); + this.begin("emu"); + } else { + this.begin("mu"); + } + if (yy_.yytext) return 15; + + break; + case 1: + return 15; + break; + case 2: + this.popState(); + return 15; + + break; + case 3: + this.begin('raw');return 15; + break; + case 4: + this.popState(); + // Should be using `this.topState()` below, but it currently + // returns the second top instead of the first top. Opened an + // issue about it at https://github.com/zaach/jison/issues/291 + if (this.conditionStack[this.conditionStack.length - 1] === 'raw') { + return 15; + } else { + strip(5, 9); + return 'END_RAW_BLOCK'; + } + + break; + case 5: + return 15; + break; + case 6: + this.popState(); + return 14; + + break; + case 7: + return 65; + break; + case 8: + return 68; + break; + case 9: + return 19; + break; + case 10: + this.popState(); + this.begin('raw'); + return 23; + + break; + case 11: + return 55; + break; + case 12: + return 60; + break; + case 13: + return 29; + break; + case 14: + return 47; + break; + case 15: + this.popState();return 44; + break; + case 16: + this.popState();return 44; + break; + case 17: + return 34; + break; + case 18: + return 39; + break; + case 19: + return 51; + break; + case 20: + return 48; + break; + case 21: + this.unput(yy_.yytext); + this.popState(); + this.begin('com'); + + break; + case 22: + this.popState(); + return 14; + + break; + case 23: + return 48; + break; + case 24: + return 73; + break; + case 25: + return 72; + break; + case 26: + return 72; + break; + case 27: + return 87; + break; + case 28: + // ignore whitespace + break; + case 29: + this.popState();return 54; + break; + case 30: + this.popState();return 33; + break; + case 31: + yy_.yytext = strip(1, 2).replace(/\\"/g, '"');return 80; + break; + case 32: + yy_.yytext = strip(1, 2).replace(/\\'/g, "'");return 80; + break; + case 33: + return 85; + break; + case 34: + return 82; + break; + case 35: + return 82; + break; + case 36: + return 83; + break; + case 37: + return 84; + break; + case 38: + return 81; + break; + case 39: + return 75; + break; + case 40: + return 77; + break; + case 41: + return 72; + break; + case 42: + yy_.yytext = yy_.yytext.replace(/\\([\\\]])/g, '$1');return 72; + break; + case 43: + return 'INVALID'; + break; + case 44: + return 5; + break; + } + }; + lexer.rules = [/^(?:[^\x00]*?(?=(\{\{)))/, /^(?:[^\x00]+)/, /^(?:[^\x00]{2,}?(?=(\{\{|\\\{\{|\\\\\{\{|$)))/, /^(?:\{\{\{\{(?=[^\/]))/, /^(?:\{\{\{\{\/[^\s!"#%-,\.\/;->@\[-\^`\{-~]+(?=[=}\s\/.])\}\}\}\})/, /^(?:[^\x00]+?(?=(\{\{\{\{)))/, /^(?:[\s\S]*?--(~)?\}\})/, /^(?:\()/, /^(?:\))/, /^(?:\{\{\{\{)/, /^(?:\}\}\}\})/, /^(?:\{\{(~)?>)/, /^(?:\{\{(~)?#>)/, /^(?:\{\{(~)?#\*?)/, /^(?:\{\{(~)?\/)/, /^(?:\{\{(~)?\^\s*(~)?\}\})/, /^(?:\{\{(~)?\s*else\s*(~)?\}\})/, /^(?:\{\{(~)?\^)/, /^(?:\{\{(~)?\s*else\b)/, /^(?:\{\{(~)?\{)/, /^(?:\{\{(~)?&)/, /^(?:\{\{(~)?!--)/, /^(?:\{\{(~)?![\s\S]*?\}\})/, /^(?:\{\{(~)?\*?)/, /^(?:=)/, /^(?:\.\.)/, /^(?:\.(?=([=~}\s\/.)|])))/, /^(?:[\/.])/, /^(?:\s+)/, /^(?:\}(~)?\}\})/, /^(?:(~)?\}\})/, /^(?:"(\\["]|[^"])*")/, /^(?:'(\\[']|[^'])*')/, /^(?:@)/, /^(?:true(?=([~}\s)])))/, /^(?:false(?=([~}\s)])))/, /^(?:undefined(?=([~}\s)])))/, /^(?:null(?=([~}\s)])))/, /^(?:-?[0-9]+(?:\.[0-9]+)?(?=([~}\s)])))/, /^(?:as\s+\|)/, /^(?:\|)/, /^(?:([^\s!"#%-,\.\/;->@\[-\^`\{-~]+(?=([=~}\s\/.)|]))))/, /^(?:\[(\\\]|[^\]])*\])/, /^(?:.)/, /^(?:$)/]; + lexer.conditions = { "mu": { "rules": [7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44], "inclusive": false }, "emu": { "rules": [2], "inclusive": false }, "com": { "rules": [6], "inclusive": false }, "raw": { "rules": [3, 4, 5], "inclusive": false }, "INITIAL": { "rules": [0, 1, 44], "inclusive": true } }; + return lexer; + })(); + parser.lexer = lexer; + function Parser() { + this.yy = {}; + }Parser.prototype = parser;parser.Parser = Parser; + return new Parser(); + })();exports["default"] = handlebars; + module.exports = exports["default"]; + +/***/ }), +/* 48 */ +/***/ (function(module, exports, __webpack_require__) { + + 'use strict'; + + var _interopRequireDefault = __webpack_require__(1)['default']; + + exports.__esModule = true; + + var _visitor = __webpack_require__(49); + + var _visitor2 = _interopRequireDefault(_visitor); + + function WhitespaceControl() { + var options = arguments.length <= 0 || arguments[0] === undefined ? {} : arguments[0]; + + this.options = options; + } + WhitespaceControl.prototype = new _visitor2['default'](); + + WhitespaceControl.prototype.Program = function (program) { + var doStandalone = !this.options.ignoreStandalone; + + var isRoot = !this.isRootSeen; + this.isRootSeen = true; + + var body = program.body; + for (var i = 0, l = body.length; i < l; i++) { + var current = body[i], + strip = this.accept(current); + + if (!strip) { + continue; + } + + var _isPrevWhitespace = isPrevWhitespace(body, i, isRoot), + _isNextWhitespace = isNextWhitespace(body, i, isRoot), + openStandalone = strip.openStandalone && _isPrevWhitespace, + closeStandalone = strip.closeStandalone && _isNextWhitespace, + inlineStandalone = strip.inlineStandalone && _isPrevWhitespace && _isNextWhitespace; + + if (strip.close) { + omitRight(body, i, true); + } + if (strip.open) { + omitLeft(body, i, true); + } + + if (doStandalone && inlineStandalone) { + omitRight(body, i); + + if (omitLeft(body, i)) { + // If we are on a standalone node, save the indent info for partials + if (current.type === 'PartialStatement') { + // Pull out the whitespace from the final line + current.indent = /([ \t]+$)/.exec(body[i - 1].original)[1]; + } + } + } + if (doStandalone && openStandalone) { + omitRight((current.program || current.inverse).body); + + // Strip out the previous content node if it's whitespace only + omitLeft(body, i); + } + if (doStandalone && closeStandalone) { + // Always strip the next node + omitRight(body, i); + + omitLeft((current.inverse || current.program).body); + } + } + + return program; + }; + + WhitespaceControl.prototype.BlockStatement = WhitespaceControl.prototype.DecoratorBlock = WhitespaceControl.prototype.PartialBlockStatement = function (block) { + this.accept(block.program); + this.accept(block.inverse); + + // Find the inverse program that is involed with whitespace stripping. + var program = block.program || block.inverse, + inverse = block.program && block.inverse, + firstInverse = inverse, + lastInverse = inverse; + + if (inverse && inverse.chained) { + firstInverse = inverse.body[0].program; + + // Walk the inverse chain to find the last inverse that is actually in the chain. + while (lastInverse.chained) { + lastInverse = lastInverse.body[lastInverse.body.length - 1].program; + } + } + + var strip = { + open: block.openStrip.open, + close: block.closeStrip.close, + + // Determine the standalone candiacy. Basically flag our content as being possibly standalone + // so our parent can determine if we actually are standalone + openStandalone: isNextWhitespace(program.body), + closeStandalone: isPrevWhitespace((firstInverse || program).body) + }; + + if (block.openStrip.close) { + omitRight(program.body, null, true); + } + + if (inverse) { + var inverseStrip = block.inverseStrip; + + if (inverseStrip.open) { + omitLeft(program.body, null, true); + } + + if (inverseStrip.close) { + omitRight(firstInverse.body, null, true); + } + if (block.closeStrip.open) { + omitLeft(lastInverse.body, null, true); + } + + // Find standalone else statments + if (!this.options.ignoreStandalone && isPrevWhitespace(program.body) && isNextWhitespace(firstInverse.body)) { + omitLeft(program.body); + omitRight(firstInverse.body); + } + } else if (block.closeStrip.open) { + omitLeft(program.body, null, true); + } + + return strip; + }; + + WhitespaceControl.prototype.Decorator = WhitespaceControl.prototype.MustacheStatement = function (mustache) { + return mustache.strip; + }; + + WhitespaceControl.prototype.PartialStatement = WhitespaceControl.prototype.CommentStatement = function (node) { + /* istanbul ignore next */ + var strip = node.strip || {}; + return { + inlineStandalone: true, + open: strip.open, + close: strip.close + }; + }; + + function isPrevWhitespace(body, i, isRoot) { + if (i === undefined) { + i = body.length; + } + + // Nodes that end with newlines are considered whitespace (but are special + // cased for strip operations) + var prev = body[i - 1], + sibling = body[i - 2]; + if (!prev) { + return isRoot; + } + + if (prev.type === 'ContentStatement') { + return (sibling || !isRoot ? /\r?\n\s*?$/ : /(^|\r?\n)\s*?$/).test(prev.original); + } + } + function isNextWhitespace(body, i, isRoot) { + if (i === undefined) { + i = -1; + } + + var next = body[i + 1], + sibling = body[i + 2]; + if (!next) { + return isRoot; + } + + if (next.type === 'ContentStatement') { + return (sibling || !isRoot ? /^\s*?\r?\n/ : /^\s*?(\r?\n|$)/).test(next.original); + } + } + + // Marks the node to the right of the position as omitted. + // I.e. {{foo}}' ' will mark the ' ' node as omitted. + // + // If i is undefined, then the first child will be marked as such. + // + // If mulitple is truthy then all whitespace will be stripped out until non-whitespace + // content is met. + function omitRight(body, i, multiple) { + var current = body[i == null ? 0 : i + 1]; + if (!current || current.type !== 'ContentStatement' || !multiple && current.rightStripped) { + return; + } + + var original = current.value; + current.value = current.value.replace(multiple ? /^\s+/ : /^[ \t]*\r?\n?/, ''); + current.rightStripped = current.value !== original; + } + + // Marks the node to the left of the position as omitted. + // I.e. ' '{{foo}} will mark the ' ' node as omitted. + // + // If i is undefined then the last child will be marked as such. + // + // If mulitple is truthy then all whitespace will be stripped out until non-whitespace + // content is met. + function omitLeft(body, i, multiple) { + var current = body[i == null ? body.length - 1 : i - 1]; + if (!current || current.type !== 'ContentStatement' || !multiple && current.leftStripped) { + return; + } + + // We omit the last node if it's whitespace only and not preceded by a non-content node. + var original = current.value; + current.value = current.value.replace(multiple ? /\s+$/ : /[ \t]+$/, ''); + current.leftStripped = current.value !== original; + return current.leftStripped; + } + + exports['default'] = WhitespaceControl; + module.exports = exports['default']; + +/***/ }), +/* 49 */ +/***/ (function(module, exports, __webpack_require__) { + + 'use strict'; + + var _interopRequireDefault = __webpack_require__(1)['default']; + + exports.__esModule = true; + + var _exception = __webpack_require__(6); + + var _exception2 = _interopRequireDefault(_exception); + + function Visitor() { + this.parents = []; + } + + Visitor.prototype = { + constructor: Visitor, + mutating: false, + + // Visits a given value. If mutating, will replace the value if necessary. + acceptKey: function acceptKey(node, name) { + var value = this.accept(node[name]); + if (this.mutating) { + // Hacky sanity check: This may have a few false positives for type for the helper + // methods but will generally do the right thing without a lot of overhead. + if (value && !Visitor.prototype[value.type]) { + throw new _exception2['default']('Unexpected node type "' + value.type + '" found when accepting ' + name + ' on ' + node.type); + } + node[name] = value; + } + }, + + // Performs an accept operation with added sanity check to ensure + // required keys are not removed. + acceptRequired: function acceptRequired(node, name) { + this.acceptKey(node, name); + + if (!node[name]) { + throw new _exception2['default'](node.type + ' requires ' + name); + } + }, + + // Traverses a given array. If mutating, empty respnses will be removed + // for child elements. + acceptArray: function acceptArray(array) { + for (var i = 0, l = array.length; i < l; i++) { + this.acceptKey(array, i); + + if (!array[i]) { + array.splice(i, 1); + i--; + l--; + } + } + }, + + accept: function accept(object) { + if (!object) { + return; + } + + /* istanbul ignore next: Sanity code */ + if (!this[object.type]) { + throw new _exception2['default']('Unknown type: ' + object.type, object); + } + + if (this.current) { + this.parents.unshift(this.current); + } + this.current = object; + + var ret = this[object.type](object); + + this.current = this.parents.shift(); + + if (!this.mutating || ret) { + return ret; + } else if (ret !== false) { + return object; + } + }, + + Program: function Program(program) { + this.acceptArray(program.body); + }, + + MustacheStatement: visitSubExpression, + Decorator: visitSubExpression, + + BlockStatement: visitBlock, + DecoratorBlock: visitBlock, + + PartialStatement: visitPartial, + PartialBlockStatement: function PartialBlockStatement(partial) { + visitPartial.call(this, partial); + + this.acceptKey(partial, 'program'); + }, + + ContentStatement: function ContentStatement() /* content */{}, + CommentStatement: function CommentStatement() /* comment */{}, + + SubExpression: visitSubExpression, + + PathExpression: function PathExpression() /* path */{}, + + StringLiteral: function StringLiteral() /* string */{}, + NumberLiteral: function NumberLiteral() /* number */{}, + BooleanLiteral: function BooleanLiteral() /* bool */{}, + UndefinedLiteral: function UndefinedLiteral() /* literal */{}, + NullLiteral: function NullLiteral() /* literal */{}, + + Hash: function Hash(hash) { + this.acceptArray(hash.pairs); + }, + HashPair: function HashPair(pair) { + this.acceptRequired(pair, 'value'); + } + }; + + function visitSubExpression(mustache) { + this.acceptRequired(mustache, 'path'); + this.acceptArray(mustache.params); + this.acceptKey(mustache, 'hash'); + } + function visitBlock(block) { + visitSubExpression.call(this, block); + + this.acceptKey(block, 'program'); + this.acceptKey(block, 'inverse'); + } + function visitPartial(partial) { + this.acceptRequired(partial, 'name'); + this.acceptArray(partial.params); + this.acceptKey(partial, 'hash'); + } + + exports['default'] = Visitor; + module.exports = exports['default']; + +/***/ }), +/* 50 */ +/***/ (function(module, exports, __webpack_require__) { + + 'use strict'; + + var _interopRequireDefault = __webpack_require__(1)['default']; + + exports.__esModule = true; + exports.SourceLocation = SourceLocation; + exports.id = id; + exports.stripFlags = stripFlags; + exports.stripComment = stripComment; + exports.preparePath = preparePath; + exports.prepareMustache = prepareMustache; + exports.prepareRawBlock = prepareRawBlock; + exports.prepareBlock = prepareBlock; + exports.prepareProgram = prepareProgram; + exports.preparePartialBlock = preparePartialBlock; + + var _exception = __webpack_require__(6); + + var _exception2 = _interopRequireDefault(_exception); + + function validateClose(open, close) { + close = close.path ? close.path.original : close; + + if (open.path.original !== close) { + var errorNode = { loc: open.path.loc }; + + throw new _exception2['default'](open.path.original + " doesn't match " + close, errorNode); + } + } + + function SourceLocation(source, locInfo) { + this.source = source; + this.start = { + line: locInfo.first_line, + column: locInfo.first_column + }; + this.end = { + line: locInfo.last_line, + column: locInfo.last_column + }; + } + + function id(token) { + if (/^\[.*\]$/.test(token)) { + return token.substring(1, token.length - 1); + } else { + return token; + } + } + + function stripFlags(open, close) { + return { + open: open.charAt(2) === '~', + close: close.charAt(close.length - 3) === '~' + }; + } + + function stripComment(comment) { + return comment.replace(/^\{\{~?!-?-?/, '').replace(/-?-?~?\}\}$/, ''); + } + + function preparePath(data, parts, loc) { + loc = this.locInfo(loc); + + var original = data ? '@' : '', + dig = [], + depth = 0; + + for (var i = 0, l = parts.length; i < l; i++) { + var part = parts[i].part, + + // If we have [] syntax then we do not treat path references as operators, + // i.e. foo.[this] resolves to approximately context.foo['this'] + isLiteral = parts[i].original !== part; + original += (parts[i].separator || '') + part; + + if (!isLiteral && (part === '..' || part === '.' || part === 'this')) { + if (dig.length > 0) { + throw new _exception2['default']('Invalid path: ' + original, { loc: loc }); + } else if (part === '..') { + depth++; + } + } else { + dig.push(part); + } + } + + return { + type: 'PathExpression', + data: data, + depth: depth, + parts: dig, + original: original, + loc: loc + }; + } + + function prepareMustache(path, params, hash, open, strip, locInfo) { + // Must use charAt to support IE pre-10 + var escapeFlag = open.charAt(3) || open.charAt(2), + escaped = escapeFlag !== '{' && escapeFlag !== '&'; + + var decorator = /\*/.test(open); + return { + type: decorator ? 'Decorator' : 'MustacheStatement', + path: path, + params: params, + hash: hash, + escaped: escaped, + strip: strip, + loc: this.locInfo(locInfo) + }; + } + + function prepareRawBlock(openRawBlock, contents, close, locInfo) { + validateClose(openRawBlock, close); + + locInfo = this.locInfo(locInfo); + var program = { + type: 'Program', + body: contents, + strip: {}, + loc: locInfo + }; + + return { + type: 'BlockStatement', + path: openRawBlock.path, + params: openRawBlock.params, + hash: openRawBlock.hash, + program: program, + openStrip: {}, + inverseStrip: {}, + closeStrip: {}, + loc: locInfo + }; + } + + function prepareBlock(openBlock, program, inverseAndProgram, close, inverted, locInfo) { + if (close && close.path) { + validateClose(openBlock, close); + } + + var decorator = /\*/.test(openBlock.open); + + program.blockParams = openBlock.blockParams; + + var inverse = undefined, + inverseStrip = undefined; + + if (inverseAndProgram) { + if (decorator) { + throw new _exception2['default']('Unexpected inverse block on decorator', inverseAndProgram); + } + + if (inverseAndProgram.chain) { + inverseAndProgram.program.body[0].closeStrip = close.strip; + } + + inverseStrip = inverseAndProgram.strip; + inverse = inverseAndProgram.program; + } + + if (inverted) { + inverted = inverse; + inverse = program; + program = inverted; + } + + return { + type: decorator ? 'DecoratorBlock' : 'BlockStatement', + path: openBlock.path, + params: openBlock.params, + hash: openBlock.hash, + program: program, + inverse: inverse, + openStrip: openBlock.strip, + inverseStrip: inverseStrip, + closeStrip: close && close.strip, + loc: this.locInfo(locInfo) + }; + } + + function prepareProgram(statements, loc) { + if (!loc && statements.length) { + var firstLoc = statements[0].loc, + lastLoc = statements[statements.length - 1].loc; + + /* istanbul ignore else */ + if (firstLoc && lastLoc) { + loc = { + source: firstLoc.source, + start: { + line: firstLoc.start.line, + column: firstLoc.start.column + }, + end: { + line: lastLoc.end.line, + column: lastLoc.end.column + } + }; + } + } + + return { + type: 'Program', + body: statements, + strip: {}, + loc: loc + }; + } + + function preparePartialBlock(open, program, close, locInfo) { + validateClose(open, close); + + return { + type: 'PartialBlockStatement', + name: open.path, + params: open.params, + hash: open.hash, + program: program, + openStrip: open.strip, + closeStrip: close && close.strip, + loc: this.locInfo(locInfo) + }; + } + +/***/ }), +/* 51 */ +/***/ (function(module, exports, __webpack_require__) { + + /* eslint-disable new-cap */ + + 'use strict'; + + var _Object$create = __webpack_require__(34)['default']; + + var _interopRequireDefault = __webpack_require__(1)['default']; + + exports.__esModule = true; + exports.Compiler = Compiler; + exports.precompile = precompile; + exports.compile = compile; + + var _exception = __webpack_require__(6); + + var _exception2 = _interopRequireDefault(_exception); + + var _utils = __webpack_require__(5); + + var _ast = __webpack_require__(45); + + var _ast2 = _interopRequireDefault(_ast); + + var slice = [].slice; + + function Compiler() {} + + // the foundHelper register will disambiguate helper lookup from finding a + // function in a context. This is necessary for mustache compatibility, which + // requires that context functions in blocks are evaluated by blockHelperMissing, + // and then proceed as if the resulting value was provided to blockHelperMissing. + + Compiler.prototype = { + compiler: Compiler, + + equals: function equals(other) { + var len = this.opcodes.length; + if (other.opcodes.length !== len) { + return false; + } + + for (var i = 0; i < len; i++) { + var opcode = this.opcodes[i], + otherOpcode = other.opcodes[i]; + if (opcode.opcode !== otherOpcode.opcode || !argEquals(opcode.args, otherOpcode.args)) { + return false; + } + } + + // We know that length is the same between the two arrays because they are directly tied + // to the opcode behavior above. + len = this.children.length; + for (var i = 0; i < len; i++) { + if (!this.children[i].equals(other.children[i])) { + return false; + } + } + + return true; + }, + + guid: 0, + + compile: function compile(program, options) { + this.sourceNode = []; + this.opcodes = []; + this.children = []; + this.options = options; + this.stringParams = options.stringParams; + this.trackIds = options.trackIds; + + options.blockParams = options.blockParams || []; + + options.knownHelpers = _utils.extend(_Object$create(null), { + helperMissing: true, + blockHelperMissing: true, + each: true, + 'if': true, + unless: true, + 'with': true, + log: true, + lookup: true + }, options.knownHelpers); + + return this.accept(program); + }, + + compileProgram: function compileProgram(program) { + var childCompiler = new this.compiler(), + // eslint-disable-line new-cap + result = childCompiler.compile(program, this.options), + guid = this.guid++; + + this.usePartial = this.usePartial || result.usePartial; + + this.children[guid] = result; + this.useDepths = this.useDepths || result.useDepths; + + return guid; + }, + + accept: function accept(node) { + /* istanbul ignore next: Sanity code */ + if (!this[node.type]) { + throw new _exception2['default']('Unknown type: ' + node.type, node); + } + + this.sourceNode.unshift(node); + var ret = this[node.type](node); + this.sourceNode.shift(); + return ret; + }, + + Program: function Program(program) { + this.options.blockParams.unshift(program.blockParams); + + var body = program.body, + bodyLength = body.length; + for (var i = 0; i < bodyLength; i++) { + this.accept(body[i]); + } + + this.options.blockParams.shift(); + + this.isSimple = bodyLength === 1; + this.blockParams = program.blockParams ? program.blockParams.length : 0; + + return this; + }, + + BlockStatement: function BlockStatement(block) { + transformLiteralToPath(block); + + var program = block.program, + inverse = block.inverse; + + program = program && this.compileProgram(program); + inverse = inverse && this.compileProgram(inverse); + + var type = this.classifySexpr(block); + + if (type === 'helper') { + this.helperSexpr(block, program, inverse); + } else if (type === 'simple') { + this.simpleSexpr(block); + + // now that the simple mustache is resolved, we need to + // evaluate it by executing `blockHelperMissing` + this.opcode('pushProgram', program); + this.opcode('pushProgram', inverse); + this.opcode('emptyHash'); + this.opcode('blockValue', block.path.original); + } else { + this.ambiguousSexpr(block, program, inverse); + + // now that the simple mustache is resolved, we need to + // evaluate it by executing `blockHelperMissing` + this.opcode('pushProgram', program); + this.opcode('pushProgram', inverse); + this.opcode('emptyHash'); + this.opcode('ambiguousBlockValue'); + } + + this.opcode('append'); + }, + + DecoratorBlock: function DecoratorBlock(decorator) { + var program = decorator.program && this.compileProgram(decorator.program); + var params = this.setupFullMustacheParams(decorator, program, undefined), + path = decorator.path; + + this.useDecorators = true; + this.opcode('registerDecorator', params.length, path.original); + }, + + PartialStatement: function PartialStatement(partial) { + this.usePartial = true; + + var program = partial.program; + if (program) { + program = this.compileProgram(partial.program); + } + + var params = partial.params; + if (params.length > 1) { + throw new _exception2['default']('Unsupported number of partial arguments: ' + params.length, partial); + } else if (!params.length) { + if (this.options.explicitPartialContext) { + this.opcode('pushLiteral', 'undefined'); + } else { + params.push({ type: 'PathExpression', parts: [], depth: 0 }); + } + } + + var partialName = partial.name.original, + isDynamic = partial.name.type === 'SubExpression'; + if (isDynamic) { + this.accept(partial.name); + } + + this.setupFullMustacheParams(partial, program, undefined, true); + + var indent = partial.indent || ''; + if (this.options.preventIndent && indent) { + this.opcode('appendContent', indent); + indent = ''; + } + + this.opcode('invokePartial', isDynamic, partialName, indent); + this.opcode('append'); + }, + PartialBlockStatement: function PartialBlockStatement(partialBlock) { + this.PartialStatement(partialBlock); + }, + + MustacheStatement: function MustacheStatement(mustache) { + this.SubExpression(mustache); + + if (mustache.escaped && !this.options.noEscape) { + this.opcode('appendEscaped'); + } else { + this.opcode('append'); + } + }, + Decorator: function Decorator(decorator) { + this.DecoratorBlock(decorator); + }, + + ContentStatement: function ContentStatement(content) { + if (content.value) { + this.opcode('appendContent', content.value); + } + }, + + CommentStatement: function CommentStatement() {}, + + SubExpression: function SubExpression(sexpr) { + transformLiteralToPath(sexpr); + var type = this.classifySexpr(sexpr); + + if (type === 'simple') { + this.simpleSexpr(sexpr); + } else if (type === 'helper') { + this.helperSexpr(sexpr); + } else { + this.ambiguousSexpr(sexpr); + } + }, + ambiguousSexpr: function ambiguousSexpr(sexpr, program, inverse) { + var path = sexpr.path, + name = path.parts[0], + isBlock = program != null || inverse != null; + + this.opcode('getContext', path.depth); + + this.opcode('pushProgram', program); + this.opcode('pushProgram', inverse); + + path.strict = true; + this.accept(path); + + this.opcode('invokeAmbiguous', name, isBlock); + }, + + simpleSexpr: function simpleSexpr(sexpr) { + var path = sexpr.path; + path.strict = true; + this.accept(path); + this.opcode('resolvePossibleLambda'); + }, + + helperSexpr: function helperSexpr(sexpr, program, inverse) { + var params = this.setupFullMustacheParams(sexpr, program, inverse), + path = sexpr.path, + name = path.parts[0]; + + if (this.options.knownHelpers[name]) { + this.opcode('invokeKnownHelper', params.length, name); + } else if (this.options.knownHelpersOnly) { + throw new _exception2['default']('You specified knownHelpersOnly, but used the unknown helper ' + name, sexpr); + } else { + path.strict = true; + path.falsy = true; + + this.accept(path); + this.opcode('invokeHelper', params.length, path.original, _ast2['default'].helpers.simpleId(path)); + } + }, + + PathExpression: function PathExpression(path) { + this.addDepth(path.depth); + this.opcode('getContext', path.depth); + + var name = path.parts[0], + scoped = _ast2['default'].helpers.scopedId(path), + blockParamId = !path.depth && !scoped && this.blockParamIndex(name); + + if (blockParamId) { + this.opcode('lookupBlockParam', blockParamId, path.parts); + } else if (!name) { + // Context reference, i.e. `{{foo .}}` or `{{foo ..}}` + this.opcode('pushContext'); + } else if (path.data) { + this.options.data = true; + this.opcode('lookupData', path.depth, path.parts, path.strict); + } else { + this.opcode('lookupOnContext', path.parts, path.falsy, path.strict, scoped); + } + }, + + StringLiteral: function StringLiteral(string) { + this.opcode('pushString', string.value); + }, + + NumberLiteral: function NumberLiteral(number) { + this.opcode('pushLiteral', number.value); + }, + + BooleanLiteral: function BooleanLiteral(bool) { + this.opcode('pushLiteral', bool.value); + }, + + UndefinedLiteral: function UndefinedLiteral() { + this.opcode('pushLiteral', 'undefined'); + }, + + NullLiteral: function NullLiteral() { + this.opcode('pushLiteral', 'null'); + }, + + Hash: function Hash(hash) { + var pairs = hash.pairs, + i = 0, + l = pairs.length; + + this.opcode('pushHash'); + + for (; i < l; i++) { + this.pushParam(pairs[i].value); + } + while (i--) { + this.opcode('assignToHash', pairs[i].key); + } + this.opcode('popHash'); + }, + + // HELPERS + opcode: function opcode(name) { + this.opcodes.push({ + opcode: name, + args: slice.call(arguments, 1), + loc: this.sourceNode[0].loc + }); + }, + + addDepth: function addDepth(depth) { + if (!depth) { + return; + } + + this.useDepths = true; + }, + + classifySexpr: function classifySexpr(sexpr) { + var isSimple = _ast2['default'].helpers.simpleId(sexpr.path); + + var isBlockParam = isSimple && !!this.blockParamIndex(sexpr.path.parts[0]); + + // a mustache is an eligible helper if: + // * its id is simple (a single part, not `this` or `..`) + var isHelper = !isBlockParam && _ast2['default'].helpers.helperExpression(sexpr); + + // if a mustache is an eligible helper but not a definite + // helper, it is ambiguous, and will be resolved in a later + // pass or at runtime. + var isEligible = !isBlockParam && (isHelper || isSimple); + + // if ambiguous, we can possibly resolve the ambiguity now + // An eligible helper is one that does not have a complex path, i.e. `this.foo`, `../foo` etc. + if (isEligible && !isHelper) { + var _name = sexpr.path.parts[0], + options = this.options; + if (options.knownHelpers[_name]) { + isHelper = true; + } else if (options.knownHelpersOnly) { + isEligible = false; + } + } + + if (isHelper) { + return 'helper'; + } else if (isEligible) { + return 'ambiguous'; + } else { + return 'simple'; + } + }, + + pushParams: function pushParams(params) { + for (var i = 0, l = params.length; i < l; i++) { + this.pushParam(params[i]); + } + }, + + pushParam: function pushParam(val) { + var value = val.value != null ? val.value : val.original || ''; + + if (this.stringParams) { + if (value.replace) { + value = value.replace(/^(\.?\.\/)*/g, '').replace(/\//g, '.'); + } + + if (val.depth) { + this.addDepth(val.depth); + } + this.opcode('getContext', val.depth || 0); + this.opcode('pushStringParam', value, val.type); + + if (val.type === 'SubExpression') { + // SubExpressions get evaluated and passed in + // in string params mode. + this.accept(val); + } + } else { + if (this.trackIds) { + var blockParamIndex = undefined; + if (val.parts && !_ast2['default'].helpers.scopedId(val) && !val.depth) { + blockParamIndex = this.blockParamIndex(val.parts[0]); + } + if (blockParamIndex) { + var blockParamChild = val.parts.slice(1).join('.'); + this.opcode('pushId', 'BlockParam', blockParamIndex, blockParamChild); + } else { + value = val.original || value; + if (value.replace) { + value = value.replace(/^this(?:\.|$)/, '').replace(/^\.\//, '').replace(/^\.$/, ''); + } + + this.opcode('pushId', val.type, value); + } + } + this.accept(val); + } + }, + + setupFullMustacheParams: function setupFullMustacheParams(sexpr, program, inverse, omitEmpty) { + var params = sexpr.params; + this.pushParams(params); + + this.opcode('pushProgram', program); + this.opcode('pushProgram', inverse); + + if (sexpr.hash) { + this.accept(sexpr.hash); + } else { + this.opcode('emptyHash', omitEmpty); + } + + return params; + }, + + blockParamIndex: function blockParamIndex(name) { + for (var depth = 0, len = this.options.blockParams.length; depth < len; depth++) { + var blockParams = this.options.blockParams[depth], + param = blockParams && _utils.indexOf(blockParams, name); + if (blockParams && param >= 0) { + return [depth, param]; + } + } + } + }; + + function precompile(input, options, env) { + if (input == null || typeof input !== 'string' && input.type !== 'Program') { + throw new _exception2['default']('You must pass a string or Handlebars AST to Handlebars.precompile. You passed ' + input); + } + + options = options || {}; + if (!('data' in options)) { + options.data = true; + } + if (options.compat) { + options.useDepths = true; + } + + var ast = env.parse(input, options), + environment = new env.Compiler().compile(ast, options); + return new env.JavaScriptCompiler().compile(environment, options); + } + + function compile(input, options, env) { + if (options === undefined) options = {}; + + if (input == null || typeof input !== 'string' && input.type !== 'Program') { + throw new _exception2['default']('You must pass a string or Handlebars AST to Handlebars.compile. You passed ' + input); + } + + options = _utils.extend({}, options); + if (!('data' in options)) { + options.data = true; + } + if (options.compat) { + options.useDepths = true; + } + + var compiled = undefined; + + function compileInput() { + var ast = env.parse(input, options), + environment = new env.Compiler().compile(ast, options), + templateSpec = new env.JavaScriptCompiler().compile(environment, options, undefined, true); + return env.template(templateSpec); + } + + // Template is only compiled on first use and cached after that point. + function ret(context, execOptions) { + if (!compiled) { + compiled = compileInput(); + } + return compiled.call(this, context, execOptions); + } + ret._setup = function (setupOptions) { + if (!compiled) { + compiled = compileInput(); + } + return compiled._setup(setupOptions); + }; + ret._child = function (i, data, blockParams, depths) { + if (!compiled) { + compiled = compileInput(); + } + return compiled._child(i, data, blockParams, depths); + }; + return ret; + } + + function argEquals(a, b) { + if (a === b) { + return true; + } + + if (_utils.isArray(a) && _utils.isArray(b) && a.length === b.length) { + for (var i = 0; i < a.length; i++) { + if (!argEquals(a[i], b[i])) { + return false; + } + } + return true; + } + } + + function transformLiteralToPath(sexpr) { + if (!sexpr.path.parts) { + var literal = sexpr.path; + // Casting to string here to make false and 0 literal values play nicely with the rest + // of the system. + sexpr.path = { + type: 'PathExpression', + data: false, + depth: 0, + parts: [literal.original + ''], + original: literal.original + '', + loc: literal.loc + }; + } + } + +/***/ }), +/* 52 */ +/***/ (function(module, exports, __webpack_require__) { + + 'use strict'; + + var _Object$keys = __webpack_require__(13)['default']; + + var _interopRequireDefault = __webpack_require__(1)['default']; + + exports.__esModule = true; + + var _base = __webpack_require__(4); + + var _exception = __webpack_require__(6); + + var _exception2 = _interopRequireDefault(_exception); + + var _utils = __webpack_require__(5); + + var _codeGen = __webpack_require__(53); + + var _codeGen2 = _interopRequireDefault(_codeGen); + + function Literal(value) { + this.value = value; + } + + function JavaScriptCompiler() {} + + JavaScriptCompiler.prototype = { + // PUBLIC API: You can override these methods in a subclass to provide + // alternative compiled forms for name lookup and buffering semantics + nameLookup: function nameLookup(parent, name /*, type */) { + return this.internalNameLookup(parent, name); + }, + depthedLookup: function depthedLookup(name) { + return [this.aliasable('container.lookup'), '(depths, "', name, '")']; + }, + + compilerInfo: function compilerInfo() { + var revision = _base.COMPILER_REVISION, + versions = _base.REVISION_CHANGES[revision]; + return [revision, versions]; + }, + + appendToBuffer: function appendToBuffer(source, location, explicit) { + // Force a source as this simplifies the merge logic. + if (!_utils.isArray(source)) { + source = [source]; + } + source = this.source.wrap(source, location); + + if (this.environment.isSimple) { + return ['return ', source, ';']; + } else if (explicit) { + // This is a case where the buffer operation occurs as a child of another + // construct, generally braces. We have to explicitly output these buffer + // operations to ensure that the emitted code goes in the correct location. + return ['buffer += ', source, ';']; + } else { + source.appendToBuffer = true; + return source; + } + }, + + initializeBuffer: function initializeBuffer() { + return this.quotedString(''); + }, + // END PUBLIC API + internalNameLookup: function internalNameLookup(parent, name) { + this.lookupPropertyFunctionIsUsed = true; + return ['lookupProperty(', parent, ',', JSON.stringify(name), ')']; + }, + + lookupPropertyFunctionIsUsed: false, + + compile: function compile(environment, options, context, asObject) { + this.environment = environment; + this.options = options; + this.stringParams = this.options.stringParams; + this.trackIds = this.options.trackIds; + this.precompile = !asObject; + + this.name = this.environment.name; + this.isChild = !!context; + this.context = context || { + decorators: [], + programs: [], + environments: [] + }; + + this.preamble(); + + this.stackSlot = 0; + this.stackVars = []; + this.aliases = {}; + this.registers = { list: [] }; + this.hashes = []; + this.compileStack = []; + this.inlineStack = []; + this.blockParams = []; + + this.compileChildren(environment, options); + + this.useDepths = this.useDepths || environment.useDepths || environment.useDecorators || this.options.compat; + this.useBlockParams = this.useBlockParams || environment.useBlockParams; + + var opcodes = environment.opcodes, + opcode = undefined, + firstLoc = undefined, + i = undefined, + l = undefined; + + for (i = 0, l = opcodes.length; i < l; i++) { + opcode = opcodes[i]; + + this.source.currentLocation = opcode.loc; + firstLoc = firstLoc || opcode.loc; + this[opcode.opcode].apply(this, opcode.args); + } + + // Flush any trailing content that might be pending. + this.source.currentLocation = firstLoc; + this.pushSource(''); + + /* istanbul ignore next */ + if (this.stackSlot || this.inlineStack.length || this.compileStack.length) { + throw new _exception2['default']('Compile completed with content left on stack'); + } + + if (!this.decorators.isEmpty()) { + this.useDecorators = true; + + this.decorators.prepend(['var decorators = container.decorators, ', this.lookupPropertyFunctionVarDeclaration(), ';\n']); + this.decorators.push('return fn;'); + + if (asObject) { + this.decorators = Function.apply(this, ['fn', 'props', 'container', 'depth0', 'data', 'blockParams', 'depths', this.decorators.merge()]); + } else { + this.decorators.prepend('function(fn, props, container, depth0, data, blockParams, depths) {\n'); + this.decorators.push('}\n'); + this.decorators = this.decorators.merge(); + } + } else { + this.decorators = undefined; + } + + var fn = this.createFunctionContext(asObject); + if (!this.isChild) { + var ret = { + compiler: this.compilerInfo(), + main: fn + }; + + if (this.decorators) { + ret.main_d = this.decorators; // eslint-disable-line camelcase + ret.useDecorators = true; + } + + var _context = this.context; + var programs = _context.programs; + var decorators = _context.decorators; + + for (i = 0, l = programs.length; i < l; i++) { + if (programs[i]) { + ret[i] = programs[i]; + if (decorators[i]) { + ret[i + '_d'] = decorators[i]; + ret.useDecorators = true; + } + } + } + + if (this.environment.usePartial) { + ret.usePartial = true; + } + if (this.options.data) { + ret.useData = true; + } + if (this.useDepths) { + ret.useDepths = true; + } + if (this.useBlockParams) { + ret.useBlockParams = true; + } + if (this.options.compat) { + ret.compat = true; + } + + if (!asObject) { + ret.compiler = JSON.stringify(ret.compiler); + + this.source.currentLocation = { start: { line: 1, column: 0 } }; + ret = this.objectLiteral(ret); + + if (options.srcName) { + ret = ret.toStringWithSourceMap({ file: options.destName }); + ret.map = ret.map && ret.map.toString(); + } else { + ret = ret.toString(); + } + } else { + ret.compilerOptions = this.options; + } + + return ret; + } else { + return fn; + } + }, + + preamble: function preamble() { + // track the last context pushed into place to allow skipping the + // getContext opcode when it would be a noop + this.lastContext = 0; + this.source = new _codeGen2['default'](this.options.srcName); + this.decorators = new _codeGen2['default'](this.options.srcName); + }, + + createFunctionContext: function createFunctionContext(asObject) { + // istanbul ignore next + + var _this = this; + + var varDeclarations = ''; + + var locals = this.stackVars.concat(this.registers.list); + if (locals.length > 0) { + varDeclarations += ', ' + locals.join(', '); + } + + // Generate minimizer alias mappings + // + // When using true SourceNodes, this will update all references to the given alias + // as the source nodes are reused in situ. For the non-source node compilation mode, + // aliases will not be used, but this case is already being run on the client and + // we aren't concern about minimizing the template size. + var aliasCount = 0; + _Object$keys(this.aliases).forEach(function (alias) { + var node = _this.aliases[alias]; + if (node.children && node.referenceCount > 1) { + varDeclarations += ', alias' + ++aliasCount + '=' + alias; + node.children[0] = 'alias' + aliasCount; + } + }); + + if (this.lookupPropertyFunctionIsUsed) { + varDeclarations += ', ' + this.lookupPropertyFunctionVarDeclaration(); + } + + var params = ['container', 'depth0', 'helpers', 'partials', 'data']; + + if (this.useBlockParams || this.useDepths) { + params.push('blockParams'); + } + if (this.useDepths) { + params.push('depths'); + } + + // Perform a second pass over the output to merge content when possible + var source = this.mergeSource(varDeclarations); + + if (asObject) { + params.push(source); + + return Function.apply(this, params); + } else { + return this.source.wrap(['function(', params.join(','), ') {\n ', source, '}']); + } + }, + mergeSource: function mergeSource(varDeclarations) { + var isSimple = this.environment.isSimple, + appendOnly = !this.forceBuffer, + appendFirst = undefined, + sourceSeen = undefined, + bufferStart = undefined, + bufferEnd = undefined; + this.source.each(function (line) { + if (line.appendToBuffer) { + if (bufferStart) { + line.prepend(' + '); + } else { + bufferStart = line; + } + bufferEnd = line; + } else { + if (bufferStart) { + if (!sourceSeen) { + appendFirst = true; + } else { + bufferStart.prepend('buffer += '); + } + bufferEnd.add(';'); + bufferStart = bufferEnd = undefined; + } + + sourceSeen = true; + if (!isSimple) { + appendOnly = false; + } + } + }); + + if (appendOnly) { + if (bufferStart) { + bufferStart.prepend('return '); + bufferEnd.add(';'); + } else if (!sourceSeen) { + this.source.push('return "";'); + } + } else { + varDeclarations += ', buffer = ' + (appendFirst ? '' : this.initializeBuffer()); + + if (bufferStart) { + bufferStart.prepend('return buffer + '); + bufferEnd.add(';'); + } else { + this.source.push('return buffer;'); + } + } + + if (varDeclarations) { + this.source.prepend('var ' + varDeclarations.substring(2) + (appendFirst ? '' : ';\n')); + } + + return this.source.merge(); + }, + + lookupPropertyFunctionVarDeclaration: function lookupPropertyFunctionVarDeclaration() { + return '\n lookupProperty = container.lookupProperty || function(parent, propertyName) {\n if (Object.prototype.hasOwnProperty.call(parent, propertyName)) {\n return parent[propertyName];\n }\n return undefined\n }\n '.trim(); + }, + + // [blockValue] + // + // On stack, before: hash, inverse, program, value + // On stack, after: return value of blockHelperMissing + // + // The purpose of this opcode is to take a block of the form + // `{{#this.foo}}...{{/this.foo}}`, resolve the value of `foo`, and + // replace it on the stack with the result of properly + // invoking blockHelperMissing. + blockValue: function blockValue(name) { + var blockHelperMissing = this.aliasable('container.hooks.blockHelperMissing'), + params = [this.contextName(0)]; + this.setupHelperArgs(name, 0, params); + + var blockName = this.popStack(); + params.splice(1, 0, blockName); + + this.push(this.source.functionCall(blockHelperMissing, 'call', params)); + }, + + // [ambiguousBlockValue] + // + // On stack, before: hash, inverse, program, value + // Compiler value, before: lastHelper=value of last found helper, if any + // On stack, after, if no lastHelper: same as [blockValue] + // On stack, after, if lastHelper: value + ambiguousBlockValue: function ambiguousBlockValue() { + // We're being a bit cheeky and reusing the options value from the prior exec + var blockHelperMissing = this.aliasable('container.hooks.blockHelperMissing'), + params = [this.contextName(0)]; + this.setupHelperArgs('', 0, params, true); + + this.flushInline(); + + var current = this.topStack(); + params.splice(1, 0, current); + + this.pushSource(['if (!', this.lastHelper, ') { ', current, ' = ', this.source.functionCall(blockHelperMissing, 'call', params), '}']); + }, + + // [appendContent] + // + // On stack, before: ... + // On stack, after: ... + // + // Appends the string value of `content` to the current buffer + appendContent: function appendContent(content) { + if (this.pendingContent) { + content = this.pendingContent + content; + } else { + this.pendingLocation = this.source.currentLocation; + } + + this.pendingContent = content; + }, + + // [append] + // + // On stack, before: value, ... + // On stack, after: ... + // + // Coerces `value` to a String and appends it to the current buffer. + // + // If `value` is truthy, or 0, it is coerced into a string and appended + // Otherwise, the empty string is appended + append: function append() { + if (this.isInline()) { + this.replaceStack(function (current) { + return [' != null ? ', current, ' : ""']; + }); + + this.pushSource(this.appendToBuffer(this.popStack())); + } else { + var local = this.popStack(); + this.pushSource(['if (', local, ' != null) { ', this.appendToBuffer(local, undefined, true), ' }']); + if (this.environment.isSimple) { + this.pushSource(['else { ', this.appendToBuffer("''", undefined, true), ' }']); + } + } + }, + + // [appendEscaped] + // + // On stack, before: value, ... + // On stack, after: ... + // + // Escape `value` and append it to the buffer + appendEscaped: function appendEscaped() { + this.pushSource(this.appendToBuffer([this.aliasable('container.escapeExpression'), '(', this.popStack(), ')'])); + }, + + // [getContext] + // + // On stack, before: ... + // On stack, after: ... + // Compiler value, after: lastContext=depth + // + // Set the value of the `lastContext` compiler value to the depth + getContext: function getContext(depth) { + this.lastContext = depth; + }, + + // [pushContext] + // + // On stack, before: ... + // On stack, after: currentContext, ... + // + // Pushes the value of the current context onto the stack. + pushContext: function pushContext() { + this.pushStackLiteral(this.contextName(this.lastContext)); + }, + + // [lookupOnContext] + // + // On stack, before: ... + // On stack, after: currentContext[name], ... + // + // Looks up the value of `name` on the current context and pushes + // it onto the stack. + lookupOnContext: function lookupOnContext(parts, falsy, strict, scoped) { + var i = 0; + + if (!scoped && this.options.compat && !this.lastContext) { + // The depthed query is expected to handle the undefined logic for the root level that + // is implemented below, so we evaluate that directly in compat mode + this.push(this.depthedLookup(parts[i++])); + } else { + this.pushContext(); + } + + this.resolvePath('context', parts, i, falsy, strict); + }, + + // [lookupBlockParam] + // + // On stack, before: ... + // On stack, after: blockParam[name], ... + // + // Looks up the value of `parts` on the given block param and pushes + // it onto the stack. + lookupBlockParam: function lookupBlockParam(blockParamId, parts) { + this.useBlockParams = true; + + this.push(['blockParams[', blockParamId[0], '][', blockParamId[1], ']']); + this.resolvePath('context', parts, 1); + }, + + // [lookupData] + // + // On stack, before: ... + // On stack, after: data, ... + // + // Push the data lookup operator + lookupData: function lookupData(depth, parts, strict) { + if (!depth) { + this.pushStackLiteral('data'); + } else { + this.pushStackLiteral('container.data(data, ' + depth + ')'); + } + + this.resolvePath('data', parts, 0, true, strict); + }, + + resolvePath: function resolvePath(type, parts, i, falsy, strict) { + // istanbul ignore next + + var _this2 = this; + + if (this.options.strict || this.options.assumeObjects) { + this.push(strictLookup(this.options.strict && strict, this, parts, type)); + return; + } + + var len = parts.length; + for (; i < len; i++) { + /* eslint-disable no-loop-func */ + this.replaceStack(function (current) { + var lookup = _this2.nameLookup(current, parts[i], type); + // We want to ensure that zero and false are handled properly if the context (falsy flag) + // needs to have the special handling for these values. + if (!falsy) { + return [' != null ? ', lookup, ' : ', current]; + } else { + // Otherwise we can use generic falsy handling + return [' && ', lookup]; + } + }); + /* eslint-enable no-loop-func */ + } + }, + + // [resolvePossibleLambda] + // + // On stack, before: value, ... + // On stack, after: resolved value, ... + // + // If the `value` is a lambda, replace it on the stack by + // the return value of the lambda + resolvePossibleLambda: function resolvePossibleLambda() { + this.push([this.aliasable('container.lambda'), '(', this.popStack(), ', ', this.contextName(0), ')']); + }, + + // [pushStringParam] + // + // On stack, before: ... + // On stack, after: string, currentContext, ... + // + // This opcode is designed for use in string mode, which + // provides the string value of a parameter along with its + // depth rather than resolving it immediately. + pushStringParam: function pushStringParam(string, type) { + this.pushContext(); + this.pushString(type); + + // If it's a subexpression, the string result + // will be pushed after this opcode. + if (type !== 'SubExpression') { + if (typeof string === 'string') { + this.pushString(string); + } else { + this.pushStackLiteral(string); + } + } + }, + + emptyHash: function emptyHash(omitEmpty) { + if (this.trackIds) { + this.push('{}'); // hashIds + } + if (this.stringParams) { + this.push('{}'); // hashContexts + this.push('{}'); // hashTypes + } + this.pushStackLiteral(omitEmpty ? 'undefined' : '{}'); + }, + pushHash: function pushHash() { + if (this.hash) { + this.hashes.push(this.hash); + } + this.hash = { values: {}, types: [], contexts: [], ids: [] }; + }, + popHash: function popHash() { + var hash = this.hash; + this.hash = this.hashes.pop(); + + if (this.trackIds) { + this.push(this.objectLiteral(hash.ids)); + } + if (this.stringParams) { + this.push(this.objectLiteral(hash.contexts)); + this.push(this.objectLiteral(hash.types)); + } + + this.push(this.objectLiteral(hash.values)); + }, + + // [pushString] + // + // On stack, before: ... + // On stack, after: quotedString(string), ... + // + // Push a quoted version of `string` onto the stack + pushString: function pushString(string) { + this.pushStackLiteral(this.quotedString(string)); + }, + + // [pushLiteral] + // + // On stack, before: ... + // On stack, after: value, ... + // + // Pushes a value onto the stack. This operation prevents + // the compiler from creating a temporary variable to hold + // it. + pushLiteral: function pushLiteral(value) { + this.pushStackLiteral(value); + }, + + // [pushProgram] + // + // On stack, before: ... + // On stack, after: program(guid), ... + // + // Push a program expression onto the stack. This takes + // a compile-time guid and converts it into a runtime-accessible + // expression. + pushProgram: function pushProgram(guid) { + if (guid != null) { + this.pushStackLiteral(this.programExpression(guid)); + } else { + this.pushStackLiteral(null); + } + }, + + // [registerDecorator] + // + // On stack, before: hash, program, params..., ... + // On stack, after: ... + // + // Pops off the decorator's parameters, invokes the decorator, + // and inserts the decorator into the decorators list. + registerDecorator: function registerDecorator(paramSize, name) { + var foundDecorator = this.nameLookup('decorators', name, 'decorator'), + options = this.setupHelperArgs(name, paramSize); + + this.decorators.push(['fn = ', this.decorators.functionCall(foundDecorator, '', ['fn', 'props', 'container', options]), ' || fn;']); + }, + + // [invokeHelper] + // + // On stack, before: hash, inverse, program, params..., ... + // On stack, after: result of helper invocation + // + // Pops off the helper's parameters, invokes the helper, + // and pushes the helper's return value onto the stack. + // + // If the helper is not found, `helperMissing` is called. + invokeHelper: function invokeHelper(paramSize, name, isSimple) { + var nonHelper = this.popStack(), + helper = this.setupHelper(paramSize, name); + + var possibleFunctionCalls = []; + + if (isSimple) { + // direct call to helper + possibleFunctionCalls.push(helper.name); + } + // call a function from the input object + possibleFunctionCalls.push(nonHelper); + if (!this.options.strict) { + possibleFunctionCalls.push(this.aliasable('container.hooks.helperMissing')); + } + + var functionLookupCode = ['(', this.itemsSeparatedBy(possibleFunctionCalls, '||'), ')']; + var functionCall = this.source.functionCall(functionLookupCode, 'call', helper.callParams); + this.push(functionCall); + }, + + itemsSeparatedBy: function itemsSeparatedBy(items, separator) { + var result = []; + result.push(items[0]); + for (var i = 1; i < items.length; i++) { + result.push(separator, items[i]); + } + return result; + }, + // [invokeKnownHelper] + // + // On stack, before: hash, inverse, program, params..., ... + // On stack, after: result of helper invocation + // + // This operation is used when the helper is known to exist, + // so a `helperMissing` fallback is not required. + invokeKnownHelper: function invokeKnownHelper(paramSize, name) { + var helper = this.setupHelper(paramSize, name); + this.push(this.source.functionCall(helper.name, 'call', helper.callParams)); + }, + + // [invokeAmbiguous] + // + // On stack, before: hash, inverse, program, params..., ... + // On stack, after: result of disambiguation + // + // This operation is used when an expression like `{{foo}}` + // is provided, but we don't know at compile-time whether it + // is a helper or a path. + // + // This operation emits more code than the other options, + // and can be avoided by passing the `knownHelpers` and + // `knownHelpersOnly` flags at compile-time. + invokeAmbiguous: function invokeAmbiguous(name, helperCall) { + this.useRegister('helper'); + + var nonHelper = this.popStack(); + + this.emptyHash(); + var helper = this.setupHelper(0, name, helperCall); + + var helperName = this.lastHelper = this.nameLookup('helpers', name, 'helper'); + + var lookup = ['(', '(helper = ', helperName, ' || ', nonHelper, ')']; + if (!this.options.strict) { + lookup[0] = '(helper = '; + lookup.push(' != null ? helper : ', this.aliasable('container.hooks.helperMissing')); + } + + this.push(['(', lookup, helper.paramsInit ? ['),(', helper.paramsInit] : [], '),', '(typeof helper === ', this.aliasable('"function"'), ' ? ', this.source.functionCall('helper', 'call', helper.callParams), ' : helper))']); + }, + + // [invokePartial] + // + // On stack, before: context, ... + // On stack after: result of partial invocation + // + // This operation pops off a context, invokes a partial with that context, + // and pushes the result of the invocation back. + invokePartial: function invokePartial(isDynamic, name, indent) { + var params = [], + options = this.setupParams(name, 1, params); + + if (isDynamic) { + name = this.popStack(); + delete options.name; + } + + if (indent) { + options.indent = JSON.stringify(indent); + } + options.helpers = 'helpers'; + options.partials = 'partials'; + options.decorators = 'container.decorators'; + + if (!isDynamic) { + params.unshift(this.nameLookup('partials', name, 'partial')); + } else { + params.unshift(name); + } + + if (this.options.compat) { + options.depths = 'depths'; + } + options = this.objectLiteral(options); + params.push(options); + + this.push(this.source.functionCall('container.invokePartial', '', params)); + }, + + // [assignToHash] + // + // On stack, before: value, ..., hash, ... + // On stack, after: ..., hash, ... + // + // Pops a value off the stack and assigns it to the current hash + assignToHash: function assignToHash(key) { + var value = this.popStack(), + context = undefined, + type = undefined, + id = undefined; + + if (this.trackIds) { + id = this.popStack(); + } + if (this.stringParams) { + type = this.popStack(); + context = this.popStack(); + } + + var hash = this.hash; + if (context) { + hash.contexts[key] = context; + } + if (type) { + hash.types[key] = type; + } + if (id) { + hash.ids[key] = id; + } + hash.values[key] = value; + }, + + pushId: function pushId(type, name, child) { + if (type === 'BlockParam') { + this.pushStackLiteral('blockParams[' + name[0] + '].path[' + name[1] + ']' + (child ? ' + ' + JSON.stringify('.' + child) : '')); + } else if (type === 'PathExpression') { + this.pushString(name); + } else if (type === 'SubExpression') { + this.pushStackLiteral('true'); + } else { + this.pushStackLiteral('null'); + } + }, + + // HELPERS + + compiler: JavaScriptCompiler, + + compileChildren: function compileChildren(environment, options) { + var children = environment.children, + child = undefined, + compiler = undefined; + + for (var i = 0, l = children.length; i < l; i++) { + child = children[i]; + compiler = new this.compiler(); // eslint-disable-line new-cap + + var existing = this.matchExistingProgram(child); + + if (existing == null) { + this.context.programs.push(''); // Placeholder to prevent name conflicts for nested children + var index = this.context.programs.length; + child.index = index; + child.name = 'program' + index; + this.context.programs[index] = compiler.compile(child, options, this.context, !this.precompile); + this.context.decorators[index] = compiler.decorators; + this.context.environments[index] = child; + + this.useDepths = this.useDepths || compiler.useDepths; + this.useBlockParams = this.useBlockParams || compiler.useBlockParams; + child.useDepths = this.useDepths; + child.useBlockParams = this.useBlockParams; + } else { + child.index = existing.index; + child.name = 'program' + existing.index; + + this.useDepths = this.useDepths || existing.useDepths; + this.useBlockParams = this.useBlockParams || existing.useBlockParams; + } + } + }, + matchExistingProgram: function matchExistingProgram(child) { + for (var i = 0, len = this.context.environments.length; i < len; i++) { + var environment = this.context.environments[i]; + if (environment && environment.equals(child)) { + return environment; + } + } + }, + + programExpression: function programExpression(guid) { + var child = this.environment.children[guid], + programParams = [child.index, 'data', child.blockParams]; + + if (this.useBlockParams || this.useDepths) { + programParams.push('blockParams'); + } + if (this.useDepths) { + programParams.push('depths'); + } + + return 'container.program(' + programParams.join(', ') + ')'; + }, + + useRegister: function useRegister(name) { + if (!this.registers[name]) { + this.registers[name] = true; + this.registers.list.push(name); + } + }, + + push: function push(expr) { + if (!(expr instanceof Literal)) { + expr = this.source.wrap(expr); + } + + this.inlineStack.push(expr); + return expr; + }, + + pushStackLiteral: function pushStackLiteral(item) { + this.push(new Literal(item)); + }, + + pushSource: function pushSource(source) { + if (this.pendingContent) { + this.source.push(this.appendToBuffer(this.source.quotedString(this.pendingContent), this.pendingLocation)); + this.pendingContent = undefined; + } + + if (source) { + this.source.push(source); + } + }, + + replaceStack: function replaceStack(callback) { + var prefix = ['('], + stack = undefined, + createdStack = undefined, + usedLiteral = undefined; + + /* istanbul ignore next */ + if (!this.isInline()) { + throw new _exception2['default']('replaceStack on non-inline'); + } + + // We want to merge the inline statement into the replacement statement via ',' + var top = this.popStack(true); + + if (top instanceof Literal) { + // Literals do not need to be inlined + stack = [top.value]; + prefix = ['(', stack]; + usedLiteral = true; + } else { + // Get or create the current stack name for use by the inline + createdStack = true; + var _name = this.incrStack(); + + prefix = ['((', this.push(_name), ' = ', top, ')']; + stack = this.topStack(); + } + + var item = callback.call(this, stack); + + if (!usedLiteral) { + this.popStack(); + } + if (createdStack) { + this.stackSlot--; + } + this.push(prefix.concat(item, ')')); + }, + + incrStack: function incrStack() { + this.stackSlot++; + if (this.stackSlot > this.stackVars.length) { + this.stackVars.push('stack' + this.stackSlot); + } + return this.topStackName(); + }, + topStackName: function topStackName() { + return 'stack' + this.stackSlot; + }, + flushInline: function flushInline() { + var inlineStack = this.inlineStack; + this.inlineStack = []; + for (var i = 0, len = inlineStack.length; i < len; i++) { + var entry = inlineStack[i]; + /* istanbul ignore if */ + if (entry instanceof Literal) { + this.compileStack.push(entry); + } else { + var stack = this.incrStack(); + this.pushSource([stack, ' = ', entry, ';']); + this.compileStack.push(stack); + } + } + }, + isInline: function isInline() { + return this.inlineStack.length; + }, + + popStack: function popStack(wrapped) { + var inline = this.isInline(), + item = (inline ? this.inlineStack : this.compileStack).pop(); + + if (!wrapped && item instanceof Literal) { + return item.value; + } else { + if (!inline) { + /* istanbul ignore next */ + if (!this.stackSlot) { + throw new _exception2['default']('Invalid stack pop'); + } + this.stackSlot--; + } + return item; + } + }, + + topStack: function topStack() { + var stack = this.isInline() ? this.inlineStack : this.compileStack, + item = stack[stack.length - 1]; + + /* istanbul ignore if */ + if (item instanceof Literal) { + return item.value; + } else { + return item; + } + }, + + contextName: function contextName(context) { + if (this.useDepths && context) { + return 'depths[' + context + ']'; + } else { + return 'depth' + context; + } + }, + + quotedString: function quotedString(str) { + return this.source.quotedString(str); + }, + + objectLiteral: function objectLiteral(obj) { + return this.source.objectLiteral(obj); + }, + + aliasable: function aliasable(name) { + var ret = this.aliases[name]; + if (ret) { + ret.referenceCount++; + return ret; + } + + ret = this.aliases[name] = this.source.wrap(name); + ret.aliasable = true; + ret.referenceCount = 1; + + return ret; + }, + + setupHelper: function setupHelper(paramSize, name, blockHelper) { + var params = [], + paramsInit = this.setupHelperArgs(name, paramSize, params, blockHelper); + var foundHelper = this.nameLookup('helpers', name, 'helper'), + callContext = this.aliasable(this.contextName(0) + ' != null ? ' + this.contextName(0) + ' : (container.nullContext || {})'); + + return { + params: params, + paramsInit: paramsInit, + name: foundHelper, + callParams: [callContext].concat(params) + }; + }, + + setupParams: function setupParams(helper, paramSize, params) { + var options = {}, + contexts = [], + types = [], + ids = [], + objectArgs = !params, + param = undefined; + + if (objectArgs) { + params = []; + } + + options.name = this.quotedString(helper); + options.hash = this.popStack(); + + if (this.trackIds) { + options.hashIds = this.popStack(); + } + if (this.stringParams) { + options.hashTypes = this.popStack(); + options.hashContexts = this.popStack(); + } + + var inverse = this.popStack(), + program = this.popStack(); + + // Avoid setting fn and inverse if neither are set. This allows + // helpers to do a check for `if (options.fn)` + if (program || inverse) { + options.fn = program || 'container.noop'; + options.inverse = inverse || 'container.noop'; + } + + // The parameters go on to the stack in order (making sure that they are evaluated in order) + // so we need to pop them off the stack in reverse order + var i = paramSize; + while (i--) { + param = this.popStack(); + params[i] = param; + + if (this.trackIds) { + ids[i] = this.popStack(); + } + if (this.stringParams) { + types[i] = this.popStack(); + contexts[i] = this.popStack(); + } + } + + if (objectArgs) { + options.args = this.source.generateArray(params); + } + + if (this.trackIds) { + options.ids = this.source.generateArray(ids); + } + if (this.stringParams) { + options.types = this.source.generateArray(types); + options.contexts = this.source.generateArray(contexts); + } + + if (this.options.data) { + options.data = 'data'; + } + if (this.useBlockParams) { + options.blockParams = 'blockParams'; + } + return options; + }, + + setupHelperArgs: function setupHelperArgs(helper, paramSize, params, useRegister) { + var options = this.setupParams(helper, paramSize, params); + options.loc = JSON.stringify(this.source.currentLocation); + options = this.objectLiteral(options); + if (useRegister) { + this.useRegister('options'); + params.push('options'); + return ['options=', options]; + } else if (params) { + params.push(options); + return ''; + } else { + return options; + } + } + }; + + (function () { + var reservedWords = ('break else new var' + ' case finally return void' + ' catch for switch while' + ' continue function this with' + ' default if throw' + ' delete in try' + ' do instanceof typeof' + ' abstract enum int short' + ' boolean export interface static' + ' byte extends long super' + ' char final native synchronized' + ' class float package throws' + ' const goto private transient' + ' debugger implements protected volatile' + ' double import public let yield await' + ' null true false').split(' '); + + var compilerWords = JavaScriptCompiler.RESERVED_WORDS = {}; + + for (var i = 0, l = reservedWords.length; i < l; i++) { + compilerWords[reservedWords[i]] = true; + } + })(); + + /** + * @deprecated May be removed in the next major version + */ + JavaScriptCompiler.isValidJavaScriptVariableName = function (name) { + return !JavaScriptCompiler.RESERVED_WORDS[name] && /^[a-zA-Z_$][0-9a-zA-Z_$]*$/.test(name); + }; + + function strictLookup(requireTerminal, compiler, parts, type) { + var stack = compiler.popStack(), + i = 0, + len = parts.length; + if (requireTerminal) { + len--; + } + + for (; i < len; i++) { + stack = compiler.nameLookup(stack, parts[i], type); + } + + if (requireTerminal) { + return [compiler.aliasable('container.strict'), '(', stack, ', ', compiler.quotedString(parts[i]), ', ', JSON.stringify(compiler.source.currentLocation), ' )']; + } else { + return stack; + } + } + + exports['default'] = JavaScriptCompiler; + module.exports = exports['default']; + +/***/ }), +/* 53 */ +/***/ (function(module, exports, __webpack_require__) { + + /* global define */ + 'use strict'; + + var _Object$keys = __webpack_require__(13)['default']; + + exports.__esModule = true; + + var _utils = __webpack_require__(5); + + var SourceNode = undefined; + + try { + /* istanbul ignore next */ + if (false) { + // We don't support this in AMD environments. For these environments, we asusme that + // they are running on the browser and thus have no need for the source-map library. + var SourceMap = require('source-map'); + SourceNode = SourceMap.SourceNode; + } + } catch (err) {} + /* NOP */ + + /* istanbul ignore if: tested but not covered in istanbul due to dist build */ + if (!SourceNode) { + SourceNode = function (line, column, srcFile, chunks) { + this.src = ''; + if (chunks) { + this.add(chunks); + } + }; + /* istanbul ignore next */ + SourceNode.prototype = { + add: function add(chunks) { + if (_utils.isArray(chunks)) { + chunks = chunks.join(''); + } + this.src += chunks; + }, + prepend: function prepend(chunks) { + if (_utils.isArray(chunks)) { + chunks = chunks.join(''); + } + this.src = chunks + this.src; + }, + toStringWithSourceMap: function toStringWithSourceMap() { + return { code: this.toString() }; + }, + toString: function toString() { + return this.src; + } + }; + } + + function castChunk(chunk, codeGen, loc) { + if (_utils.isArray(chunk)) { + var ret = []; + + for (var i = 0, len = chunk.length; i < len; i++) { + ret.push(codeGen.wrap(chunk[i], loc)); + } + return ret; + } else if (typeof chunk === 'boolean' || typeof chunk === 'number') { + // Handle primitives that the SourceNode will throw up on + return chunk + ''; + } + return chunk; + } + + function CodeGen(srcFile) { + this.srcFile = srcFile; + this.source = []; + } + + CodeGen.prototype = { + isEmpty: function isEmpty() { + return !this.source.length; + }, + prepend: function prepend(source, loc) { + this.source.unshift(this.wrap(source, loc)); + }, + push: function push(source, loc) { + this.source.push(this.wrap(source, loc)); + }, + + merge: function merge() { + var source = this.empty(); + this.each(function (line) { + source.add([' ', line, '\n']); + }); + return source; + }, + + each: function each(iter) { + for (var i = 0, len = this.source.length; i < len; i++) { + iter(this.source[i]); + } + }, + + empty: function empty() { + var loc = this.currentLocation || { start: {} }; + return new SourceNode(loc.start.line, loc.start.column, this.srcFile); + }, + wrap: function wrap(chunk) { + var loc = arguments.length <= 1 || arguments[1] === undefined ? this.currentLocation || { start: {} } : arguments[1]; + + if (chunk instanceof SourceNode) { + return chunk; + } + + chunk = castChunk(chunk, this, loc); + + return new SourceNode(loc.start.line, loc.start.column, this.srcFile, chunk); + }, + + functionCall: function functionCall(fn, type, params) { + params = this.generateList(params); + return this.wrap([fn, type ? '.' + type + '(' : '(', params, ')']); + }, + + quotedString: function quotedString(str) { + return '"' + (str + '').replace(/\\/g, '\\\\').replace(/"/g, '\\"').replace(/\n/g, '\\n').replace(/\r/g, '\\r').replace(/\u2028/g, '\\u2028') // Per Ecma-262 7.3 + 7.8.4 + .replace(/\u2029/g, '\\u2029') + '"'; + }, + + objectLiteral: function objectLiteral(obj) { + // istanbul ignore next + + var _this = this; + + var pairs = []; + + _Object$keys(obj).forEach(function (key) { + var value = castChunk(obj[key], _this); + if (value !== 'undefined') { + pairs.push([_this.quotedString(key), ':', value]); + } + }); + + var ret = this.generateList(pairs); + ret.prepend('{'); + ret.add('}'); + return ret; + }, + + generateList: function generateList(entries) { + var ret = this.empty(); + + for (var i = 0, len = entries.length; i < len; i++) { + if (i) { + ret.add(','); + } + + ret.add(castChunk(entries[i], this)); + } + + return ret; + }, + + generateArray: function generateArray(entries) { + var ret = this.generateList(entries); + ret.prepend('['); + ret.add(']'); + + return ret; + } + }; + + exports['default'] = CodeGen; + module.exports = exports['default']; + +/***/ }) +/******/ ]) +}); +; \ No newline at end of file diff --git a/www/test/0.0.8/test/lib/morphdom-umd.js b/www/test/0.0.8/test/lib/morphdom-umd.js new file mode 100644 index 00000000..21fdc3a9 --- /dev/null +++ b/www/test/0.0.8/test/lib/morphdom-umd.js @@ -0,0 +1,763 @@ +(function (global, factory) { + typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() : + typeof define === 'function' && define.amd ? define(factory) : + (global = global || self, global.morphdom = factory()); +}(this, function () { 'use strict'; + + var DOCUMENT_FRAGMENT_NODE = 11; + + function morphAttrs(fromNode, toNode) { + var toNodeAttrs = toNode.attributes; + var attr; + var attrName; + var attrNamespaceURI; + var attrValue; + var fromValue; + + // document-fragments dont have attributes so lets not do anything + if (toNode.nodeType === DOCUMENT_FRAGMENT_NODE || fromNode.nodeType === DOCUMENT_FRAGMENT_NODE) { + return; + } + + // update attributes on original DOM element + for (var i = toNodeAttrs.length - 1; i >= 0; i--) { + attr = toNodeAttrs[i]; + attrName = attr.name; + attrNamespaceURI = attr.namespaceURI; + attrValue = attr.value; + + if (attrNamespaceURI) { + attrName = attr.localName || attrName; + fromValue = fromNode.getAttributeNS(attrNamespaceURI, attrName); + + if (fromValue !== attrValue) { + if (attr.prefix === 'xmlns'){ + attrName = attr.name; // It's not allowed to set an attribute with the XMLNS namespace without specifying the `xmlns` prefix + } + fromNode.setAttributeNS(attrNamespaceURI, attrName, attrValue); + } + } else { + fromValue = fromNode.getAttribute(attrName); + + if (fromValue !== attrValue) { + fromNode.setAttribute(attrName, attrValue); + } + } + } + + // Remove any extra attributes found on the original DOM element that + // weren't found on the target element. + var fromNodeAttrs = fromNode.attributes; + + for (var d = fromNodeAttrs.length - 1; d >= 0; d--) { + attr = fromNodeAttrs[d]; + attrName = attr.name; + attrNamespaceURI = attr.namespaceURI; + + if (attrNamespaceURI) { + attrName = attr.localName || attrName; + + if (!toNode.hasAttributeNS(attrNamespaceURI, attrName)) { + fromNode.removeAttributeNS(attrNamespaceURI, attrName); + } + } else { + if (!toNode.hasAttribute(attrName)) { + fromNode.removeAttribute(attrName); + } + } + } + } + + var range; // Create a range object for efficently rendering strings to elements. + var NS_XHTML = 'http://www.w3.org/1999/xhtml'; + + var doc = typeof document === 'undefined' ? undefined : document; + var HAS_TEMPLATE_SUPPORT = !!doc && 'content' in doc.createElement('template'); + var HAS_RANGE_SUPPORT = !!doc && doc.createRange && 'createContextualFragment' in doc.createRange(); + + function createFragmentFromTemplate(str) { + var template = doc.createElement('template'); + template.innerHTML = str; + return template.content.childNodes[0]; + } + + function createFragmentFromRange(str) { + if (!range) { + range = doc.createRange(); + range.selectNode(doc.body); + } + + var fragment = range.createContextualFragment(str); + return fragment.childNodes[0]; + } + + function createFragmentFromWrap(str) { + var fragment = doc.createElement('body'); + fragment.innerHTML = str; + return fragment.childNodes[0]; + } + + /** + * This is about the same + * var html = new DOMParser().parseFromString(str, 'text/html'); + * return html.body.firstChild; + * + * @method toElement + * @param {String} str + */ + function toElement(str) { + str = str.trim(); + if (HAS_TEMPLATE_SUPPORT) { + // avoid restrictions on content for things like `Hi` which + // createContextualFragment doesn't support + //