muu

DEPRECATED lightweight JS framework
git clone https://git.ce9e.org/muu.git

commit
26cbd7bae82f6ddc65afb4eddd6f9e38cabca571
parent
8e4681e8b146d79e3eddac3927cd14f90d61534f
Author
Tobias Bengfort <tobias.bengfort@gmx.net>
Date
2015-09-11 05:51
bump version to 0.1.2

Diffstat

M CHANGES.md 40 ++++++++++++++++++++++++++++++++++++++++
M bower.json 2 +-
M dist/muu-core.js 71 +++++++++++++++++++++++++++++++++++++++----------------------
M dist/muu-core.min.js 22 +++++++++++-----------
M dist/muu.js 71 +++++++++++++++++++++++++++++++++++++++----------------------
M dist/muu.min.js 39 ++++++++++++++++++++-------------------

6 files changed, 164 insertions, 81 deletions


diff --git a/CHANGES.md b/CHANGES.md

@@ -1,3 +1,43 @@
   -1     1 0.1.2 (2015-09-11)
   -1     2 ==================
   -1     3 
   -1     4 Breaking changes
   -1     5 ----------------
   -1     6 
   -1     7 -   The interface to register event listeners has been simplified. Before you
   -1     8     had to write this:
   -1     9 
   -1    10         muu.$.on(element, 'muu-event-name', function(wrapperEvent) {
   -1    11             var event = wrapperEvent.detail;
   -1    12             ...
   -1    13         });
   -1    14 
   -1    15     Now you should use this instead:
   -1    16 
   -1    17         directive.on('event-name', function(event) {
   -1    18             ...
   -1    19         });
   -1    20 
   -1    21     The old interface is deprecated, but guranteed to work until the next minor
   -1    22     release.
   -1    23 
   -1    24 -   The interface of `updateDOM()` has been changed to take a HTML string
   -1    25     instead of a DOM node. This will make it easier to exchange it by third
   -1    26     party libraries in the future.
   -1    27 
   -1    28 Enhancements
   -1    29 ------------
   -1    30 
   -1    31 -   `Directive.setModel()` now only changes the DOM if the value has actually
   -1    32     changed. This way, selection is preserved in more cases.
   -1    33 
   -1    34 Bugfixes
   -1    35 --------
   -1    36 
   -1    37 -   A bug in `updateDOM()` has been fixed where replacing more than one node in a
   -1    38     parent threw an exception.
   -1    39 
   -1    40 
    1    41 0.1.1 (2015-08-31)
    2    42 ==================
    3    43 

diff --git a/bower.json b/bower.json

@@ -1,6 +1,6 @@
    1     1 {
    2     2   "name": "muu",
    3    -1   "version": "0.1.1",
   -1     3   "version": "0.1.2",
    4     4   "authors": [
    5     5     "Tobias Bengfort <tobias.bengfort@posteo.de>"
    6     6   ],

diff --git a/dist/muu-core.js b/dist/muu-core.js

@@ -68,8 +68,8 @@
   68    68              * - You can react to DOM events by specifying an alias for them. In the
   69    69              *   template, you might for example add the attribute
   70    70              *   `data-onclick="custom"` to an element. When there is `click` event on
   71    -1              *   that element, a `muu-custom` event will be triggered on the
   72    -1              *   directive's root element.
   -1    71              *   that element, a `custom` event will be triggered on the directive. See
   -1    72              *   {@link Directive#on}.
   73    73              *
   74    74              * Directives are typically not created directly but via {@link
   75    75              * Registry#link}.
@@ -103,10 +103,7 @@
  103   103                  * @see The templating system can be defined in the {@link Registry}.
  104   104                  */
  105   105                 this.update = function(data) {
  106    -1                     var tmp = document.createElement('div');
  107    -1                     tmp.innerHTML = registry.renderer(template, data);
  108    -1 
  109    -1                     updateDOM(root, tmp);
   -1   106                     updateDOM(root, registry.renderer(template, data));
  110   107 
  111   108                     _.forEach(['keydown', 'keyup', 'click', 'change', 'search'], function(eventType) {
  112   109                         var selector = '[data-on' + eventType + ']';
@@ -116,7 +113,7 @@
  116   113                     });
  117   114 
  118   115                     var updateEvent = $.createEvent('muu-parent-update');
  119    -1                     var subDirectives = this.querySelectorAll('muu.muu-initialised');
   -1   116                     var subDirectives = self.querySelectorAll('muu.muu-initialised');
  120   117                     _.forEach(subDirectives, function(element) {
  121   118                         element.dispatchEvent(updateEvent);
  122   119                     });
@@ -167,6 +164,17 @@
  167   164                 };
  168   165 
  169   166                 /**
   -1   167                  * @param {string} eventName
   -1   168                  * @param {Function} callback
   -1   169                  * @return {function()} An unregister function
   -1   170                  */
   -1   171                 this.on = function(eventName, fn) {
   -1   172                     return $.on(root, 'muu-' + eventName, function(event) {
   -1   173                         return fn(event.detail);
   -1   174                     });
   -1   175                 };
   -1   176 
   -1   177                 /**
  170   178                  * Get all model data as a flat object.
  171   179                  *
  172   180                  * @return {Object.<string, string|number|boolean>}
@@ -193,7 +201,7 @@
  193   201                         if (element === undefined) {
  194   202                             return _default;
  195   203                         } else if (element.getAttribute('type') === 'number') {
  196    -1                             return parseFloat(element.value, 10);
   -1   204                             return parseFloat(element.value);
  197   205                         } else if (element.getAttribute('type') === 'checkbox') {
  198   206                             return element.checked;
  199   207                         } else if (element.getAttribute('type') === 'radio') {
@@ -215,6 +223,10 @@
  215   223                  * @param {string|number|boolean} value
  216   224                  */
  217   225                 this.setModel = function(name, value) {
   -1   226                     if (self.getModel(name) === value) {
   -1   227                         return;
   -1   228                     }
   -1   229 
  218   230                     var element = self.querySelector('[name=' + name + ']');
  219   231                     if (element.getAttribute('type') === 'checkbox') {
  220   232                         element.checked = value;
@@ -443,8 +455,8 @@
  443   455              * - **debug** - `{boolean}` - Enable debug mode. In debug mode,
  444   456              *   directive objects are available as properties from the DOM as
  445   457              *   `element.directive`.
  446    -1              * - **renderer** - `{function(string, Object)}` - The template renderer
  447    -1              *   to be used. Defaults to {@link module:muu-template}.
   -1   458              * - **renderer** - `{function(string, Object): string}` - The template
   -1   459              *   renderer to be used. Defaults to {@link module:muu-template}.
  448   460              */
  449   461             var Registry = function(config) {
  450   462                 var self = this;
@@ -563,32 +575,37 @@
  563   575             return Registry;
  564   576         });
  565   577         /**
  566    -1          * Recreate children of `source` in `target` by making only small adjustments.
   -1   578          * Recreate `html` in `target` by making only small adjustments.
  567   579          *
  568   580          * *The following section explains details about the current implementation.
  569   581          * These are likely to change in the future.*
  570   582          *
  571   583          * The algorithms is relatively simple. It just iterates through all top level
  572   584          * nodes. If a node has a different `nodeType` (e.g. text or element) or a
  573    -1          * different `nodeName` (e.g. div or ul) it is replaced completely and the
  574    -1          * algorithm proceeds with the node's children recursively.  Otherwise, only
  575    -1          * the nodes's attributes are updated.
   -1   585          * different `nodeName` (e.g. div or ul) it is replaced completely. Otherwise,
   -1   586          * only the nodes's attributes are updated and the algorithm proceeds with the
   -1   587          * node's children recursively.
  576   588          *
  577    -1          * Note that non-attribute properties (e.g. value) are lost in the first case
   -1   589          * Note that non-attribute properties (e.g. `value`) are lost in the first case
  578   590          * and preserved in the second.
  579   591          *
  580   592          * If the algorithm encounters an element with the class `muu-isolate` it does
  581   593          * not recurse into its children. This way, you can protect dynamically
  582   594          * generated content from being overwritten.
  583   595          *
   -1   596          * All classes prefixed with `muu-` will be preserved.
   -1   597          *
  584   598          * @module muu-update-dom
  585    -1          * @param {Element} target
  586    -1          * @param {Element} source
   -1   599          * @param {Node} target
   -1   600          * @param {string} html
  587   601          */
  588   602         _define('muu-update-dom', ['muu-js-helpers'], function(_) {
  589   603             "use strict";
  590   604 
  591   605             var updateAttributes = function(target, source) {
   -1   606                 var muuClasses = _.filter(target.classList, function(cls) {
   -1   607                     return cls.lastIndexOf('muu-', 0) === 0;
   -1   608                 });
  592   609                 var targetAttrNames = _.map(target.attributes, function(item) {
  593   610                     return item.name;
  594   611                 });
@@ -607,11 +624,15 @@
  607   624                         target.setAttribute(name, source.getAttribute(name));
  608   625                     }
  609   626                 });
   -1   627                 _.forEach(muuClasses, function(cls) {
   -1   628                     target.classList.add(cls);
   -1   629                 });
  610   630             };
  611   631 
  612   632             var updateDOM = function(target, source) {
  613   633                 var nt = target.childNodes.length;
  614   634                 var ns = source.childNodes.length;
   -1   635                 var offset = 0;
  615   636 
  616   637                 for (var i = ns; i < nt; i++) {
  617   638                     target.removeChild(target.childNodes[ns]);
@@ -621,17 +642,11 @@
  621   642                 }
  622   643                 for (i = 0; i < nt && i < ns; i++) {
  623   644                     var tchild = target.childNodes[i];
  624    -1                     var schild = source.childNodes[i];
   -1   645                     var schild = source.childNodes[i - offset];
  625   646 
  626   647                     if (tchild.nodeType === schild.nodeType && tchild.nodeName === schild.nodeName && tchild.type === schild.type) {
  627   648                         if (tchild.nodeType === 1) {
  628    -1                             var muuClasses = _.filter(tchild.classList, function(cls) {
  629    -1                                 return cls.lastIndexOf('muu-', 0) === 0;
  630    -1                             });
  631   649                             updateAttributes(tchild, schild);
  632    -1                             _.forEach(muuClasses, function(cls) {
  633    -1                                 tchild.classList.add(cls);
  634    -1                             });
  635   650                         } else if (tchild.nodeType === 3) {
  636   651                             tchild.nodeValue = schild.nodeValue;
  637   652                         }
@@ -640,11 +655,17 @@
  640   655                         }
  641   656                     } else {
  642   657                         tchild.parentNode.replaceChild(schild, tchild);
   -1   658                         offset += 1;
  643   659                     }
  644   660                 }
  645   661             };
  646   662 
  647    -1             return updateDOM;
   -1   663             return function(target, html) {
   -1   664                 var tmp = document.createElement('div');
   -1   665                 tmp.innerHTML = html;
   -1   666 
   -1   667                 updateDOM(target, tmp);
   -1   668             }
  648   669         });
  649   670 
  650   671         return _require(name);

