muu

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

commit
7eba03f70b04c8feb854d0fc3f1bf5824881f6a2
parent
f4287dfb6c4aa08e899947fa2611444db635d893
Author
Tobias Bengfort <tobias.bengfort@gmx.net>
Date
2015-08-28 09:06
change dist layout

- dist files are in dist/
- minification is done by closure compiler instead of uglify.js
- UML instead of pure AMD
- only the muu module is made available

Diffstat

A .build/externs.js 13 +++++++++++++
A .build/template.js 45 +++++++++++++++++++++++++++++++++++++++++++++
M Makefile 29 +++++++++++++++++++++++++----
D build.js 8 --------
A dist/muu.js 1244 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
A dist/muu.min.js 19 +++++++++++++++++++
M examples/example/example.js 8 ++++----
M examples/example/index.html 1 -
M examples/phonecat/index.html 1 -
M examples/phonecat/phonecat.js 4 ++--
D muu.min.js 3 ---
D muu.min.js.map 2 --

12 files changed, 1352 insertions, 25 deletions


diff --git a/.build/externs.js b/.build/externs.js

@@ -0,0 +1,13 @@
   -1     1 /** @type {Object} */
   -1     2 var history;
   -1     3 
   -1     4 /**
   -1     5  * @param {string} name
   -1     6  * @param {Array.<string>} deps
   -1     7  * @param {Function} factory
   -1     8  * @return {*}
   -1     9  */
   -1    10 var define = function(name, deps, factory) {};
   -1    11 
   -1    12 /** @type {boolean} */
   -1    13 define.amd = false;

diff --git a/.build/template.js b/.build/template.js

@@ -0,0 +1,45 @@
   -1     1 (function(window, document, undefined) {
   -1     2     var name = 'muu';
   -1     3 
   -1     4     (function(factory) {
   -1     5         if (typeof define === 'function' && define.amd) {
   -1     6             define(name, ['lodash'], factory);
   -1     7         } else {
   -1     8             window[name] = factory(_);
   -1     9         }
   -1    10     })(function() {
   -1    11         var modules = {};
   -1    12 
   -1    13         var map = function(a, fn) {
   -1    14             var b = [];
   -1    15             for (var i = 0; i < a.length; i++) {
   -1    16                 b.push(fn(a[i]));
   -1    17             }
   -1    18             return b;
   -1    19         };
   -1    20 
   -1    21         var _define = function(name, deps, factory) {
   -1    22             modules[name] = {
   -1    23                 deps: deps,
   -1    24                 factory: factory
   -1    25             };
   -1    26         };
   -1    27 
   -1    28         var _require = function(name) {
   -1    29             if (!modules[name]) {
   -1    30                 return undefined;
   -1    31             }
   -1    32 
   -1    33             if (!modules[name].instance) {
   -1    34                 var deps = modules[name].deps;
   -1    35                 var factory = modules[name].factory;
   -1    36 
   -1    37                 modules[name].instance = factory.apply(undefined, map(deps, _require));
   -1    38             }
   -1    39 
   -1    40             return modules[name].instance;
   -1    41         };
   -1    42 
   -1    43         return _require(name);
   -1    44     });
   -1    45 })(window, document, void 0);

diff --git a/Makefile b/Makefile

