diff --git a/lib/util/create_component_class.js b/lib/util/create_component_class.js index bdb63fd..7bf507f 100644 --- a/lib/util/create_component_class.js +++ b/lib/util/create_component_class.js @@ -1,6 +1,10 @@ 'use strict'; -var _ = require('milo-core').proto; +var miloCore = require('milo-core') + , _ = miloCore.proto + , check = miloCore.util.check + , Match = check.Match + , componentRegistry = require('../components/c_registry'); module.exports = createComponentClass; @@ -16,23 +20,24 @@ module.exports = createComponentClass; * @param {object=} config.staticMethods - Static methods of the new component (Hash of function name {string} to function {function}) */ function createComponentClass(config) { - var componentRegistry = milo.registry.components; + check(config, { + superClassName: Match.Optional(String), + className: String, + facets: Match.Optional(Object), + methods: Match.Optional(Match.ObjectHash(Function)), + staticMethods: Match.Optional(Match.ObjectHash(Function)), + }); var SuperClass = componentRegistry.get(config.superClassName || 'Component'); var ComponentClass = SuperClass.createComponentClass(config.className, config.facets); - if(config.methods) { - _.extendProto(ComponentClass, config.methods); - } - - if(config.staticMethods) { - if(config.staticMethods.super !== undefined) throw '\'super\' is a reserved keyword'; + if (config.methods) _.extendProto(ComponentClass, config.methods); + if (config.staticMethods) { + if (config.staticMethods.super !== undefined) throw '\'super\' is a reserved keyword'; _.extend(ComponentClass, config.staticMethods); } ComponentClass.super = SuperClass.prototype; - componentRegistry.add(ComponentClass); - return ComponentClass; } diff --git a/milo.bundle.js b/milo.bundle.js index 946caac..9a5a541 100644 --- a/milo.bundle.js +++ b/milo.bundle.js @@ -29,7 +29,7 @@ _.extendProto(Facet, { init: function() {} }); -},{"milo-core":107}],2:[function(require,module,exports){ +},{"milo-core":105}],2:[function(require,module,exports){ 'use strict'; @@ -238,7 +238,7 @@ function FacetedObject$$createFacetedClass(name, facetsClasses, facetsConfig) { } }; -},{"./facet":1,"milo-core":107}],3:[function(require,module,exports){ +},{"./facet":1,"milo-core":105}],3:[function(require,module,exports){ 'use strict'; var miloCore = require('milo-core') @@ -358,7 +358,7 @@ function setClass(FoundationClass) { _.defineProperty(this, 'FoundationClass', FoundationClass, _.ENUM); } -},{"milo-core":107}],4:[function(require,module,exports){ +},{"milo-core":105}],4:[function(require,module,exports){ 'use strict'; var Attribute = require('./a_class') @@ -508,7 +508,7 @@ function BindAttribute$$setInfo(el, componentClass, componentName, componentFace attr.decorate(); } -},{"../config":64,"./a_class":5,"milo-core":107}],5:[function(require,module,exports){ +},{"../config":64,"./a_class":5,"milo-core":105}],5:[function(require,module,exports){ 'use strict'; var miloCore = require('milo-core') @@ -628,7 +628,7 @@ function toBeImplemented() { throw new Error('calling the method of an absctract class'); } -},{"milo-core":107}],6:[function(require,module,exports){ +},{"milo-core":105}],6:[function(require,module,exports){ 'use strict'; var Attribute = require('./a_class') @@ -714,7 +714,7 @@ function render() { return this.loadUrl; } -},{"../config":64,"./a_class":5,"milo-core":107}],7:[function(require,module,exports){ +},{"../config":64,"./a_class":5,"milo-core":105}],7:[function(require,module,exports){ 'use strict'; /** @@ -894,7 +894,7 @@ function createBinderScope(scopeEl, scopeObjectFactory, rootScope, bindRootEleme } } -},{"./attributes/a_bind":4,"./components/c_facets/cf_registry":30,"./components/c_info":31,"./components/c_registry":32,"./components/scope":40,"./services/mail":70,"./util/dom":79,"milo-core":107}],9:[function(require,module,exports){ +},{"./attributes/a_bind":4,"./components/c_facets/cf_registry":30,"./components/c_info":31,"./components/c_registry":32,"./components/scope":40,"./services/mail":70,"./util/dom":79,"milo-core":105}],9:[function(require,module,exports){ 'use strict'; var coreClasses = require('milo-core').classes; @@ -921,7 +921,7 @@ var classes = { module.exports = classes; -},{"./abstract/facet":1,"./abstract/faceted_object":2,"./abstract/registry":3,"./command/transaction":13,"./command/transaction_history":14,"./components/msg_src/dom_events":38,"./components/scope":40,"milo-core":107}],10:[function(require,module,exports){ +},{"./abstract/facet":1,"./abstract/faceted_object":2,"./abstract/registry":3,"./command/transaction":13,"./command/transaction_history":14,"./components/msg_src/dom_events":38,"./components/scope":40,"milo-core":105}],10:[function(require,module,exports){ 'use strict'; @@ -1071,7 +1071,7 @@ function ActionsHistory$getDescription() { }; } -},{"milo-core":107}],11:[function(require,module,exports){ +},{"milo-core":105}],11:[function(require,module,exports){ 'use strict'; var ClassRegistry = require('../abstract/registry') @@ -1288,7 +1288,7 @@ function Command$getDescription() { }; } -},{"milo-core":107}],13:[function(require,module,exports){ +},{"milo-core":105}],13:[function(require,module,exports){ 'use strict'; @@ -1362,7 +1362,7 @@ function Transaction$getDescription() { } } -},{"./actions_history":10,"milo-core":107}],14:[function(require,module,exports){ +},{"./actions_history":10,"milo-core":105}],14:[function(require,module,exports){ 'use strict'; @@ -1520,7 +1520,7 @@ function TransactionHistory$destroy() { delete this.transactions; } -},{"./actions_history":10,"./transaction":13,"milo-core":107}],15:[function(require,module,exports){ +},{"./actions_history":10,"./transaction":13,"milo-core":105}],15:[function(require,module,exports){ 'use strict'; @@ -2442,7 +2442,7 @@ function Component$isDestroyed() { return this._destroyed; } -},{"../abstract/faceted_object":2,"../attributes/a_bind":4,"../binder":8,"../config":64,"../util/component_name":76,"../util/dom":79,"../util/storage":89,"./c_facets/cf_registry":30,"./c_utils":33,"./scope":40,"milo-core":107}],16:[function(require,module,exports){ +},{"../abstract/faceted_object":2,"../attributes/a_bind":4,"../binder":8,"../config":64,"../util/component_name":76,"../util/dom":79,"../util/storage":89,"./c_facets/cf_registry":30,"./c_utils":33,"./scope":40,"milo-core":105}],16:[function(require,module,exports){ 'use strict'; /** @@ -2663,7 +2663,7 @@ function requiresFacet(facetName) { || facetRequire.indexOf(_.firstLowerCase(facetName)) >= 0); } -},{"../abstract/facet":1,"./c_utils":33,"milo-core":107}],17:[function(require,module,exports){ +},{"../abstract/facet":1,"./c_utils":33,"milo-core":105}],17:[function(require,module,exports){ 'use strict'; @@ -2853,7 +2853,7 @@ function Container$remove(comp) { this.owner.el.removeChild(comp.el); } -},{"../../binder":8,"../../util/dom":79,"../c_facet":16,"../scope":40,"./cf_registry":30,"milo-core":107}],18:[function(require,module,exports){ +},{"../../binder":8,"../../util/dom":79,"../c_facet":16,"../scope":40,"./cf_registry":30,"milo-core":105}],18:[function(require,module,exports){ 'use strict'; var miloCore = require('milo-core') @@ -3533,7 +3533,7 @@ function Data$setState(state) { return this.set(state.state); } -},{"../c_facet":16,"../msg_api/data":35,"../msg_api/de_data":36,"../msg_src/dom_events":38,"./cf_registry":30,"milo-core":107}],19:[function(require,module,exports){ +},{"../c_facet":16,"../msg_api/data":35,"../msg_api/de_data":36,"../msg_src/dom_events":38,"./cf_registry":30,"milo-core":105}],19:[function(require,module,exports){ 'use strict'; @@ -3871,7 +3871,7 @@ function hasTextAfterSelection() { return isText; } -},{"../../attributes/a_bind":4,"../../binder":8,"../../config":64,"../../util/dom":79,"../c_facet":16,"./cf_registry":30,"milo-core":107}],20:[function(require,module,exports){ +},{"../../attributes/a_bind":4,"../../binder":8,"../../config":64,"../../util/dom":79,"../c_facet":16,"./cf_registry":30,"milo-core":105}],20:[function(require,module,exports){ 'use strict'; // @@ -4090,7 +4090,7 @@ function _dragIsDisabled(event) { return false; } -},{"../../util/dragdrop":82,"../c_class":15,"../c_facet":16,"../msg_src/dom_events":38,"./cf_registry":30,"milo-core":107}],21:[function(require,module,exports){ +},{"../../util/dragdrop":82,"../c_class":15,"../c_facet":16,"../msg_src/dom_events":38,"./cf_registry":30,"milo-core":105}],21:[function(require,module,exports){ 'use strict'; // @@ -4276,7 +4276,7 @@ function _isDropAllowed(dt, originalDropComponent) { // TODO test for other data types } -},{"../../util/dragdrop":82,"../c_facet":16,"../msg_api/drop":37,"../msg_src/dom_events":38,"./cf_registry":30,"milo-core":107}],22:[function(require,module,exports){ +},{"../../util/dragdrop":82,"../c_facet":16,"../msg_api/drop":37,"../msg_src/dom_events":38,"./cf_registry":30,"milo-core":105}],22:[function(require,module,exports){ 'use strict'; var ComponentFacet = require('../c_facet') @@ -4336,7 +4336,7 @@ function Events$init() { _.defineProperty(this, MSG_SOURCE_KEY, domEventsSource); } -},{"../c_facet":16,"../msg_src/dom_events":38,"./cf_registry":30,"milo-core":107}],23:[function(require,module,exports){ +},{"../c_facet":16,"../msg_src/dom_events":38,"./cf_registry":30,"milo-core":105}],23:[function(require,module,exports){ 'use strict'; @@ -4526,7 +4526,7 @@ function _makeWhenReadyFunc(isReadyFunc, event) { } } -},{"../../services/de_constrs":68,"../c_facet":16,"../msg_src/frame":39,"./cf_registry":30,"milo-core":107}],24:[function(require,module,exports){ +},{"../../services/de_constrs":68,"../c_facet":16,"../msg_src/frame":39,"./cf_registry":30,"milo-core":105}],24:[function(require,module,exports){ 'use strict'; @@ -4605,7 +4605,7 @@ function ItemFacet$extractItem() { this.list.extractItem(this.index); } -},{"../../services/mail":70,"../c_facet":16,"./cf_registry":30,"milo-core":107}],25:[function(require,module,exports){ +},{"../../services/mail":70,"../c_facet":16,"./cf_registry":30,"milo-core":105}],25:[function(require,module,exports){ 'use strict'; var ComponentFacet = require('../c_facet') @@ -5037,7 +5037,7 @@ function List$destroy() { ComponentFacet.prototype.destroy.apply(this, arguments); } -},{"../../binder":8,"../../config":64,"../../services/mail":70,"../../util/component_name":76,"../../util/dom":79,"../c_class":15,"../c_facet":16,"./cf_registry":30,"milo-core":107}],26:[function(require,module,exports){ +},{"../../binder":8,"../../config":64,"../../services/mail":70,"../../util/component_name":76,"../../util/dom":79,"../c_class":15,"../c_facet":16,"./cf_registry":30,"milo-core":105}],26:[function(require,module,exports){ 'use strict'; var ComponentFacet = require('../c_facet') @@ -5114,7 +5114,7 @@ function ModelFacet$destroy() { ComponentFacet.prototype.destroy.apply(this, arguments); } -},{"../c_facet":16,"./cf_registry":30,"milo-core":107}],27:[function(require,module,exports){ +},{"../c_facet":16,"./cf_registry":30,"milo-core":105}],27:[function(require,module,exports){ 'use strict'; var ComponentFacet = require('../c_facet') @@ -5155,7 +5155,7 @@ function Options$destroy() { ComponentFacet.prototype.destroy.apply(this, arguments); } -},{"../c_facet":16,"./cf_registry":30,"milo-core":107}],28:[function(require,module,exports){ +},{"../c_facet":16,"./cf_registry":30,"milo-core":105}],28:[function(require,module,exports){ 'use strict'; // @@ -5264,7 +5264,7 @@ function Template$binder() { logger.error('TemplateFacet: Binder called without container facet.'); } -},{"../../binder":8,"../c_facet":16,"./cf_registry":30,"milo-core":107}],29:[function(require,module,exports){ +},{"../../binder":8,"../c_facet":16,"./cf_registry":30,"milo-core":105}],29:[function(require,module,exports){ 'use strict'; var ComponentFacet = require('../c_facet') @@ -5367,7 +5367,7 @@ function Transfer$getComponentMeta() { }; } -},{"../c_facet":16,"./cf_registry":30,"milo-core":107}],30:[function(require,module,exports){ +},{"../c_facet":16,"./cf_registry":30,"milo-core":105}],30:[function(require,module,exports){ 'use strict'; var ClassRegistry = require('../../abstract/registry') @@ -5518,7 +5518,7 @@ function hasContainerFacet(ComponentClass, extraFacetsClasses) { } } -},{"../util/component_name":76,"./c_facets/cf_registry":30,"./c_registry":32,"./scope":40,"milo-core":107}],32:[function(require,module,exports){ +},{"../util/component_name":76,"./c_facets/cf_registry":30,"./c_registry":32,"./scope":40,"milo-core":105}],32:[function(require,module,exports){ 'use strict'; var ClassRegistry = require('../abstract/registry') @@ -5628,7 +5628,7 @@ function _getContainingComponent(el, returnCurrent, conditionFunc) { return _getContainingComponent(el.parentNode, true, conditionFunc); } -},{"../config":64,"milo-core":107}],34:[function(require,module,exports){ +},{"../config":64,"milo-core":105}],34:[function(require,module,exports){ 'use strict'; var Component = require('../c_class') @@ -5727,7 +5727,7 @@ function createInternalData(sourceMessage, message, data) { return internalData; } -},{"./de_data":36,"milo-core":107}],36:[function(require,module,exports){ +},{"./de_data":36,"milo-core":105}],36:[function(require,module,exports){ 'use strict'; @@ -5871,7 +5871,7 @@ function inputChangeEvent(el) { : inputElementTypes.byDefault.event; } -},{"milo-core":107}],37:[function(require,module,exports){ +},{"milo-core":105}],37:[function(require,module,exports){ 'use strict'; @@ -5923,7 +5923,7 @@ function filterSourceMessage(sourceMessage, message, data) { // data is DOM even return ok; } -},{"milo-core":107}],38:[function(require,module,exports){ +},{"milo-core":105}],38:[function(require,module,exports){ 'use strict'; @@ -5970,7 +5970,7 @@ function emitter() { return this.component.el; } -},{"../../services/dom_source":69,"../c_class":15,"milo-core":107}],39:[function(require,module,exports){ +},{"../../services/dom_source":69,"../c_class":15,"milo-core":105}],39:[function(require,module,exports){ 'use strict'; // ###component iframe source @@ -6046,7 +6046,7 @@ function handleEvent(event) { this.dispatchMessage(event.data.type, event); } -},{"../c_class":15,"milo-core":107}],40:[function(require,module,exports){ +},{"../c_class":15,"milo-core":105}],40:[function(require,module,exports){ 'use strict'; var miloCore = require('milo-core') @@ -6312,7 +6312,7 @@ function Scope$$rename(obj, name, renameInScope) { obj.name = name; } -},{"../util/component_name":76,"milo-core":107}],41:[function(require,module,exports){ +},{"../util/component_name":76,"milo-core":105}],41:[function(require,module,exports){ 'use strict'; var Component = require('../c_class') @@ -6346,7 +6346,7 @@ function MLButton$isDisabled() { } -},{"../c_class":15,"../c_registry":32,"milo-core":107}],42:[function(require,module,exports){ +},{"../c_class":15,"../c_registry":32,"milo-core":105}],42:[function(require,module,exports){ 'use strict'; var Component = require('../c_class') @@ -6439,7 +6439,7 @@ function onOptionsChange(msg, data) { }); } -},{"../c_class":15,"../c_registry":32,"milo-core":107}],43:[function(require,module,exports){ +},{"../c_class":15,"../c_registry":32,"milo-core":105}],43:[function(require,module,exports){ 'use strict'; var Component = require('../c_class') @@ -6585,7 +6585,7 @@ function onAddItem(msg, data) { this.events.postMessage('milo_combolistadditem', data); } -},{"../c_class":15,"../c_registry":32,"milo-core":107}],44:[function(require,module,exports){ +},{"../c_class":15,"../c_registry":32,"milo-core":105}],44:[function(require,module,exports){ 'use strict'; var Component = require('../c_class') @@ -6678,7 +6678,7 @@ function toISO8601Format(date) { function pad(n) { return n < 10 ? '0' + n : n; } } -},{"../c_class":15,"../c_registry":32,"milo-core":107}],45:[function(require,module,exports){ +},{"../c_class":15,"../c_registry":32,"milo-core":105}],45:[function(require,module,exports){ 'use strict'; @@ -6797,7 +6797,7 @@ function MLFoldTree$renderTree (data) { } } -},{"../../util/count":77,"../c_class":15,"../c_registry":32,"milo-core":107}],47:[function(require,module,exports){ +},{"../../util/count":77,"../c_class":15,"../c_registry":32,"milo-core":105}],47:[function(require,module,exports){ 'use strict'; var Component = require('../c_class') @@ -6930,7 +6930,7 @@ function onModelChange(path, data) { dispatchChangeMessage.call(this); } -},{"../c_class":15,"../c_registry":32,"milo-core":107}],50:[function(require,module,exports){ +},{"../c_class":15,"../c_registry":32,"milo-core":105}],50:[function(require,module,exports){ 'use strict'; var Component = require('../c_class') @@ -6968,7 +6968,7 @@ function MLInput$setMaxLength(length) { this.el.setAttribute('maxlength', length); } -},{"../c_class":15,"../c_registry":32,"milo-core":107}],51:[function(require,module,exports){ +},{"../c_class":15,"../c_registry":32,"milo-core":105}],51:[function(require,module,exports){ 'use strict'; var Component = require('../c_class') @@ -7091,7 +7091,7 @@ function MLInputList_del() { function MLInputList_splice() { // ... arguments this.model.splice.apply(this.model, arguments); } -},{"../c_class":15,"../c_registry":32,"milo-core":107}],52:[function(require,module,exports){ +},{"../c_class":15,"../c_registry":32,"milo-core":105}],52:[function(require,module,exports){ 'use strict'; var Component = require('../c_class') @@ -7155,7 +7155,7 @@ function onChildrenBound() { this._connector = milo.minder(this.model, '<<<-', this.data).deferChangeMode('<<<->>>'); } -},{"../c_class":15,"../c_registry":32,"milo-core":107}],53:[function(require,module,exports){ +},{"../c_class":15,"../c_registry":32,"milo-core":105}],53:[function(require,module,exports){ 'use strict'; var Component = require('../c_class') @@ -7300,7 +7300,7 @@ function _sendChangeMessage() { -},{"../../util/dragdrop":82,"../c_class":15,"../c_registry":32,"milo-core":107}],54:[function(require,module,exports){ +},{"../../util/dragdrop":82,"../c_class":15,"../c_registry":32,"milo-core":105}],54:[function(require,module,exports){ 'use strict'; var Component = require('../c_class') @@ -7464,7 +7464,7 @@ function MLRadioGroup$destroy() { Component.prototype.destroy.apply(this, arguments); } -},{"../../util/count":77,"../c_class":15,"../c_registry":32,"milo-core":107}],55:[function(require,module,exports){ +},{"../../util/count":77,"../c_class":15,"../c_registry":32,"milo-core":105}],55:[function(require,module,exports){ 'use strict'; var Component = require('../c_class') @@ -7523,7 +7523,7 @@ function onOptionsChange(path, data) { this.template.render({ selectOptions: this.model.get() }); } -},{"../c_class":15,"../c_registry":32,"milo-core":107}],56:[function(require,module,exports){ +},{"../c_class":15,"../c_registry":32,"milo-core":105}],56:[function(require,module,exports){ 'use strict'; /** @@ -8148,7 +8148,7 @@ function _setData() { this.setFilteredOptions(this._optionsData); } -},{"../c_class":15,"../c_registry":32,"milo-core":107}],57:[function(require,module,exports){ +},{"../c_class":15,"../c_registry":32,"milo-core":105}],57:[function(require,module,exports){ 'use strict'; var Component = require('../c_class') @@ -8257,7 +8257,7 @@ function MLTextarea$destroy() { function MLTextarea$disable(disable) { this.el.disabled = disable; } -},{"../c_class":15,"../c_registry":32,"milo-core":107}],59:[function(require,module,exports){ +},{"../c_class":15,"../c_registry":32,"milo-core":105}],59:[function(require,module,exports){ 'use strict'; var Component = require('../c_class') @@ -8320,7 +8320,7 @@ function MLTime_del() { this.el.value = ''; } -},{"../c_class":15,"../c_registry":32,"milo-core":107}],60:[function(require,module,exports){ +},{"../c_class":15,"../c_registry":32,"milo-core":105}],60:[function(require,module,exports){ 'use strict'; var Component = require('../c_class') @@ -8511,7 +8511,7 @@ function _toggleAlert(doShow) { this.el[doShow ? 'focus' : 'blur'](); } -},{"../../../util/component_name":76,"../../c_class":15,"../../c_registry":32,"milo-core":107}],62:[function(require,module,exports){ +},{"../../../util/component_name":76,"../../c_class":15,"../../c_registry":32,"milo-core":105}],62:[function(require,module,exports){ 'use strict'; var Component = require('../../c_class') @@ -8855,7 +8855,7 @@ function MLDialog$destroy() { Component.prototype.destroy.apply(this, arguments); } -},{"../../../util/component_name":76,"../../c_class":15,"../../c_registry":32,"milo-core":107}],63:[function(require,module,exports){ +},{"../../../util/component_name":76,"../../c_class":15,"../../c_registry":32,"milo-core":105}],63:[function(require,module,exports){ 'use strict'; var Component = require('../../c_class') @@ -8970,7 +8970,7 @@ function MLDropdown$toggleMenu(doShow) { : 'none'; } -},{"../../../util/dom_listeners":80,"../../c_class":15,"../../c_registry":32,"milo-core":107}],64:[function(require,module,exports){ +},{"../../../util/dom_listeners":80,"../../c_class":15,"../../c_registry":32,"milo-core":105}],64:[function(require,module,exports){ 'use strict'; @@ -9043,7 +9043,7 @@ config({ } }); -},{"milo-core":107}],65:[function(require,module,exports){ +},{"milo-core":105}],65:[function(require,module,exports){ 'use strict'; @@ -9146,7 +9146,7 @@ function loadView(el, removeAttribute, callback) { }); } -},{"./attributes/a_load":6,"./config":64,"./services/mail":70,"./util/dom":79,"./util/request":87,"milo-core":107}],66:[function(require,module,exports){ +},{"./attributes/a_load":6,"./config":64,"./services/mail":70,"./util/dom":79,"./util/request":87,"milo-core":105}],66:[function(require,module,exports){ 'use strict'; var miloCore = require('milo-core') @@ -9236,7 +9236,7 @@ function destroy() { milo.util.destroy(); } -},{"./attributes":7,"./binder":8,"./classes":9,"./command":12,"./components/c_class":15,"./components/c_facet":16,"./config":64,"./loader":65,"./registry":67,"./services/mail":70,"./services/window":73,"./use_components":74,"./use_facets":75,"./util":85,"./util/create_component_class":78,"milo-core":107}],67:[function(require,module,exports){ +},{"./attributes":7,"./binder":8,"./classes":9,"./command":12,"./components/c_class":15,"./components/c_facet":16,"./config":64,"./loader":65,"./registry":67,"./services/mail":70,"./services/window":73,"./use_components":74,"./use_facets":75,"./util":85,"./util/create_component_class":78,"milo-core":105}],67:[function(require,module,exports){ 'use strict'; /** @@ -9302,7 +9302,7 @@ _.eachKey(eventTypes, function(eTypes, eventConstructorName) { module.exports = domEventsConstructors; -},{"milo-core":107}],69:[function(require,module,exports){ +},{"milo-core":105}],69:[function(require,module,exports){ 'use strict'; @@ -9402,7 +9402,7 @@ function trigger(eventType, properties) { return notCancelled; } -},{"../components/c_class":15,"./de_constrs":68,"milo-core":107}],70:[function(require,module,exports){ +},{"../components/c_class":15,"./de_constrs":68,"milo-core":105}],70:[function(require,module,exports){ 'use strict'; /** @@ -9435,7 +9435,7 @@ miloMail._setMessageSource(mailMsgSource); module.exports = miloMail; -},{"./mail_api":71,"./mail_source":72,"milo-core":107}],71:[function(require,module,exports){ +},{"./mail_api":71,"./mail_source":72,"milo-core":105}],71:[function(require,module,exports){ 'use strict'; var miloCore = require('milo-core') @@ -9481,7 +9481,7 @@ function filterSourceMessage(sourceMessage, msgType, msgData) { return windowMessagePrefix + msgData.data.type == msgType; }; -},{"milo-core":107}],72:[function(require,module,exports){ +},{"milo-core":105}],72:[function(require,module,exports){ 'use strict'; var miloCore = require('milo-core') @@ -9560,7 +9560,7 @@ function trigger(msgType, data) { window.postMessage(data, '*') } -},{"../de_constrs":68,"milo-core":107}],73:[function(require,module,exports){ +},{"../de_constrs":68,"milo-core":105}],73:[function(require,module,exports){ 'use strict'; @@ -9587,7 +9587,7 @@ function windowService_isTop() { return window.top == window.self || window.__karma__; } -},{"./dom_source":69,"milo-core":107}],74:[function(require,module,exports){ +},{"./dom_source":69,"milo-core":105}],74:[function(require,module,exports){ 'use strict'; require('./components/classes/View'); @@ -9677,7 +9677,11 @@ module.exports = uniqueCount; },{}],78:[function(require,module,exports){ 'use strict'; -var _ = require('milo-core').proto; +var miloCore = require('milo-core') + , _ = miloCore.proto + , check = miloCore.util.check + , Match = check.Match + , componentRegistry = require('../components/c_registry'); module.exports = createComponentClass; @@ -9693,28 +9697,29 @@ module.exports = createComponentClass; * @param {object=} config.staticMethods - Static methods of the new component (Hash of function name {string} to function {function}) */ function createComponentClass(config) { - var componentRegistry = milo.registry.components; + check(config, { + superClassName: Match.Optional(String), + className: String, + facets: Match.Optional(Object), + methods: Match.Optional(Match.ObjectHash(Function)), + staticMethods: Match.Optional(Match.ObjectHash(Function)), + }); var SuperClass = componentRegistry.get(config.superClassName || 'Component'); var ComponentClass = SuperClass.createComponentClass(config.className, config.facets); - if(config.methods) { - _.extendProto(ComponentClass, config.methods); - } - - if(config.staticMethods) { - if(config.staticMethods.super !== undefined) throw '\'super\' is a reserved keyword'; + if (config.methods) _.extendProto(ComponentClass, config.methods); + if (config.staticMethods) { + if (config.staticMethods.super !== undefined) throw '\'super\' is a reserved keyword'; _.extend(ComponentClass, config.staticMethods); } ComponentClass.super = SuperClass.prototype; - componentRegistry.add(ComponentClass); - return ComponentClass; } -},{"milo-core":107}],79:[function(require,module,exports){ +},{"../components/c_registry":32,"milo-core":105}],79:[function(require,module,exports){ 'use strict'; @@ -10397,7 +10402,7 @@ function addDebugPoint(x, y) { setTimeout(function() {document.body.appendChild(dbEl);}, 200); } -},{"../config":64,"milo-core":107}],80:[function(require,module,exports){ +},{"../config":64,"milo-core":105}],80:[function(require,module,exports){ 'use strict'; @@ -10454,7 +10459,7 @@ function _removeListener(l) { l.target.removeEventListener(l.eventType, l.handler); } -},{"milo-core":107}],81:[function(require,module,exports){ +},{"milo-core":105}],81:[function(require,module,exports){ 'use strict'; @@ -10503,7 +10508,7 @@ function isReady() { return readyState == 'loading' ? false : readyState; } -},{"milo-core":107}],82:[function(require,module,exports){ +},{"milo-core":105}],82:[function(require,module,exports){ 'use strict'; var Component = require('../components/c_class') @@ -10768,7 +10773,7 @@ function DragDrop_destroy() { dragDropService.offAll(); } -},{"../components/c_class":15,"../config":64,"base32":95,"milo-core":107}],83:[function(require,module,exports){ +},{"../components/c_class":15,"../config":64,"base32":95,"milo-core":105}],83:[function(require,module,exports){ // // milo.utils.error // ----------- @@ -10811,7 +10816,7 @@ function error$toBeImplemented() { throw new error.AbstractClass('calling the method of an absctract class'); } -},{"milo-core":107}],84:[function(require,module,exports){ +},{"milo-core":105}],84:[function(require,module,exports){ 'use strict'; @@ -11016,7 +11021,7 @@ function _createNodesAndPathsFunc(func) { -},{"../attributes/a_bind":4,"../binder":8,"../components/c_class":15,"./dom":79,"milo-core":107}],85:[function(require,module,exports){ +},{"../attributes/a_bind":4,"../binder":8,"../components/c_class":15,"./dom":79,"milo-core":105}],85:[function(require,module,exports){ 'use strict'; var miloCore = require('milo-core'); @@ -11055,7 +11060,7 @@ function util_destroy() { util.dragDrop.destroy(); } -},{"../components/ui/bootstrap/Alert":61,"../components/ui/bootstrap/Dialog":62,"./component_name":76,"./count":77,"./dom":79,"./dom_listeners":80,"./domready":81,"./dragdrop":82,"./error":83,"./fragment":84,"./json_parse":86,"./request":87,"./selection":88,"./storage":89,"./websocket":92,"milo-core":107}],86:[function(require,module,exports){ +},{"../components/ui/bootstrap/Alert":61,"../components/ui/bootstrap/Dialog":62,"./component_name":76,"./count":77,"./dom":79,"./dom_listeners":80,"./domready":81,"./dragdrop":82,"./error":83,"./fragment":84,"./json_parse":86,"./request":87,"./selection":88,"./storage":89,"./websocket":92,"milo-core":105}],86:[function(require,module,exports){ 'use strict'; @@ -11401,7 +11406,7 @@ function whenRequestsCompleted(callback, timeout) { _.defer(callback); } -},{"../config":64,"./count":77,"milo-core":107}],88:[function(require,module,exports){ +},{"../config":64,"./count":77,"milo-core":105}],88:[function(require,module,exports){ 'use strict'; @@ -11843,7 +11848,7 @@ function TextSelection$$getDirection(){ } -},{"../../components/c_class":15,"../dom":79,"milo-core":107}],89:[function(require,module,exports){ +},{"../../components/c_class":15,"../dom":79,"milo-core":105}],89:[function(require,module,exports){ 'use strict'; @@ -12258,7 +12263,7 @@ function DOMStorage$destroy() { this._destroyed = true; } -},{"../../config":64,"./model":90,"./msg_src":91,"milo-core":107}],90:[function(require,module,exports){ +},{"../../config":64,"./model":90,"./msg_src":91,"milo-core":105}],90:[function(require,module,exports){ 'use strict'; var miloCore = require('milo-core') @@ -12286,7 +12291,7 @@ function Model_domStorageParser(valueStr) { return new Model(data); } -},{"./index":89,"milo-core":107}],91:[function(require,module,exports){ +},{"./index":89,"milo-core":105}],91:[function(require,module,exports){ 'use strict'; @@ -12355,7 +12360,7 @@ function handleEvent(event) { this.dispatchMessage(msgType, data); } -},{"../../config":64,"../../util/count":77,"milo-core":107}],92:[function(require,module,exports){ +},{"../../config":64,"../../util/count":77,"milo-core":105}],92:[function(require,module,exports){ 'use strict'; /** @@ -12378,7 +12383,7 @@ function websocket() { module.exports = websocket; -},{"./msg_api":93,"./msg_src":94,"milo-core":107}],93:[function(require,module,exports){ +},{"./msg_api":93,"./msg_src":94,"milo-core":105}],93:[function(require,module,exports){ 'use strict'; var miloCore = require('milo-core') @@ -12425,7 +12430,7 @@ function createInternalData(sourceMessage, message, event) { return internalData; } -},{"milo-core":107}],94:[function(require,module,exports){ +},{"milo-core":105}],94:[function(require,module,exports){ 'use strict'; @@ -12536,7 +12541,7 @@ function WSMessageSource$trigger (msg, data, callback) { } } -},{"../../config":64,"../../util/count":77,"milo-core":107}],95:[function(require,module,exports){ +},{"../../config":64,"../../util/count":77,"milo-core":105}],95:[function(require,module,exports){ ;(function(){ // This would be the place to edit if you want a different @@ -12740,380 +12745,93 @@ if (typeof module !== 'undefined' && module.exports) { // untraditional implementation of this module. },{}],97:[function(require,module,exports){ -// doT.js -// 2011-2014, Laura Doktorova, https://github.com/olado/doT -// Licensed under the MIT license. +'use strict'; -(function() { - "use strict"; +var _ = require('mol-proto') + , check = require('../util/check') + , Match = check.Match + , config = require('../config'); - var doT = { - version: "1.0.3", - templateSettings: { - evaluate: /\{\{([\s\S]+?(\}?)+)\}\}/g, - interpolate: /\{\{=([\s\S]+?)\}\}/g, - encode: /\{\{!([\s\S]+?)\}\}/g, - use: /\{\{#([\s\S]+?)\}\}/g, - useParams: /(^|[^\w$])def(?:\.|\[[\'\"])([\w$\.]+)(?:[\'\"]\])?\s*\:\s*([\w$\.]+|\"[^\"]+\"|\'[^\']+\'|\{[^\}]+\})/g, - define: /\{\{##\s*([\w\.$]+)\s*(\:|=)([\s\S]+?)#\}\}/g, - defineParams:/^\s*([\w$]+):([\s\S]+)/, - conditional: /\{\{\?(\?)?\s*([\s\S]*?)\s*\}\}/g, - iterate: /\{\{~\s*(?:\}\}|([\s\S]+?)\s*\:\s*([\w$]+)\s*(?:\:\s*([\w$]+))?\s*\}\})/g, - varname: "it", - strip: true, - append: true, - selfcontained: false, - doNotSkipEncoded: false - }, - template: undefined, //fn, compile template - compile: undefined //fn, for express - }, _globals; - doT.encodeHTMLSource = function(doNotSkipEncoded) { - var encodeHTMLRules = { "&": "&", "<": "<", ">": ">", '"': """, "'": "'", "/": "/" }, - matchHTML = doNotSkipEncoded ? /[&<>"'\/]/g : /&(?!#?\w+;)|<|>|"|'|\//g; - return function(code) { - return code ? code.toString().replace(matchHTML, function(m) {return encodeHTMLRules[m] || m;}) : ""; - }; - }; +module.exports = Mixin; - _globals = (function(){ return this || (0,eval)("this"); }()); +/** + * `milo.classes.Mixin` - an abstract Mixin class. + * Can be subclassed using: + * ``` + * var MyMixin = _.createSubclass(milo.classes.Mixin, 'MyMixin'); + * ``` + * + * Mixin pattern is also used, but Mixin in milo is implemented as a separate object that is stored on the property of the host object and can create proxy methods on the host object if required. + * Classes [Messenger](../messenger/index.js.html) and [MessageSource](../messenger/m_source.js.html) are subclasses of Mixin abstract class. `this` in proxy methods refers to Mixin instance, the reference to the host object is `this._hostObject`. + * + * @param {Object} hostObject Optional object where a Mixin instance will be stored on. It is used to proxy methods and also to find the reference when it is needed for host object implementation. + * @param {Object} proxyMethods Optional map of proxy method names as keys and Mixin methods names as values, so proxied methods can be renamed to avoid name-space conflicts if two different Mixin instances with the same method names are put on the object + * @param {List} arguments all constructor arguments will be passed to init method of Mixin subclass together with hostObject and proxyMethods + * @return {Mixin} + */ +function Mixin(hostObject, proxyMethods) { // , other args - passed to init method + check(hostObject, Match.Optional(Match.OneOf(Object, Function))); - if (typeof module !== "undefined" && module.exports) { - module.exports = doT; - } else if (typeof define === "function" && define.amd) { - define(function(){return doT;}); - } else { - _globals.doT = doT; - } + // store hostObject + _.defineProperty(this, '_hostObject', hostObject); - var startend = { - append: { start: "'+(", end: ")+'", startencode: "'+encodeHTML(" }, - split: { start: "';out+=(", end: ");out+='", startencode: "';out+=encodeHTML(" } - }, skip = /$^/; + // proxy methods to hostObject + if (proxyMethods) + this._createProxyMethods(proxyMethods); - function resolveDefs(c, block, def) { - return ((typeof block === "string") ? block : block.toString()) - .replace(c.define || skip, function(m, code, assign, value) { - if (code.indexOf("def.") === 0) { - code = code.substring(4); - } - if (!(code in def)) { - if (assign === ":") { - if (c.defineParams) value.replace(c.defineParams, function(m, param, v) { - def[code] = {arg: param, text: v}; - }); - if (!(code in def)) def[code]= value; - } else { - new Function("def", "def['"+code+"']=" + value)(def); - } - } - return ""; - }) - .replace(c.use || skip, function(m, code) { - if (c.useParams) code = code.replace(c.useParams, function(m, s, d, param) { - if (def[d] && def[d].arg && param) { - var rw = (d+":"+param).replace(/'|\\/g, "_"); - def.__exp = def.__exp || {}; - def.__exp[rw] = def[d].text.replace(new RegExp("(^|[^\\w$])" + def[d].arg + "([^\\w$])", "g"), "$1" + param + "$2"); - return s + "def.__exp['"+rw+"']"; - } - }); - var v = new Function("def", "return " + code)(def); - return v ? resolveDefs(c, v, def) : v; - }); - } + // calling init if it is defined in the class + if (this.init) + this.init.apply(this, arguments); +} - function unescape(code) { - return code.replace(/\\('|\\)/g, "$1").replace(/[\r\t\n]/g, " "); - } - doT.template = function(tmpl, c, def) { - c = c || doT.templateSettings; - var cse = c.append ? startend.append : startend.split, needhtmlencode, sid = 0, indv, - str = (c.use || c.define) ? resolveDefs(c, tmpl, def || {}) : tmpl; +/** + * ####Mixin instance methods#### + * These methods are called by constructor, they are not to be called from subclasses. + * + * - [_createProxyMethod](#_createProxyMethod) + * - [_createProxyMethods](#_createProxyMethods) + */ +_.extendProto(Mixin, { + _createProxyMethod: _createProxyMethod, // deprecated, should not be used + _createProxyMethods: _createProxyMethods // deprecated, should not be used +}); - str = ("var out='" + (c.strip ? str.replace(/(^|\r|\n)\t* +| +\t*(\r|\n|$)/g," ") - .replace(/\r|\n|\t|\/\*[\s\S]*?\*\//g,""): str) - .replace(/'|\\/g, "\\$&") - .replace(c.interpolate || skip, function(m, code) { - return cse.start + unescape(code) + cse.end; - }) - .replace(c.encode || skip, function(m, code) { - needhtmlencode = true; - return cse.startencode + unescape(code) + cse.end; - }) - .replace(c.conditional || skip, function(m, elsecase, code) { - return elsecase ? - (code ? "';}else if(" + unescape(code) + "){out+='" : "';}else{out+='") : - (code ? "';if(" + unescape(code) + "){out+='" : "';}out+='"); - }) - .replace(c.iterate || skip, function(m, iterate, vname, iname) { - if (!iterate) return "';} } out+='"; - sid+=1; indv=iname || "i"+sid; iterate=unescape(iterate); - return "';var arr"+sid+"="+iterate+";if(arr"+sid+"){var "+vname+","+indv+"=-1,l"+sid+"=arr"+sid+".length-1;while("+indv+" @@ -13257,7 +12975,7 @@ var classes = { module.exports = classes; -},{"./abstract/mixin":99,"./messenger/m_api":103,"./messenger/m_api_rx":104,"./messenger/m_source":105,"./messenger/msngr_source":106}],101:[function(require,module,exports){ +},{"./abstract/mixin":97,"./messenger/m_api":101,"./messenger/m_api_rx":102,"./messenger/m_source":103,"./messenger/msngr_source":104}],99:[function(require,module,exports){ 'use strict'; @@ -13278,7 +12996,7 @@ config({ debug: false }); -},{"mol-proto":122}],102:[function(require,module,exports){ +},{"mol-proto":122}],100:[function(require,module,exports){ 'use strict'; var Mixin = require('../abstract/mixin') @@ -13943,7 +13661,7 @@ function getMessageSource() { return this._messageSource } -},{"../abstract/mixin":99,"../util/check":118,"./m_source":105,"mol-proto":122}],103:[function(require,module,exports){ +},{"../abstract/mixin":97,"../util/check":116,"./m_source":103,"mol-proto":122}],101:[function(require,module,exports){ 'use strict'; var _ = require('mol-proto') @@ -14136,7 +13854,7 @@ function filterSourceMessage(sourceMessage, message, internalData) { return true; } -},{"../util/logger":120,"mol-proto":122}],104:[function(require,module,exports){ +},{"../util/logger":118,"mol-proto":122}],102:[function(require,module,exports){ 'use strict'; var MessengerAPI = require('./m_api') @@ -14250,7 +13968,7 @@ function getInternalMessages(sourceMessage) { return internalMessages; } -},{"./m_api":103,"mol-proto":122}],105:[function(require,module,exports){ +},{"./m_api":101,"mol-proto":122}],103:[function(require,module,exports){ 'use strict'; var Mixin = require('../abstract/mixin') @@ -14426,7 +14144,7 @@ function toBeImplemented() { throw new Error('calling the method of an absctract class'); } -},{"../abstract/mixin":99,"../util/check":118,"../util/logger":120,"./m_api":103,"mol-proto":122}],106:[function(require,module,exports){ +},{"../abstract/mixin":97,"../util/check":116,"../util/logger":118,"./m_api":101,"mol-proto":122}],104:[function(require,module,exports){ 'use strict'; @@ -14495,7 +14213,7 @@ function MessengerMessageSource$postMessage(message, data) { this.messenger.postMessageSync(message, data); } -},{"../util/check":118,"./m_source":105,"mol-proto":122}],107:[function(require,module,exports){ +},{"../util/check":116,"./m_source":103,"mol-proto":122}],105:[function(require,module,exports){ 'use strict'; var _ = require('mol-proto'); @@ -14536,7 +14254,7 @@ function destroy() { milo.minder.destroy(); } -},{"./classes":100,"./config":101,"./messenger":102,"./minder":108,"./model":111,"./util":119,"mol-proto":122}],108:[function(require,module,exports){ +},{"./classes":98,"./config":99,"./messenger":100,"./minder":106,"./model":109,"./util":117,"mol-proto":122}],106:[function(require,module,exports){ 'use strict'; var Connector = require('./model/connector') @@ -14756,7 +14474,7 @@ function minder_destroy() { } } -},{"./messenger":102,"./model/connector":110,"./util/logger":120,"mol-proto":122}],109:[function(require,module,exports){ +},{"./messenger":100,"./model/connector":108,"./util/logger":118,"mol-proto":122}],107:[function(require,module,exports){ 'use strict'; @@ -14991,7 +14709,7 @@ function executeMethod(modelPath, data) { logger.error('unknown data change type'); } -},{"../config":101,"../util/logger":120,"./path_utils":116,"mol-proto":122}],110:[function(require,module,exports){ +},{"../config":99,"../util/logger":118,"./path_utils":114,"mol-proto":122}],108:[function(require,module,exports){ 'use strict'; var Messenger = require('../messenger') @@ -15404,7 +15122,7 @@ function Connector$destroy() { this._destroyed = true; } -},{"../messenger":102,"../util/logger":120,"./path_utils":116,"mol-proto":122}],111:[function(require,module,exports){ +},{"../messenger":100,"../util/logger":118,"./path_utils":114,"mol-proto":122}],109:[function(require,module,exports){ 'use strict'; var ModelPath = require('./m_path') @@ -15633,7 +15351,7 @@ function Model$destroy() { this._destroyed = true; } -},{"../abstract/mixin":99,"../messenger":102,"../messenger/msngr_source":106,"../util/check":118,"../util/logger":120,"./change_data":109,"./m_msg_api":112,"./m_path":113,"./model_utils":114,"./path_utils":116,"./synthesize":117,"mol-proto":122}],112:[function(require,module,exports){ +},{"../abstract/mixin":97,"../messenger":100,"../messenger/msngr_source":104,"../util/check":116,"../util/logger":118,"./change_data":107,"./m_msg_api":110,"./m_path":111,"./model_utils":112,"./path_utils":114,"./synthesize":115,"mol-proto":122}],110:[function(require,module,exports){ 'use strict'; var MessengerRegexpAPI = require('../messenger/m_api_rx') @@ -15672,7 +15390,7 @@ function translateToSourceMessage(accessPath) { return pathUtils.createRegexPath(accessPath); } -},{"../messenger/m_api_rx":104,"./path_utils":116,"mol-proto":122}],113:[function(require,module,exports){ +},{"../messenger/m_api_rx":102,"./path_utils":114,"mol-proto":122}],111:[function(require,module,exports){ 'use strict'; var synthesize = require('./synthesize') @@ -15969,7 +15687,7 @@ function ModelPath$destroy() { this[MESSENGER_PROPERTY].destroy(); } -},{"../messenger":102,"../messenger/msngr_source":106,"../util/check":118,"./change_data":109,"./path_msg_api":115,"./path_utils":116,"./synthesize":117,"mol-proto":122}],114:[function(require,module,exports){ +},{"../messenger":100,"../messenger/msngr_source":104,"../util/check":116,"./change_data":107,"./path_msg_api":113,"./path_utils":114,"./synthesize":115,"mol-proto":122}],112:[function(require,module,exports){ 'use strict'; @@ -15990,7 +15708,7 @@ function normalizeSpliceIndex(spliceIndex, length) { : 0; } -},{}],115:[function(require,module,exports){ +},{}],113:[function(require,module,exports){ 'use strict'; var MessengerAPI = require('../messenger/m_api') @@ -16091,7 +15809,7 @@ function truncateChangePath(change) { } } -},{"../messenger/m_api":103,"../util/logger":120,"./path_utils":116,"mol-proto":122}],116:[function(require,module,exports){ +},{"../messenger/m_api":101,"../util/logger":118,"./path_utils":114,"mol-proto":122}],114:[function(require,module,exports){ 'use strict'; // @@ -16235,7 +15953,7 @@ function wrapMessengerMethods(methodsNames) { _.defineProperties(this, wrappedMethods); } -},{"../util/check":118,"mol-proto":122}],117:[function(require,module,exports){ +},{"../util/check":116,"mol-proto":122}],115:[function(require,module,exports){ 'use strict'; var pathUtils = require('../path_utils') @@ -16439,7 +16157,7 @@ var modelMethods = _.mapKeys(modelSynthesizers, function(synthesizer) { synthesizePathMethods.modelMethods = modelMethods; -},{"../../util/logger":120,"../change_data":109,"../model_utils":114,"../path_utils":116,"dot":98,"fs":96,"mol-proto":122}],118:[function(require,module,exports){ +},{"../../util/logger":118,"../change_data":107,"../model_utils":112,"../path_utils":114,"dot":121,"fs":96,"mol-proto":122}],116:[function(require,module,exports){ 'use strict'; /** @@ -16815,7 +16533,7 @@ function _prependPath(key, base) { return key + base; }; -},{"../config":101,"mol-proto":122}],119:[function(require,module,exports){ +},{"../config":99,"mol-proto":122}],117:[function(require,module,exports){ 'use strict'; /** @@ -16829,7 +16547,7 @@ var util = { module.exports = util; -},{"./check":118,"./logger":120,"dot":98}],120:[function(require,module,exports){ +},{"./check":116,"./logger":118,"dot":121}],118:[function(require,module,exports){ 'use strict'; // @@ -16859,7 +16577,7 @@ var logger = new Logger({ level: 3 }); module.exports = logger; -},{"./logger_class":121}],121:[function(require,module,exports){ +},{"./logger_class":119}],119:[function(require,module,exports){ 'use strict'; // ### Logger Class @@ -16984,7 +16702,294 @@ levels.forEach(function (name) { module.exports = Logger; -},{"mol-proto":122}],122:[function(require,module,exports){ +},{"mol-proto":122}],120:[function(require,module,exports){ +// doT.js +// 2011-2014, Laura Doktorova, https://github.com/olado/doT +// Licensed under the MIT license. + +(function() { + "use strict"; + + var doT = { + version: "1.0.3", + templateSettings: { + evaluate: /\{\{([\s\S]+?(\}?)+)\}\}/g, + interpolate: /\{\{=([\s\S]+?)\}\}/g, + encode: /\{\{!([\s\S]+?)\}\}/g, + use: /\{\{#([\s\S]+?)\}\}/g, + useParams: /(^|[^\w$])def(?:\.|\[[\'\"])([\w$\.]+)(?:[\'\"]\])?\s*\:\s*([\w$\.]+|\"[^\"]+\"|\'[^\']+\'|\{[^\}]+\})/g, + define: /\{\{##\s*([\w\.$]+)\s*(\:|=)([\s\S]+?)#\}\}/g, + defineParams:/^\s*([\w$]+):([\s\S]+)/, + conditional: /\{\{\?(\?)?\s*([\s\S]*?)\s*\}\}/g, + iterate: /\{\{~\s*(?:\}\}|([\s\S]+?)\s*\:\s*([\w$]+)\s*(?:\:\s*([\w$]+))?\s*\}\})/g, + varname: "it", + strip: true, + append: true, + selfcontained: false, + doNotSkipEncoded: false + }, + template: undefined, //fn, compile template + compile: undefined //fn, for express + }, _globals; + + doT.encodeHTMLSource = function(doNotSkipEncoded) { + var encodeHTMLRules = { "&": "&", "<": "<", ">": ">", '"': """, "'": "'", "/": "/" }, + matchHTML = doNotSkipEncoded ? /[&<>"'\/]/g : /&(?!#?\w+;)|<|>|"|'|\//g; + return function(code) { + return code ? code.toString().replace(matchHTML, function(m) {return encodeHTMLRules[m] || m;}) : ""; + }; + }; + + _globals = (function(){ return this || (0,eval)("this"); }()); + + if (typeof module !== "undefined" && module.exports) { + module.exports = doT; + } else if (typeof define === "function" && define.amd) { + define(function(){return doT;}); + } else { + _globals.doT = doT; + } + + var startend = { + append: { start: "'+(", end: ")+'", startencode: "'+encodeHTML(" }, + split: { start: "';out+=(", end: ");out+='", startencode: "';out+=encodeHTML(" } + }, skip = /$^/; + + function resolveDefs(c, block, def) { + return ((typeof block === "string") ? block : block.toString()) + .replace(c.define || skip, function(m, code, assign, value) { + if (code.indexOf("def.") === 0) { + code = code.substring(4); + } + if (!(code in def)) { + if (assign === ":") { + if (c.defineParams) value.replace(c.defineParams, function(m, param, v) { + def[code] = {arg: param, text: v}; + }); + if (!(code in def)) def[code]= value; + } else { + new Function("def", "def['"+code+"']=" + value)(def); + } + } + return ""; + }) + .replace(c.use || skip, function(m, code) { + if (c.useParams) code = code.replace(c.useParams, function(m, s, d, param) { + if (def[d] && def[d].arg && param) { + var rw = (d+":"+param).replace(/'|\\/g, "_"); + def.__exp = def.__exp || {}; + def.__exp[rw] = def[d].text.replace(new RegExp("(^|[^\\w$])" + def[d].arg + "([^\\w$])", "g"), "$1" + param + "$2"); + return s + "def.__exp['"+rw+"']"; + } + }); + var v = new Function("def", "return " + code)(def); + return v ? resolveDefs(c, v, def) : v; + }); + } + + function unescape(code) { + return code.replace(/\\('|\\)/g, "$1").replace(/[\r\t\n]/g, " "); + } + + doT.template = function(tmpl, c, def) { + c = c || doT.templateSettings; + var cse = c.append ? startend.append : startend.split, needhtmlencode, sid = 0, indv, + str = (c.use || c.define) ? resolveDefs(c, tmpl, def || {}) : tmpl; + + str = ("var out='" + (c.strip ? str.replace(/(^|\r|\n)\t* +| +\t*(\r|\n|$)/g," ") + .replace(/\r|\n|\t|\/\*[\s\S]*?\*\//g,""): str) + .replace(/'|\\/g, "\\$&") + .replace(c.interpolate || skip, function(m, code) { + return cse.start + unescape(code) + cse.end; + }) + .replace(c.encode || skip, function(m, code) { + needhtmlencode = true; + return cse.startencode + unescape(code) + cse.end; + }) + .replace(c.conditional || skip, function(m, elsecase, code) { + return elsecase ? + (code ? "';}else if(" + unescape(code) + "){out+='" : "';}else{out+='") : + (code ? "';if(" + unescape(code) + "){out+='" : "';}out+='"); + }) + .replace(c.iterate || skip, function(m, iterate, vname, iname) { + if (!iterate) return "';} } out+='"; + sid+=1; indv=iname || "i"+sid; iterate=unescape(iterate); + return "';var arr"+sid+"="+iterate+";if(arr"+sid+"){var "+vname+","+indv+"=-1,l"+sid+"=arr"+sid+".length-1;while("+indv+" 23 || mins > 59) return;\n var time = new Date(1970, 0, 1, hours, mins);\n\n return _.toDate(time);\n}\n\n\nfunction MLTime_set(value) {\n var time = _.toDate(value);\n if (! time) {\n this.el.value = '';\n return;\n }\n\n var timeStr = TIME_TEMPLATE\n .replace('hh', pad(time.getHours()))\n .replace('mm', pad(time.getMinutes()));\n\n this.el.value = timeStr;\n return timeStr;\n\n function pad(n) {return n < 10 ? '0' + n : n; }\n}\n\n\nfunction MLTime_del() {\n this.el.value = '';\n}\n", "'use strict';\n\nvar Component = require('../c_class')\n , componentsRegistry = require('../c_registry');\n\n\nvar MLWrapper = Component.createComponentClass('MLWrapper', {\n container: undefined,\n data: undefined,\n events: undefined,\n dom: {\n cls: 'ml-ui-wrapper'\n }\n});\n\ncomponentsRegistry.add(MLWrapper);\n\nmodule.exports = MLWrapper;\n", "'use strict';\n\nvar Component = require('../../c_class')\n , componentsRegistry = require('../../c_registry')\n , componentName = require('../../../util/component_name')\n , miloCore = require('milo-core')\n , logger = miloCore.util.logger\n , check = miloCore.util.check\n , Match = check.Match\n , _ = miloCore.proto;\n\n\nvar ALERT_CSS_CLASSES = {\n success: 'alert-success',\n warning: 'alert-warning',\n info: 'alert-info',\n danger: 'alert-danger',\n fixed: 'alert-fixed'\n};\n\n\nvar MLAlert = Component.createComponentClass('MLAlert', {\n container: undefined,\n events: undefined,\n dom: {\n cls: ['ml-bs-alert', 'alert', 'fade'],\n attributes: {\n 'role': 'alert',\n 'aria-hidden': 'true'\n }\n },\n template: {\n template: '\\\n {{? it.close }}\\\n \\\n {{?}}\\\n {{= it.message}}'\n }\n});\n\ncomponentsRegistry.add(MLAlert);\n\nmodule.exports = MLAlert;\n\n\n_.extend(MLAlert, {\n createAlert: MLAlert$$createAlert,\n openAlert: MLAlert$$openAlert,\n});\n\n\n_.extendProto(MLAlert, {\n openAlert: MLAlert$openAlert,\n closeAlert: MLAlert$closeAlert\n});\n\n\n/**\n * Creates and returns a new alert instance. To create and open at the same time use [openAlert](#MLAlert$$openAlert)\n * `options` is an object with the following properties:\n *\n * message: string alert message\n * type: optional string the type of alert message, one of success, warning, info, danger, fixed\n * default 'info'\n * close: optional false to prevent user from closing\n * or true (default) to enable closing and render a close button\n * timeout: optional timer, in milliseconds to automatically close the alert\n *\n * @param {Object} options alert configuration\n */\nfunction MLAlert$$createAlert(options) {\n check(options, {\n message: String,\n type: Match.Optional(String),\n close: Match.Optional(Boolean),\n timeout: Match.Optional(Number)\n });\n\n var alert = MLAlert.createOnElement();\n\n options = _prepareOptions(options);\n\n var alertCls = ALERT_CSS_CLASSES[options.type];\n alert.dom.addCssClasses(alertCls);\n\n alert._alert = {\n options: options,\n visible: false\n };\n\n alert.template.render(options).binder();\n\n var alertScope = alert.container.scope;\n\n if (options.close)\n alertScope.closeBtn.events.on('click',\n { subscriber: _onCloseBtnClick, context: alert });\n\n if (options.timeout)\n var timer = setTimeout(function(){\n if(alert._alert.visible)\n alert.closeAlert();\n }, options.timeout);\n\n return alert;\n}\n\n\n/**\n * Create and show alert popup\n *\n * @param {Object} options object with message, type, close and timeout\n * @return {MLAlert} the alert instance\n */\nfunction MLAlert$$openAlert(options) {\n var alert = MLAlert.createAlert(options);\n alert.openAlert();\n return alert;\n}\n\n\nfunction _onCloseBtnClick(type, event) {\n this.closeAlert();\n}\n\n\nfunction _prepareOptions(options) {\n options = _.clone(options);\n options.close = typeof options.close == 'undefined' || options.close === true;\n options.timeout = Math.floor(options.timeout);\n options.type = options.type || 'info';\n\n return options;\n}\n\n\n/**\n * Open the alert\n */\nfunction MLAlert$openAlert() {\n _toggleAlert.call(this, true);\n}\n\n\n/**\n * Close the alert\n */\nfunction MLAlert$closeAlert() {\n _toggleAlert.call(this, false);\n this.destroy();\n}\n\n\nfunction _toggleAlert(doShow) {\n doShow = typeof doShow == 'undefined'\n ? ! this._alert.visible\n : !! doShow;\n\n var addRemove = doShow ? 'add' : 'remove'\n , appendRemove = doShow ? 'appendChild' : 'removeChild';\n\n this._alert.visible = doShow;\n\n document.body[appendRemove](this.el);\n this.dom.toggle(doShow);\n this.el.setAttribute('aria-hidden', !doShow);\n this.el.classList[addRemove]('in');\n this.el[doShow ? 'focus' : 'blur']();\n}\n", - "'use strict';\n\nvar Component = require('../../c_class')\n , componentsRegistry = require('../../c_registry')\n , componentName = require('../../../util/component_name')\n , miloCore = require('milo-core')\n , logger = miloCore.util.logger\n , check = miloCore.util.check\n , Match = check.Match\n , _ = miloCore.proto;\n\n\nvar DEFAULT_BUTTONS = [ { type: 'default', label: 'OK', result: 'OK' } ];\n\nvar CLOSE_OPTIONS = ['backdrop', 'keyboard', 'button'];\n\nvar BUTTON_CSS_CLASSES = { // TODO - use in template\n default: 'btn-default',\n primary: 'btn-primary',\n success: 'btn-success',\n info: 'btn-info',\n warning: 'btn-warning',\n danger: 'btn-danger',\n link: 'btn-link'\n};\n\n\n/**\n * Dialog class to show custom dialog boxes based on configuration - see [createDialog](#MLDialog$$createDialog) method.\n * Only one dialog can be opened at a time - trying to open another will log error to console. Currently opened dialog can be retrieved using [getCurrentDialog](#MLDialog$$getCurrentDialog) class method.\n */\nvar MLDialog = Component.createComponentClass('MLDialog', {\n container: undefined,\n events: undefined,\n dom: {\n cls: ['ml-bs-dialog', 'modal', 'fade'],\n attributes: {\n 'role': 'dialog',\n 'aria-hidden': 'true'\n }\n },\n template: {\n template: '\\\n
\\\n
\\\n {{? it.title }}\\\n
\\\n {{? it.close.button }}\\\n \\\n {{?}}\\\n

{{= it.title }}

\\\n
\\\n {{?}}\\\n {{? it.html || it.text }}\\\n
\\\n {{? it.html }}\\\n {{= it.html }}\\\n {{??}}\\\n

{{= it.text }}

\\\n {{?}}\\\n
\\\n {{?}}\\\n {{? it.buttons && it.buttons.length }}\\\n
\\\n {{~ it.buttons :btn }}\\\n \\\n {{~}}\\\n
\\\n {{?}}\\\n
\\\n
'\n }\n});\n\ncomponentsRegistry.add(MLDialog);\n\nmodule.exports = MLDialog;\n\n\n_.extend(MLDialog, {\n createDialog: MLDialog$$createDialog,\n openDialog: MLDialog$$openDialog,\n getOpenedDialog: MLDialog$$getOpenedDialog\n});\n\n\n_.extendProto(MLDialog, {\n openDialog: MLDialog$openDialog,\n closeDialog: MLDialog$closeDialog,\n destroy: MLDialog$destroy\n});\n\n\n/**\n * Creates and returns dialog instance. To create and open at the same time [openDialog](#MLDialog$$openDialog)\n * `options` is an object with the following properties:\n *\n * title: optional dialog title\n * html: optional dialog text as html (will take precedence over text if both text nd html are passed)\n * or\n * text: optional dialog text\n * close: optional false to prevent backdrop and esc key from closing the dialog and removing close button in top right corner\n * or true (default) to enable all close options\n * or object with properties\n * backdrop: false or true (default), close dialog when backdrop clicked\n * keyboard: false or true (default), close dialog when esc key is pressed\n * button: false or true (default), show close button in the header (won't be shown if there is no header when title is not passed)\n * buttons: optional array of buttons configurations, where each button config is an object\n * name: optional name of component, should be unique and should not be `closeBtn`, if not passed a timestamp based name will be used\n * type: button type, will determine button CSS style. Possible types are: defult, primary, success, info, warning, danger, link (map to related bootstrap button styles)\n * label: button label\n * close: optional false to prevent this button from closing dialog\n * result: string with dialog close result that will be passed to dialog subscriber as the first parameter\n * data: any value/object or function to create data that will be passed to dialog subscriber as the second parameter.\n * If function is passed it will be called with dialog as context and button options as parameter.\n *\n * If `title` is not passed, dialog will not have title section \n * If neither `text` nor `html` is passed, dialog will not have body section.\n * If `buttons` are not passed, there will only be OK button.\n *\n * When dialog is closed, the subscriber is called with reault and optional data as defined in buttons configurations.\n * If backdrop is clicked or ESC key is pressed the result will be 'dismissed'\n * If close button in the top right corner is clicked, the result will be 'closed' (default result)\n * \n * @param {Object} options dialog configuration\n * @param {Function} initialize function that is called to initialize the dialog\n */\nfunction MLDialog$$createDialog(options, initialize) {\n check(options, {\n title: Match.Optional(String),\n html: Match.Optional(String),\n text: Match.Optional(String),\n close: Match.Optional(Match.OneOf(Boolean, {\n backdrop: Match.Optional(Boolean),\n keyboard: Match.Optional(Boolean),\n button: Match.Optional(Boolean)\n })),\n buttons: Match.Optional([ {\n name: Match.Optional(String),\n type: String,\n label: String,\n close: Match.Optional(Boolean),\n result: Match.Optional(String),\n data: Match.Optional(Match.Any),\n cls: Match.Optional(String)\n } ])\n });\n\n var dialog = MLDialog.createOnElement();\n\n options = _prepareOptions(options);\n dialog._dialog = {\n options: options,\n visible: false\n };\n\n dialog.template\n .render(options)\n .binder();\n\n var dialogScope = dialog.container.scope;\n\n if (options.close.backdrop)\n dialog.events.on('click',\n { subscriber: _onBackdropClick, context: dialog });\n\n if (options.title && options.close.button)\n dialogScope.closeBtn.events.on('click',\n { subscriber: _onCloseBtnClick, context: dialog });\n\n options.buttons.forEach(function(btn) {\n var buttonSubscriber = {\n subscriber: _.partial(_dialogButtonClick, btn),\n context: dialog\n };\n dialogScope[btn.name].events.on('click', buttonSubscriber);\n });\n\n if (initialize) initialize(dialog);\n return dialog;\n}\n\n\nfunction _dialogButtonClick(button) {\n if (button.close !== false)\n _toggleDialog.call(this, false);\n\n var data = _.result(button.data, this, button);\n _dispatchResult.call(this, button.result, data);\n}\n\n\nfunction _dispatchResult(result, data) {\n var subscriber = this._dialog.subscriber;\n if (typeof subscriber == 'function')\n subscriber.call(this, result, data);\n else\n subscriber.subscriber.call(subscriber.context, result, data);\n}\n\n\nfunction _onBackdropClick(eventType, event) {\n if (event.target == this.el)\n this.closeDialog('dismissed');\n}\n\n\nfunction _onCloseBtnClick() {\n this.closeDialog('closed');\n}\n\n\nfunction _onKeyDown(event) {\n if (openedDialog\n && openedDialog._dialog.options.close.keyboard\n && event.keyCode == 27) // esc key\n openedDialog.closeDialog('dismissed');\n}\n\n\nfunction _prepareOptions(options) {\n options = _.clone(options);\n options.buttons = _.clone(options.buttons || DEFAULT_BUTTONS);\n options.buttons.forEach(function(btn) {\n btn.name = btn.name || componentName();\n });\n\n options.close = typeof options.close == 'undefined' || options.close === true\n ? _.object(CLOSE_OPTIONS, true)\n : typeof options.close == 'object'\n ? _.mapToObject(CLOSE_OPTIONS,\n function(opt) { return options.close[opt] !== false; })\n : _.object(CLOSE_OPTIONS, false);\n\n return options;\n}\n\n\n/**\n * Create and show dialog popup\n * \n * @param {Object} options object with title, text and buttons. See [createDialog](#MLDialog$$createDialog) for more information.\n * @param {Function|Object} subscriber optional subscriber function or object that is passed result and optional data. Unless context is defined, dialog will be the context.\n */\nfunction MLDialog$$openDialog(options, subscriber, initialize) {\n var dialog = MLDialog.createDialog(options, initialize);\n dialog.openDialog(subscriber);\n return dialog;\n}\n\n\n\nfunction _toggleDialog(doShow) {\n doShow = typeof doShow == 'undefined'\n ? ! this._dialog.visible\n : !! doShow;\n\n var addRemove = doShow ? 'add' : 'remove'\n , appendRemove = doShow ? 'appendChild' : 'removeChild';\n\n this._dialog.visible = doShow;\n\n if (doShow && ! dialogsInitialized)\n _initializeDialogs();\n\n document.body[appendRemove](this.el);\n if (backdropEl)\n document.body[appendRemove](backdropEl);\n this.dom.toggle(doShow);\n this.el.setAttribute('aria-hidden', !doShow);\n document.body.classList[addRemove]('modal-open');\n this.el.classList[addRemove]('in');\n\n openedDialog = doShow ? this : undefined;\n this.el[doShow ? 'focus' : 'blur']();\n}\n\n\nvar dialogsInitialized, backdropEl;\n\nfunction _initializeDialogs() {\n backdropEl = document.createElement('div');\n backdropEl.className = 'modal-backdrop fade in';\n document.addEventListener('keydown', _onKeyDown);\n dialogsInitialized = true;\n}\n\n\nvar openedDialog;\n\n/**\n * Opens dialog instance.\n * Subscriber object should have the same format as the subscriber for the Messenger (although Messenger is not used) - either function or object with subscriber and context properties.\n * \n * @param {Function|Object} subscriber subscriber object\n */\nfunction MLDialog$openDialog(subscriber) {\n check(subscriber, Match.OneOf(Function, { subscriber: Function, context: Match.Any }));\n\n if (openedDialog)\n return logger.warn('MLDialog openDialog: can\\'t open dialog, another dialog is already open');\n\n this._dialog.subscriber = subscriber;\n _toggleDialog.call(this, true);\n}\n\n\n/**\n * Closes dialog instance, optionally passing result and data to dialog subscriber.\n * If no result is passed, 'closed' will be passed to subscriber.\n *\n * @param {String} result dialog result, passed as the first parameter to subcsriber\n * @param {Any} data optional dialog data, passed as the second parameter to subscriber\n */\nfunction MLDialog$closeDialog(result, data) {\n if (! openedDialog)\n return logger.warn('MLDialog closeDialog: can\\'t close dialog, no dialog open');\n\n result = result || 'closed';\n\n _toggleDialog.call(this, false);\n _dispatchResult.call(this, result, data);\n}\n\n\n/**\n * Returns currently opened dialog\n *\n * @return {MLDialog}\n */\nfunction MLDialog$$getOpenedDialog() {\n return openedDialog;\n}\n\n\nfunction MLDialog$destroy() {\n document.removeEventListener('keydown', _onKeyDown);\n Component.prototype.destroy.apply(this, arguments);\n}\n", + "'use strict';\n\nvar Component = require('../../c_class')\n , componentsRegistry = require('../../c_registry')\n , componentName = require('../../../util/component_name')\n , miloCore = require('milo-core')\n , logger = miloCore.util.logger\n , check = miloCore.util.check\n , Match = check.Match\n , _ = miloCore.proto;\n\n\nvar DEFAULT_BUTTONS = [ { type: 'default', label: 'OK', result: 'OK' } ];\n\nvar CLOSE_OPTIONS = ['backdrop', 'keyboard', 'button'];\n\nvar BUTTON_CSS_CLASSES = { // TODO - use in template\n default: 'btn-default',\n primary: 'btn-primary',\n success: 'btn-success',\n info: 'btn-info',\n warning: 'btn-warning',\n danger: 'btn-danger',\n link: 'btn-link'\n};\n\n\n/**\n * Dialog class to show custom dialog boxes based on configuration - see [createDialog](#MLDialog$$createDialog) method.\n * Only one dialog can be opened at a time - trying to open another will log error to console. Currently opened dialog can be retrieved using [getCurrentDialog](#MLDialog$$getCurrentDialog) class method.\n */\nvar MLDialog = Component.createComponentClass('MLDialog', {\n container: undefined,\n events: undefined,\n dom: {\n cls: ['ml-bs-dialog', 'modal', 'fade'],\n attributes: {\n 'role': 'dialog',\n 'aria-hidden': 'true'\n }\n },\n template: {\n template: '\\\n
\\\n
\\\n {{? it.title }}\\\n
\\\n {{? it.close.button }}\\\n \\\n {{?}}\\\n

{{= it.title }}

\\\n
\\\n {{?}}\\\n {{? it.html || it.text }}\\\n
\\\n {{? it.html }}\\\n {{= it.html }}\\\n {{??}}\\\n

{{= it.text }}

\\\n {{?}}\\\n
\\\n {{?}}\\\n {{? it.buttons && it.buttons.length }}\\\n
\\\n {{~ it.buttons :btn }}\\\n \\\n {{~}}\\\n
\\\n {{?}}\\\n
\\\n
'\n }\n});\n\ncomponentsRegistry.add(MLDialog);\n\nmodule.exports = MLDialog;\n\n\n_.extend(MLDialog, {\n createDialog: MLDialog$$createDialog,\n openDialog: MLDialog$$openDialog,\n getOpenedDialog: MLDialog$$getOpenedDialog\n});\n\n\n_.extendProto(MLDialog, {\n openDialog: MLDialog$openDialog,\n closeDialog: MLDialog$closeDialog,\n destroy: MLDialog$destroy\n});\n\n\n/**\n * Creates and returns dialog instance. To create and open at the same time [openDialog](#MLDialog$$openDialog)\n * `options` is an object with the following properties:\n *\n * title: optional dialog title\n * html: optional dialog text as html (will take precedence over text if both text nd html are passed)\n * or\n * text: optional dialog text\n * close: optional false to prevent backdrop and esc key from closing the dialog and removing close button in top right corner\n * or true (default) to enable all close options\n * or object with properties\n * backdrop: false or true (default), close dialog when backdrop clicked\n * keyboard: false or true (default), close dialog when esc key is pressed\n * button: false or true (default), show close button in the header (won't be shown if there is no header when title is not passed)\n * buttons: optional array of buttons configurations, where each button config is an object\n * name: optional name of component, should be unique and should not be `closeBtn`, if not passed a timestamp based name will be used\n * type: button type, will determine button CSS style. Possible types are: defult, primary, success, info, warning, danger, link (map to related bootstrap button styles)\n * label: button label\n * close: optional false to prevent this button from closing dialog\n * result: string with dialog close result that will be passed to dialog subscriber as the first parameter\n * data: any value/object or function to create data that will be passed to dialog subscriber as the second parameter.\n * If function is passed it will be called with dialog as context and button options as parameter.\n *\n * If `title` is not passed, dialog will not have title section\n * If neither `text` nor `html` is passed, dialog will not have body section.\n * If `buttons` are not passed, there will only be OK button.\n *\n * When dialog is closed, the subscriber is called with reault and optional data as defined in buttons configurations.\n * If backdrop is clicked or ESC key is pressed the result will be 'dismissed'\n * If close button in the top right corner is clicked, the result will be 'closed' (default result)\n *\n * @param {Object} options dialog configuration\n * @param {Function} initialize function that is called to initialize the dialog\n */\nfunction MLDialog$$createDialog(options, initialize) {\n check(options, {\n title: Match.Optional(String),\n html: Match.Optional(String),\n text: Match.Optional(String),\n close: Match.Optional(Match.OneOf(Boolean, {\n backdrop: Match.Optional(Boolean),\n keyboard: Match.Optional(Boolean),\n button: Match.Optional(Boolean)\n })),\n buttons: Match.Optional([ {\n name: Match.Optional(String),\n type: String,\n label: String,\n close: Match.Optional(Boolean),\n result: Match.Optional(String),\n data: Match.Optional(Match.Any),\n cls: Match.Optional(String)\n } ]),\n cssClass: Match.Optional(String)\n });\n\n var dialog = MLDialog.createOnElement();\n\n options = _prepareOptions(options);\n dialog._dialog = {\n options: options,\n visible: false\n };\n\n dialog.template\n .render(options)\n .binder();\n\n var dialogScope = dialog.container.scope;\n\n if (options.close.backdrop)\n dialog.events.on('click',\n { subscriber: _onBackdropClick, context: dialog });\n\n if (options.title && options.close.button)\n dialogScope.closeBtn.events.on('click',\n { subscriber: _onCloseBtnClick, context: dialog });\n\n options.buttons.forEach(function(btn) {\n var buttonSubscriber = {\n subscriber: _.partial(_dialogButtonClick, btn),\n context: dialog\n };\n dialogScope[btn.name].events.on('click', buttonSubscriber);\n });\n\n if (initialize) initialize(dialog);\n return dialog;\n}\n\n\nfunction _dialogButtonClick(button) {\n if (button.close !== false)\n _toggleDialog.call(this, false);\n\n var data = _.result(button.data, this, button);\n _dispatchResult.call(this, button.result, data);\n}\n\n\nfunction _dispatchResult(result, data) {\n var subscriber = this._dialog.subscriber;\n if (typeof subscriber == 'function')\n subscriber.call(this, result, data);\n else\n subscriber.subscriber.call(subscriber.context, result, data);\n}\n\n\nfunction _onBackdropClick(eventType, event) {\n if (event.target == this.el)\n this.closeDialog('dismissed');\n}\n\n\nfunction _onCloseBtnClick() {\n this.closeDialog('closed');\n}\n\n\nfunction _onKeyDown(event) {\n if (openedDialog\n && openedDialog._dialog.options.close.keyboard\n && event.keyCode == 27) // esc key\n openedDialog.closeDialog('dismissed');\n}\n\n\nfunction _prepareOptions(options) {\n options = _.clone(options);\n options.buttons = _.clone(options.buttons || DEFAULT_BUTTONS);\n options.buttons.forEach(function(btn) {\n btn.name = btn.name || componentName();\n });\n\n options.close = typeof options.close == 'undefined' || options.close === true\n ? _.object(CLOSE_OPTIONS, true)\n : typeof options.close == 'object'\n ? _.mapToObject(CLOSE_OPTIONS,\n function(opt) { return options.close[opt] !== false; })\n : _.object(CLOSE_OPTIONS, false);\n\n return options;\n}\n\n\n/**\n * Create and show dialog popup\n *\n * @param {Object} options object with title, text and buttons. See [createDialog](#MLDialog$$createDialog) for more information.\n * @param {Function|Object} subscriber optional subscriber function or object that is passed result and optional data. Unless context is defined, dialog will be the context.\n */\nfunction MLDialog$$openDialog(options, subscriber, initialize) {\n var dialog = MLDialog.createDialog(options, initialize);\n dialog.openDialog(subscriber);\n return dialog;\n}\n\n\n\nfunction _toggleDialog(doShow) {\n doShow = typeof doShow == 'undefined'\n ? ! this._dialog.visible\n : !! doShow;\n\n var addRemove = doShow ? 'add' : 'remove'\n , appendRemove = doShow ? 'appendChild' : 'removeChild';\n\n this._dialog.visible = doShow;\n\n if (doShow && ! dialogsInitialized)\n _initializeDialogs();\n\n document.body[appendRemove](this.el);\n if (backdropEl)\n document.body[appendRemove](backdropEl);\n this.dom.toggle(doShow);\n this.el.setAttribute('aria-hidden', !doShow);\n document.body.classList[addRemove]('modal-open');\n this.el.classList[addRemove]('in');\n\n openedDialog = doShow ? this : undefined;\n this.el[doShow ? 'focus' : 'blur']();\n}\n\n\nvar dialogsInitialized, backdropEl;\n\nfunction _initializeDialogs() {\n backdropEl = document.createElement('div');\n backdropEl.className = 'modal-backdrop fade in';\n document.addEventListener('keydown', _onKeyDown);\n dialogsInitialized = true;\n}\n\n\nvar openedDialog;\n\n/**\n * Opens dialog instance.\n * Subscriber object should have the same format as the subscriber for the Messenger (although Messenger is not used) - either function or object with subscriber and context properties.\n *\n * @param {Function|Object} subscriber subscriber object\n */\nfunction MLDialog$openDialog(subscriber) {\n check(subscriber, Match.OneOf(Function, { subscriber: Function, context: Match.Any }));\n\n if (openedDialog)\n return logger.warn('MLDialog openDialog: can\\'t open dialog, another dialog is already open');\n\n this._dialog.subscriber = subscriber;\n _toggleDialog.call(this, true);\n}\n\n\n/**\n * Closes dialog instance, optionally passing result and data to dialog subscriber.\n * If no result is passed, 'closed' will be passed to subscriber.\n *\n * @param {String} result dialog result, passed as the first parameter to subcsriber\n * @param {Any} data optional dialog data, passed as the second parameter to subscriber\n */\nfunction MLDialog$closeDialog(result, data) {\n if (! openedDialog)\n return logger.warn('MLDialog closeDialog: can\\'t close dialog, no dialog open');\n\n result = result || 'closed';\n\n _toggleDialog.call(this, false);\n _dispatchResult.call(this, result, data);\n}\n\n\n/**\n * Returns currently opened dialog\n *\n * @return {MLDialog}\n */\nfunction MLDialog$$getOpenedDialog() {\n return openedDialog;\n}\n\n\nfunction MLDialog$destroy() {\n document.removeEventListener('keydown', _onKeyDown);\n Component.prototype.destroy.apply(this, arguments);\n}\n", "'use strict';\n\nvar Component = require('../../c_class')\n , componentsRegistry = require('../../c_registry')\n , miloCore = require('milo-core')\n , _ = miloCore.proto\n , logger = miloCore.util.logger\n , DOMListeners = require('../../../util/dom_listeners');\n\n\nvar TOGGLE_CSS_CLASS = 'dropdown-toggle'\n , MENU_CSS_CLASS = 'dropdown-menu';\n\n\nvar MLDropdown = Component.createComponentClass('MLDropdown', {\n events: undefined,\n dom: {\n cls: ['ml-bs-dropdown', 'dropdown']\n }\n});\n\ncomponentsRegistry.add(MLDropdown);\n\nmodule.exports = MLDropdown;\n\n\n_.extendProto(MLDropdown, {\n start: MLDropdown$start,\n destroy: MLDropdown$destroy,\n toggleMenu: MLDropdown$toggleMenu,\n showMenu: MLDropdown$showMenu,\n hideMenu: MLDropdown$hideMenu\n});\n\n\nfunction MLDropdown$start() {\n var toggleEl = this.el.querySelector('.' + TOGGLE_CSS_CLASS)\n , menuEl = this.el.querySelector('.' + MENU_CSS_CLASS);\n\n if (! (toggleEl && menuEl))\n return logger.error('MLDropdown:', TOGGLE_CSS_CLASS, 'or', MENU_CSS_CLASS, 'isn\\'t found');\n\n var doc = window.document\n , clickHandler = this.toggleMenu.bind(this, undefined);\n\n var listeners = new DOMListeners;\n this._dropdown = {\n menu: menuEl,\n visible: false,\n listeners: listeners\n };\n this.hideMenu();\n var self = this;\n\n listeners.add(toggleEl, 'click', clickHandler);\n //maybe only add this events if is open?\n listeners.add(doc, 'mouseout', onDocOut);\n listeners.add(doc, 'click', onClick);\n\n\n function onDocOut(event) {\n var target = event.target\n , relatedTarget = event.relatedTarget\n , listeners = self._dropdown.listeners;\n\n if (isIframe(target))\n listeners.remove(target.contentWindow.document, 'click', onClick);\n\n if (isIframe(relatedTarget))\n listeners.add(relatedTarget.contentWindow.document, 'click', onClick);\n }\n\n function onClick(event) {\n if (!self.el.contains(event.target))\n self.hideMenu();\n }\n}\n\n\nfunction isIframe(el) {\n return el && el.tagName == 'IFRAME';\n}\n\n\nfunction MLDropdown$destroy() {\n this._dropdown.listeners.removeAll();\n delete this._dropdown;\n Component.prototype.destroy.apply(this, arguments);\n}\n\n\nfunction MLDropdown$showMenu() {\n this.toggleMenu(true);\n}\n\n\nfunction MLDropdown$hideMenu() {\n this.toggleMenu(false);\n}\n\n\nfunction MLDropdown$toggleMenu(doShow) {\n doShow = typeof doShow == 'undefined'\n ? ! this._dropdown.visible\n : !! doShow;\n\n this._dropdown.visible = doShow;\n\n var menu = this._dropdown.menu;\n menu.style.display = doShow\n ? 'block'\n : 'none';\n}\n", "'use strict';\n\n\n// \n// milo.config\n// -----------\n\n// It is the function that allows to change milo configurations and also\n// access them on config's properties.\n\n// ```javascript\n// milo.config({\n// attrs: {\n// bind: 'ml-bind',\n// load: 'ml-load'\n// }\n// });\n// ```\n\n\nvar miloCore = require('milo-core')\n , _ = miloCore.proto\n , doT = miloCore.util.doT;\n\n\nvar config = module.exports = miloCore.config;\n\n\nconfig({\n attrs: {\n bind: 'ml-bind',\n load: 'ml-load'\n },\n componentRef: '___milo_component',\n componentPrefix: 'milo_',\n template: {\n compile: doT.compile\n },\n domStorage: {\n typeSuffix: ':___milo_data_type',\n prefixSeparator: '/',\n root: '',\n messageKey: '___milo_message/',\n messageTimestamp: '___milo_timestamp',\n quotaExceeded: {\n throwError: true,\n message: false\n }\n },\n dragDrop: {\n dataTypes: {\n component: 'x-application/milo/component',\n componentMetaTemplate: 'x-application/milo/component-meta/%class/%name/%params',\n componentMetaRegex: /^x\\-application\\/milo\\/component\\-meta\\/([a-z0-9]+)\\/([a-z0-9]+)\\/([a-z0-9]*)$/,\n }\n },\n request: {\n jsonpTimeout: 60000,\n jsonpCallbackPrefix: '___milo_callback_',\n optionsKey: '___milo_options',\n defaults: {\n timeout: 60000\n }\n },\n websocket: {\n rpc: {\n timeout: 15000,\n responsePrefix: 'response_'\n }\n }\n});\n", "'use strict';\n\n\nvar miloMail = require('./services/mail')\n , request = require('./util/request')\n , miloCore = require('milo-core')\n , logger = miloCore.util.logger\n , _ = miloCore.proto\n , utilDom = require('./util/dom')\n , config = require('./config')\n , LoadAttribute = require('./attributes/a_load');\n\n\nmodule.exports = loader;\n\n/**\n * `milo.loader`\n * \n * Recursively scans the document tree inside `rootEl` (document.body by default) looking for __ml-load__ @attribute.\n * One level load is executed. No additional loader get called on inside __ml-load__ attributes. \n *\n * Possible usages:\n * - milo.loader([myRootEl,][myRemoveAttribute,]myCallback)\n * \n * @param {Element} rootEl Root element inside which DOM will be scanned (document.body by default).\n * @param {Boolean} removeAttribute If set to true, then the __ml-load__ attribute will be removed once loader has been executed (False by default).\n * @param {Function} callback Callback to call after all elements get loaded (Required).\n */\nfunction loader(rootEl, removeAttribute, callback) {\n milo(function() {\n _loader(rootEl, removeAttribute, callback);\n });\n}\n\n\nfunction _loader(rootEl, removeAttribute, callback) {\n if (typeof rootEl == 'function') {\n callback = rootEl;\n rootEl = undefined;\n removeAttribute = false;\n }\n\n if (typeof removeAttribute == 'function') {\n callback = removeAttribute;\n removeAttribute = false;\n }\n\n rootEl = rootEl || document.body;\n\n miloMail.postMessage('loader', { state: 'started' });\n _loadViewsInElement(rootEl, removeAttribute, function(views) {\n miloMail.postMessage('loader', { \n state: 'finished',\n views: views\n });\n callback(views);\n });\n}\n\n\nfunction _loadViewsInElement(rootEl, removeAttribute, callback) {\n var loadElements = rootEl.getAttribute(config.attrs.load)\n ? [rootEl]\n : rootEl.querySelectorAll('[' + config.attrs.load + ']');\n\n var views = {}\n , totalCount = loadElements.length\n , loadedCount = 0;\n\n _.forEach(loadElements, function (el) {\n loadView(el, removeAttribute, function(err) {\n views[el.id] = err || el;\n loadedCount++;\n if (loadedCount == totalCount)\n callback(views);\n });\n });\n};\n\n\nfunction loadView(el, removeAttribute, callback) {\n if (utilDom.children(el).length)\n throw new Error('can\\'t load html into element that is not empty');\n\n var attr = new LoadAttribute(el);\n\n attr.parse().validate();\n\n request.get(attr.loadUrl, function(err, html) {\n if (err) {\n err.message = err.message || 'can\\'t load file ' + attr.loadUrl;\n // logger.error(err.message);\n callback(err);\n return;\n }\n\n el.innerHTML = html;\n if (removeAttribute) LoadAttribute.remove(el);\n callback(null);\n });\n}\n", @@ -214,7 +214,7 @@ "'use strict';\n\nrequire('./components/c_facets/Dom');\nrequire('./components/c_facets/Data');\nrequire('./components/c_facets/Frame');\nrequire('./components/c_facets/Events');\nrequire('./components/c_facets/Options');\nrequire('./components/c_facets/Template');\nrequire('./components/c_facets/Container');\nrequire('./components/c_facets/ModelFacet');\nrequire('./components/c_facets/Drag');\nrequire('./components/c_facets/Drop');\nrequire('./components/c_facets/List');\nrequire('./components/c_facets/Item');\nrequire('./components/c_facets/Transfer');\n", "'use strict';\n\nvar count = require('./count')\n , config = require('../config')\n , prefix = config.componentPrefix;\n\n\nmodule.exports = componentName;\n\n\nfunction componentName() {\n return prefix + count();\n}\n", "'use strict';\n\nvar timestamp = Date.now()\n , count = ''\n , uniqueID = '' + timestamp;\n\nfunction uniqueCount() {\n var newTimestamp = Date.now();\n uniqueID = '' + newTimestamp;\n if (timestamp == newTimestamp) {\n count = count === '' ? 0 : count + 1;\n uniqueID += '_' + count;\n } else {\n timestamp = newTimestamp;\n count = '';\n }\n\n return uniqueID;\n}\n\nuniqueCount.get = function() {\n return uniqueID;\n}\n\nmodule.exports = uniqueCount;\n", - "'use strict';\n\nvar _ = require('milo-core').proto;\n\n\nmodule.exports = createComponentClass;\n\n/**\n * Utility function which creates and registers new milo component. The component created will have\n * a reference to the super class used in its creation (Accessable using .super).\n *\n * @param {string} config.className - The name of the new component\n * @param {string} ['Component'] config.superClassName - The name of an existing component to be used as the new component's super class\n * @param {object=} config.facets - Facet configuration (Hash of facet name {string} to config {object})\n * @param {object=} config.methods - Methods of the new component (Hash of function name {string} to function {function})\n * @param {object=} config.staticMethods - Static methods of the new component (Hash of function name {string} to function {function})\n */\nfunction createComponentClass(config) {\n var componentRegistry = milo.registry.components;\n var SuperClass = componentRegistry.get(config.superClassName || 'Component');\n var ComponentClass = SuperClass.createComponentClass(config.className, config.facets);\n\n if(config.methods) {\n _.extendProto(ComponentClass, config.methods);\n }\n\n if(config.staticMethods) {\n if(config.staticMethods.super !== undefined) throw '\\'super\\' is a reserved keyword';\n\n _.extend(ComponentClass, config.staticMethods);\n }\n\n ComponentClass.super = SuperClass.prototype;\n \n componentRegistry.add(ComponentClass);\n\n return ComponentClass;\n}\n", + "'use strict';\n\nvar miloCore = require('milo-core')\n , _ = miloCore.proto\n , check = miloCore.util.check\n , Match = check.Match\n , componentRegistry = require('../components/c_registry');\n\n\nmodule.exports = createComponentClass;\n\n/**\n * Utility function which creates and registers new milo component. The component created will have\n * a reference to the super class used in its creation (Accessable using .super).\n *\n * @param {string} config.className - The name of the new component\n * @param {string} ['Component'] config.superClassName - The name of an existing component to be used as the new component's super class\n * @param {object=} config.facets - Facet configuration (Hash of facet name {string} to config {object})\n * @param {object=} config.methods - Methods of the new component (Hash of function name {string} to function {function})\n * @param {object=} config.staticMethods - Static methods of the new component (Hash of function name {string} to function {function})\n */\nfunction createComponentClass(config) {\n check(config, {\n superClassName: Match.Optional(String),\n className: String,\n facets: Match.Optional(Object),\n methods: Match.Optional(Match.ObjectHash(Function)),\n staticMethods: Match.Optional(Match.ObjectHash(Function)),\n });\n var SuperClass = componentRegistry.get(config.superClassName || 'Component');\n var ComponentClass = SuperClass.createComponentClass(config.className, config.facets);\n\n if (config.methods) _.extendProto(ComponentClass, config.methods);\n\n if (config.staticMethods) {\n if (config.staticMethods.super !== undefined) throw '\\'super\\' is a reserved keyword';\n _.extend(ComponentClass, config.staticMethods);\n }\n\n ComponentClass.super = SuperClass.prototype;\n componentRegistry.add(ComponentClass);\n return ComponentClass;\n}\n", "'use strict';\n\n\nvar config = require('../config')\n , miloCore = require('milo-core')\n , _ = miloCore.proto\n , logger = miloCore.util.logger;\n\nvar domUtils = {\n children: children,\n filterNodeListByType: filterNodeListByType,\n containingElement: containingElement,\n selectElementContents: selectElementContents,\n selectElementText: selectElementText,\n getElementOffset: getElementOffset,\n setCaretPosition: setCaretPosition,\n getSelectionDirection: getSelectionDirection,\n setSelection: setSelection,\n clearSelection: clearSelection,\n removeElement: removeElement,\n unwrapElement: unwrapElement,\n wrapInElement: wrapInElement,\n detachComponent: detachComponent,\n firstTextNode: firstTextNode,\n lastTextNode: lastTextNode,\n trimNodeRight: trimNodeRight,\n trimNodeLeft: trimNodeLeft,\n stripHtml: stripHtml,\n htmlEntities: htmlEntities,\n walkTree: walkTree,\n createTreeWalker: createTreeWalker,\n\n treePathOf: treePathOf,\n getNodeAtTreePath: getNodeAtTreePath,\n insertAtTreePath: insertAtTreePath,\n isTreePathBefore: isTreePathBefore,\n\n getNodeWindow: getNodeWindow,\n\n getComponentsFromRange: getComponentsFromRange,\n deleteRangeWithComponents: deleteRangeWithComponents,\n forEachNodesInRange: forEachNodesInRange,\n areRangesEqual: areRangesEqual,\n\n addDebugPoint: addDebugPoint\n};\n\nmodule.exports = domUtils;\n\n\n/**\n * Returns the list of element children of DOM element\n *\n * @param {Element} el element to return the children of (only DOM elements)\n * @return {Array[Element]}\n */\n function children(el) {\n return filterNodeListByType(el.childNodes, Node.ELEMENT_NODE);\n }\n\n\n/**\n * Filters the list of nodes by type\n *\n * @param {NodeList} nodeList the list of nodes, for example childNodes property of DOM element\n * @param {Integer} nodeType an integer constant [defined by DOM API](https://developer.mozilla.org/en-US/docs/Web/API/Node.nodeType), e.g. `Node.ELEMENT_NODE` or `Node.TEXT_NODE`\n * @return {Array[Node]}\n */\nfunction filterNodeListByType(nodeList, nodeType) {\n return _.filter(nodeList, function (node) {\n return node.nodeType == nodeType;\n });\n}\n\n\n/**\n * Find nearest parent element for node.\n * If node is an element, it will be returned.\n *\n * @param {Node} node\n * @return {Element|null}\n */\nfunction containingElement(node) {\n while (node) {\n if (node.nodeType == Node.ELEMENT_NODE)\n return node;\n node = node.parentNode;\n }\n return null;\n}\n\n\n/**\n * Selects inner contents of DOM element\n *\n * @param {Element} el DOM element\n */\nfunction selectElementContents(el) {\n var doc = el.ownerDocument;\n if (! doc) return logger.error('selectElementContents: element has no document');\n var range = doc.createRange();\n range.selectNodeContents(el);\n var win = getNodeWindow(el)\n , sel = win.getSelection();\n sel.removeAllRanges();\n sel.addRange(range);\n}\n\n\n/**\n * Selects text inside element\n * @param {Element} el\n */\nfunction selectElementText(el) {\n var fromNode = firstTextNode(el)\n , toNode = lastTextNode(el);\n\n if (fromNode && toNode)\n setSelection(fromNode, 0, toNode, toNode.textContent.length);\n}\n\n\n/**\n * Sets the caret position to the position in the node\n *\n * @param {Node} node DOM node\n * @param {Number} pos caret position\n */\nfunction setCaretPosition(node, pos) {\n var doc = node.ownerDocument;\n if (! doc) return logger.error('setCaretPosition: element has no document');\n var range = doc.createRange();\n range.setStart(node, pos);\n var win = getNodeWindow(node)\n , sel = win.getSelection();\n sel.removeAllRanges();\n sel.addRange(range);\n}\n\n/**\n * get the direction of a selection\n *\n * 1 forward, -1 backward, 0 no direction, undefined one of the node is detached or in a different frame\n *\n * @param {sel} a selection object\n * @return {-1|0|1|undefined}\n */\nfunction getSelectionDirection(sel){\n return _getDirection(sel.anchorNode, sel.anchorOffset, sel.focusNode, sel.focusOffset);\n}\n\nfunction _getDirection(fromNode, startOffset, toNode, endOffset){\n var docPosition = fromNode.compareDocumentPosition(toNode);\n if (docPosition & Node.DOCUMENT_POSITION_FOLLOWING){\n return 1;\n }\n else if (docPosition & Node.DOCUMENT_POSITION_PRECEDING){\n return -1;\n }\n else if (fromNode == toNode){\n if (startOffset < endOffset){\n return 1;\n }\n else if (startOffset > endOffset){\n return -1;\n }\n else {\n return 0;\n }\n }\n}\n\n/**\n * Selects a range in a document\n *\n * @param {Node} fromNode DOM node to start selection in\n * @param {Number} startOffset\n * @param {Node} toNode DOM node to end selection in\n * @param {Number} endOffset\n */\nfunction setSelection(fromNode, startOffset, toNode, endOffset) {\n var doc = fromNode.ownerDocument;\n if (! doc) return logger('setCaretPosition: element has no document');\n var backward = _getDirection(fromNode, startOffset, toNode, endOffset) == -1;\n var range = doc.createRange();\n var container, originalContentEditable;\n // does not work in non contentEditable items\n\n var win = getNodeWindow(fromNode)\n , sel = win.getSelection();\n\n\n if (backward){\n range.setStart(toNode, endOffset);\n range.setEnd(fromNode, startOffset);\n range.collapse(false);\n }\n else {\n range.setStart(fromNode, startOffset);\n range.setEnd(toNode, endOffset);\n }\n\n container = range.commonAncestorContainer == Node.ELEMENT_NODE ?\n range.commonAncestorContainer :\n range.commonAncestorContainer.parentElement;\n\n if (!container.isContentEditable){\n originalContentEditable = container.contentEditable; // false or inherit\n container.contentEditable = \"true\";\n }\n\n sel.removeAllRanges();\n sel.addRange(range);\n\n if (backward){\n sel.extend(toNode, endOffset);\n }\n\n if (originalContentEditable){\n // restoring contentEditable\n container.contentEditable = originalContentEditable;\n }\n}\n\n/**\n * Clears selection in a given window\n * @param {Window} win\n */\nfunction clearSelection(win) {\n win = win || window;\n var sel = win.getSelection();\n sel.removeAllRanges();\n}\n\n\n/**\n * Calculates an element's total top and left offset from the document edge.\n *\n * @param {Element} el the element for which position needs to be returned\n * @param {includeBorder} if is to include the border width\n * @return {Object} vector object with properties topOffset and leftOffset\n */\nfunction getElementOffset(el, includeBorder) {\n var yPos, xPos;\n\n yPos = el.offsetTop;\n xPos = el.offsetLeft;\n el = el.offsetParent;\n\n while (el) {\n yPos += el.offsetTop + getBorder(el, 'Height', includeBorder);\n xPos += el.offsetLeft + getBorder(el, 'Width', includeBorder);\n el = el.offsetParent;\n }\n\n return { topOffset: yPos, leftOffset: xPos };\n}\n\n\nfunction getBorder(el, type, includeBorder) {\n if (includeBorder) {\n var side = (type == 'Height') ? 'top' : 'left',\n styles = window.getComputedStyle(el),\n sideValue = parseInt(styles.getPropertyValue('border-' + side + '-width'), 10);\n\n if (sideValue) return sideValue;\n }\n return 0;\n}\n\n\n/**\n * Removes element from the document\n *\n * @param {Element} el the element to be removed\n */\nfunction removeElement(el) {\n var parent = el.parentNode;\n if (parent){\n parent.removeChild(el);\n parent.normalize();\n }\n}\n\n\n/**\n * Returns the first child text node of an element\n *\n * @param {Element|Node} node the node to be searched, if the node is text node we return the node.\n * @return {TextNode}\n */\nfunction firstTextNode(node) {\n if (node.nodeType == Node.TEXT_NODE) return node;\n var treeWalker = createTreeWalker(node, NodeFilter.SHOW_TEXT);\n return treeWalker.firstChild();\n}\n\n\n/**\n * Returns the last child text node of an element\n *\n * @param {Element|Node} node the node to be searched, if the node is text node we return the node.\n * @return {TextNode}\n */\nfunction lastTextNode(node) {\n if (node.nodeType == Node.TEXT_NODE) return node;\n var treeWalker = createTreeWalker(node, NodeFilter.SHOW_TEXT);\n return treeWalker.lastChild();\n}\n\n\n/**\n * Removes element from the document putting its children in its place\n *\n * @param {Element} el the element to be \"unwrapped\"\n */\nfunction unwrapElement(el) {\n var parent = el.parentNode;\n\n if (parent) {\n var frag = document.createDocumentFragment();\n // must be copied to avoid iterating a mutating list of childNodes\n var children = _.slice(el.childNodes);\n children.forEach(frag.appendChild, frag);\n parent.replaceChild(frag, el);\n parent.normalize();\n }\n}\n\n\n/**\n * Wraps an element in another element\n *\n * @param {Element} wrapIntoEl\n * @param {Element} el\n */\nfunction wrapInElement(wrapIntoEl, el) {\n var parent = el.parentNode;\n\n if (parent) {\n parent.insertBefore(wrapIntoEl, el);\n wrapIntoEl.appendChild(el);\n }\n}\n\n\n/**\n * Trims a text node of trailing spaces, and returns true if a trim was performed.\n *\n * @param {TextNode} node\n * @return {Boolean}\n */\nfunction trimNodeRight(node) {\n return _trimNode(node, 'trimRight');\n}\n\n\n/**\n * Trims a text node of leading spaces, and returns true if a trim was performed.\n *\n * @param {TextNode} node\n * @return {Boolean}\n */\nfunction trimNodeLeft(node) {\n return _trimNode(node, 'trimLeft');\n}\n\n\nfunction _trimNode(node, methodName) {\n var len = node.length;\n node.textContent = node.textContent[methodName]();\n return len !== node.length;\n}\n\n\n/**\n * Removes the reference to component from element\n *\n * @param {Element} el\n */\nfunction detachComponent(el) {\n delete el[config.componentRef];\n}\n\n\n/**\n * Retrieves the content of a html string\n * @param {String} str Any string\n * @return {String} returns the string cleaned of any html content.\n */\nfunction stripHtml(str) {\n var div = document.createElement('DIV');\n div.innerHTML = str;\n return div.textContent || '';\n}\n\n\n/**\n * Convenience wrapper for native TreeWalker that automatically walks the tree and calls an iterator function.\n * This will not iterate the root element.\n * @param {HTMLElement} root The containing root element to be walked. Will not be iterated.\n * @param {NodeFiler} filter A NodeFilter constant, see https://developer.mozilla.org/en/docs/Web/API/TreeWalker\n * @param {Function} iterator A function to be called on each node. Returning 'false' will break.\n * @param {Object} context An optional context to passed, defaults to root.\n */\nfunction walkTree(root, filter, iterator, context) {\n var tw = document.createTreeWalker(root, filter);\n while(tw.nextNode()) {\n var result = iterator.call(context || root, tw.currentNode);\n if (result === false) break;\n }\n}\n\n\n/**\n * Returns array of child indexes of element path inside root element in DOM tree using breadth first tree traversal.\n * Returns undefined if the element is not inside root element, 0 if the root element itself is passed.\n *\n * @param {Element} rootEl element to search\n * @param {Element} el element to find the index of\n * @return {Array[Number]}\n */\nfunction treePathOf(rootEl, el) {\n if (! (rootEl && rootEl.contains(el))) return;\n\n var treePath = []\n , node = rootEl;\n\n while (node != el) {\n var nodeIndex = _.findIndex(node.childNodes, containsEl);\n treePath.push(nodeIndex);\n node = node.childNodes[nodeIndex];\n }\n\n return treePath;\n\n function containsEl(child) {\n return child.contains(el);\n }\n}\n\n\n/**\n * Returns element at given tree path\n *\n * @param {Element} rootEl\n * @param {Array[Number]} treePath\n * @param {Boolean} nearest return nearest possible node if exact node does not exist\n * @return {Node}\n */\nfunction getNodeAtTreePath(rootEl, treePath, nearest) {\n if (!treePath) return;\n\n var len = treePath.length;\n if (len === 0) return rootEl;\n\n var node = rootEl;\n\n for (var i = 0; i < len; i++) {\n var children = node.childNodes;\n if (! children) {\n if (! nearest) node = undefined;\n break;\n }\n var childIndex = treePath[i]\n , child = children[childIndex];\n if (! child) {\n node = nearest\n ? children[children.length - 1]\n : undefined;\n break;\n }\n node = child;\n }\n\n return node;\n}\n\n\n/**\n * Inserts an element inside root at a given path in tree (that has the same meaning as the index returned by `treePathOf` function). If element is already in the root's tree, it will be removed first and then moved to the passed treeIndex\n * Insertion at index 0 is not possible and will return undefined as it would mean replacing the root element.\n *\n * @param {Element} rootEl element into which to insert\n * @param {Number} treeIndex index in DOM tree inside root element (see treePathOf)\n * @param {Element} el element to be inserted\n * @return {Boolean} true if was successfully inserted\n */\nfunction insertAtTreePath(rootEl, treePath, el, nearest) {\n var toNormalize = el.nodeType == Node.TEXT_NODE;\n if (rootEl.contains(el))\n removeElement(el); // can't use removeChild as rootEl here is not an immediate parent\n\n if (treePath.length == 0) return;\n\n var parent = getNodeAtTreePath(rootEl, treePath.slice(0, -1), nearest)\n , children = parent.childNodes;\n\n if (! children) {\n if (nearest) {\n parent = parent.parentNode;\n children = parent.childNodes;\n } else return;\n }\n\n var childIndex = treePath[treePath.length - 1]\n , child = children[childIndex];\n\n if (child) {\n parent.insertBefore(el, child);\n if (toNormalize) parent.normalize();\n return true;\n } else if (children.length === 0 && (childIndex === 0 || nearest)) {\n parent.appendChild(el);\n if (toNormalize) parent.normalize();\n return true;\n } else {\n child = children[childIndex - 1];\n if (child || nearest) {\n parent.appendChild(el);\n if (toNormalize) parent.normalize();\n return true;\n }\n }\n}\n\n\n/**\n * Returns `true` if the first tree path points to a node which is before the other in the document order.\n * @param {Array} path1 A treepath array\n * @param {Array} path2 A treepath array\n * @return {Boolean}\n */\nfunction isTreePathBefore(path1, path2) {\n var i = 0\n , isBefore;\n if (!Array.isArray(path1) && Array.isArray(path2))\n return logger.error('isTreePathBefore: One or both paths are not valid treepath arrays.');\n\n for (i; i < path1.length; i++) {\n if (path1[i] < path2[i]) {\n isBefore = true;\n break;\n } else if (path1[i] > path2[i]) {\n isBefore = false;\n break;\n }\n }\n\n if (typeof isBefore == 'undefined')\n if (path1.length < path2.length)\n logger.warn('isTreePathBefore: One node is inside another');\n\n return isBefore || false;\n}\n\n\n/**\n * Converts non latin characters to HTML entity codes.\n * @param {String} str the string to convert\n * @return {String} the string with html entities\n */\nfunction htmlEntities(str) {\n return str.replace(/[\\u00A0-\\u99999<>\\&]/gim, function(i) {\n return '&#'+i.charCodeAt(0)+';';\n });\n}\n\n\nfunction createTreeWalker(el, whatToShow) {\n whatToShow = whatToShow || (NodeFilter.SHOW_TEXT | NodeFilter.SHOW_ELEMENT);\n return document.createTreeWalker(el, whatToShow);\n}\n\n\n/**\n * Returns the reference to the window the node is in\n *\n * @param {Node} node\n * @return {Window}\n */\nfunction getNodeWindow(node) {\n var doc = node.ownerDocument;\n return doc && (doc.defaultView || doc.parentWindow);\n}\n\n\n\n/**\n * do something for each nodes contained in a range\n *\n * @param {range} a range\n * @param {cb} a function taking a node as argument\n\n */\nfunction forEachNodesInRange(range, cb){\n var rangeContainer = range.commonAncestorContainer\n , doc = rangeContainer.ownerDocument;\n\n function isNodeInsideRange(node){\n var nodeRange = document.createRange();\n var isInside = false;\n nodeRange.selectNode(node);\n\n if (nodeRange.compareBoundaryPoints(window.Range.START_TO_START, range) != -1\n && nodeRange.compareBoundaryPoints(window.Range.END_TO_END, range) != 1){\n isInside = true;\n }\n nodeRange.detach();\n return isInside;\n }\n\n var treeWalker = doc.createTreeWalker(rangeContainer,\n NodeFilter.SHOW_ELEMENT | NodeFilter.SHOW_TEXT);\n\n var currentNode;\n while (currentNode = treeWalker.nextNode()){ // should be assignment\n if (isNodeInsideRange(currentNode)){\n cb(currentNode);\n }\n }\n}\n\n/**\n * get all components contained in a range\n *\n * @param {range} a DOM range.\n */\nfunction getComponentsFromRange(range) {\n var win = getNodeWindow(range.startContainer)\n , Component = win.milo.Component;\n\n var components = [];\n forEachNodesInRange(range, function (node){\n if (node.nodeType != Node.TEXT_NODE) {\n var comp = Component.getComponent(node);\n if (comp)\n components.push(comp);\n }\n });\n\n return components;\n}\n\n/**\n * delete a range\n *\n * @param {range} delete a DOM range and all the components inside\n */\nfunction deleteRangeWithComponents(range) {\n var components = getComponentsFromRange(range);\n\n components.forEach(function(comp) {\n comp.destroy(true);\n });\n\n range.deleteContents();\n}\n\n/**\n * check if two ranges are equivalent\n *\n * @param {range} range1\n * @param {range} range2\n * @return {Boolean} are the two ranges equivalent\n */\nfunction areRangesEqual(range1, range2){\n return range1.compareBoundaryPoints(window.Range.START_TO_START, range2) == 0 && range1.compareBoundaryPoints(window.Range.END_TO_END, range2) == 0;\n}\n\n\n/**\n * Adds a single pixel div to the body at a given x and y position. Useful for debugging position specific code.\n * @param {Number} x\n * @param {Number} y\n */\nfunction addDebugPoint(x, y) {\n var dbEl = document.createElement('div');\n dbEl.setAttribute('style', 'width: 1px; height: 1px; position:fixed; left:'+x+'px; top:'+y+'px; background-color:red; z-index: 100');\n setTimeout(function() {document.body.appendChild(dbEl);}, 200);\n}\n", "'use strict';\n\n\nvar _ = require('milo-core').proto;\n\n\nmodule.exports = DOMListeners;\n\n\nfunction DOMListeners() {\n this.listeners = [];\n}\n\n\n_.extendProto(DOMListeners, {\n add: DOMListeners$add,\n remove: DOMListeners$remove,\n removeAll: DOMListeners$removeAll\n});\n\n\nfunction DOMListeners$add(target, eventType, handler) {\n this.listeners.push({\n target: target,\n eventType: eventType,\n handler: handler\n });\n target.addEventListener(eventType, handler);\n}\n\n\nfunction DOMListeners$remove(target, eventType, handler) {\n var listener = {\n target: target,\n eventType: eventType,\n handler: handler\n };\n var idx = _.findIndex(this.listeners, _.partial(_.isEqual, listener));\n\n if (idx > -1) {\n this.listeners.splice(idx, 1);\n _removeListener(listener);\n }\n}\n\n\nfunction DOMListeners$removeAll() {\n this.listeners.forEach(_removeListener);\n this.listeners = [];\n}\n\n\nfunction _removeListener(l) {\n l.target.removeEventListener(l.eventType, l.handler);\n}\n", "'use strict';\n\n\nvar _ = require('milo-core').proto;\n\n\nmodule.exports = domReady;\n\n\nvar domReadyFuncs = []\n , domReadySubscribed = false;\n\n\nfunction domReady(func) { // , arguments\n var self = this\n , args = _.slice(arguments, 1);\n if (isReady.call(this))\n callFunc();\n else {\n if (!domReadySubscribed) {\n document.addEventListener('readystatechange', onDomReady);\n domReadySubscribed = true;\n }\n domReadyFuncs.push(callFunc); // closure is added, so every time different function will be called\n }\n\n function callFunc() {\n func.apply(self, args);\n }\n}\n\n\nfunction onDomReady() {\n document.removeEventListener('readystatechange', onDomReady);\n domReadyFuncs.forEach(function(func) { func(); });\n}\n\n\n_.extend(domReady, {\n isReady: isReady\n});\n\n\nfunction isReady() {\n var readyState = document.readyState;\n return readyState == 'loading' ? false : readyState;\n}\n",