'\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});\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",