@@ -1,13 +1,34 @@
    1    -1 muu.min.js: build.js src/*.js node_modules/requirejs/bin/r.js
    2    -1 	./node_modules/requirejs/bin/r.js -o build.js
   -1     1 dist/muu.min.js: dist/muu.js node_modules/closure-compiler-jar/compiler.jar .build/externs.js
   -1     2 	java -jar node_modules/closure-compiler-jar/compiler.jar \
   -1     3 		--compilation_level SIMPLE_OPTIMIZATIONS \
   -1     4 		--use_types_for_optimization \
   -1     5 		--warning_level=VERBOSE \
   -1     6 		--jscomp_warning=missingProperties \
   -1     7 		--jscomp_warning=checkTypes \
   -1     8 		--externs .build/externs.js \
   -1     9 		--js $< \
   -1    10 		--js_output_file $@
   -1    11 
   -1    12 dist/muu.js: .build/template.js src/*.js
   -1    13 	mkdir -p dist
   -1    14 	head -n -3 $< > .build/head.js
   -1    15 	tail -n 4 $< > .build/tail.js
   -1    16 	cat src/*.js |\
   -1    17 		sed 's/^/        /g' |\
   -1    18 		sed 's/ *$$//g' |\
   -1    19 		sed 's/define(/_define(/g' > .build/modules.js
   -1    20 	cat .build/head.js .build/modules.js .build/tail.js > $@
   -1    21 	rm .build/head.js
   -1    22 	rm .build/tail.js
   -1    23 	rm .build/modules.js
    3    24 
    4    25 doc: doc/.touch
    5    26 
    6    27 doc/.touch: src/*.js node_modules/jsdoc/jsdoc.js .doc/conf.json .doc/styles/* .doc/tutorials/*.md bower.json README.md
    7    28 	./node_modules/jsdoc/jsdoc.js --pedantic --package bower.json -u .doc/tutorials -c .doc/conf.json README.md src/*.js && touch doc/.touch
    8    29 
    9    -1 node_modules/requirejs/bin/r.js:
   10    -1 	npm install requirejs
   -1    30 node_modules/closure-compiler-jar/compiler.jar:
   -1    31 	npm install closure-compiler-jar
   11    32 
   12    33 node_modules/jsdoc/jsdoc.js:
   13    34 	npm install jsdoc

diff --git a/build.js b/build.js

@@ -1,8 +0,0 @@
    1    -1 ({
    2    -1     "baseUrl": "src",
    3    -1     "optimize": "uglify2",
    4    -1     "generateSourceMaps": true,
    5    -1     "preserveLicenseComments": false,
    6    -1     "name": "muu",
    7    -1     "out": "muu.min.js"
    8    -1 })

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

@@ -0,0 +1,1244 @@
   -1     1 (function(window, document, undefined) {
   -1     2     (function(factory) {
   -1     3         if (typeof define === 'function' && define.amd) {
   -1     4             define('muu', [], factory);
   -1     5         } else {
   -1     6             window['muu'] = factory();
   -1     7         }
   -1     8     })(function() {
   -1     9         var modules = {};
   -1    10 
   -1    11         var map = function(a, fn) {
   -1    12             var b = [];
   -1    13             for (var i = 0; i < a.length; i++) {
   -1    14                 b.push(fn(a[i]));
   -1    15             }
   -1    16             return b;
   -1    17         };
   -1    18 
   -1    19         var _define = function(name, deps, factory) {
   -1    20             modules[name] = {
   -1    21                 deps: deps,
   -1    22                 factory: factory
   -1    23             };
   -1    24         };
   -1    25 
   -1    26         var _require = function(name) {
   -1    27             if (!modules[name]) {
   -1    28                 return undefined;
   -1    29             }
   -1    30 
   -1    31             if (!modules[name].instance) {
   -1    32                 var deps = modules[name].deps;
   -1    33                 var factory = modules[name].factory;
   -1    34 
   -1    35                 modules[name].instance = factory.apply(undefined, map(deps, _require));
   -1    36             }
   -1    37 
   -1    38             return modules[name].instance;
   -1    39         };
   -1    40 
   -1    41     /**
   -1    42      * Exports the {@link Directive} class.
   -1    43      * @module muu-directive
   -1    44      * @ignore
   -1    45      */
   -1    46     _define('muu-directive', ['muu-dom-helpers', 'muu-js-helpers', 'muu-update-dom'], function($, _, updateDOM) {
   -1    47         "use strict";
   -1    48 
   -1    49         /**
   -1    50          * A directive is linked to a Element and manages the DOM tree below
   -1    51          * that element (excluding any isolated subtrees, e.g. those managed by
   -1    52          * subdirectives).
   -1    53          *
   -1    54          * It provides a set of methods to interact with the managed part of the
   -1    55          * DOM. This is separated into three distinct parts:
   -1    56          *
   -1    57          * - You can push data to the DOM using the {@link Directive#update}
   -1    58          *   method. The DOM will than be updated using the template that was
   -1    59          *   provided at construction.
   -1    60          * - You can get data from the DOM using the {@link Directive#getModel}
   -1    61          *   method. This is however restricted to form field by design.
   -1    62          * - You can react to DOM events by specifying an alias for them. In the
   -1    63          *   template, you might for example add the attribute
   -1    64          *   `data-onclick="custom"` to an element. When there is `click` event on
   -1    65          *   that element, a `muu-custom` event will be triggered on the
   -1    66          *   directive's root element.
   -1    67          *
   -1    68          * Directives are typically not created directly but via {@link
   -1    69          * Registry#link}.
   -1    70          *
   -1    71          * @constructs Directive
   -1    72          * @param {Element} root
   -1    73          * @param {string} template
   -1    74          * @param {Registry} registry
   -1    75          */
   -1    76         var Directive = function(root, template, registry) {
   -1    77             var self = this;
   -1    78 
   -1    79             root.innerHTML = '';
   -1    80 
   -1    81             var eventCallback = function(originalEvent) {
   -1    82                 var attrName = 'data-on' + originalEvent.type;
   -1    83                 if (originalEvent.target.hasAttribute(attrName)) {
   -1    84                     var eventName = originalEvent.target.getAttribute(attrName);
   -1    85                     var event = $.createEvent('muu-' + eventName, originalEvent);
   -1    86                     root.dispatchEvent(event);
   -1    87                 }
   -1    88             };
   -1    89 
   -1    90             /**
   -1    91              * Rerender `template` with `data` and push the changes to the DOM.
   -1    92              *
   -1    93              * @param {Object.<string, *>} data
   -1    94              * @see {@link module:muu-update-dom} for details.
   -1    95              * @see The templating system can be defined in the {@link Registry}.
   -1    96              */
   -1    97             this.update = function(data) {
   -1    98                 var tmp = document.createElement('div');
   -1    99                 tmp.innerHTML = registry.renderer(template, data);
   -1   100 
   -1   101                 updateDOM(root, tmp);
   -1   102 
   -1   103                 _.forEach(['keydown', 'keyup', 'click', 'change', 'search'], function(eventType) {
   -1   104                     var selector = '[data-on' + eventType + ']';
   -1   105                     _.forEach(self.querySelectorAll(selector), function(element) {
   -1   106                         element.addEventListener(eventType, eventCallback, false);
   -1   107                     });
   -1   108                 });
   -1   109 
   -1   110                 var updateEvent = $.createEvent('muu-parent-update');
   -1   111                 var subDirectives = this.querySelectorAll('muu.muu-initialised');
   -1   112                 _.forEach(subDirectives, function(element) {
   -1   113                     element.dispatchEvent(updateEvent);
   -1   114                 });
   -1   115 
   -1   116                 registry.linkAll(self);
   -1   117             };
   -1   118 
   -1   119             /**
   -1   120              * A variant of `querySelectorAll` that returns only elements from
   -1   121              * the managed part of the DOM.
   -1   122              *
   -1   123              * @private
   -1   124              * @param {string} selector
   -1   125              * @return {Array.<Element>} All child elements that match the given
   -1   126              *     selector and are not isolated.
   -1   127              */
   -1   128             this.querySelectorAll = function(selector) {
   -1   129                 var hits = root.querySelectorAll(selector);
   -1   130 
   -1   131                 // NOTE: querySelectorAll returns all elements in the tree that
   -1   132                 // match the given selector.  findAll does the same with *relative
   -1   133                 // selectors* but does not seem to be available yet.
   -1   134                 var isolations = root.querySelectorAll('.muu-isolate');
   -1   135                 var isolated = _.union(_.map(isolations, function(isolation) {
   -1   136                     return isolation.querySelectorAll(selector);
   -1   137                 }));
   -1   138 
   -1   139                 return _.difference(hits, isolated);
   -1   140             };
   -1   141 
   -1   142             /**
   -1   143              * A variant of `querySelector` that returns only elements from the
   -1   144              * managed part of the DOM.
   -1   145              *
   -1   146              * @private
   -1   147              * @param {String} selector
   -1   148              * @return {Element} First child element that matches the given
   -1   149              *     selector and is not isolated.
   -1   150              * @suppress {missingReturn}
   -1   151              */
   -1   152             this.querySelector = function(selector) {
   -1   153                 var all = self.querySelectorAll(selector);
   -1   154                 if (all.length > 0) {
   -1   155                     return all[0];
   -1   156                 }
   -1   157             };
   -1   158 
   -1   159             /**
   -1   160              * Get all model data as a flat object.
   -1   161              *
   -1   162              * @return {Object.<string, string|number|boolean>}
   -1   163              *//**
   -1   164              * Get the value of a form input by name.
   -1   165              *
   -1   166              * In case of a checkbox, returns `boolean`.
   -1   167              * In case of radioboxes, returns the value of the selected box.
   -1   168              *
   -1   169              * @param {string} name
   -1   170              * @param {*} [_default]
   -1   171              * @return {string|number|boolean|*}
   -1   172              */
   -1   173             this.getModel = function(name, _default) {
   -1   174                 if (name === undefined) {
   -1   175                     var model = {};
   -1   176                     _.forEach(self.querySelectorAll('[name]'), function(element) {
   -1   177                         model[element.name] = self.getModel(element.name);
   -1   178                     });
   -1   179                     return model;
   -1   180                 } else {
   -1   181                     var element = self.querySelector('[name=' + name + ']');
   -1   182                     if (element === undefined) {
   -1   183                         return _default;
   -1   184                     } else if (element.type === 'checkbox') {
   -1   185                         return element.checked;
   -1   186                     } else if (element.type === 'radio') {
   -1   187                         var options = self.querySelectorAll('[name=' + name + ']');
   -1   188                         return $.getRadio(options) || _default;
   -1   189                     } else {
   -1   190                         return element.value;
   -1   191                     }
   -1   192                 }
   -1   193             };
   -1   194 
   -1   195             /**
   -1   196              * Set the value of a form input by name.
   -1   197              *
   -1   198              * In case of a checkbox, sets `element.checked`.
   -1   199              * In case of radioboxes, selects the box with matching value.
   -1   200              *
   -1   201              * @param {string} name
   -1   202              * @param {string|number|boolean} value
   -1   203              */
   -1   204             this.setModel = function(name, value) {
   -1   205                 var element = self.querySelector('[name=' + name + ']');
   -1   206                 if (element.type === 'checkbox') {
   -1   207                     element.checked = value;
   -1   208                 } else if (element.type === 'radio') {
   -1   209                     var options = self.querySelectorAll('[name=' + name + ']');
   -1   210                     $.setRadio(options, value);
   -1   211                 } else {
   -1   212                     element.value = value;
   -1   213                 }
   -1   214             };
   -1   215         };
   -1   216 
   -1   217         return Directive;
   -1   218     });
   -1   219     /**
   -1   220      * DOM related helper functions
   -1   221      * @module muu-dom-helpers
   -1   222      */
   -1   223     _define("muu-dom-helpers", ['muu-js-helpers'], function(_) {
   -1   224         "use strict";
   -1   225 
   -1   226         var entityMap = {
   -1   227             '&': '&amp;',
   -1   228             '<': '&lt;',
   -1   229             '>': '&gt;',
   -1   230             '"': '&quot;',
   -1   231             "'": '&#39;',
   -1   232             '/': '&#x2F;'
   -1   233         };
   -1   234 
   -1   235         /** @lends module:muu-dom-helpers */
   -1   236         var $ = {};
   -1   237 
   -1   238         $.DELAY = 1000;
   -1   239 
   -1   240         /**
   -1   241          * @param {string} string
   -1   242          * @return {string} - escaped HTML
   -1   243          */
   -1   244         $.escapeHtml = function(string) {
   -1   245             return String(string).replace(/[&<>"'\/]/g, function(s) {
   -1   246                 return entityMap[s];
   -1   247             });
   -1   248         };
   -1   249 
   -1   250         /**
   -1   251          * Cross browser custom events.
   -1   252          *
   -1   253          * *Note*: IE does not seem to like it when you use existing event names
   -1   254          * with this.
   -1   255          *
   -1   256          * @param {string} type
   -1   257          * @param {*} detail
   -1   258          * @return {Event}
   -1   259          * @see https://developer.mozilla.org/en-US/docs/Web/Guide/Events/Creating_and_triggering_events
   -1   260          */
   -1   261         $.createEvent = function(type, detail) {
   -1   262             if (typeof CustomEvent === 'function') {
   -1   263                 return new CustomEvent(type, {
   -1   264                     detail: detail
   -1   265                 });
   -1   266             } else {
   -1   267                 var event = document.createEvent('CustomEvent');
   -1   268                 event.initCustomEvent(type, false, true, detail);
   -1   269                 return event;
   -1   270             }
   -1   271         };
   -1   272 
   -1   273         /**
   -1   274          * @param {EventTarget} element
   -1   275          * @param {string} eventName
   -1   276          * @param {Function} callback
   -1   277          * @return {function()} An unregister function
   -1   278          */
   -1   279         $.on = function(element, eventName, callback) {
   -1   280             element.addEventListener(eventName, callback, false);
   -1   281             return function() {
   -1   282                 element.removeEventListener(eventName, callback, false);
   -1   283             };
   -1   284         };
   -1   285 
   -1   286         /**
   -1   287          * @param {Function} fn
   -1   288          * @return {function()} An unregister function
   -1   289          */
   -1   290         $.ready = function(fn) {
   -1   291             var _fn = _.once(fn);
   -1   292             if (document.readyState === 'complete') {
   -1   293                 _fn();
   -1   294                 return function() {};
   -1   295             } else {
   -1   296                 var u1 = $.on(document, 'DOMContentLoaded', _fn);
   -1   297                 var u2 = $.on(window, 'load', _fn);
   -1   298                 return function() {
   -1   299                     u1();
   -1   300                     u2();
   -1   301                 };
   -1   302             }
   -1   303         };
   -1   304 
   -1   305         /**
   -1   306          * @param {Node} desc
   -1   307          * @param {Node} root
   -1   308          * @return {boolean}
   -1   309          */
   -1   310         $.isDescendant = function(desc, root) {
   -1   311              return !!desc && (desc === root || $.isDescendant(desc.parentNode, root));
   -1   312         };
   -1   313 
   -1   314         /**
   -1   315          * Execute a function when `element` is removed from the DOM.
   -1   316          *
   -1   317          * *Note*: The callback is not executed directly when (or even before) the
   -1   318          * element is removed but with a slight delay. So the only way to test this
   -1   319          * is to use a timeout in the test.
   -1   320          *
   -1   321          * @param {Element} element
   -1   322          * @param {Function} fn
   -1   323          * @return {function()} An unregister function
   -1   324          */
   -1   325         $.destroy = function(element, fn) {
   -1   326             var unregister;
   -1   327 
   -1   328             if (!!window.MutationObserver) {
   -1   329                 var observer = new MutationObserver(function() {
   -1   330                     if (!$.isDescendant(element, document)) {
   -1   331                         fn();
   -1   332                         unregister();
   -1   333                     }
   -1   334                 });
   -1   335 
   -1   336                 observer.observe(document, {
   -1   337                      childList: true,
   -1   338                      subtree: true
   -1   339                 });
   -1   340 
   -1   341                 unregister = _.once(function() {
   -1   342                     observer.disconnect();
   -1   343                     observer = undefined;
   -1   344                 });
   -1   345             } else {
   -1   346                 var intervalID = setInterval(function() {
   -1   347                     if (!$.isDescendant(element, document)) {
   -1   348                         fn();
   -1   349                         unregister();
   -1   350                     }
   -1   351                 }, $.DELAY);
   -1   352 
   -1   353                 unregister = function() {
   -1   354                     clearInterval(intervalID);
   -1   355                 };
   -1   356             }
   -1   357 
   -1   358             return unregister;
   -1   359         };
   -1   360 
   -1   361         /**
   -1   362          * @param {Array.<Element>} options
   -1   363          * @return {string}
   -1   364          * @suppress {missingReturn}
   -1   365          */
   -1   366         $.getRadio = function(options) {
   -1   367             for (var i = 0; i < options.length; i++) {
   -1   368                 if (options[i].checked) {
   -1   369                     return options[i].value;
   -1   370                 }
   -1   371             }
   -1   372         };
   -1   373 
   -1   374         /**
   -1   375          * @param {Array.<Element>} options
   -1   376          * @param {string} value
   -1   377          */
   -1   378         $.setRadio = function(options, value) {
   -1   379             for (var i = 0; i < options.length; i++) {
   -1   380                 if (options[i].value === value) {
   -1   381                     options[i].checked = true;
   -1   382                 } else {
   -1   383                     options[i].checked = false;
   -1   384                 }
   -1   385             }
   -1   386         };
   -1   387 
   -1   388         return $;
   -1   389     });
   -1   390     /**
   -1   391      * Minimal implementation of an underscore/lodash subset.
   -1   392      * @module muu-js-helpers
   -1   393      */
   -1   394     _define('muu-js-helpers', [], function() {
   -1   395         "use strict";
   -1   396 
   -1   397         /** @lends module:muu-js-helpers */
   -1   398         var _ = {};
   -1   399 
   -1   400         /**
   -1   401          * @param {Object} value
   -1   402          * @return {string}
   -1   403          */
   -1   404         var objToString = function(value) {
   -1   405             return Object.prototype.toString.call(value);
   -1   406         };
   -1   407 
   -1   408         /**
   -1   409          * @param {*} value
   -1   410          * @return {boolean}
   -1   411          */
   -1   412         _.isString = function(value) {
   -1   413             return typeof value === 'string' || objToString(value) === '[object String]';
   -1   414         };
   -1   415 
   -1   416         /**
   -1   417          * @function
   -1   418          * @param {*} value
   -1   419          * @return {boolean}
   -1   420          */
   -1   421         _.isArray = Array.isArray;
   -1   422 
   -1   423         /**
   -1   424          * @param {*} value
   -1   425          * @return {boolean}
   -1   426          */
   -1   427         _.isFunction = function(value) {
   -1   428             return typeof value === 'function';
   -1   429         };
   -1   430 
   -1   431         /**
   -1   432          * @param {Function} fn
   -1   433          * @return {Function}
   -1   434          */
   -1   435         _.once = function(fn) {
   -1   436             var result;
   -1   437             var called = false;
   -1   438 
   -1   439             return function() {
   -1   440                 if (!called) {
   -1   441                     result = fn.apply(this, arguments);
   -1   442                     called = true;
   -1   443                 }
   -1   444                 return result;
   -1   445             };
   -1   446         };
   -1   447 
   -1   448         /**
   -1   449          * @param {Array} array
   -1   450          * @param {*} value
   -1   451          * @return {number}
   -1   452          */
   -1   453         _.indexOf = function(array, value) {
   -1   454             if ('indexOf' in array) {
   -1   455                 return array.indexOf(value);
   -1   456             }
   -1   457 
   -1   458             for (var i = 0; i < array.length; i++) {
   -1   459                 if (array[i] === value) {
   -1   460                     return i;
   -1   461                 }
   -1   462             }
   -1   463             return -1;
   -1   464         };
   -1   465 
   -1   466         /**
   -1   467          * @param {Array} array
   -1   468          * @param {Function} fn
   -1   469          */
   -1   470         _.forEach = function(array, fn) {
   -1   471             if ('forEach' in array) {
   -1   472                 return array.forEach(fn);
   -1   473             }
   -1   474 
   -1   475             for (var i = 0; i < array.length; i++) {
   -1   476                 fn(array[i]);
   -1   477             }
   -1   478         };
   -1   479 
   -1   480         /**
   -1   481          * @param {Array} array
   -1   482          * @param {Function} fn
   -1   483          * @return {Array}
   -1   484          */
   -1   485         _.map = function(array, fn) {
   -1   486             if ('map' in array) {
   -1   487                 return array.map(fn);
   -1   488             }
   -1   489 
   -1   490             var results = [];
   -1   491             for (var i = 0; i < array.length; i++) {
   -1   492                 results.push(fn(array[i]));
   -1   493             }
   -1   494             return results;
   -1   495         };
   -1   496 
   -1   497         /**
   -1   498          * @param {Array} array
   -1   499          * @param {Function} fn
   -1   500          * @return {Array}
   -1   501          */
   -1   502         _.filter = function(array, fn) {
   -1   503             if ('filter' in array) {
   -1   504                 return array.filter(fn);
   -1   505             }
   -1   506 
   -1   507             var results = [];
   -1   508             for (var i = 0; i < array.length; i++) {
   -1   509                 if (fn(array[i])) {
   -1   510                     results.push(array[i]);
   -1   511                 }
   -1   512             }
   -1   513             return results;
   -1   514         };
   -1   515 
   -1   516         /**
   -1   517          * @param {Array.<Array>} arrays
   -1   518          * @return {Array}
   -1   519          */
   -1   520         _.union = function(arrays) {
   -1   521             var results = [];
   -1   522             for (var i = 0; i < arrays.length; i++) {
   -1   523                 for (var j = 0; j < arrays[i].length; j++) {
   -1   524                     if (_.indexOf(results, arrays[i][j]) === -1) {
   -1   525                         results.push(arrays[i][j]);
   -1   526                     }
   -1   527                 }
   -1   528             }
   -1   529             return results;
   -1   530         };
   -1   531 
   -1   532         /**
   -1   533          * @param {Array} a
   -1   534          * @param {Array} b
   -1   535          * @return {Array}
   -1   536          */
   -1   537         _.difference = function(a, b) {
   -1   538             var results = [];
   -1   539             for (var i = 0; i < a.length; i++) {
   -1   540                 if (_.indexOf(b, a[i]) === -1) {
   -1   541                     results.push(a[i]);
   -1   542                 }
   -1   543             }
   -1   544             return results;
   -1   545         };
   -1   546 
   -1   547         /**
   -1   548          * @param {Array} a
   -1   549          * @return {Array}
   -1   550          */
   -1   551         _.flatten = function(a) {
   -1   552             var o = [];
   -1   553             _.forEach(a, function(item) {
   -1   554                 if (_.isArray(item)) {
   -1   555                     o = o.concat(_.flatten(item));
   -1   556                 } else {
   -1   557                     o.push(item);
   -1   558                 }
   -1   559             });
   -1   560             return o;
   -1   561         };
   -1   562 
   -1   563         return _;
   -1   564     });
   -1   565     /**
   -1   566      * angular inspired location service.
   -1   567      * @module muu-location
   -1   568      */
   -1   569     _define('muu-location', ['muu-search'], function(q) {
   -1   570         "use strict";
   -1   571 
   -1   572         /** @lends module:muu-location */
   -1   573         var loc = {};
   -1   574 
   -1   575         /**
   -1   576          * @return {string}
   -1   577          */
   -1   578         loc.absUrl = function() {
   -1   579             return location.href;
   -1   580         };
   -1   581 
   -1   582         /**
   -1   583          * @return {string}
   -1   584          *//**
   -1   585          * @param {string} value
   -1   586          * @param {boolean} [replace]
   -1   587          * @return {muu-location}
   -1   588          */
   -1   589         loc.url = function(value, replace) {
   -1   590             if (value === undefined) {
   -1   591                 return location.pathname + location.search + location.hash;
   -1   592             } else if (replace) {
   -1   593                 history.replaceState(null, null, value);
   -1   594             } else {
   -1   595                 history.pushState(null, null, value);
   -1   596             }
   -1   597             return loc;
   -1   598         };
   -1   599 
   -1   600         /**
   -1   601          * @return {string}
   -1   602          */
   -1   603         loc.protocol = function() {
   -1   604             return location.protocol;
   -1   605         };
   -1   606 
   -1   607         /**
   -1   608          * @return {string}
   -1   609          */
   -1   610         loc.host = function() {
   -1   611             return location.host;
   -1   612         };
   -1   613 
   -1   614         /**
   -1   615          * @return {string}
   -1   616          */
   -1   617         loc.port = function() {
   -1   618             return location.port;
   -1   619         };
   -1   620 
   -1   621         /**
   -1   622          * @return {string}
   -1   623          *//**
   -1   624          * @param {string} value
   -1   625          * @param {boolean} [replace]
   -1   626          * @return {muu-location}
   -1   627          */
   -1   628         loc.path = function(value, replace) {
   -1   629             if (value === undefined) {
   -1   630                 return location.pathname;
   -1   631             } else {
   -1   632                 var url = value + location.search + location.hash;
   -1   633                 loc.url(url, replace);
   -1   634                 return loc;
   -1   635             }
   -1   636         };
   -1   637 
   -1   638         var _search = function(value, replace) {
   -1   639             if (value === undefined) {
   -1   640                 return location.search;
   -1   641             } else {
   -1   642                 if (value && value[0] !== '?') {
   -1   643                     value = '?' + value;
   -1   644                 }
   -1   645                 if (value.length === 1) {
   -1   646                     value = '';
   -1   647                 }
   -1   648 
   -1   649                 var url = location.pathname + value + location.hash;
   -1   650                 loc.url(url, replace);
   -1   651                 return loc;
   -1   652             }
   -1   653         };
   -1   654 
   -1   655         /**
   -1   656          * @return {Object}
   -1   657          *//**
   -1   658          * @param {string|object} value
   -1   659          * @return {muu-location}
   -1   660          *//**
   -1   661          * @param {string} key
   -1   662          * @param {*} value
   -1   663          * @param {boolean} [replace]
   -1   664          * @return {muu-location}
   -1   665          */
   -1   666         loc.search = function(key, value, replace) {
   -1   667             if (key !== undefined) {
   -1   668                 if (value !== undefined) {
   -1   669                     var search = q.parse(_search());
   -1   670                     search[key] = value;
   -1   671                     return _search(q.unparse(search), replace);
   -1   672                 } else {
   -1   673                     return _search(q.unparse(key), replace);
   -1   674                 }
   -1   675             } else {
   -1   676                 return q.parse(_search());
   -1   677             }
   -1   678         };
   -1   679 
   -1   680         /**
   -1   681          * @return {string}
   -1   682          *//**
   -1   683          * @param {string} value
   -1   684          * @param {boolean} [replace]
   -1   685          * @return {muu-location}
   -1   686          */
   -1   687         loc.hash = function(value, replace) {
   -1   688             if (value === undefined) {
   -1   689                 if (location.hash) {
   -1   690                     return location.hash.slice(1);
   -1   691                 } else {
   -1   692                     return '';
   -1   693                 }
   -1   694             } else {
   -1   695                 var url = location.pathname + location.search + '#' + value;
   -1   696                 loc.url(url, replace);
   -1   697                 return loc;
   -1   698             }
   -1   699         };
   -1   700 
   -1   701         /**
   -1   702          * @param {string} eventName
   -1   703          * @param {Function} fn
   -1   704          * @return {muu-location}
   -1   705          */
   -1   706         loc.addEventListener = function(eventName, fn) {
   -1   707             if (eventName === 'change') {
   -1   708                 window.addEventListener('popstate', fn, false);
   -1   709             }
   -1   710             return loc;
   -1   711         };
   -1   712 
   -1   713         /**
   -1   714          * @param {string} eventName
   -1   715          * @param {Function} fn
   -1   716          * @return {muu-location}
   -1   717          */
   -1   718         loc.removeEventListener = function(eventName, fn) {
   -1   719             if (eventName === 'change') {
   -1   720                 window.removeEventListener('popstate', fn, false);
   -1   721             }
   -1   722             return loc;
   -1   723         };
   -1   724 
   -1   725         return loc;
   -1   726     });
   -1   727     /**
   -1   728      * Exports the {@link Registry} class.
   -1   729      * @module muu-registry
   -1   730      * @ignore
   -1   731      */
   -1   732     _define('muu-registry', ['muu-template', 'muu-directive', 'muu-js-helpers', 'muu-dom-helpers'], function(muuTemplate, Directive, _, $) {
   -1   733         "use strict";
   -1   734 
   -1   735         /**
   -1   736          * @constructs Registry
   -1   737          * @param {Object} config The config object may have following properties:
   -1   738          *
   -1   739          * - **debug** - `{boolean}` - Enable debug mode. In debug mode,
   -1   740          *   directive objects are available as properties from the DOM as
   -1   741          *   `element.directive`.
   -1   742          * - **renderer** - `{function(string, Object)}` - The template renderer
   -1   743          *   to be used. Defaults to {@link module:muu-template}.
   -1   744          */
   -1   745         var Registry = function(config) {
   -1   746             var self = this;
   -1   747             var directives = {};
   -1   748 
   -1   749             this.config = config || {};
   -1   750             this.renderer = self.config.renderer || muuTemplate;
   -1   751 
   -1   752             /**
   -1   753              * Register a new type of {@link Directive}
   -1   754              *
   -1   755              * @param {string} type
   -1   756              * @param {string} template
   -1   757              * @param {function(Directive, Element): Function} link The link
   -1   758              *   function is called with an instance of {@link Directive} and a
   -1   759              *   Element when {@link Registry#link} is executed.
   -1   760              *
   -1   761              *   It is the only place where you can access a directive and
   -1   762              *   therefore the place where you define its behavior.
   -1   763              *
   -1   764              *   This typically means to make an initial call to {@link
   -1   765              *   Directive#update} and to add some event listeners. You should also
   -1   766              *   return an *unlink* function that clears all external references in
   -1   767              *   order to avoid memory leaks.
   -1   768              * @return {Registry} this
   -1   769              */
   -1   770             this.registerDirective = function(type, template, link) {
   -1   771                 directives[type] = {
   -1   772                     template: template,
   -1   773                     link: link
   -1   774                 };
   -1   775                 return self;
   -1   776             };
   -1   777 
   -1   778             /**
   -1   779              * Shortcut for wrapping calls to {@link Registry} in a function.
   -1   780              *
   -1   781              * This can be esepcially helpful if that function is defined in a
   -1   782              * different module.
   -1   783              *
   -1   784              * ```.js
   -1   785              * _define('foobar', [], function() {
   -1   786              *   return function(registry) {
   -1   787              *     registry
   -1   788              *        .registerDirective('foo', '...', function() {...})
   -1   789              *        .registerDirective('bar', '...', function() {...});
   -1   790              *   };
   -1   791              * });
   -1   792              *
   -1   793              * require(['foobar'], function(foobar) {
   -1   794              *   var registry = new Registry();
   -1   795              *   registry.registerModule(foobar);
   -1   796              * });
   -1   797              * ```
   -1   798              *
   -1   799              * @param {function(Registry)} module
   -1   800              * @return {Registry} this
   -1   801              */
   -1   802             this.registerModule = function(module) {
   -1   803                 module(self);
   -1   804                 return self;
   -1   805             };
   -1   806 
   -1   807             /**
   -1   808              * Create and initialise a {@link Directive} for `element`.
   -1   809              *
   -1   810              * @param {Element} element
   -1   811              * @param {string} type
   -1   812              * @return {Directive}
   -1   813              */
   -1   814             this.link = function(element, type) {
   -1   815                 if (type === undefined) {
   -1   816                     type = element.getAttribute('type');
   -1   817                 }
   -1   818 
   -1   819                 if (!directives.hasOwnProperty(type)) {
   -1   820                     throw new Error('Unknown directive type: ' + type);
   -1   821                 }
   -1   822 
   -1   823                 var template = directives[type].template;
   -1   824                 var link = directives[type].link;
   -1   825 
   -1   826                 var directive = new Directive(element, template, self);
   -1   827                 var unlink = link(directive, element);
   -1   828                 element.classList.add('muu-isolate');
   -1   829                 element.classList.add('muu-initialised');
   -1   830 
   -1   831                 if (self.config.debug) {
   -1   832                     element.directive = directive;
   -1   833                 }
   -1   834 
   -1   835                 if (unlink !== undefined) {
   -1   836                     $.destroy(element, unlink);
   -1   837                 }
   -1   838 
   -1   839                 return directive;
   -1   840             };
   -1   841 
   -1   842             /**
   -1   843              * Link all directives that can be found inside `root`.
   -1   844              *
   -1   845              * @param {Element} root
   -1   846              * @return {Array.<Directive>}
   -1   847              */
   -1   848             this.linkAll = function(root) {
   -1   849                 // NOTE: root may be a DOM Node or a directive
   -1   850                 var elements = _.filter(root.querySelectorAll('muu'), function(element) {
   -1   851                     return !element.classList.contains('muu-initialised');
   -1   852                 });
   -1   853                 return _.map(elements, function(element) {
   -1   854                     return self.link(element);
   -1   855                 });
   -1   856             };
   -1   857         };
   -1   858 
   -1   859         return Registry;
   -1   860     });
   -1   861     _define('muu-search', ['muu-js-helpers'], function(_) {
   -1   862         "use strict";
   -1   863 
   -1   864         var q = {};
   -1   865 
   -1   866         q.parse = function(s) {
   -1   867             var q = {};
   -1   868 
   -1   869             var set = function(key, value) {
   -1   870                 if (!q.hasOwnProperty(key)) {
   -1   871                     q[key] = value;
   -1   872                 } else if (_.isArray(q[key])) {
   -1   873                     q[key].push(value);
   -1   874                 } else {
   -1   875                     q[key] = [q[key], value];
   -1   876                 }
   -1   877             };
   -1   878 
   -1   879             _.forEach(s.substring(1).split('&'), function(item) {
   -1   880                 var i = _.map(item.split('='), decodeURIComponent);
   -1   881                 if (i.length === 2) {
   -1   882                     set(i[0], i[1]);
   -1   883                 } else if (i[0]) {
   -1   884                     set(i[0], true);
   -1   885                 }
   -1   886             });
   -1   887             return q;
   -1   888         };
   -1   889 
   -1   890         var unparseItem = function(key, value) {
   -1   891             if (value === undefined || value === null || value === false) {
   -1   892                 return [];
   -1   893             } else if (_.isArray(value)) {
   -1   894                 return _.flatten(_.map(value, function(v) {
   -1   895                     return unparseItem(key, v);
   -1   896                 }));
   -1   897             } else if (value === true) {
   -1   898                 return [encodeURIComponent(key)];
   -1   899             } else {
   -1   900                 return [encodeURIComponent(key) + '=' + encodeURIComponent(value)];
   -1   901             }
   -1   902         };
   -1   903 
   -1   904         q.unparse = function(q) {
   -1   905             if (_.isString(q)) {
   -1   906                 return q;
   -1   907             }
   -1   908 
   -1   909             var a = []
   -1   910             for (var key in q) {
   -1   911                 if (q.hasOwnProperty(key)) {
   -1   912                     a = a.concat(unparseItem(key, q[key]));
   -1   913                 }
   -1   914             }
   -1   915             if (a.length > 0) {
   -1   916                 return '?' + a.join('&');
   -1   917             } else {
   -1   918                 return '';
   -1   919             }
   -1   920         };
   -1   921 
   -1   922         return q;
   -1   923     });
   -1   924     /**
   -1   925      * minimal mustache insipred templating
   -1   926      *
   -1   927      * ## Variables
   -1   928      *
   -1   929      * Variables are created with a `{{name}}` tag. These are always escaped.
   -1   930      *
   -1   931      * ## Loops
   -1   932      *
   -1   933      * Loops render blocks of text a number of times, depending on the value of
   -1   934      * the key in the current context.
   -1   935      *
   -1   936      * A loop begins with a pound and ends with a slash. That is, `{{#person}}`
   -1   937      * begins a "person" section while `{{/person}}` ends it.
   -1   938      *
   -1   939      * If the value is an array, the block is repeated for each item in that array.
   -1   940      * In any other case, the block is rendered with the outer scope, but only if
   -1   941      * the value is truthy.
   -1   942      *
   -1   943      * ## Inverted loops
   -1   944      *
   -1   945      * Inverted loops render blocks of test if the value of the key is falsy. They
   -1   946      * begin with a caret.
   -1   947      *
   -1   948      * ## Comments
   -1   949      *
   -1   950      * Comments begin with a bang and are ignored.
   -1   951      *
   -1   952      * ## Pairs
   -1   953      *
   -1   954      * Pairs look like JSON objects. The result is a space separated list of all
   -1   955      * keys with truthy values.
   -1   956      *
   -1   957      * ```
   -1   958      * muuTemplate('{{foo: var1, bar: var2, baz: var3}}', {
   -1   959      *   var1: true,
   -1   960      *   var2: false,
   -1   961      *   var3: true
   -1   962      * });  // 'foo baz'
   -1   963      * ```
   -1   964      *
   -1   965      * ## Special variable `this`
   -1   966      *
   -1   967      * `this` always refers to the current context. So the following expressions
   -1   968      * are equivalent:
   -1   969      *
   -1   970      * ```
   -1   971      * muuTemplate('{{#items}}{{content}}{{/items}}', {
   -1   972      *   item: [{
   -1   973      *     content: 1
   -1   974      *   }, {
   -1   975      *     content: 2
   -1   976      *   }]
   -1   977      * });
   -1   978      *
   -1   979      * muuTemplate('{{#this}}{{this}}{{/this}}', [1, 2]);
   -1   980      * ```
   -1   981      *
   -1   982      * @module muu-template
   -1   983      * @param {string} template
   -1   984      * @param {Object} data
   -1   985      * @return {string}
   -1   986      */
   -1   987     _define('muu-template', ['muu-js-helpers', 'muu-dom-helpers'], function(_, $) {
   -1   988         "use strict";
   -1   989 
   -1   990         var openTag = '{{';
   -1   991         var closeTag = '}}';
   -1   992 
   -1   993         var getValue = function(key, data) {
   -1   994             return key === 'this' ? data : data[key];
   -1   995         };
   -1   996 
   -1   997         var parseVariableTemplate = function(template) {
   -1   998             var content = template.slice(2, -2);
   -1   999 
   -1  1000             if (template.indexOf(':') === -1) {
   -1  1001                 return function(data) {
   -1  1002                     return $.escapeHtml(getValue(content, data) || '');
   -1  1003                 };
   -1  1004             } else {
   -1  1005                 var pairs = content.split(',').map(function(pair) {
   -1  1006                     var v = pair.split(':');
   -1  1007                     var key = v[0].trim();
   -1  1008                     var value = v.slice(1).join(':').trim();
   -1  1009                     return [key, value];
   -1  1010                 });
   -1  1011 
   -1  1012                 return function(data) {
   -1  1013                     var results = [];
   -1  1014 
   -1  1015                     for (var i = 0; i < pairs.length; i++) {
   -1  1016                         var key = pairs[i][0];
   -1  1017                         var value = pairs[i][1];
   -1  1018 
   -1  1019                         if (getValue(value, data)) {
   -1  1020                             results.push(key);
   -1  1021                         }
   -1  1022                     }
   -1  1023 
   -1  1024                     return $.escapeHtml(results.join(' '));
   -1  1025                 };
   -1  1026             }
   -1  1027         };
   -1  1028 
   -1  1029         var parseLoopTemplate = function(tag, afterTag, inverted) {
   -1  1030             var tagName = tag.slice(3, -2);
   -1  1031 
   -1  1032             var v = parseTemplate(afterTag, tagName);
   -1  1033             var inner = v[0];
   -1  1034             var afterLoop = v[1];
   -1  1035 
   -1  1036             var render = function(data) {
   -1  1037                 if (inverted) {
   -1  1038                     if (getValue(tagName, data)) {
   -1  1039                         return '';
   -1  1040                     } else {
   -1  1041                         return inner(data);
   -1  1042                     }
   -1  1043                 } else {
   -1  1044                     if (_.isArray(getValue(tagName, data))) {
   -1  1045                         var result = '';
   -1  1046                         for (var i = 0; i < getValue(tagName, data).length; i++) {
   -1  1047                             result += inner(getValue(tagName, data)[i]);
   -1  1048                         }
   -1  1049                         return result;
   -1  1050                     } else if (getValue(tagName, data)) {
   -1  1051                         return inner(data);
   -1  1052                     } else {
   -1  1053                         return '';
   -1  1054                     }
   -1  1055                 }
   -1  1056             };
   -1  1057 
   -1  1058             return [render, afterLoop];
   -1  1059         };
   -1  1060 
   -1  1061         var concat = function(a) {
   -1  1062             var last = a.pop();
   -1  1063 
   -1  1064             if (_.isArray(last)) {
   -1  1065                 a.push(last[0]);
   -1  1066                 return [concat(a), last[1]];
   -1  1067             } else {
   -1  1068                 a.push(last);
   -1  1069 
   -1  1070                 return function(data) {
   -1  1071                     return a.map(function(item) {
   -1  1072                         if (_.isString(item)) {
   -1  1073                             return item;
   -1  1074                         } else if (_.isFunction(item)) {
   -1  1075                             return item(data);
   -1  1076                         }
   -1  1077                     }).join('');
   -1  1078                 };
   -1  1079             }
   -1  1080         };
   -1  1081 
   -1  1082         var parseTemplate = function(template, loopName) {
   -1  1083             var openIndex = template.indexOf(openTag);
   -1  1084             if (openIndex === -1) {
   -1  1085                 if (loopName === undefined) {
   -1  1086                     return function() {
   -1  1087                         return template;
   -1  1088                     };
   -1  1089                 } else {
   -1  1090                     throw new Error('unclosed loop: ' + loopName);
   -1  1091                 }
   -1  1092             } else {
   -1  1093                 var beforeTag = template.slice(0, openIndex);
   -1  1094                 var tmp = template.slice(openIndex);
   -1  1095 
   -1  1096                 var closeIndex = tmp.indexOf(closeTag) + 2;
   -1  1097                 if (closeIndex === 1) {
   -1  1098                     throw new Error('unclosed tag: ' + tmp);
   -1  1099                 }
   -1  1100                 var tag = tmp.slice(0, closeIndex);
   -1  1101                 var afterTag = tmp.slice(closeIndex);
   -1  1102 
   -1  1103                 if (tag.lastIndexOf('{{#', 0) === 0) {
   -1  1104                     var v = parseLoopTemplate(tag, afterTag);
   -1  1105                     var loop = v[0];
   -1  1106                     var after = parseTemplate(v[1], loopName);
   -1  1107                     return concat([beforeTag, loop, after]);
   -1  1108                 } else if (tag.lastIndexOf('{{^', 0) === 0) {
   -1  1109                     var v = parseLoopTemplate(tag, afterTag, true);
   -1  1110                     var loop = v[0];
   -1  1111                     var after = parseTemplate(v[1], loopName);
   -1  1112                     return concat([beforeTag, loop, after]);
   -1  1113                 } else if (tag.lastIndexOf('{{!', 0) === 0) {
   -1  1114                     var after = parseTemplate(afterTag, loopName);
   -1  1115                     return concat([beforeTag, after]);
   -1  1116                 } else if (tag.lastIndexOf('{{/', 0) === 0) {
   -1  1117                     if (tag.slice(3, -2) === loopName) {
   -1  1118                         var render = function() {
   -1  1119                             return beforeTag;
   -1  1120                         };
   -1  1121                         return [render, afterTag];
   -1  1122                     } else {
   -1  1123                         throw new Error('unexpected closing loop: ' + tag);
   -1  1124                     }
   -1  1125                 } else {
   -1  1126                     var render = parseVariableTemplate(tag);
   -1  1127                     var after = parseTemplate(afterTag, loopName);
   -1  1128                     return concat([beforeTag, render, after]);
   -1  1129                 }
   -1  1130             }
   -1  1131         };
   -1  1132 
   -1  1133         return function(template, data) {
   -1  1134             return parseTemplate(template)(data);
   -1  1135         };
   -1  1136     });
   -1  1137     /**
   -1  1138      * Recreate children of `source` in `target` by making only small adjustments.
   -1  1139      *
   -1  1140      * *The following section explains details about the current implementation.
   -1  1141      * These are likely to change in the future.*
   -1  1142      *
   -1  1143      * The algorithms is relatively simple. It just iterates through all top level
   -1  1144      * nodes. If a node has a different `nodeType` (e.g. text or element) or a
   -1  1145      * different `nodeName` (e.g. div or ul) it is replaced completely and the
   -1  1146      * algorithm proceeds with the node's children recursively.  Otherwise, only
   -1  1147      * the nodes's attributes are updated.
   -1  1148      *
   -1  1149      * Note that non-attribute properties (e.g. value) are lost in the first case
   -1  1150      * and preserved in the second.
   -1  1151      *
   -1  1152      * If the algorithm encounters an element with the class `muu-isolate` it does
   -1  1153      * not recurse into its children. This way, you can protect dynamically
   -1  1154      * generated content from being overwritten.
   -1  1155      *
   -1  1156      * @module muu-update-dom
   -1  1157      * @param {Element} target
   -1  1158      * @param {Element} source
   -1  1159      */
   -1  1160     _define('muu-update-dom', ['muu-js-helpers'], function(_) {
   -1  1161         "use strict";
   -1  1162 
   -1  1163         var updateAttributes = function(target, source) {
   -1  1164             var targetAttrNames = _.map(target.attributes, function(item) {
   -1  1165                 return item.name;
   -1  1166             });
   -1  1167             var sourceAttrNames = _.map(source.attributes, function(item) {
   -1  1168                 return item.name;
   -1  1169             });
   -1  1170 
   -1  1171             _.forEach(targetAttrNames, function(name) {
   -1  1172                 // NOTE: ie8.js creates some attribute
   -1  1173                 if (!source.hasAttribute(name) && name.substr(0, 7) !== '__IE8__') {
   -1  1174                     target.removeAttribute(name);
   -1  1175                 }
   -1  1176             });
   -1  1177             _.forEach(sourceAttrNames, function(name) {
   -1  1178                 if (target.getAttribute(name) !== source.getAttribute(name)) {
   -1  1179                     target.setAttribute(name, source.getAttribute(name));
   -1  1180                 }
   -1  1181             });
   -1  1182         };
   -1  1183 
   -1  1184         var updateDOM = function(target, source) {
   -1  1185             var nt = target.childNodes.length;
   -1  1186             var ns = source.childNodes.length;
   -1  1187 
   -1  1188             for (var i = ns; i < nt; i++) {
   -1  1189                 target.removeChild(target.childNodes[ns]);
   -1  1190             }
   -1  1191             for (i = nt; i < ns; i++) {
   -1  1192                 target.appendChild(source.childNodes[nt]);
   -1  1193             }
   -1  1194             for (i = 0; i < nt && i < ns; i++) {
   -1  1195                 var tchild = target.childNodes[i];
   -1  1196                 var schild = source.childNodes[i];
   -1  1197 
   -1  1198                 if (tchild.nodeType === schild.nodeType && tchild.nodeName === schild.nodeName && tchild.type === schild.type) {
   -1  1199                     if (tchild.nodeType === 1) {
   -1  1200                         var muuClasses = _.filter(tchild.classList, function(cls) {
   -1  1201                             return cls.lastIndexOf('muu-', 0) === 0;
   -1  1202                         });
   -1  1203                         updateAttributes(tchild, schild);
   -1  1204                         _.forEach(muuClasses, function(cls) {
   -1  1205                             tchild.classList.add(cls);
   -1  1206                         });
   -1  1207                     } else if (tchild.nodeType === 3) {
   -1  1208                         tchild.nodeValue = schild.nodeValue;
   -1  1209                     }
   -1  1210                     if (tchild.nodeType !== 3 && !tchild.classList.contains('muu-isolate')) {
   -1  1211                         updateDOM(tchild, schild);
   -1  1212                     }
   -1  1213                 } else {
   -1  1214                     tchild.parentNode.replaceChild(schild, tchild);
   -1  1215                 }
   -1  1216             }
   -1  1217         };
   -1  1218 
   -1  1219         return updateDOM;
   -1  1220     });
   -1  1221     /**
   -1  1222      * This module gives access to the following objects:
   -1  1223      *
   -1  1224      * -   `Registry` - {@link Registry}
   -1  1225      * -   `$` - {@link module:muu-dom-helpers}
   -1  1226      * -   `$location` - {@link module:muu-location}
   -1  1227      *
   -1  1228      * @module muu
   -1  1229      */
   -1  1230     _define('muu', ['muu-registry', 'muu-dom-helpers', 'muu-location'], function(Registry, $, $location) {
   -1  1231         "use strict";
   -1  1232 
   -1  1233         var module = {};
   -1  1234 
   -1  1235         module.Registry = Registry;
   -1  1236         module.$ = $;
   -1  1237         module.$location = $location;
   -1  1238 
   -1  1239         return module;
   -1  1240     });
   -1  1241 
   -1  1242         return _require('muu');
   -1  1243     });
   -1  1244 })(window, document, void 0);

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

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