diff --git a/dist/muu-core.min.js b/dist/muu-core.min.js

@@ -1,11 +1,11 @@
    1    -1 (function(q,p,m){(function(l){"function"===typeof define&&define.amd?define("muu",["lodash"],l):q.muu=l(q._)})(function(l){var n={};n["muu-js-helpers"]={instance:l};var t=function(d,k){for(var g=[],a=0;a<d.length;a++)g.push(k(d[a]));return g};l=function(d,k,g){n[d]={deps:k,factory:g}};var r=function(d){if(!n[d])return m;n[d].instance||(n[d].instance=n[d].factory.apply(m,t(n[d].deps,r)));return n[d].instance};l("muu-directive",["muu-dom-helpers","muu-js-helpers","muu-update-dom"],function(d,k,g){return function(a,
    2    -1 b,e){var h=this;a.innerHTML="";var c=function(f){var c=f.currentTarget,b="data-on"+f.type;c.hasAttribute(b)&&(c=c.getAttribute(b),f=d.createEvent("muu-"+c,m,m,f),a.dispatchEvent(f))};this.update=function(f){var s=p.createElement("div");s.innerHTML=e.renderer(b,f);g(a,s);k.forEach(["keydown","keyup","click","change","search"],function(a){k.forEach(h.querySelectorAll("[data-on"+a+"]"),function(f){f.addEventListener(a,c,!1)})});var u=d.createEvent("muu-parent-update");f=this.querySelectorAll("muu.muu-initialised");
    3    -1 k.forEach(f,function(a){a.dispatchEvent(u)});e.linkAll(h)};this.querySelectorAll=function(f){var c=a.querySelectorAll(f),b=a.querySelectorAll(".muu-isolate"),b=k.union(k.map(b,function(a){return a.querySelectorAll(f)}));return k.difference(c,b)};this.querySelector=function(a){a=h.querySelectorAll(a);if(0<a.length)return a[0]};this.getModel=function(a,c){if(a===m){var b={};k.forEach(h.querySelectorAll("[name]"),function(a){b[a.name]=h.getModel(a.name)});return b}var e=h.querySelector("[name="+a+"]");
    4    -1 return e===m?c:"number"===e.getAttribute("type")?parseFloat(e.value,10):"checkbox"===e.getAttribute("type")?e.checked:"radio"===e.getAttribute("type")?(e=h.querySelectorAll("[name="+a+"]"),d.getRadio(e)||c):e.value};this.setModel=function(a,c){var b=h.querySelector("[name="+a+"]");"checkbox"===b.getAttribute("type")?b.checked=c:"radio"===b.getAttribute("type")?(b=h.querySelectorAll("[name="+a+"]"),d.setRadio(b,c)):b.value=c}}});l("muu-dom-helpers",["muu-js-helpers"],function(d){var k={"&":"&amp;",
    5    -1 "<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#39;","/":"&#x2F;"},g={DELAY:1E3,escapeHtml:function(a){return String(a).replace(/[&<>"'\/]/g,function(a){return k[a]})},createEvent:function(a,b,e,d){if("function"===typeof CustomEvent)return new CustomEvent(a,{detail:d,bubbles:b,cancelable:e});var c=p.createEvent("CustomEvent");c.initCustomEvent(a,b,e,d);return c},on:function(a,b,e){a.addEventListener(b,e,!1);return function(){a.removeEventListener(b,e,!1)}},ready:function(a){a=d.once(a);if("complete"===
    6    -1 p.readyState)return a(),function(){};var b=g.on(p,"DOMContentLoaded",a),e=g.on(q,"load",a);return function(){b();e()}},isDescendant:function(a,b){return!!a&&(a===b||g.isDescendant(a.parentNode,b))},destroy:function(a,b){var e;if(q.MutationObserver){var h=new MutationObserver(function(){g.isDescendant(a,p)||(b(),e())});h.observe(p,{childList:!0,subtree:!0});e=d.once(function(){h.disconnect();h=m})}else{var c=setInterval(function(){g.isDescendant(a,p)||(b(),e())},g.DELAY);e=function(){clearInterval(c)}}return e},
    7    -1 getRadio:function(a){for(var b=0;b<a.length;b++)if(a[b].checked)return a[b].value},setRadio:function(a,b){d.forEach(a,function(a){a.checked=a.value===b?!0:!1})}};return g});l("muu",["muu-registry","muu-dom-helpers","muu-location"],function(d,k,g){var a={};a.Registry=d;a.$=k;a.$location=g;return a});l("muu-registry",["muu-template","muu-directive","muu-js-helpers","muu-dom-helpers"],function(d,k,g,a){return function(b){var e=this,h={};this.config=b||{};this.renderer=e.config.renderer||d;this.registerDirective=
    8    -1 function(a,b,d){h[a]={template:b,link:d};return e};this.registerModule=function(a){a(e);return e};this.link=function(c,b){b===m&&(b=c.getAttribute("type"));if(!h.hasOwnProperty(b))throw Error("Unknown directive type: "+b);var d=h[b].link,g=new k(c,h[b].template,e),d=d(g,c);c.classList.add("muu-isolate");c.classList.add("muu-initialised");e.config.debug&&(c.directive=g);d!==m&&a.destroy(c,d);return g};this.linkAll=function(a){a=g.filter(a.querySelectorAll("muu"),function(a){return!a.classList.contains("muu-initialised")});
    9    -1 return g.map(a,function(a){return e.link(a)})}}});l("muu-update-dom",["muu-js-helpers"],function(d){var k=function(a,b){var e=d.map(a.attributes,function(a){return a.name}),g=d.map(b.attributes,function(a){return a.name});d.forEach(e,function(c){b.hasAttribute(c)||"__IE8__"===c.substr(0,7)||a.removeAttribute(c)});d.forEach(g,function(c){a.getAttribute(c)!==b.getAttribute(c)&&a.setAttribute(c,b.getAttribute(c))})},g=function(a,b){for(var e=a.childNodes.length,h=b.childNodes.length,c=h;c<e;c++)a.removeChild(a.childNodes[h]);
   10    -1 for(c=e;c<h;c++)a.appendChild(b.childNodes[e]);for(c=0;c<e&&c<h;c++){var f=a.childNodes[c],l=b.childNodes[c];if(f.nodeType===l.nodeType&&f.nodeName===l.nodeName&&f.type===l.type){if(1===f.nodeType){var m=d.filter(f.classList,function(a){return 0===a.lastIndexOf("muu-",0)});k(f,l);d.forEach(m,function(a){f.classList.add(a)})}else 3===f.nodeType&&(f.nodeValue=l.nodeValue);3===f.nodeType||f.classList.contains("muu-isolate")||g(f,l)}else f.parentNode.replaceChild(l,f)}};return g});return r("muu")})})(window,
   11    -1 document,void 0);
   -1     1 (function(r,p,l){(function(m){"function"===typeof define&&define.amd?define("muu",["lodash"],m):r.muu=m(r._)})(function(m){var n={};n["muu-js-helpers"]={instance:m};var t=function(e,h){for(var f=[],a=0;a<e.length;a++)f.push(h(e[a]));return f};m=function(e,h,f){n[e]={deps:h,factory:f}};var s=function(e){if(!n[e])return l;n[e].instance||(n[e].instance=n[e].factory.apply(l,t(n[e].deps,s)));return n[e].instance};m("muu-directive",["muu-dom-helpers","muu-js-helpers","muu-update-dom"],function(e,h,f){return function(a,
   -1     2 c,d){var g=this;a.innerHTML="";var q=function(b){var k=b.currentTarget,c="data-on"+b.type;k.hasAttribute(c)&&(k=k.getAttribute(c),b=e.createEvent("muu-"+k,l,l,b),a.dispatchEvent(b))};this.update=function(b){f(a,d.renderer(c,b));h.forEach(["keydown","keyup","click","change","search"],function(b){h.forEach(g.querySelectorAll("[data-on"+b+"]"),function(a){a.addEventListener(b,q,!1)})});var k=e.createEvent("muu-parent-update");b=g.querySelectorAll("muu.muu-initialised");h.forEach(b,function(b){b.dispatchEvent(k)});
   -1     3 d.linkAll(g)};this.querySelectorAll=function(b){var c=a.querySelectorAll(b),d=a.querySelectorAll(".muu-isolate"),d=h.union(h.map(d,function(a){return a.querySelectorAll(b)}));return h.difference(c,d)};this.querySelector=function(b){b=g.querySelectorAll(b);if(0<b.length)return b[0]};this.on=function(b,c){return e.on(a,"muu-"+b,function(b){return c(b.detail)})};this.getModel=function(b,a){if(b===l){var c={};h.forEach(g.querySelectorAll("[name]"),function(b){c[b.name]=g.getModel(b.name)});return c}var d=
   -1     4 g.querySelector("[name="+b+"]");return d===l?a:"number"===d.getAttribute("type")?parseFloat(d.value):"checkbox"===d.getAttribute("type")?d.checked:"radio"===d.getAttribute("type")?(d=g.querySelectorAll("[name="+b+"]"),e.getRadio(d)||a):d.value};this.setModel=function(b,a){if(g.getModel(b)!==a){var d=g.querySelector("[name="+b+"]");"checkbox"===d.getAttribute("type")?d.checked=a:"radio"===d.getAttribute("type")?(d=g.querySelectorAll("[name="+b+"]"),e.setRadio(d,a)):d.value=a}}}});m("muu-dom-helpers",
   -1     5 ["muu-js-helpers"],function(e){var h={"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#39;","/":"&#x2F;"},f={DELAY:1E3,escapeHtml:function(a){return String(a).replace(/[&<>"'\/]/g,function(a){return h[a]})},createEvent:function(a,c,d,e){if("function"===typeof CustomEvent)return new CustomEvent(a,{detail:e,bubbles:c,cancelable:d});var q=p.createEvent("CustomEvent");q.initCustomEvent(a,c,d,e);return q},on:function(a,c,d){a.addEventListener(c,d,!1);return function(){a.removeEventListener(c,d,!1)}},
   -1     6 ready:function(a){a=e.once(a);if("complete"===p.readyState)return a(),function(){};var c=f.on(p,"DOMContentLoaded",a),d=f.on(r,"load",a);return function(){c();d()}},isDescendant:function(a,c){return!!a&&(a===c||f.isDescendant(a.parentNode,c))},destroy:function(a,c){var d;if(r.MutationObserver){var g=new MutationObserver(function(){f.isDescendant(a,p)||(c(),d())});g.observe(p,{childList:!0,subtree:!0});d=e.once(function(){g.disconnect();g=l})}else{var q=setInterval(function(){f.isDescendant(a,p)||
   -1     7 (c(),d())},f.DELAY);d=function(){clearInterval(q)}}return d},getRadio:function(a){for(var c=0;c<a.length;c++)if(a[c].checked)return a[c].value},setRadio:function(a,c){e.forEach(a,function(a){a.checked=a.value===c?!0:!1})}};return f});m("muu",["muu-registry","muu-dom-helpers","muu-location"],function(e,h,f){var a={};a.Registry=e;a.$=h;a.$location=f;return a});m("muu-registry",["muu-template","muu-directive","muu-js-helpers","muu-dom-helpers"],function(e,h,f,a){return function(c){var d=this,g={};this.config=
   -1     8 c||{};this.renderer=d.config.renderer||e;this.registerDirective=function(a,b,c){g[a]={template:b,link:c};return d};this.registerModule=function(a){a(d);return d};this.link=function(c,b){b===l&&(b=c.getAttribute("type"));if(!g.hasOwnProperty(b))throw Error("Unknown directive type: "+b);var e=g[b].link,f=new h(c,g[b].template,d),e=e(f,c);c.classList.add("muu-isolate");c.classList.add("muu-initialised");d.config.debug&&(c.directive=f);e!==l&&a.destroy(c,e);return f};this.linkAll=function(a){a=f.filter(a.querySelectorAll("muu"),
   -1     9 function(a){return!a.classList.contains("muu-initialised")});return f.map(a,function(a){return d.link(a)})}}});m("muu-update-dom",["muu-js-helpers"],function(e){var h=function(a,c){var d=e.filter(a.classList,function(a){return 0===a.lastIndexOf("muu-",0)}),g=e.map(a.attributes,function(a){return a.name}),f=e.map(c.attributes,function(a){return a.name});e.forEach(g,function(b){c.hasAttribute(b)||"__IE8__"===b.substr(0,7)||a.removeAttribute(b)});e.forEach(f,function(b){a.getAttribute(b)!==c.getAttribute(b)&&
   -1    10 a.setAttribute(b,c.getAttribute(b))});e.forEach(d,function(b){a.classList.add(b)})},f=function(a,c){for(var d=a.childNodes.length,e=c.childNodes.length,m=0,b=e;b<d;b++)a.removeChild(a.childNodes[e]);for(b=d;b<e;b++)a.appendChild(c.childNodes[d]);for(b=0;b<d&&b<e;b++){var k=a.childNodes[b],l=c.childNodes[b-m];k.nodeType===l.nodeType&&k.nodeName===l.nodeName&&k.type===l.type?(1===k.nodeType?h(k,l):3===k.nodeType&&(k.nodeValue=l.nodeValue),3===k.nodeType||k.classList.contains("muu-isolate")||f(k,l)):
   -1    11 (k.parentNode.replaceChild(l,k),m+=1)}};return function(a,c){var d=p.createElement("div");d.innerHTML=c;f(a,d)}});return s("muu")})})(window,document,void 0);

diff --git a/dist/muu.js b/dist/muu.js

@@ -68,8 +68,8 @@
   68    68              * - You can react to DOM events by specifying an alias for them. In the
   69    69              *   template, you might for example add the attribute
   70    70              *   `data-onclick="custom"` to an element. When there is `click` event on
   71    -1              *   that element, a `muu-custom` event will be triggered on the
   72    -1              *   directive's root element.
   -1    71              *   that element, a `custom` event will be triggered on the directive. See
   -1    72              *   {@link Directive#on}.
   73    73              *
   74    74              * Directives are typically not created directly but via {@link
   75    75              * Registry#link}.
@@ -103,10 +103,7 @@
  103   103                  * @see The templating system can be defined in the {@link Registry}.
  104   104                  */
  105   105                 this.update = function(data) {
  106    -1                     var tmp = document.createElement('div');
  107    -1                     tmp.innerHTML = registry.renderer(template, data);
  108    -1 
  109    -1                     updateDOM(root, tmp);
   -1   106                     updateDOM(root, registry.renderer(template, data));
  110   107 
  111   108                     _.forEach(['keydown', 'keyup', 'click', 'change', 'search'], function(eventType) {
  112   109                         var selector = '[data-on' + eventType + ']';
@@ -116,7 +113,7 @@
  116   113                     });
  117   114 
  118   115                     var updateEvent = $.createEvent('muu-parent-update');
  119    -1                     var subDirectives = this.querySelectorAll('muu.muu-initialised');
   -1   116                     var subDirectives = self.querySelectorAll('muu.muu-initialised');
  120   117                     _.forEach(subDirectives, function(element) {
  121   118                         element.dispatchEvent(updateEvent);
  122   119                     });
@@ -167,6 +164,17 @@
  167   164                 };
  168   165 
  169   166                 /**
   -1   167                  * @param {string} eventName
   -1   168                  * @param {Function} callback
   -1   169                  * @return {function()} An unregister function
   -1   170                  */
   -1   171                 this.on = function(eventName, fn) {
   -1   172                     return $.on(root, 'muu-' + eventName, function(event) {
   -1   173                         return fn(event.detail);
   -1   174                     });
   -1   175                 };
   -1   176 
   -1   177                 /**
  170   178                  * Get all model data as a flat object.
  171   179                  *
  172   180                  * @return {Object.<string, string|number|boolean>}
@@ -193,7 +201,7 @@
  193   201                         if (element === undefined) {
  194   202                             return _default;
  195   203                         } else if (element.getAttribute('type') === 'number') {
  196    -1                             return parseFloat(element.value, 10);
   -1   204                             return parseFloat(element.value);
  197   205                         } else if (element.getAttribute('type') === 'checkbox') {
  198   206                             return element.checked;
  199   207                         } else if (element.getAttribute('type') === 'radio') {
@@ -215,6 +223,10 @@
  215   223                  * @param {string|number|boolean} value
  216   224                  */
  217   225                 this.setModel = function(name, value) {
   -1   226                     if (self.getModel(name) === value) {
   -1   227                         return;
   -1   228                     }
   -1   229 
  218   230                     var element = self.querySelector('[name=' + name + ']');
  219   231                     if (element.getAttribute('type') === 'checkbox') {
  220   232                         element.checked = value;
@@ -782,8 +794,8 @@
  782   794              * - **debug** - `{boolean}` - Enable debug mode. In debug mode,
  783   795              *   directive objects are available as properties from the DOM as
  784   796              *   `element.directive`.
  785    -1              * - **renderer** - `{function(string, Object)}` - The template renderer
  786    -1              *   to be used. Defaults to {@link module:muu-template}.
   -1   797              * - **renderer** - `{function(string, Object): string}` - The template
   -1   798              *   renderer to be used. Defaults to {@link module:muu-template}.
  787   799              */
  788   800             var Registry = function(config) {
  789   801                 var self = this;
@@ -1185,32 +1197,37 @@
 1185  1197             };
 1186  1198         });
 1187  1199         /**
 1188    -1          * Recreate children of `source` in `target` by making only small adjustments.
   -1  1200          * Recreate `html` in `target` by making only small adjustments.
 1189  1201          *
 1190  1202          * *The following section explains details about the current implementation.
 1191  1203          * These are likely to change in the future.*
 1192  1204          *
 1193  1205          * The algorithms is relatively simple. It just iterates through all top level
 1194  1206          * nodes. If a node has a different `nodeType` (e.g. text or element) or a
 1195    -1          * different `nodeName` (e.g. div or ul) it is replaced completely and the
 1196    -1          * algorithm proceeds with the node's children recursively.  Otherwise, only
 1197    -1          * the nodes's attributes are updated.
   -1  1207          * different `nodeName` (e.g. div or ul) it is replaced completely. Otherwise,
   -1  1208          * only the nodes's attributes are updated and the algorithm proceeds with the
   -1  1209          * node's children recursively.
 1198  1210          *
 1199    -1          * Note that non-attribute properties (e.g. value) are lost in the first case
   -1  1211          * Note that non-attribute properties (e.g. `value`) are lost in the first case
 1200  1212          * and preserved in the second.
 1201  1213          *
 1202  1214          * If the algorithm encounters an element with the class `muu-isolate` it does
 1203  1215          * not recurse into its children. This way, you can protect dynamically
 1204  1216          * generated content from being overwritten.
 1205  1217          *
   -1  1218          * All classes prefixed with `muu-` will be preserved.
   -1  1219          *
 1206  1220          * @module muu-update-dom
 1207    -1          * @param {Element} target
 1208    -1          * @param {Element} source
   -1  1221          * @param {Node} target
   -1  1222          * @param {string} html
 1209  1223          */
 1210  1224         _define('muu-update-dom', ['muu-js-helpers'], function(_) {
 1211  1225             "use strict";
 1212  1226 
 1213  1227             var updateAttributes = function(target, source) {
   -1  1228                 var muuClasses = _.filter(target.classList, function(cls) {
   -1  1229                     return cls.lastIndexOf('muu-', 0) === 0;
   -1  1230                 });
 1214  1231                 var targetAttrNames = _.map(target.attributes, function(item) {
 1215  1232                     return item.name;
 1216  1233                 });
@@ -1229,11 +1246,15 @@
 1229  1246                         target.setAttribute(name, source.getAttribute(name));
 1230  1247                     }
 1231  1248                 });
   -1  1249                 _.forEach(muuClasses, function(cls) {
   -1  1250                     target.classList.add(cls);
   -1  1251                 });
 1232  1252             };
 1233  1253 
 1234  1254             var updateDOM = function(target, source) {
 1235  1255                 var nt = target.childNodes.length;
 1236  1256                 var ns = source.childNodes.length;
   -1  1257                 var offset = 0;
 1237  1258 
 1238  1259                 for (var i = ns; i < nt; i++) {
 1239  1260                     target.removeChild(target.childNodes[ns]);
@@ -1243,17 +1264,11 @@
 1243  1264                 }
 1244  1265                 for (i = 0; i < nt && i < ns; i++) {
 1245  1266                     var tchild = target.childNodes[i];
 1246    -1                     var schild = source.childNodes[i];
   -1  1267                     var schild = source.childNodes[i - offset];
 1247  1268 
 1248  1269                     if (tchild.nodeType === schild.nodeType && tchild.nodeName === schild.nodeName && tchild.type === schild.type) {
 1249  1270                         if (tchild.nodeType === 1) {
 1250    -1                             var muuClasses = _.filter(tchild.classList, function(cls) {
 1251    -1                                 return cls.lastIndexOf('muu-', 0) === 0;
 1252    -1                             });
 1253  1271                             updateAttributes(tchild, schild);
 1254    -1                             _.forEach(muuClasses, function(cls) {
 1255    -1                                 tchild.classList.add(cls);
 1256    -1                             });
 1257  1272                         } else if (tchild.nodeType === 3) {
 1258  1273                             tchild.nodeValue = schild.nodeValue;
 1259  1274                         }
@@ -1262,11 +1277,17 @@
 1262  1277                         }
 1263  1278                     } else {
 1264  1279                         tchild.parentNode.replaceChild(schild, tchild);
   -1  1280                         offset += 1;
 1265  1281                     }
 1266  1282                 }
 1267  1283             };
 1268  1284 
 1269    -1             return updateDOM;
   -1  1285             return function(target, html) {
   -1  1286                 var tmp = document.createElement('div');
   -1  1287                 tmp.innerHTML = html;
   -1  1288 
   -1  1289                 updateDOM(target, tmp);
   -1  1290             }
 1270  1291         });
 1271  1292         /**
 1272  1293          * This module gives access to the following objects:

diff --git a/dist/muu.min.js b/dist/muu.min.js

@@ -1,19 +1,20 @@
    1    -1 (function(r,p,g){(function(g){"function"===typeof define&&define.amd?define("muu",[],g):r.muu=g(r._)})(function(k){var m={};m["muu-js-helpers"]={instance:k};var v=function(d,c){for(var e=[],a=0;a<d.length;a++)e.push(c(d[a]));return e};k=function(d,c,e){m[d]={deps:c,factory:e}};var t=function(d){if(!m[d])return g;m[d].instance||(m[d].instance=m[d].factory.apply(g,v(m[d].deps,t)));return m[d].instance};k("muu-directive",["muu-dom-helpers","muu-js-helpers","muu-update-dom"],function(d,c,e){return function(a,
    2    -1 b,n){var f=this;a.innerHTML="";var h=function(b){var c=b.currentTarget,h="data-on"+b.type;c.hasAttribute(h)&&(c=c.getAttribute(h),b=d.createEvent("muu-"+c,g,g,b),a.dispatchEvent(b))};this.update=function(l){var u=p.createElement("div");u.innerHTML=n.renderer(b,l);e(a,u);c.forEach(["keydown","keyup","click","change","search"],function(a){c.forEach(f.querySelectorAll("[data-on"+a+"]"),function(b){b.addEventListener(a,h,!1)})});var s=d.createEvent("muu-parent-update");l=this.querySelectorAll("muu.muu-initialised");
    3    -1 c.forEach(l,function(a){a.dispatchEvent(s)});n.linkAll(f)};this.querySelectorAll=function(b){var h=a.querySelectorAll(b),d=a.querySelectorAll(".muu-isolate"),d=c.union(c.map(d,function(a){return a.querySelectorAll(b)}));return c.difference(h,d)};this.querySelector=function(a){a=f.querySelectorAll(a);if(0<a.length)return a[0]};this.getModel=function(a,b){if(a===g){var h={};c.forEach(f.querySelectorAll("[name]"),function(a){h[a.name]=f.getModel(a.name)});return h}var e=f.querySelector("[name="+a+"]");
    4    -1 return e===g?b:"number"===e.getAttribute("type")?parseFloat(e.value,10):"checkbox"===e.getAttribute("type")?e.checked:"radio"===e.getAttribute("type")?(e=f.querySelectorAll("[name="+a+"]"),d.getRadio(e)||b):e.value};this.setModel=function(a,b){var c=f.querySelector("[name="+a+"]");"checkbox"===c.getAttribute("type")?c.checked=b:"radio"===c.getAttribute("type")?(c=f.querySelectorAll("[name="+a+"]"),d.setRadio(c,b)):c.value=b}}});k("muu-dom-helpers",["muu-js-helpers"],function(d){var c={"&":"&amp;",
    5    -1 "<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#39;","/":"&#x2F;"},e={DELAY:1E3,escapeHtml:function(a){return String(a).replace(/[&<>"'\/]/g,function(a){return c[a]})},createEvent:function(a,b,c,d){if("function"===typeof CustomEvent)return new CustomEvent(a,{detail:d,bubbles:b,cancelable:c});var h=p.createEvent("CustomEvent");h.initCustomEvent(a,b,c,d);return h},on:function(a,b,c){a.addEventListener(b,c,!1);return function(){a.removeEventListener(b,c,!1)}},ready:function(a){a=d.once(a);if("complete"===
    6    -1 p.readyState)return a(),function(){};var b=e.on(p,"DOMContentLoaded",a),c=e.on(r,"load",a);return function(){b();c()}},isDescendant:function(a,b){return!!a&&(a===b||e.isDescendant(a.parentNode,b))},destroy:function(a,b){var c;if(r.MutationObserver){var f=new MutationObserver(function(){e.isDescendant(a,p)||(b(),c())});f.observe(p,{childList:!0,subtree:!0});c=d.once(function(){f.disconnect();f=g})}else{var h=setInterval(function(){e.isDescendant(a,p)||(b(),c())},e.DELAY);c=function(){clearInterval(h)}}return c},
    7    -1 getRadio:function(a){for(var b=0;b<a.length;b++)if(a[b].checked)return a[b].value},setRadio:function(a,b){d.forEach(a,function(a){a.checked=a.value===b?!0:!1})}};return e});k("muu-js-helpers",[],function(){var d={isString:function(c){return"string"===typeof c||"[object String]"===Object.prototype.toString.call(c)}};d.isArray=Array.isArray;d.isFunction=function(c){return"function"===typeof c};d.once=function(c){var d,a=!1;return function(){a||(d=c.apply(this,arguments),a=!0);return d}};d.indexOf=function(c,
    8    -1 d){if("indexOf"in c)return c.indexOf(d);for(var a=c.length,b=0;b<a;b++)if(c[b]===d)return b;return-1};d.forEach=function(c,d){if("forEach"in c)return c.forEach(d);for(var a=c.length,b=0;b<a;b++)d(c[b],b,c)};d.map=function(c,e){if("map"in c)return c.map(e);var a=[];d.forEach(c,function(b){a.push(e(b))});return a};d.filter=function(c,e){if("filter"in c)return c.filter(e);var a=[];d.forEach(c,function(b){e(b)&&a.push(b)});return a};d.union=function(c){var e=[];d.forEach(c,function(a){d.forEach(a,function(a){-1===
    9    -1 d.indexOf(e,a)&&e.push(a)})});return e};d.difference=function(c,e){for(var a=[],b=0;b<c.length;b++)-1===d.indexOf(e,c[b])&&a.push(c[b]);return a};d.flatten=function(c){var e=[];d.forEach(c,function(a){d.isArray(a)?e=e.concat(d.flatten(a)):e.push(a)});return e};return d});k("muu-location",["muu-search"],function(d){var c={absUrl:function(){return location.href},url:function(a,b){if(a===g)return location.pathname+location.search+location.hash;b?history.replaceState(null,null,a):history.pushState(null,
   10    -1 null,a);return c},protocol:function(){return location.protocol},host:function(){return location.host},port:function(){return location.port},path:function(a,b){if(a===g)return location.pathname;c.url(a+location.search+location.hash,b);return c}},e=function(a,b){if(a===g)return location.search;a&&"?"!==a[0]&&(a="?"+a);1===a.length&&(a="");c.url(location.pathname+a+location.hash,b);return c};c.search=function(a,b,c){if(a!==g){if(b!==g){var f=d.parse(e());f[a]=b;return e(d.unparse(f),c)}return e(d.unparse(a),
   11    -1 c)}return d.parse(e())};c.hash=function(a,b){if(a===g)return location.hash?location.hash.slice(1):"";c.url(location.pathname+location.search+"#"+a,b);return c};c.addEventListener=function(a,b){"change"===a&&r.addEventListener("popstate",b,!1);return c};c.removeEventListener=function(a,b){"change"===a&&r.removeEventListener("popstate",b,!1);return c};return c});k("muu-registry",["muu-template","muu-directive","muu-js-helpers","muu-dom-helpers"],function(d,c,e,a){return function(b){var n=this,f={};
   12    -1 this.config=b||{};this.renderer=n.config.renderer||d;this.registerDirective=function(a,b,c){f[a]={template:b,link:c};return n};this.registerModule=function(a){a(n);return n};this.link=function(b,d){d===g&&(d=b.getAttribute("type"));if(!f.hasOwnProperty(d))throw Error("Unknown directive type: "+d);var e=f[d].link,s=new c(b,f[d].template,n),e=e(s,b);b.classList.add("muu-isolate");b.classList.add("muu-initialised");n.config.debug&&(b.directive=s);e!==g&&a.destroy(b,e);return s};this.linkAll=function(a){a=
   13    -1 e.filter(a.querySelectorAll("muu"),function(a){return!a.classList.contains("muu-initialised")});return e.map(a,function(a){return n.link(a)})}}});k("muu-search",["muu-js-helpers"],function(d){var c={parse:function(a){var b={},c=function(a,c){b.hasOwnProperty(a)?d.isArray(b[a])?b[a].push(c):b[a]=[b[a],c]:b[a]=c};d.forEach(a.substring(1).split("&"),function(a){a=d.map(a.split("="),decodeURIComponent);2===a.length?c(a[0],a[1]):a[0]&&c(a[0],!0)});return b}},e=function(a,b){return b===g||null===b||!1===
   14    -1 b?[]:d.isArray(b)?d.flatten(d.map(b,function(b){return e(a,b)})):!0===b?[encodeURIComponent(a)]:[encodeURIComponent(a)+"="+encodeURIComponent(b)]};c.unparse=function(a){if(d.isString(a))return a;var b=[],c;for(c in a)a.hasOwnProperty(c)&&(b=b.concat(e(c,a[c])));return 0<b.length?"?"+b.join("&"):""};return c});k("muu-template",["muu-js-helpers","muu-dom-helpers"],function(d,c){var e=function(a,b){return"this"===a?b:b[a]},a=function(a){if(-1===a.indexOf(":"))return function(b){return c.escapeHtml(e(a,
   15    -1 b)||"")};var b=d.map(a.split(","),function(a){var b=a.split(":");a=b[0].trim();b=b.slice(1).join(":").trim();return[a,b]});return function(a){var h=d.map(d.filter(b,function(b){return e(b[1],a)}),function(a){return a[0]});return c.escapeHtml(h.join(" "))}},b=function(a,b,c){var f=n(b,a);return{render:function(b){var l=e(a,b),g="";c?l||(g+=f.render(b)):d.isArray(l)?d.forEach(l,function(a){g+=f.render(a)}):l&&(g+=f.render(b));return g},afterBlock:f.afterBlock}},n=function(c,d){var e=c.indexOf("{{");
   16    -1 if(-1===e){if(d===g)return{render:function(){return c},afterBlock:""};throw Error("unclosed loop: "+d);}var f=c.slice(0,e),q=c.slice(e),k=q.indexOf("}}");if(-1===k)throw Error("unclosed tag: "+q);var e=q.slice(2,k),q=q.slice(k+2),k=!0,m={render:function(){return""},afterBlock:q};if(0===e.lastIndexOf("#",0))m=b(e.substr(1),q);else if(0===e.lastIndexOf("^",0))m=b(e.substr(1),q,!0);else if(0===e.lastIndexOf("/",0)){if(k=!1,e.substr(1)!==d)throw Error("unexpected closing loop: "+e);}else 0!==e.lastIndexOf("!",
   17    -1 0)&&(m.render=a(e));if(k){var p=n(m.afterBlock,d);return{render:function(a){return f+m.render(a)+p.render(a)},afterBlock:p.afterBlock}}return{render:function(a){return f+m.render(a)},afterBlock:m.afterBlock}},f={};return function(a,b){f[a]===g&&(f[a]=n(a));return f[a].render(b)}});k("muu-update-dom",["muu-js-helpers"],function(d){var c=function(a,b){var c=d.map(a.attributes,function(a){return a.name}),e=d.map(b.attributes,function(a){return a.name});d.forEach(c,function(c){b.hasAttribute(c)||"__IE8__"===
   18    -1 c.substr(0,7)||a.removeAttribute(c)});d.forEach(e,function(c){a.getAttribute(c)!==b.getAttribute(c)&&a.setAttribute(c,b.getAttribute(c))})},e=function(a,b){for(var g=a.childNodes.length,f=b.childNodes.length,h=f;h<g;h++)a.removeChild(a.childNodes[f]);for(h=g;h<f;h++)a.appendChild(b.childNodes[g]);for(h=0;h<g&&h<f;h++){var l=a.childNodes[h],k=b.childNodes[h];if(l.nodeType===k.nodeType&&l.nodeName===k.nodeName&&l.type===k.type){if(1===l.nodeType){var m=d.filter(l.classList,function(a){return 0===a.lastIndexOf("muu-",
   19    -1 0)});c(l,k);d.forEach(m,function(a){l.classList.add(a)})}else 3===l.nodeType&&(l.nodeValue=k.nodeValue);3===l.nodeType||l.classList.contains("muu-isolate")||e(l,k)}else l.parentNode.replaceChild(k,l)}};return e});k("muu",["muu-registry","muu-dom-helpers","muu-location"],function(d,c,e){var a={};a.Registry=d;a.$=c;a.$location=e;return a});return t("muu")})})(window,document,void 0);
   -1     1 (function(n,k,l){(function(l){"function"===typeof define&&define.amd?define("muu",[],l):n.muu=l(n._)})(function(h){var m={};m["muu-js-helpers"]={instance:h};var t=function(d,c){for(var e=[],a=0;a<d.length;a++)e.push(c(d[a]));return e};h=function(d,c,e){m[d]={deps:c,factory:e}};var s=function(d){if(!m[d])return l;m[d].instance||(m[d].instance=m[d].factory.apply(l,t(m[d].deps,s)));return m[d].instance};h("muu-directive",["muu-dom-helpers","muu-js-helpers","muu-update-dom"],function(d,c,e){return function(a,
   -1     2 b,g){var f=this;a.innerHTML="";var r=function(b){var c=b.currentTarget,e="data-on"+b.type;c.hasAttribute(e)&&(c=c.getAttribute(e),b=d.createEvent("muu-"+c,l,l,b),a.dispatchEvent(b))};this.update=function(p){e(a,g.renderer(b,p));c.forEach(["keydown","keyup","click","change","search"],function(a){c.forEach(f.querySelectorAll("[data-on"+a+"]"),function(b){b.addEventListener(a,r,!1)})});var u=d.createEvent("muu-parent-update");p=f.querySelectorAll("muu.muu-initialised");c.forEach(p,function(a){a.dispatchEvent(u)});
   -1     3 g.linkAll(f)};this.querySelectorAll=function(b){var d=a.querySelectorAll(b),e=a.querySelectorAll(".muu-isolate"),e=c.union(c.map(e,function(a){return a.querySelectorAll(b)}));return c.difference(d,e)};this.querySelector=function(a){a=f.querySelectorAll(a);if(0<a.length)return a[0]};this.on=function(b,c){return d.on(a,"muu-"+b,function(a){return c(a.detail)})};this.getModel=function(a,b){if(a===l){var e={};c.forEach(f.querySelectorAll("[name]"),function(a){e[a.name]=f.getModel(a.name)});return e}var g=
   -1     4 f.querySelector("[name="+a+"]");return g===l?b:"number"===g.getAttribute("type")?parseFloat(g.value):"checkbox"===g.getAttribute("type")?g.checked:"radio"===g.getAttribute("type")?(g=f.querySelectorAll("[name="+a+"]"),d.getRadio(g)||b):g.value};this.setModel=function(a,b){if(f.getModel(a)!==b){var c=f.querySelector("[name="+a+"]");"checkbox"===c.getAttribute("type")?c.checked=b:"radio"===c.getAttribute("type")?(c=f.querySelectorAll("[name="+a+"]"),d.setRadio(c,b)):c.value=b}}}});h("muu-dom-helpers",
   -1     5 ["muu-js-helpers"],function(d){var c={"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#39;","/":"&#x2F;"},e={DELAY:1E3,escapeHtml:function(a){return String(a).replace(/[&<>"'\/]/g,function(a){return c[a]})},createEvent:function(a,b,c,d){if("function"===typeof CustomEvent)return new CustomEvent(a,{detail:d,bubbles:b,cancelable:c});var e=k.createEvent("CustomEvent");e.initCustomEvent(a,b,c,d);return e},on:function(a,b,c){a.addEventListener(b,c,!1);return function(){a.removeEventListener(b,c,!1)}},
   -1     6 ready:function(a){a=d.once(a);if("complete"===k.readyState)return a(),function(){};var b=e.on(k,"DOMContentLoaded",a),c=e.on(n,"load",a);return function(){b();c()}},isDescendant:function(a,b){return!!a&&(a===b||e.isDescendant(a.parentNode,b))},destroy:function(a,b){var c;if(n.MutationObserver){var f=new MutationObserver(function(){e.isDescendant(a,k)||(b(),c())});f.observe(k,{childList:!0,subtree:!0});c=d.once(function(){f.disconnect();f=l})}else{var r=setInterval(function(){e.isDescendant(a,k)||
   -1     7 (b(),c())},e.DELAY);c=function(){clearInterval(r)}}return c},getRadio:function(a){for(var b=0;b<a.length;b++)if(a[b].checked)return a[b].value},setRadio:function(a,b){d.forEach(a,function(a){a.checked=a.value===b?!0:!1})}};return e});h("muu-js-helpers",[],function(){var d={isString:function(c){return"string"===typeof c||"[object String]"===Object.prototype.toString.call(c)}};d.isArray=Array.isArray;d.isFunction=function(c){return"function"===typeof c};d.once=function(c){var d,a=!1;return function(){a||
   -1     8 (d=c.apply(this,arguments),a=!0);return d}};d.indexOf=function(c,d){if("indexOf"in c)return c.indexOf(d);for(var a=c.length,b=0;b<a;b++)if(c[b]===d)return b;return-1};d.forEach=function(c,d){if("forEach"in c)return c.forEach(d);for(var a=c.length,b=0;b<a;b++)d(c[b],b,c)};d.map=function(c,e){if("map"in c)return c.map(e);var a=[];d.forEach(c,function(b){a.push(e(b))});return a};d.filter=function(c,e){if("filter"in c)return c.filter(e);var a=[];d.forEach(c,function(b){e(b)&&a.push(b)});return a};d.union=
   -1     9 function(c){var e=[];d.forEach(c,function(a){d.forEach(a,function(a){-1===d.indexOf(e,a)&&e.push(a)})});return e};d.difference=function(c,e){for(var a=[],b=0;b<c.length;b++)-1===d.indexOf(e,c[b])&&a.push(c[b]);return a};d.flatten=function(c){var e=[];d.forEach(c,function(a){d.isArray(a)?e=e.concat(d.flatten(a)):e.push(a)});return e};return d});h("muu-location",["muu-search"],function(d){var c={absUrl:function(){return location.href},url:function(a,b){if(a===l)return location.pathname+location.search+
   -1    10 location.hash;b?history.replaceState(null,null,a):history.pushState(null,null,a);return c},protocol:function(){return location.protocol},host:function(){return location.host},port:function(){return location.port},path:function(a,b){if(a===l)return location.pathname;c.url(a+location.search+location.hash,b);return c}},e=function(a,b){if(a===l)return location.search;a&&"?"!==a[0]&&(a="?"+a);1===a.length&&(a="");c.url(location.pathname+a+location.hash,b);return c};c.search=function(a,b,c){if(a!==l){if(b!==
   -1    11 l){var f=d.parse(e());f[a]=b;return e(d.unparse(f),c)}return e(d.unparse(a),c)}return d.parse(e())};c.hash=function(a,b){if(a===l)return location.hash?location.hash.slice(1):"";c.url(location.pathname+location.search+"#"+a,b);return c};c.addEventListener=function(a,b){"change"===a&&n.addEventListener("popstate",b,!1);return c};c.removeEventListener=function(a,b){"change"===a&&n.removeEventListener("popstate",b,!1);return c};return c});h("muu-registry",["muu-template","muu-directive","muu-js-helpers",
   -1    12 "muu-dom-helpers"],function(d,c,e,a){return function(b){var g=this,f={};this.config=b||{};this.renderer=g.config.renderer||d;this.registerDirective=function(a,b,c){f[a]={template:b,link:c};return g};this.registerModule=function(a){a(g);return g};this.link=function(b,d){d===l&&(d=b.getAttribute("type"));if(!f.hasOwnProperty(d))throw Error("Unknown directive type: "+d);var e=f[d].link,q=new c(b,f[d].template,g),e=e(q,b);b.classList.add("muu-isolate");b.classList.add("muu-initialised");g.config.debug&&
   -1    13 (b.directive=q);e!==l&&a.destroy(b,e);return q};this.linkAll=function(a){a=e.filter(a.querySelectorAll("muu"),function(a){return!a.classList.contains("muu-initialised")});return e.map(a,function(a){return g.link(a)})}}});h("muu-search",["muu-js-helpers"],function(d){var c={parse:function(a){var b={},c=function(a,c){b.hasOwnProperty(a)?d.isArray(b[a])?b[a].push(c):b[a]=[b[a],c]:b[a]=c};d.forEach(a.substring(1).split("&"),function(a){a=d.map(a.split("="),decodeURIComponent);2===a.length?c(a[0],a[1]):
   -1    14 a[0]&&c(a[0],!0)});return b}},e=function(a,b){return b===l||null===b||!1===b?[]:d.isArray(b)?d.flatten(d.map(b,function(b){return e(a,b)})):!0===b?[encodeURIComponent(a)]:[encodeURIComponent(a)+"="+encodeURIComponent(b)]};c.unparse=function(a){if(d.isString(a))return a;var b=[],c;for(c in a)a.hasOwnProperty(c)&&(b=b.concat(e(c,a[c])));return 0<b.length?"?"+b.join("&"):""};return c});h("muu-template",["muu-js-helpers","muu-dom-helpers"],function(d,c){var e=function(a,b){return"this"===a?b:b[a]},a=
   -1    15 function(a){if(-1===a.indexOf(":"))return function(b){return c.escapeHtml(e(a,b)||"")};var b=d.map(a.split(","),function(a){var b=a.split(":");a=b[0].trim();b=b.slice(1).join(":").trim();return[a,b]});return function(a){var g=d.map(d.filter(b,function(b){return e(b[1],a)}),function(a){return a[0]});return c.escapeHtml(g.join(" "))}},b=function(a,b,c){var f=g(b,a);return{render:function(b){var p=e(a,b),g="";c?p||(g+=f.render(b)):d.isArray(p)?d.forEach(p,function(a){g+=f.render(a)}):p&&(g+=f.render(b));
   -1    16 return g},afterBlock:f.afterBlock}},g=function(c,d){var e=c.indexOf("{{");if(-1===e){if(d===l)return{render:function(){return c},afterBlock:""};throw Error("unclosed loop: "+d);}var f=c.slice(0,e),h=c.slice(e),m=h.indexOf("}}");if(-1===m)throw Error("unclosed tag: "+h);var e=h.slice(2,m),h=h.slice(m+2),m=!0,k={render:function(){return""},afterBlock:h};if(0===e.lastIndexOf("#",0))k=b(e.substr(1),h);else if(0===e.lastIndexOf("^",0))k=b(e.substr(1),h,!0);else if(0===e.lastIndexOf("/",0)){if(m=!1,e.substr(1)!==
   -1    17 d)throw Error("unexpected closing loop: "+e);}else 0!==e.lastIndexOf("!",0)&&(k.render=a(e));if(m){var n=g(k.afterBlock,d);return{render:function(a){return f+k.render(a)+n.render(a)},afterBlock:n.afterBlock}}return{render:function(a){return f+k.render(a)},afterBlock:k.afterBlock}},f={};return function(a,b){f[a]===l&&(f[a]=g(a));return f[a].render(b)}});h("muu-update-dom",["muu-js-helpers"],function(d){var c=function(a,b){var c=d.filter(a.classList,function(a){return 0===a.lastIndexOf("muu-",0)}),
   -1    18 e=d.map(a.attributes,function(a){return a.name}),l=d.map(b.attributes,function(a){return a.name});d.forEach(e,function(c){b.hasAttribute(c)||"__IE8__"===c.substr(0,7)||a.removeAttribute(c)});d.forEach(l,function(c){a.getAttribute(c)!==b.getAttribute(c)&&a.setAttribute(c,b.getAttribute(c))});d.forEach(c,function(b){a.classList.add(b)})},e=function(a,b){for(var d=a.childNodes.length,f=b.childNodes.length,l=0,h=f;h<d;h++)a.removeChild(a.childNodes[f]);for(h=d;h<f;h++)a.appendChild(b.childNodes[d]);for(h=
   -1    19 0;h<d&&h<f;h++){var k=a.childNodes[h],m=b.childNodes[h-l];k.nodeType===m.nodeType&&k.nodeName===m.nodeName&&k.type===m.type?(1===k.nodeType?c(k,m):3===k.nodeType&&(k.nodeValue=m.nodeValue),3===k.nodeType||k.classList.contains("muu-isolate")||e(k,m)):(k.parentNode.replaceChild(m,k),l+=1)}};return function(a,b){var c=k.createElement("div");c.innerHTML=b;e(a,c)}});h("muu",["muu-registry","muu-dom-helpers","muu-location"],function(d,c,e){var a={};a.Registry=d;a.$=c;a.$location=e;return a});return s("muu")})})(window,
   -1    20 document,void 0);