diff --git a/examples/example/example.js b/examples/example/example.js

@@ -1,9 +1,9 @@
    1     1 requirejs.config({
    2    -1     baseUrl: '../../src/',
    3     2     paths: {
    4    -1         xhr: '../lib/promise-xhr/promise-xhr',
    5    -1         moment: '../lib/moment/moment',
    6    -1         'muu-moment': '../examples/example/muu-moment'
   -1     3         muu: '../../dist/muu.min',
   -1     4         xhr: '../../lib/promise-xhr/promise-xhr',
   -1     5         moment: '../../lib/moment/moment',
   -1     6         'muu-moment': './muu-moment'
    7     7     }
    8     8 });
    9     9 

diff --git a/examples/example/index.html b/examples/example/index.html

@@ -1,7 +1,6 @@
    1     1 <html>
    2     2     <head>
    3     3         <script src="../../lib/requirejs/require.js"></script>
    4    -1         <script src="../../muu.min.js"></script>
    5     4         <script src="example.js"></script>
    6     5     </head>
    7     6     <body>

diff --git a/examples/phonecat/index.html b/examples/phonecat/index.html

@@ -1,7 +1,6 @@
    1     1 <html>
    2     2     <head>
    3     3         <script src="../../lib/requirejs/require.js"></script>
    4    -1         <script src="../../muu.min.js"></script>
    5     4         <script src="phonecat.js"></script>
    6     5     </head>
    7     6     <body>

diff --git a/examples/phonecat/phonecat.js b/examples/phonecat/phonecat.js

@@ -1,7 +1,7 @@
    1     1 requirejs.config({
    2    -1     baseUrl: '../../src/',
    3     2     paths: {
    4    -1         xhr: '../lib/promise-xhr/promise-xhr'
   -1     3         muu: '../../dist/muu.min',
   -1     4         xhr: '../../lib/promise-xhr/promise-xhr'
    5     5     }
    6     6 });
    7     7 

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

@@ -1,2 +0,0 @@
    1    -1 define("muu-js-helpers",[],function(){"use strict";var e={},t=function(e){return Object.prototype.toString.call(e)};return e.isString=function(e){return"string"==typeof e||"[object String]"===t(e)},e.isArray=Array.isArray,e.isFunction=function(e){return"function"==typeof e},e.once=function(e){var t,n=!1;return function(){return n||(t=e.apply(this,arguments),n=!0),t}},e.indexOf=function(e,t){if("indexOf"in e)return e.indexOf(t);for(var n=0;n<e.length;n++)if(e[n]===t)return n;return-1},e.forEach=function(e,t){if("forEach"in e)return e.forEach(t);for(var n=0;n<e.length;n++)t(e[n])},e.map=function(e,t){if("map"in e)return e.map(t);for(var n=[],r=0;r<e.length;r++)n.push(t(e[r]));return n},e.filter=function(e,t){if("filter"in e)return e.filter(t);for(var n=[],r=0;r<e.length;r++)t(e[r])&&n.push(e[r]);return n},e.union=function(t){for(var n=[],r=0;r<t.length;r++)for(var i=0;i<t[r].length;i++)-1===e.indexOf(n,t[r][i])&&n.push(t[r][i]);return n},e.difference=function(t,n){for(var r=[],i=0;i<t.length;i++)-1===e.indexOf(n,t[i])&&r.push(t[i]);return r},e.flatten=function(t){var n=[];return e.forEach(t,function(t){e.isArray(t)?n=n.concat(e.flatten(t)):n.push(t)}),n},e}),define("muu-dom-helpers",["muu-js-helpers"],function(e){"use strict";var t={"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#39;","/":"&#x2F;"},n={};return n.DELAY=1e3,n.escapeHtml=function(e){return String(e).replace(/[&<>"'\/]/g,function(e){return t[e]})},n.createEvent=function(e,t){if("function"==typeof CustomEvent)return new CustomEvent(e,{detail:t});var n=document.createEvent("CustomEvent");return n.initCustomEvent(e,!1,!0,t),n},n.on=function(e,t,n){return e.addEventListener(t,n,!1),function(){e.removeEventListener(t,n,!1)}},n.ready=function(t){var r=e.once(t);if("complete"===document.readyState)return r(),function(){};var i=n.on(document,"DOMContentLoaded",r),u=n.on(window,"load",r);return function(){i(),u()}},n.isDescendant=function(e,t){return!!e&&(e===t||n.isDescendant(e.parentNode,t))},n.destroy=function(e,t){var r,i=setInterval(function(){n.isDescendant(e,document)||(t(),r())},n.DELAY);return r=function(){clearInterval(i)}},n.getRadio=function(e){for(var t=0;t<e.length;t++)if(e[t].checked)return e[t].value},n.setRadio=function(e,t){for(var n=0;n<e.length;n++)e[n].value===t?e[n].checked=!0:e[n].checked=!1},n}),define("muu-template",["muu-js-helpers","muu-dom-helpers"],function(e,t){"use strict";var n="{{",r="}}",i=function(e){var n=e.slice(2,-2);if(-1===e.indexOf(":"))return function(e){return t.escapeHtml(e[n]||"")};var r=n.split(",").map(function(e){var t=e.split(":"),n=t[0].trim(),r=t.slice(1).join(":").trim();return[n,r]});return function(e){for(var n=[],i=0;i<r.length;i++){var u=r[i][0],o=r[i][1];e[o]&&n.push(u)}return t.escapeHtml(n.join(" "))}},u=function(t,n){var r=t.slice(3,-2),i=c(n,r),u=i[0],o=i[1],a=function(t){if(e.isArray(t[r])){for(var n="",i=0;i<t[r].length;i++)n+=u(t[r][i]);return n}return t[r]?u(t):""};return[a,o]},o=function(t){var n=t.pop();return e.isArray(n)?(t.push(n[0]),[o(t),n[1]]):(t.push(n),function(n){return t.map(function(t){return e.isString(t)?t:e.isFunction(t)?t(n):void 0}).join("")})},c=function(e,t){var a=e.indexOf(n);if(-1===a){if(void 0===t)return function(){return e};throw new Error("unclosed loop: "+t)}var f=e.slice(0,a),l=e.slice(a),s=l.indexOf(r)+2;if(1===s)throw new Error("unclosed tag: "+l);var d=l.slice(0,s),v=l.slice(s);if(0===d.lastIndexOf("{{#",0)){var h=u(d,v),m=h[0],p=c(h[1],t);return o([f,m,p])}if(0===d.lastIndexOf("{{!",0)){var p=c(v,t);return o([f,p])}if(0===d.lastIndexOf("{{/",0)){if(d.slice(3,-2)===t){var y=function(){return f};return[y,v]}throw new Error("unexpected closing loop: "+d)}var y=i(d),p=c(v,t);return o([f,y,p])};return function(e,t){return c(e)(t)}}),define("muu-update-dom",["muu-js-helpers"],function(e){"use strict";var t=function(t,n){var r=e.map(t.attributes,function(e){return e.name}),i=e.map(n.attributes,function(e){return e.name});e.forEach(r,function(e){n.hasAttribute(e)||"__IE8__"===e.substr(0,7)||t.removeAttribute(e)}),e.forEach(i,function(e){t.getAttribute(e)!==n.getAttribute(e)&&t.setAttribute(e,n.getAttribute(e))})},n=function(r,i){var u=r.childNodes.length,o=i.childNodes.length;if(r.nodeType===i.nodeType&&r.nodeName===i.nodeName&&r.type===i.type){if(1===r.nodeType){var c=e.filter(r.classList,function(e){return 0===e.lastIndexOf("muu-",0)});t(r,i),e.forEach(c,function(e){r.classList.add(e)})}else 3===r.nodeType&&(r.nodeValue=i.nodeValue);if(1!==r.nodeType||!r.classList.contains("muu-isolate")){for(var a=o;u>a;a++)r.removeChild(r.childNodes[o]);for(a=u;o>a;a++)r.appendChild(i.childNodes[u]);for(a=0;u>a&&o>a;a++)n(r.childNodes[a],i.childNodes[a])}}else r.parentNode.replaceChild(i,r)};return n}),define("muu-directive",["muu-dom-helpers","muu-js-helpers","muu-update-dom"],function(e,t,n){"use strict";var r=function(r,i,u){var o=this;r.innerHTML="<div></div>";var c=function(t){var n="data-on"+t.type;if(t.target.hasAttribute(n)){var i=t.target.getAttribute(n),u=e.createEvent("muu-"+i,t);r.dispatchEvent(u)}};this.update=function(a){var f=document.createElement("div");f.innerHTML=u.renderer(i,a),n(r.children[0],f),t.forEach(["keydown","keyup","click","change","search"],function(e){var n="[data-on"+e+"]";t.forEach(o.querySelectorAll(n),function(t){t.addEventListener(e,c,!1)})});var l=e.createEvent("muu-parent-update"),s=this.querySelectorAll("muu.muu-initialised");t.forEach(s,function(e){e.dispatchEvent(l)}),u.linkAll(o)},this.querySelectorAll=function(e){var n=r.querySelectorAll(e),i=r.querySelectorAll(".muu-isolate"),u=t.union(t.map(i,function(t){return t.querySelectorAll(e)}));return t.difference(n,u)},this.querySelector=function(e){var t=o.querySelectorAll(e);return t.length>0?t[0]:void 0},this.getModel=function(n,r){if(void 0===n){var i={};return t.forEach(o.querySelectorAll("[name]"),function(e){i[e.name]=o.getModel(e.name)}),i}var u=o.querySelector("[name="+n+"]");if(void 0===u)return r;if("checkbox"===u.type)return u.checked;if("radio"===u.type){var c=o.querySelectorAll("[name="+n+"]");return e.getRadio(c)||r}return u.value},this.setModel=function(t,n){var r=o.querySelector("[name="+t+"]");if("checkbox"===r.type)r.checked=n;else if("radio"===r.type){var i=o.querySelectorAll("[name="+t+"]");e.setRadio(i,n)}else r.value=n}};return r}),define("muu",["muu-template","muu-directive","muu-js-helpers","muu-dom-helpers"],function(e,t,n,r){"use strict";var i=function(i){var u=this,o={};this.config=i||{},this.renderer=u.config.renderer||e,this.registerDirective=function(e,t,n){return o[e]={template:t,link:n},u},this.registerModule=function(e){return e(u),u},this.link=function(e,n){if(void 0===n&&(n=e.getAttribute("type")),!o.hasOwnProperty(n))throw new Error("Unknown directive type: "+n);var i=o[n].template,c=o[n].link,a=new t(e,i,u),f=c(a,e);return e.classList.add("muu-isolate"),e.classList.add("muu-initialised"),u.config.debug&&(e.directive=a),void 0!==f&&r.destroy(e,f),a},this.linkAll=function(e){var t=n.filter(e.querySelectorAll("muu"),function(e){return!e.classList.contains("muu-initialised")});return n.map(t,function(e){return u.link(e)})}};return i});
    2    -1 //# sourceMappingURL=muu.min.js.ma
    2    -1 
\ No newline at end of file

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

@@ -1 +0,0 @@
    1    -1 {"version":3,"file":"muu.min.js","sources":["muu-js-helpers.js","muu-dom-helpers.js","muu-template.js","muu-update-dom.js","muu-directive.js","muu.js"],"names":["define","_","objToString","value","Object","prototype","toString","call","isString","isArray","Array","isFunction","once","fn","result","called","apply","this","arguments","indexOf","array","i","length","forEach","map","results","push","filter","union","arrays","j","difference","a","b","flatten","o","item","concat","entityMap","&","<",">","\"","'","/","$","DELAY","escapeHtml","string","String","replace","s","createEvent","type","detail","CustomEvent","event","document","initCustomEvent","on","element","eventName","callback","addEventListener","removeEventListener","ready","_fn","readyState","u1","u2","window","isDescendant","desc","root","parentNode","destroy","unregister","intervalID","setInterval","clearInterval","getRadio","options","checked","setRadio","openTag","closeTag","parseVariableTemplate","template","content","slice","data","pairs","split","pair","v","key","trim","join","parseLoopTemplate","tag","afterTag","tagName","parseTemplate","inner","afterLoop","render","last","pop","loopName","openIndex","Error","beforeTag","tmp","closeIndex","lastIndexOf","loop","after","updateAttributes","target","source","targetAttrNames","attributes","name","sourceAttrNames","hasAttribute","substr","removeAttribute","getAttribute","setAttribute","updateDOM","nt","childNodes","ns","nodeType","nodeName","muuClasses","classList","cls","add","nodeValue","contains","removeChild","appendChild","replaceChild","Directive","registry","self","innerHTML","eventCallback","originalEvent","attrName","dispatchEvent","update","createElement","renderer","children","eventType","selector","querySelectorAll","updateEvent","subDirectives","linkAll","hits","isolations","isolated","isolation","querySelector","all","getModel","_default","model","setModel","muuTemplate","Registry","config","directives","registerDirective","link","registerModule","module","hasOwnProperty","directive","unlink","debug","elements"],"mappings":"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B,KAAArH,MAKA,OAAAiH;ALlIA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AC/KA,ADgLA;AC/KA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,ACnKA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,AC/KA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AClFA,ADmFA;AClFA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,AClLA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA","sourcesContent":["/**\n * Minimal implementation of an underscore/lodash subset.\n * @module muu-js-helpers\n */\ndefine('muu-js-helpers',[],function() {\n    \"use strict\";\n\n    /** @lends module:muu-js-helpers */\n    var _ = {};\n\n    /**\n     * @param {object} value\n     * @return {string}\n     */\n    var objToString = function(value) {\n        return Object.prototype.toString.call(value);\n    };\n\n    /**\n     * @param {*} value\n     * @return {boolean}\n     */\n    _.isString = function(value) {\n        return typeof value === 'string' || objToString(value) === '[object String]';\n    };\n\n    /**\n     * @function\n     * @param {*} value\n     * @return {boolean}\n     */\n    _.isArray = Array.isArray;\n\n    /**\n     * @param {*} value\n     * @return {boolean}\n     */\n    _.isFunction = function(value) {\n        return typeof value === 'function';\n    };\n\n    /**\n     * @param {function} fn\n     * @return {function}\n     */\n    _.once = function(fn) {\n        var result;\n        var called = false;\n\n        return function() {\n            if (!called) {\n                result = fn.apply(this, arguments);\n                called = true;\n            }\n            return result;\n        };\n    };\n\n    /**\n     * @param {array} array\n     * @param {*} value\n     * @return {number}\n     */\n    _.indexOf = function(array, value) {\n        if ('indexOf' in array) {\n            return array.indexOf(value);\n        }\n\n        for (var i = 0; i < array.length; i++) {\n            if (array[i] === value) {\n                return i;\n            }\n        }\n        return -1;\n    };\n\n    /**\n     * @param {array} array\n     * @param {function} fn\n     */\n    _.forEach = function(array, fn) {\n        if ('forEach' in array) {\n            return array.forEach(fn);\n        }\n\n        for (var i = 0; i < array.length; i++) {\n            fn(array[i]);\n        }\n    };\n\n    /**\n     * @param {array} array\n     * @param {function} fn\n     * @return {array}\n     */\n    _.map = function(array, fn) {\n        if ('map' in array) {\n            return array.map(fn);\n        }\n\n        var results = [];\n        for (var i = 0; i < array.length; i++) {\n            results.push(fn(array[i]));\n        }\n        return results;\n    };\n\n    /**\n     * @param {array} array\n     * @param {function} fn\n     * @return {array}\n     */\n    _.filter = function(array, fn) {\n        if ('filter' in array) {\n            return array.filter(fn);\n        }\n\n        var results = [];\n        for (var i = 0; i < array.length; i++) {\n            if (fn(array[i])) {\n                results.push(array[i]);\n            }\n        }\n        return results;\n    };\n\n    /**\n     * @param {array[]} arrays\n     * @return {array}\n     */\n    _.union = function(arrays) {\n        var results = [];\n        for (var i = 0; i < arrays.length; i++) {\n            for (var j = 0; j < arrays[i].length; j++) {\n                if (_.indexOf(results, arrays[i][j]) === -1) {\n                    results.push(arrays[i][j]);\n                }\n            }\n        }\n        return results;\n    };\n\n    /**\n     * @param {array} a\n     * @param {array} b\n     * @return {array}\n     */\n    _.difference = function(a, b) {\n        var results = [];\n        for (var i = 0; i < a.length; i++) {\n            if (_.indexOf(b, a[i]) === -1) {\n                results.push(a[i]);\n            }\n        }\n        return results;\n    };\n\n    /**\n     * @param {array} a\n     * @return {array}\n     */\n    _.flatten = function(a) {\n        var o = [];\n        _.forEach(a, function(item) {\n            if (_.isArray(item)) {\n                o = o.concat(_.flatten(item));\n            } else {\n                o.push(item);\n            }\n        });\n        return o;\n    };\n\n    return _;\n});\n\n","/**\n * DOM related helper functions\n * @module muu-dom-helpers\n */\ndefine('muu-dom-helpers',['muu-js-helpers'], function(_) {\n    \"use strict\";\n\n    var entityMap = {\n        '&': '&amp;',\n        '<': '&lt;',\n        '>': '&gt;',\n        '\"': '&quot;',\n        \"'\": '&#39;',\n        '/': '&#x2F;'\n    };\n\n    /** @lends module:muu-dom-helpers */\n    var $ = {};\n\n    $.DELAY = 1000;\n\n    /**\n     * @param {string} string\n     * @return {string} - escaped HTML\n     */\n    $.escapeHtml = function(string) {\n        return String(string).replace(/[&<>\"'\\/]/g, function(s) {\n            return entityMap[s];\n        });\n    };\n\n    /**\n     * Cross browser custom events.\n     *\n     * See https://developer.mozilla.org/en-US/docs/Web/Guide/Events/Creating_and_triggering_events\n     *\n     * *Note*: IE does not seem to like it when you use existing event names\n     * with this.\n     *\n     * @param {string} type\n     * @param {*} detail\n     * @return {DOMEvent}\n     */\n    $.createEvent = function(type, detail) {\n        if (typeof CustomEvent === 'function') {\n            return new CustomEvent(type, {\n                detail: detail\n            });\n        } else {\n            var event = document.createEvent('CustomEvent');\n            event.initCustomEvent(type, false, true, detail);\n            return event;\n        }\n    };\n\n    /**\n     * @param {DOMElement} element\n     * @param {string} eventName\n     * @param {function} callback\n     * @return {Function()} An unregister function\n     */\n    $.on = function(element, eventName, callback) {\n        element.addEventListener(eventName, callback, false);\n        return function() {\n            element.removeEventListener(eventName, callback, false);\n        };\n    };\n\n    /**\n     * @param {function} fn\n     * @return {Function()} An unregister function\n     */\n    $.ready = function(fn) {\n        var _fn = _.once(fn);\n        if (document.readyState === 'complete') {\n            _fn();\n            return function() {};\n        } else {\n            var u1 = $.on(document, 'DOMContentLoaded', _fn);\n            var u2 = $.on(window, 'load', _fn);\n            return function() {\n                u1();\n                u2();\n            };\n        }\n    };\n\n    $.isDescendant = function(desc, root) {\n         return !!desc && (desc === root || $.isDescendant(desc.parentNode, root));\n    };\n\n    /**\n     * Execute a function when `element` is removed from the DOM.\n     *\n     * @param {DOMElement} element\n     * @param {function} fn\n     * @return {Function()} An unregister function\n     */\n    $.destroy = function(element, fn) {\n        var unregister;\n\n        if (false) {\n            var observer = new MutationObserver(function() {\n                if (!$.isDescendant(element, document)) {\n                    fn();\n                    unregister();\n                }\n            });\n\n            observer.observe(document, {\n                 childList: true,\n                 subtree: true\n            });\n\n            unregister = _.once(function() {\n                observer.disconnect();\n                observer = undefined;\n            });\n        } else {\n            var intervalID = setInterval(function() {\n                if (!$.isDescendant(element, document)) {\n                    fn();\n                    unregister();\n                }\n            }, $.DELAY);\n\n            unregister = function() {\n                clearInterval(intervalID);\n            };\n        }\n\n        return unregister;\n    };\n\n    /**\n     * @param {DOMElement[]} options\n     * @return {string}\n     */\n    $.getRadio = function(options) {\n        for (var i = 0; i < options.length; i++) {\n            if (options[i].checked) {\n                return options[i].value;\n            }\n        }\n    };\n\n    /**\n     * @param {DOMElement[]} options\n     * @param {string} value\n     */\n    $.setRadio = function(options, value) {\n        for (var i = 0; i < options.length; i++) {\n            if (options[i].value === value) {\n                options[i].checked = true;\n            } else {\n                options[i].checked = false;\n            }\n        }\n    };\n\n    return $;\n});\n\n","/**\n * minimal mustache insipred templating\n *\n * ## Variables\n *\n * Variables are created with a `{{name}}` tag. These are always escaped.\n *\n * ## Loops\n *\n * Loops render blocks of text a number of times, depending on the value of\n * the key in the current context.\n *\n * A loop begins with a pound and ends with a slash. That is, {{#person}}\n * begins a \"person\" section while {{/person}} ends it.\n *\n * If the value is an array, the block is repeated for each item in that array.\n * In any other case, the block is rendered with the outer scope, but only if\n * the value is truthy.\n *\n * ## Comments\n *\n * Comments begin with a bang and are ignored.\n *\n * ## Pairs\n *\n * Pairs look like JSON objects. The result is a space separated list of all\n * keys with truthy values.\n *\n * ```\n * muuTemplate('{{foo: var1, bar: var2, baz: var3}}', {\n *   var1: true,\n *   var2: false,\n *   var3: true\n * });  // 'foo baz'\n * ```\n *\n * @module muu-template\n * @param {string} template\n * @param {object} data\n * @return {string}\n */\ndefine('muu-template',['muu-js-helpers', 'muu-dom-helpers'], function(_, $) {\n    \"use strict\";\n\n    var openTag = '{{';\n    var closeTag = '}}';\n\n    var parseVariableTemplate = function(template) {\n        var content = template.slice(2, -2);\n\n        if (template.indexOf(':') === -1) {\n            return function(data) {\n                return $.escapeHtml(data[content] || '');\n            };\n        } else {\n            var pairs = content.split(',').map(function(pair) {\n                var v = pair.split(':');\n                var key = v[0].trim();\n                var value = v.slice(1).join(':').trim();\n                return [key, value];\n            });\n\n            return function(data) {\n                var results = [];\n\n                for (var i = 0; i < pairs.length; i++) {\n                    var key = pairs[i][0];\n                    var value = pairs[i][1];\n\n                    if (data[value]) {\n                        results.push(key);\n                    }\n                }\n\n                return $.escapeHtml(results.join(' '));\n            };\n        }\n    };\n\n    var parseLoopTemplate = function(tag, afterTag) {\n        var tagName = tag.slice(3, -2);\n\n        var v = parseTemplate(afterTag, tagName);\n        var inner = v[0];\n        var afterLoop = v[1];\n\n        var render = function(data) {\n            if (_.isArray(data[tagName])) {\n                var result = '';\n                for (var i = 0; i < data[tagName].length; i++) {\n                    result += inner(data[tagName][i]);\n                }\n                return result;\n            } else if (data[tagName]) {\n                return inner(data);\n            } else {\n                return '';\n            }\n        };\n\n        return [render, afterLoop];\n    };\n\n    var concat = function(a) {\n        var last = a.pop();\n\n        if (_.isArray(last)) {\n            a.push(last[0]);\n            return [concat(a), last[1]];\n        } else {\n            a.push(last);\n\n            return function(data) {\n                return a.map(function(item) {\n                    if (_.isString(item)) {\n                        return item;\n                    } else if (_.isFunction(item)) {\n                        return item(data);\n                    }\n                }).join('');\n            };\n        }\n    };\n\n    var parseTemplate = function(template, loopName) {\n        var openIndex = template.indexOf(openTag);\n        if (openIndex === -1) {\n            if (loopName === void 0) {\n                return function() {\n                    return template;\n                };\n            } else {\n                throw new Error('unclosed loop: ' + loopName);\n            }\n        } else {\n            var beforeTag = template.slice(0, openIndex);\n            var tmp = template.slice(openIndex);\n\n            var closeIndex = tmp.indexOf(closeTag) + 2;\n            if (closeIndex === 1) {\n                throw new Error('unclosed tag: ' + tmp);\n            }\n            var tag = tmp.slice(0, closeIndex);\n            var afterTag = tmp.slice(closeIndex);\n\n            if (tag.lastIndexOf('{{#', 0) === 0) {\n                var v = parseLoopTemplate(tag, afterTag);\n                var loop = v[0];\n                var after = parseTemplate(v[1], loopName);\n                return concat([beforeTag, loop, after]);\n            } else if (tag.lastIndexOf('{{!', 0) === 0) {\n                var after = parseTemplate(afterTag, loopName);\n                return concat([beforeTag, after]);\n            } else if (tag.lastIndexOf('{{/', 0) === 0) {\n                if (tag.slice(3, -2) === loopName) {\n                    var render = function() {\n                        return beforeTag;\n                    };\n                    return [render, afterTag];\n                } else {\n                    throw new Error('unexpected closing loop: ' + tag);\n                }\n            } else {\n                var render = parseVariableTemplate(tag);\n                var after = parseTemplate(afterTag, loopName);\n                return concat([beforeTag, render, after]);\n            }\n        }\n    };\n\n    return function(template, data) {\n        return parseTemplate(template)(data);\n    };\n});\n\n","/**\n * Recreate DOM `source` in `target` by making only small adjustments.\n *\n * *The following section explains details about the current implementation.\n * These are likely to change in the future.*\n *\n * The algorithms is relatively simple. It just iterates through all top level\n * nodes. If a node has a different `nodeType` (e.g. text or element) or a\n * different `nodeName` (e.g. div or ul) it is replaced completely and the\n * algorithm proceeds with the node's children recursively.  Otherwise, only\n * the nodes's attributes are updated.\n *\n * Note that non-attribute properties (e.g. value) are lost in the first case\n * and preserved in the second.\n *\n * If the algorithm encounters an element with the class `muu-isolate` it does\n * not recurse into its children. This way, you can protect dynamically\n * generated content from being overwritten.\n *\n * @module muu-update-dom\n * @param {DOMElement} target\n * @param {DOMElement} source\n */\ndefine('muu-update-dom',['muu-js-helpers'], function(_) {\n    \"use strict\";\n\n    var updateAttributes = function(target, source) {\n        var targetAttrNames = _.map(target.attributes, function(item) {\n            return item.name;\n        });\n        var sourceAttrNames = _.map(source.attributes, function(item) {\n            return item.name;\n        });\n\n        _.forEach(targetAttrNames, function(name) {\n            // NOTE: ie8.js creates some attribute\n            if (!source.hasAttribute(name) && name.substr(0, 7) !== '__IE8__') {\n                target.removeAttribute(name);\n            }\n        });\n        _.forEach(sourceAttrNames, function(name) {\n            if (target.getAttribute(name) !== source.getAttribute(name)) {\n                target.setAttribute(name, source.getAttribute(name));\n            }\n        });\n    };\n\n    var updateDOM = function(target, source) {\n        var nt = target.childNodes.length;\n        var ns = source.childNodes.length;\n\n        if (target.nodeType === source.nodeType && target.nodeName === source.nodeName && target.type === source.type) {\n            if (target.nodeType === 1) {\n                var muuClasses = _.filter(target.classList, function(cls) {\n                    return cls.lastIndexOf('muu-', 0) === 0;\n                });\n                updateAttributes(target, source);\n                _.forEach(muuClasses, function(cls) {\n                    target.classList.add(cls);\n                });\n            } else if (target.nodeType === 3) {\n                target.nodeValue = source.nodeValue;\n            }\n\n            if (target.nodeType !== 1 || !target.classList.contains('muu-isolate')) {\n                for (var i = ns; i < nt; i++) {\n                    target.removeChild(target.childNodes[ns]);\n                }\n                for (i = nt; i < ns; i++) {\n                    target.appendChild(source.childNodes[nt]);\n                }\n                for (i = 0; i < nt && i < ns; i++) {\n                    updateDOM(target.childNodes[i], source.childNodes[i]);\n                }\n            }\n        } else {\n            target.parentNode.replaceChild(source, target);\n        }\n    };\n\n    return updateDOM;\n});\n\n","/**\n * Exports the {@link Directive} class.\n * @module muu-directive\n */\ndefine('muu-directive',['muu-dom-helpers', 'muu-js-helpers', 'muu-update-dom'], function($, _, updateDOM) {\n    \"use strict\";\n\n    /**\n     * A directive is linked to a DOMElement and manages the DOM tree below\n     * that element (excluding any isolated subtrees, e.g. those managed by\n     * subdirectives).\n     *\n     * It provides a set of methods to interact with the managed part of the\n     * DOM. This is separated into three distinct parts:\n     *\n     * - You can push data to the DOM using the {@link Directive#update}\n     *   method. The DOM will than be updated using the template that was\n     *   provided at construction.\n     * - You can get data from the DOM using the {@link Directive#getModel}\n     *   method. This is however restricted to form field by design.\n     * - You can react to DOM events by specifying an alias for them. In the\n     *   template, you might for example add the attribute\n     *   `data-onclick=\"custom\"` to an element. When there is `click` event on\n     *   that element, a `muu-custom` event will be triggered on the\n     *   directive's root element.\n     *\n     * Directives are typically not created directly but via {@link\n     * Registry#link}.\n     *\n     * @constructs Directive\n     * @param {DOMElement} root\n     * @param {string} template\n     * @param {Muu} registry\n     */\n    var Directive = function(root, template, registry) {\n        var self = this;\n\n        root.innerHTML = '<div></div>';\n\n        var eventCallback = function(originalEvent) {\n            var attrName = 'data-on' + originalEvent.type;\n            if (originalEvent.target.hasAttribute(attrName)) {\n                var eventName = originalEvent.target.getAttribute(attrName);\n                var event = $.createEvent('muu-' + eventName, originalEvent);\n                root.dispatchEvent(event);\n            }\n        };\n\n        /**\n         * Rerender `template` with `data` and push the changes to the DOM.\n         *\n         * See {@link module:muu-update-dom} for details. The templating system\n         * can be defined in the {@link Registry}.\n         *\n         * @param {Object.<string, *>} data\n         */\n        this.update = function(data) {\n            var tmp = document.createElement('div');\n            tmp.innerHTML = registry.renderer(template, data);\n\n            updateDOM(root.children[0], tmp);\n\n            _.forEach(['keydown', 'keyup', 'click', 'change', 'search'], function(eventType) {\n                var selector = '[data-on' + eventType + ']';\n                _.forEach(self.querySelectorAll(selector), function(element) {\n                    element.addEventListener(eventType, eventCallback, false);\n                });\n            });\n\n            var updateEvent = $.createEvent('muu-parent-update');\n            var subDirectives = this.querySelectorAll('muu.muu-initialised');\n            _.forEach(subDirectives, function(element) {\n                element.dispatchEvent(updateEvent);\n            });\n\n            registry.linkAll(self);\n        };\n\n        /**\n         * A variant of `querySelectorAll` that returns only elements from\n         * the managed part of the DOM.\n         *\n         * @private\n         * @param {string} selector\n         * @return {DOMElement[]} All child elements that match the given\n         *     selector and are not isolated.\n         */\n        this.querySelectorAll = function(selector) {\n            var hits = root.querySelectorAll(selector);\n\n            // NOTE: querySelectorAll returns all elements in the tree that\n            // match the given selector.  findAll does the same with *relative\n            // selectors* but does not seem to be available yet.\n            var isolations = root.querySelectorAll('.muu-isolate');\n            var isolated = _.union(_.map(isolations, function(isolation) {\n                return isolation.querySelectorAll(selector);\n            }));\n\n            return _.difference(hits, isolated);\n        };\n\n        /**\n         * A variant of `querySelector` that returns only elements from the\n         * managed part of the DOM.\n         *\n         * @private\n         * @param {String} selector\n         * @return {DOMElement} First child element that matches the given\n         *     selector and is not isolated.\n         */\n        this.querySelector = function(selector) {\n            var all = self.querySelectorAll(selector);\n            if (all.length > 0) {\n                return all[0];\n            }\n        };\n\n        /**\n         * Get all model data as a flat object.\n         *\n         * @return {Object.<string, string|number|boolean>}\n         *//**\n         * Get the value of a form input by name.\n         *\n         * In case of a checkbox, returns `boolean`.\n         * In case of radioboxes, returns the value of the selected box.\n         *\n         * @param {string} name\n         * @param {*} [_default]\n         * @return {string|number|boolean|*}\n         */\n        this.getModel = function(name, _default) {\n            if (name === void 0) {\n                var model = {};\n                _.forEach(self.querySelectorAll('[name]'), function(element) {\n                    model[element.name] = self.getModel(element.name);\n                });\n                return model;\n            } else {\n                var element = self.querySelector('[name=' + name + ']');\n                if (element === void 0) {\n                    return _default;\n                } else if (element.type === 'checkbox') {\n                    return element.checked;\n                } else if (element.type === 'radio') {\n                    var options = self.querySelectorAll('[name=' + name + ']');\n                    return $.getRadio(options) || _default;\n                } else {\n                    return element.value;\n                }\n            }\n        };\n\n        /**\n         * Set the value of a form input by name.\n         *\n         * In case of a checkbox, sets `element.checked`.\n         * In case of radioboxes, selects the box with matching value.\n         *\n         * @param {string} name\n         * @param {string|number|boolean} value\n         */\n        this.setModel = function(name, value) {\n            var element = self.querySelector('[name=' + name + ']');\n            if (element.type === 'checkbox') {\n                element.checked = value;\n            } else if (element.type === 'radio') {\n                var options = self.querySelectorAll('[name=' + name + ']');\n                $.setRadio(options, value);\n            } else {\n                element.value = value;\n            }\n        };\n    };\n\n    return Directive;\n});\n\n","/**\n * Exports the {@link Registry} class.\n * @module muu\n */\ndefine('muu',['muu-template', 'muu-directive', 'muu-js-helpers', 'muu-dom-helpers'], function(muuTemplate, Directive, _, $) {\n    \"use strict\";\n\n    /**\n     * @constructs Registry\n     * @param {object} config The config object may have following properties:\n     *\n     * - **debug** - `{boolean}` - Enable debug mode. In debug mode,\n     *   directive objects are available as properties from the DOM as\n     *   `element.directive`.\n     * - **renderer** - `{Function(string, object)}` - The template renderer\n     *   to be used. Defaults to {@link module:muu-template}.\n     */\n    var Registry = function(config) {\n        var self = this;\n        var directives = {};\n\n        this.config = config || {};\n        this.renderer = self.config.renderer || muuTemplate;\n\n        /**\n         * Register a new type of {@link Directive}\n         *\n         * @param {string} type\n         * @param {string} template\n         * @param {Function(Directive, DOMElement): function} link The link\n         *   function is called with an instance of {@link Directive} and a\n         *   DOMElement when {@link Registry#link} is executed.\n         *\n         *   It is the only place where you can access a directive and\n         *   therefore the place where you define its behavior.\n         *\n         *   This typically means to make an initial call to {@link\n         *   Directive#update} and to add some event listeners. You should also\n         *   return an *unlink* function that clears all external references in\n         *   order to avoid memory leaks.\n         * @return {Registry} this\n         */\n        this.registerDirective = function(type, template, link) {\n            directives[type] = {\n                template: template,\n                link: link\n            };\n            return self;\n        };\n\n        /**\n         * Shortcut for wrapping calls to {@link Registry} in a function.\n         *\n         * This can be esepcially helpful if that function is defined in a\n         * different module.\n         *\n         * ```.js\n         * define('foobar', [], function() {\n         *   return function(registry) {\n         *     registry\n         *        .registerDirective('foo', '...', function() {...})\n         *        .registerDirective('bar', '...', function() {...});\n         *   };\n         * });\n         *\n         * require(['foobar'], function(foobar) {\n         *   var registry = new Registry();\n         *   registry.registerModule(foobar);\n         * });\n         * ```\n         *\n         * @param {Function(Registry)}\n         * @return {Registry} this\n         */\n        this.registerModule = function(module) {\n            module(self);\n            return self;\n        };\n\n        /**\n         * Create and initialise a {@link Directive} for `element`.\n         *\n         * @param {DOMElement} element\n         * @param {string} type\n         * @return {Directive}\n         */\n        this.link = function(element, type) {\n            if (type === void 0) {\n                type = element.getAttribute('type');\n            }\n\n            if (!directives.hasOwnProperty(type)) {\n                throw new Error('Unknown directive type: ' + type);\n            }\n\n            var template = directives[type].template;\n            var link = directives[type].link;\n\n            var directive = new Directive(element, template, self);\n            var unlink = link(directive, element);\n            element.classList.add('muu-isolate');\n            element.classList.add('muu-initialised');\n\n            if (self.config.debug) {\n                element.directive = directive;\n            }\n\n            if (unlink !== void 0) {\n                $.destroy(element, unlink);\n            }\n\n            return directive;\n        };\n\n        /**\n         * Link all directives that can be found inside `root`.\n         *\n         * @param {DOMElement} root\n         * @return {Directive[]}\n         */\n        this.linkAll = function(root) {\n            // NOTE: root may be a DOM Node or a directive\n            var elements = _.filter(root.querySelectorAll('muu'), function(element) {\n                return !element.classList.contains('muu-initialised');\n            });\n            return _.map(elements, function(element) {\n                return self.link(element);\n            });\n        };\n    };\n\n    return Registry;\n});\n\n"]
    1    -1 
\ No newline at end of file