1require=(function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;i<t.length;i++)o(t[i]);return o}return r})()({1:[function(require,module,exports){ 2"use strict"; 3var mouse_movement = []; 4var log_length = 50000; 5var dump_handeler = false; 6var logging = true; 7//var start = 0; 8var start_x = 0; 9var start_y = 0; 10 11var previous_x = 0; 12var previous_y = 0; 13var previous_time = 0; 14 15function createCursor() { 16 var cursor = document.createElement('div'); 17 cursor.style.zIndex = '99999'; 18 cursor.style.position = 'absolute'; 19 cursor.style.width = '0'; 20 cursor.style.height = '0'; 21 cursor.style.borderColor = '#ff0000 transparent transparent transparent'; 22 cursor.style.borderWidth = '20px 20px 0 0'; 23 cursor.style.borderStyle = 'solid'; 24 return cursor; 25} 26 27function moveMouse(cursor, index) { 28 if (mouse_movement[index + 3]) { 29 cursor.style.top = (start_y += mouse_movement[index + 2]) + 'px'; 30 cursor.style.left = (start_x += mouse_movement[index + 1]) + 'px'; 31 setTimeout(function () { 32 moveMouse(cursor, index + 3); 33 }, mouse_movement[index + 3]); 34 } else { 35 cursor.parentElement.removeChild(cursor); 36 cursor = null; 37 } 38} 39 40function log(e) { 41 mouse_movement.push((new Date().getTime() - previous_time)); 42 mouse_movement.push(e.clientX - previous_x); 43 mouse_movement.push(e.clientY - previous_y); 44 if (mouse_movement.length > log_length) { 45 if (dump_handeler && dump_handeler.fn) { 46 dump_handeler.fn.call(dump_handeler.context || this, 'mouse', JSON.stringify(mouse_movement)); 47 mouse_movement = []; 48 } else { 49 mouse_movement.shift(); 50 mouse_movement.shift(); 51 mouse_movement.shift(); 52 } 53 } 54 previous_time = new Date().getTime(); 55 previous_x = e.clientX; 56 previous_y = e.clientY; 57 logging = false; 58} 59function enableLogging() { 60 logging = true; 61} 62function onMouseMove(e) { 63 if (!logging) { 64 return; 65 } 66 log(e); 67 setTimeout(enableLogging, 5); 68} 69 70 71module.exports = { 72 initTracking: function (length, dump) { 73 log_length = length; 74 dump_handeler = dump; 75 document.body.addEventListener('mousemove', onMouseMove); 76 }, 77 mousePlay: function () {
78 var cursor = createCursor(); 79 document.body.appendChild(cursor); 80 moveMouse(cursor, 0); 81 }, 82 getData: function () { 83 return mouse_movement; 84 } 85}; 86},{}],2:[function(require,module,exports){ 87"use strict"; 88/** 89 * map of substitutions 90 */ 91var entity_map = { 92 '&': '&', 93 '<': '<', 94 '>': '>', 95 '"': '"', 96 "'": ''', 97 '/': '/', 98 '`': '`', 99 '=': '=' 100}; 101 102/** 103 * function to escape &<>"'`=\/ in string 104 * @param string string to escape 105 */ 106var escapeString = function(string) { 107 return String(string).replace(/[&<>"'`=/]/g, function (match) { 108 return entity_map[match]; 109 }); 110}; 111 112/** 113 * @module escape-string 114 */ 115module.exports = escapeString; 116 117},{}],3:[function(require,module,exports){ 118"use strict"; 119var Debugger = require('@icewarp/debugger'); 120 121/** Delete listener by given function 122 * 123 * @param {function} fn 124 * @param {object} callbacks 125 * @returns {undefined} 126 */ 127var deleteListener = function (fn, callbacks) { 128 var i; 129 for ( i = 0; i < callbacks.length; i++) { 130 if (callbacks[i].fn === fn) { 131 callbacks.splice(i, 1); 132 } 133 } 134}; 135/** 136 * Global storage for callbacks 137 * @ 138 * @type Object 139 */ 140var global_callbacks = {}; 141 142/** 143 * @classdesc Class for handling listeners and triggers. There are two options how to use EventTarget class. You can specify global flag in constructor. If global is true class is using global storage for listeners shared by all other instances created with global flag. If global is false listeners are scoped only cor current insance. 144 * @class EventTarget 145 * @example var instance = new EventTarget(); 146 * instance.on('event', someHandler); //adding event handler called someHandler 147 * instance.trigger('event', {}); //only someHandler is triggered 148 * @example var instance1 = new EventTarget(true); 149 * var instance2 = new EventTarget(true); 150 * instance1.on('event', someHandler); //adding event handler called someHandler 151 * instance2.on('event', someOtherHandler); //adding event handler called someOtherHandler 152 * instance1.trigger('event', {}); //someHandler and someOtherHandler are both triggered 153 * @param {boolean} [global] Flag for global callback storage 154 * 155 * @returns {EventTarget} 156 */ 157function EventTarget(global) { 158 /** 159 * Local storage for callbacks 160 * @type Object 161 */ 162 this.callbacks = global ? global_callbacks : {}; 163} 164/** 165 * @description Trigger event by given type. 166 * @param {string} type type of event you want to trigger 167 * @param {object} event instance of event 168 * @returns {EventTarget} 169 */ 170EventTarget.prototype.trigger = function (type, event) { 171 if (!type) { 172 throw Error('Missing Event Type'); 173 } 174 setTimeout(function() { 175 var cb, i; 176 Debugger.logAction({type: type, event: event}, Debugger.levels.MODEL_EVENT); 177 cb = (this.callbacks[type] || []).splice(0); 178 179 this.callbacks[type] = cb.filter(function (c) { 180 return !c.once; 181 }); 182 183 for (i = 0; i < cb.length; i++) { 184 cb[i].fn.call(cb[i].context || this, event || {}, type); 185 if (event && event.immediatePropagationStopped) { 186 break; 187 } 188 } 189 }.bind(this), 0); 190 return this; 191}; 192/** 193 * @description Function for removing listeners, you can remove all listeners or listeners by type only, that will remove all listeners of given type, or by type and handler that will remove all listeners with same type and handler. 194 * @param {string|function} [type] If type is supplied only listeners on given type are removed. If function is supplied only listener using that function is removed. 195 * @param {function} [fn] If function is supplied only listener using that function is removed. 196 * @returns {EventTarget} 197 */ 198EventTarget.prototype.off = function (type, fn) { 199 var event_type; 200 switch (arguments.length) { 201 case 0: 202 this.callbacks = {}; 203 break; 204 case 1: 205 if (typeof arguments[0] === 'function') { 206 for (event_type in this.callbacks) { 207 deleteListener.call(this, arguments[0], this.callbacks[event_type]); 208 } 209 } else { 210 this.callbacks[arguments[0]] = []; 211 } 212 break; 213 default: 214 deleteListener.call(this, arguments[1], this.callbacks[arguments[0]]); 215 } 216 return this; 217};
218/** 219 * @description Add function handler on specified event type 220 * @example var eventTarget = new EventTarget(); 221 * eventTarget.on('SomeEvent', function(){ 222 * //this is eventTarget object 223 * }); 224 * eventTarget.trigger('SomeEvent', {});//triggering event with empty event 225 * 226 * @param {string} type - type of event, string that identifies even type and is used for triggering events 227 * @param {function} fn - event handler, function thats gonna be called when event is triggered. First argument of this function is event 228 * @param {object} context - Context to call event handler with. default is context of class which is calling this function. 229 * @param {boolean} unshift - Put event listener on start of listeners stack. This can be used if you want to stop immediate propagation on element 230 * @param {boolean} once - Handler will be called only once then listener is removed. 231 * @returns {EventTarget} 232 */ 233EventTarget.prototype.on = function (type, fn, context, unshift, once) { 234 if (!this.callbacks[type]) { 235 this.callbacks[type] = []; 236 } 237 this.callbacks[type][unshift ? 'unshift' : 'push']({fn: fn, context: context || this, once: once || false}); 238 return this; 239}; 240/** 241 * @description Adding listener that are only triggered once and then removed. 242 * @param {string} type 243 * @param {function} fn 244 * @param {object} context 245 * @param {boolean} unshift 246 * @returns {EventTarget} 247 */ 248EventTarget.prototype.once = function (type, fn, context, unshift) { 249 return this.on(type, fn, context, unshift, true); 250}; 251 252/** 253 * Alias to off function 254 * @param {type} type 255 * @param {type} fn 256 * @returns {unresolved} 257 */ 258EventTarget.prototype.removeEventListener = function (type, fn) { 259 return this.off.apply(this, arguments); 260}; 261 262 263 264module.exports = EventTarget; 265 266},{"@icewarp/debugger":"debugger"}],4:[function(require,module,exports){ 267"use strict"; 268var ModelDataArray = require('./ModelDataArray.js'); 269 270/** 271 * array of functions allowed to be accessed 272 */ 273var allowed_fns = [ 274 'getData', 275 'getArray', 276 'setData', 277 'initArray', 278 'pushData', 279 'spliceData', 280 'unsetData', 281 'getWorkingDataKeys', 282 'getServerData', 283 'getWorkingData', 284 'saveWorkingData', 285 'flushWorkingData', 286 'destroy' 287]; 288 289/** 290 * @class ModelData 291 * @property {object} working_data object to hold unsaved object data 292 * @property {object} server_data object to hold saved object data 293 * @returns {ModelData} 294 */ 295function ModelData() { 296 this.working_data = {}; 297 this.server_data = {}; 298} 299 300/** 301 * encapsulating function 302 * @argument {string} function_name name of function to call 303 * @argument {*} function_params arguments passed to function 304 * @returns {boolean|undefined} 305 */ 306ModelData.prototype.caller = function (function_name, function_params) { 307 var args = Array.prototype.slice.apply(arguments); 308 var fn = args.shift(); 309 310 if (~allowed_fns.indexOf(fn)) { 311 return this[fn].apply(this, args); 312 } 313}; 314 315/** 316 * Getter for data, if exist working data of given key then it's value is returned otherwise server data of given key is returned 317 * @param {string} key 318 * @param {boolean} get_server_data 319 * @returns {*} 320 */ 321ModelData.prototype.getData = function (key, get_server_data) { 322 return !key ? false : (!get_server_data && typeof this.working_data[key] !== 'undefined' ? this.working_data[key] : this.server_data[key]); 323}; 324 325/** 326 * Getter for data array, if exist working data of given key then it's value is returned otherwise server data of given key is returned 327 * @param {string} key 328 * @param {boolean} get_server_data 329 * @returns {*} 330 */ 331ModelData.prototype.getArray = function (key, get_server_data) { 332 var a = this.getData(key, get_server_data); 333 return a instanceof ModelDataArray ? a : new ModelDataArray(a); 334}; 335 336/** 337 * 338 * @param {type} key 339 * @param {type} modify_server_data 340 * @returns {undefined} 341 */ 342ModelData.prototype.initArray = function (key, modify_server_data) { 343 (modify_server_data ? this.server_data : this.working_data)[key] = (modify_server_data ? (this.server_data[key] === void 0 ? new ModelDataArray() : this.server_data[key]) : (this.working_data[key] === void 0 ? (this.server_data[key] === void 0 ? new ModelDataArray() : this.server_data[key].clone()) : this.working_data[key])); 344}; 345 346/** remove value from array data 347 * 348 * @param {string} key 349 * @param {*} value 350 * @param {boolean} modify_server_data 351 * @returns {boolean|undefined} 352 */ 353ModelData.prototype.spliceData = function (key, value, modify_server_data) { 354 var model_data_array; 355 var index; 356 this.initArray(key, modify_server_data); 357 model_data_array = this.getArray(key, modify_server_data); 358 index = model_data_array.indexOf(value); 359 if (~index) { 360 Array.prototype.splice.call(model_data_array, index, 1); 361 return true; 362 } 363}; 364 365/** Push new value to data array 366 * 367 * @param {string} key 368 * @param {*} value 369 * @param {boolean} unshift 370 * @param {boolean} modify_server_data true if you want to set server data. Like to save response from server 371 * @returns {boolean|undefined} 372 */ 373ModelData.prototype.pushData = function (key, value, unshift, modify_server_data) { 374 this.initArray(key, modify_server_data); 375 if (!~this.getArray(key).indexOf(value)) { 376 Array.prototype[unshift ? 'unshift' : 'push'].call((modify_server_data ? this.server_data : this.working_data)[key], value); 377 return true; 378 } 379}; 380 381/** Setter for all data 382 * 383 * @param {string} key 384 * @param {*} value 385 * @param {boolean} modify_server_data true if you want to set server data. Like to save response from server 386 * @returns {boolean|undefined} 387 */ 388ModelData.prototype.setData = function (key, value, modify_server_data) { 389 (modify_server_data ? this.server_data : this.working_data)[key] = Array.isArray(value) ? new (ModelDataArray.bind.apply(ModelDataArray, [ModelDataArray].concat(value))) : value; 390 return true; 391}; 392 393/** 394 * Unset model property 395 * 396 * @param {string} key 397 * @param {boolean} modify_server_data true if you want to unset server data 398 * @returns {Boolean} 399 */ 400ModelData.prototype.unsetData = function (key, modify_server_data) { 401 var data = modify_server_data ? this.server_data : this.working_data; 402 data[key] = void 0; 403 delete data[key]; 404 return true; 405}; 406 407/** Propagate working data to server data 408 * 409 * @returns {BaseModel} 410 */ 411ModelData.prototype.saveWorkingData = function () { 412 var i; 413 for (i in this.working_data) { 414 this.server_data[i] = this.working_data[i]; 415 } 416 return this.flushWorkingData(); 417}; 418 419/** Returns all working data 420 * 421 * @returns {object} 422 */ 423ModelData.prototype.getWorkingData = function () { 424 return this.working_data; 425}; 426ModelData.prototype.getServerData = function () { 427 return this.server_data; 428}; 429 430/** get keys of all working data 431 * 432 * @returns {array} 433 */ 434ModelData.prototype.getWorkingDataKeys = function () { 435 return Object.keys(this.getWorkingData()); 436}; 437 438/** Flush all working data 439 * 440 * @returns {BaseModel} 441 */ 442ModelData.prototype.flushWorkingData = function () { 443 this.working_data = {}; 444 return this; 445};
446 447/** 448 * Destructor 449 * @returns {ModelData.prototype} 450 */ 451ModelData.prototype.destroy = function () { 452 this.working_data = {}; 453 this.server_data = {}; 454 return this; 455}; 456 457module.exports = ModelData; 458 459},{"./ModelDataArray.js":5}],5:[function(require,module,exports){ 460"use strict"; 461/** 462 * @class 463 * @extends Array 464 * @description Special ArrayLike class that restricts mutable actions 465 */ 466function ModelDataArray() { 467 Array.prototype.forEach.call(arguments, function (v) { 468 Array.prototype.push.call(this, v); 469 }, this); 470} 471ModelDataArray.prototype = Object.create(Array.prototype); 472ModelDataArray.prototype.constructor = ModelDataArray; 473 474[ 475 'fill', 476 'pop', 477 'push', 478 'reverse', 479 'shift', 480 'splice', 481 'unshift' 482].forEach(function (action) { 483 ModelDataArray.prototype[action] = function () { 484 console.error('Action', action, 'is not allowed. Use ModelData functions instead', this); 485 }; 486}); 487 488/** 489 * Creates clone of this array, If items are objects they are shared by reference. 490 * @returns {ModelDataArray} 491 */ 492ModelDataArray.prototype.clone = function () { 493 var clone = new ModelDataArray(); 494 var i; 495 for (i = 0; i < this.length; i++) { 496 Array.prototype.push.call(clone, this[i]); 497 } 498 return clone; 499}; 500 501module.exports = ModelDataArray; 502 503},{}],6:[function(require,module,exports){ 504"use strict"; 505var Template = require('@icewarp/icebrace-runtime'); 506var BaseController = require('./BaseController.js'); 507var logger = require('@icewarp/logger'); 508 509/** 510 * Handle subcomponent. 511 * @param {string} name 512 * @param {Object} context 513 * @returns {string} 514 */ 515module.exports = function (name, context) { 516 var style_mod = name.split(':'); 517 var no_mod, controller; 518 var styleModifier = ''; 519 var template; 520 name = style_mod[0]; 521 if (style_mod[1]) { 522 styleModifier = (' ' + style_mod[1].split('|').join(' ') + ' '); 523 } 524 if (context instanceof BaseController) { 525 controller = context; 526 controller.data.styleModifier = styleModifier; 527 context = controller.getView(); 528 controller.view_data = context; 529 BaseController.reinstance(controller); 530 } 531 context.styleModifier = styleModifier; 532 context.hook = context.hook || ''; 533 name = context[name] || name; 534 no_mod = name.split('~')[0]; 535 if (!Template.t(no_mod)) { 536 logger.warning('Missing template "' + no_mod + '"'); 537 return ''; 538 } 539 template = Template.t(no_mod)()(context);
540 name = context._mod ? (no_mod + '~' + context._mod) : name; 541 if (!/^\s*(<[\w\d]+\s+data-component)/.test(template)) { // component with a wrapper 542 template = template.replace(/^\s*(<[\w\d]+)/, '$1' + ' data-component="' + name + '-' + (controller || new (BaseController.static(name))(context)).id + '"'); 543 } 544 return template; 545}; 546 547},{"./BaseController.js":"BaseController","@icewarp/icebrace-runtime":"icebrace-runtime","@icewarp/logger":"logger"}],7:[function(require,module,exports){ 548"use strict"; 549var Debugger = require('@icewarp/debugger'); 550var Template = require('@icewarp/icebrace-runtime'); 551 552Template.c = require('./component_handler'); 553 554Debugger.addLogLevel('MODEL_EVENT'); 555/* eslint-disable */ 556/** Static core of framework 557 * 558 559 * @type Object 560 */ 561var Core = { 562}; 563/* eslint-enable */ 564/** 565 * @external @icewarp/socket 566 * @see {@link ../../socket/1.0.8/|@icewarp/socket} 567 */ 568/** 569 * @external @icewarp/extend 570 * @see {@link ../../extend/1.0.4/|@icewarp/extend} 571 */ 572/** 573 * @external @icewarp/delayed 574 * @see {@link http://192.168.6.5/jsframework/delayed/1.0.7/|@icewarp/delayed} 575 */ 576/** 577 * @external @icewarp/request 578 * @see {@link http://192.168.6.5/jsframework/request/1.0.3/|@icewarp/request} 579 */ 580/** 581 * @external @icewarp/logger 582 * @see {@link http://192.168.6.5/jsframework/logger/1.0.1/|@icewarp/logger} 583 */ 584/** 585 * @external @icewarp/overtype 586 * @see {@link http://192.168.6.5/jsframework/overtype/1.0.0/|@icewarp/overtype} 587 */ 588/** 589 * @external @icewarp/icebrace-runtime 590 * @see {@link http://192.168.6.5/jsframework/icebrace-runtime/1.0.5/|@icewarp/icebrace-runtime} 591 592 */ 593 594},{"./component_handler":6,"@icewarp/debugger":"debugger","@icewarp/icebrace-runtime":"icebrace-runtime"}],8:[function(require,module,exports){ 595"use strict"; 596/** Module of evertyping properties 597 * @module overtype 598 * @param {string} type 599 * @param {*} value 600 * @returns {Array|Number|undefined|String|Boolean|Object} 601 */ 602module.exports = function (type, value) { 603 if(!type) { 604 return value; 605 } 606 switch (type.toLowerCase()) { 607 case 'array': 608 return Array.isArray(value) ? value : [value]; 609 case 'boolean': 610 return Array.isArray(value) && !value.length ? false : !!value; 611 case 'null': 612 return null; 613 case 'undefined': 614 return undefined; 615 case 'number': 616 return value * 1; 617 case 'string': 618 return '' + value; 619 case 'symbol': 620 return value; // todo 621 } 622 return value; 623}; 624 625},{}],9:[function(require,module,exports){ 626"use strict"; 627/** Eception on missing key in required options in request 628 * @class 629 * @param {string} key 630 * @returns {MissingOptionException} 631 */ 632function MissingOptionException(key) { 633 this.key = key; 634 this.message = "Missing required key " + key; 635} 636module.exports = MissingOptionException; 637},{}],10:[function(require,module,exports){ 638"use strict"; 639/** 640 * @external @icewarp/delayed 641 */ 642var delayed = require('@icewarp/delayed'); 643/** 644 * @external @icewarp/logger 645 */ 646var Logger = require('@icewarp/logger'); 647 648 649/** Function that decides how long to wait before another reconnect 650 * 651 * @returns {Number} 652 */ 653var howLongToWait = function () { 654 if (!this.wait) { 655 this.wait = 0; 656 } 657 this.wait = (this.wait + 1) % 30; 658 return this.wait * 1000; 659}; 660 661/** Init ping timer 662 * 663 * @returns {undefined} 664 */ 665var initPing = function () { 666 clearInterval(this.pingID); 667 this.pingID = setInterval(function () { 668 ping.call(this); 669 }.bind(this), 14000); 670}; 671 672/** send ping message 673 * 674 * @returns {undefined} 675 */ 676var ping = function () { 677 this.send({ping: 1}); 678}; 679/** 680 * 681 * @param {object} options object with listeners objects 682 * @returns {undefined} 683 */ 684var setListeners = function (options) { 685 this.connection.onclose = function () { 686 Logger.info("Closing connection"); 687 this.autoreconnect && reconnect.call(this); 688 this.autoreconnect = true; 689 if (options.onclose) { 690 options.onclose.func.call(options.onclose.context); 691 } 692 }.bind(this); 693 this.connection.onopen = function (e) { 694 Logger.info("Connection open"); 695 this.allow_ping && initPing.call(this); 696 this.interval = 0; 697 clearInterval(this._retry_interval); 698 clearInterval(this._close_interval); 699 if (options.onopen) { 700 options.onopen.func.call(options.onopen.context); 701 } 702 }.bind(this); 703 if (options.onerror) { 704 this.connection.onerror = options.onerror.func.bind(options.onerror.context); 705 } 706 if (options.onmessage) { 707 this.connection.onmessage = options.onmessage.func.bind(options.onmessage.context); 708 } 709}; 710 711/** Connect to endpoint 712 * 713 * @returns {undefined} 714 */
715var connect = function () { 716 if (!this.connection) { 717 try { 718 this.connection = new Connection.websocket(this.host, this.protocol); 719 } catch (e) { 720 return; 721 } 722 setListeners.call(this, this.listeners); 723 } 724 this._close_interval = setTimeout(function () { 725 this.close(); 726 }.bind(this), howLongToWait.call(this)); 727}; 728 729/** Recconect to endpoint 730 * 731 * @returns {undefined} 732 */ 733var reconnect = function () { 734 this._retry_interval = setTimeout(function () { 735 Logger.info("Recconect"); 736 if (!this.connection || (!!this.connection && (this.connection.readyState === this.connection.CLOSED || this.connection.readyState === this.connection.CLOSING))) { 737 clearInterval(this._close_interval); 738 this.connection = false; 739 connect.call(this); 740 } 741 }.bind(this), howLongToWait.call(this)); 742}; 743 744/** Encode message by given type 745 * 746 * @param {object} data 747 * @param {string} content_type 748 * @returns {String} 749 */ 750var contentType = function (data, content_type) { 751 switch (content_type) { 752 case "json": 753 return JSON.stringify(data); 754 } 755 return data; 756}; 757 758/** 759 * @class 760 * @param {object} options 761 * @requires module:@icewarp/delayed 762 * @requires module:@icewarp/logger 763 * @property {number} _retry_interval id of timeout for reconnection on connection failure 764 * @property {number} _close_interval id of timeout for closing pending connection 765 * @property {boolean} autoreconnect flag for aout reconect if connections fails (can be set from options) 766 * @property {array} dataToSend queue for messages if connections fails 767 * @property {string} host host 768 * @property {string} protocol protocol for we connection default '' 769 * @property {number} _retry_time how long to wait before another reconnect attempt 770 * @property {object} listeners object of listeners attaached on connection 771 * @property {boolean} allow_ping allow browser to ping server 772 * @returns {Connection} 773 */ 774function Connection(options) { 775 this._retry_interval = 0; 776 this._close_interval = 0; 777 this.autoreconnect = options.autoreconnect || true; 778 this.dataToSend = []; 779 this.host = options.host; 780 this.protocol = options.protocol || ''; 781 this._retry_time = options.retry_time || 5000; 782 this.listeners = options.listeners || {}; 783 this.allow_ping = options.allow_ping || false; 784 connect.call(this); 785} 786/** 787 * 788 * @param {object} data data payload 789 * @param {string} content_type xml|json 790 * @returns {Boolean} 791 */ 792Connection.prototype.send = function (data, content_type) { 793 content_type = content_type || "json"; 794 Logger.info("Sending Data", data); 795 if (!!this.connection && this.connection.readyState === 1) { 796 this.connection.send(contentType(data, content_type)); 797 return true; 798 } else { 799 this.dataToSend.push(data); 800 delayed(function () { 801 while (this.dataToSend.length) { 802 if (!this.send(this.dataToSend.pop())) { 803 break; 804 } 805 } 806 }, this, 1000); 807 return false; 808 } 809}; 810 811/** 812 * Close connection 813 * @returns {undefined} 814 */ 815Connection.prototype.close = function () { 816 this.connection && this.connection.close && this.connection.close(); 817}; 818 819/** WS unification 820 * 821 */ 822Connection.websocket = window.WebSocket || window.MozWebSocket; 823 824module.exports = Connection; 825 826},{"@icewarp/delayed":"delayed","@icewarp/logger":"logger"}],11:[function(require,module,exports){ 827"use strict";
vendor: 4,476 bytes, lines 828-973
828// shim for using process in browser 829var process = module.exports = {}; 830 831// cached from whatever global is present so that test runners that stub it 832// don't break things. But we need to wrap it in a try catch in case it is 833// wrapped in strict mode code which doesn't define any globals. It's inside a 834// function because try/catches deoptimize in certain engines. 835 836var cachedSetTimeout; 837var cachedClearTimeout; 838 839function defaultSetTimout() { 840 throw new Error('setTimeout has not been defined'); 841} 842function defaultClearTimeout () { 843 throw new Error('clearTimeout has not been defined'); 844} 845(function () { 846 try { 847 if (typeof setTimeout === 'function') { 848 cachedSetTimeout = setTimeout; 849 } else { 850 cachedSetTimeout = defaultSetTimout; 851 } 852 } catch (e) { 853 cachedSetTimeout = defaultSetTimout; 854 } 855 try { 856 if (typeof clearTimeout === 'function') { 857 cachedClearTimeout = clearTimeout; 858 } else { 859 cachedClearTimeout = defaultClearTimeout; 860 } 861 } catch (e) { 862 cachedClearTimeout = defaultClearTimeout; 863 } 864} ()) 865function runTimeout(fun) { 866 if (cachedSetTimeout === setTimeout) { 867 //normal enviroments in sane situations 868 return setTimeout(fun, 0); 869 } 870 // if setTimeout wasn't available but was latter defined 871 if ((cachedSetTimeout === defaultSetTimout || !cachedSetTimeout) && setTimeout) { 872 cachedSetTimeout = setTimeout; 873 return setTimeout(fun, 0); 874 } 875 try { 876 // when when somebody has screwed with setTimeout but no I.E. maddness 877 return cachedSetTimeout(fun, 0); 878 } catch(e){ 879 try { 880 // When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally 881 return cachedSetTimeout.call(null, fun, 0); 882 } catch(e){ 883 // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error 884 return cachedSetTimeout.call(this, fun, 0); 885 } 886 } 887 888 889} 890function runClearTimeout(marker) { 891 if (cachedClearTimeout === clearTimeout) { 892 //normal enviroments in sane situations 893 return clearTimeout(marker); 894 } 895 // if clearTimeout wasn't available but was latter defined 896 if ((cachedClearTimeout === defaultClearTimeout || !cachedClearTimeout) && clearTimeout) { 897 cachedClearTimeout = clearTimeout; 898 return clearTimeout(marker); 899 } 900 try { 901 // when when somebody has screwed with setTimeout but no I.E. maddness 902 return cachedClearTimeout(marker); 903 } catch (e){ 904 try { 905 // When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally 906 return cachedClearTimeout.call(null, marker); 907 } catch (e){ 908 // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error. 909 // Some versions of I.E. have different rules for clearTimeout vs setTimeout 910 return cachedClearTimeout.call(this, marker); 911 } 912 } 913 914 915 916} 917var queue = []; 918var draining = false; 919var currentQueue; 920var queueIndex = -1; 921 922function cleanUpNextTick() { 923 if (!draining || !currentQueue) { 924 return; 925 } 926 draining = false; 927 if (currentQueue.length) { 928 queue = currentQueue.concat(queue); 929 } else { 930 queueIndex = -1; 931 } 932 if (queue.length) { 933 drainQueue(); 934 } 935} 936 937function drainQueue() { 938 if (draining) { 939 return; 940 } 941 var timeout = runTimeout(cleanUpNextTick); 942 draining = true; 943 944 var len = queue.length; 945 while(len) { 946 currentQueue = queue; 947 queue = []; 948 while (++queueIndex < len) { 949 if (currentQueue) { 950 currentQueue[queueIndex].run(); 951 } 952 } 953 queueIndex = -1; 954 len = queue.length; 955 } 956 currentQueue = null; 957 draining = false; 958 runClearTimeout(timeout); 959} 960 961process.nextTick = function (fun) { 962 var args = new Array(arguments.length - 1); 963 if (arguments.length > 1) { 964 for (var i = 1; i < arguments.length; i++) { 965 args[i - 1] = arguments[i]; 966 } 967 } 968 queue.push(new Item(fun, args)); 969 if (queue.length === 1 && !draining) { 970 runTimeout(drainQueue); 971 } 972}; 973
974// v8 likes predictible objects 975function Item(fun, array) { 976 this.fun = fun; 977 this.array = array; 978} 979Item.prototype.run = function () { 980 this.fun.apply(null, this.array); 981}; 982process.title = 'browser'; 983process.browser = true; 984process.env = {}; 985process.argv = []; 986process.version = ''; // empty string to avoid regexp issues 987process.versions = {}; 988 989function noop() {} 990 991process.on = noop; 992process.addListener = noop; 993process.once = noop; 994process.off = noop; 995process.removeListener = noop; 996process.removeAllListeners = noop; 997process.emit = noop; 998process.prependListener = noop; 999process.prependOnceListener = noop; 1000 1001process.listeners = function (name) { return [] } 1002 1003process.binding = function (name) { 1004 throw new Error('process.binding is not supported'); 1005}; 1006 1007process.cwd = function () { return '/' }; 1008process.chdir = function (dir) { 1009 throw new Error('process.chdir is not supported'); 1010}; 1011process.umask = function() { return 0; }; 1012 1013},{}],12:[function(require,module,exports){ 1014(function (setImmediate){(function (){ 1015"use strict"; 1016'use strict'; 1017 1018/** 1019 * @this {Promise} 1020 */ 1021function finallyConstructor(callback) { 1022 var constructor = this.constructor; 1023 return this.then( 1024 function(value) { 1025 // @ts-ignore 1026 return constructor.resolve(callback()).then(function() { 1027 return value; 1028 }); 1029 }, 1030 function(reason) { 1031 // @ts-ignore 1032 return constructor.resolve(callback()).then(function() { 1033 // @ts-ignore 1034 return constructor.reject(reason); 1035 }); 1036 } 1037 ); 1038} 1039 1040function allSettled(arr) { 1041 var P = this; 1042 return new P(function(resolve, reject) { 1043 if (!(arr && typeof arr.length !== 'undefined')) { 1044 return reject( 1045 new TypeError( 1046 typeof arr + 1047 ' ' + 1048 arr + 1049 ' is not iterable(cannot read property Symbol(Symbol.iterator))' 1050 ) 1051 ); 1052 } 1053 var args = Array.prototype.slice.call(arr); 1054 if (args.length === 0) return resolve([]); 1055 var remaining = args.length; 1056 1057 function res(i, val) { 1058 if (val && (typeof val === 'object' || typeof val === 'function')) { 1059 var then = val.then; 1060 if (typeof then === 'function') { 1061 then.call( 1062 val, 1063 function(val) { 1064 res(i, val); 1065 }, 1066 function(e) { 1067 args[i] = { status: 'rejected', reason: e }; 1068 if (--remaining === 0) { 1069 resolve(args); 1070 } 1071 } 1072 ); 1073 return; 1074 } 1075 } 1076 args[i] = { status: 'fulfilled', value: val }; 1077 if (--remaining === 0) { 1078 resolve(args); 1079 } 1080 } 1081 1082 for (var i = 0; i < args.length; i++) { 1083 res(i, args[i]); 1084 } 1085 }); 1086} 1087 1088/** 1089 * @constructor 1090 */ 1091function AggregateError(errors, message) { 1092 this.name = 'AggregateError', this.errors = errors; 1093 this.message = message || ''; 1094} 1095AggregateError.prototype = Error.prototype; 1096 1097function any(arr) { 1098 var P = this; 1099 return new P(function(resolve, reject) { 1100 if (!(arr && typeof arr.length !== 'undefined')) { 1101 return reject(new TypeError('Promise.any accepts an array')); 1102 } 1103 1104 var args = Array.prototype.slice.call(arr); 1105 if (args.length === 0) return reject(); 1106 1107 var rejectionReasons = []; 1108 for (var i = 0; i < args.length; i++) { 1109 try { 1110 P.resolve(args[i]) 1111 .then(resolve) 1112 .catch(function(error) { 1113 rejectionReasons.push(error); 1114 if (rejectionReasons.length === args.length) { 1115 reject( 1116 new AggregateError( 1117 rejectionReasons, 1118 'All promises were rejected' 1119 ) 1120 ); 1121 } 1122 }); 1123 } catch (ex) { 1124 reject(ex); 1125 } 1126 } 1127 }); 1128} 1129 1130// Store setTimeout reference so promise-polyfill will be unaffected by 1131// other code modifying setTimeout (like sinon.useFakeTimers()) 1132var setTimeoutFunc = setTimeout; 1133 1134function isArray(x) { 1135 return Boolean(x && typeof x.length !== 'undefined'); 1136} 1137 1138function noop() {} 1139 1140// Polyfill for Function.prototype.bind 1141function bind(fn, thisArg) { 1142 return function() { 1143 fn.apply(thisArg, arguments); 1144 }; 1145} 1146 1147/** 1148 * @constructor 1149 * @param {Function} fn 1150 */ 1151function Promise(fn) { 1152 if (!(this instanceof Promise)) 1153 throw new TypeError('Promises must be constructed via new'); 1154 if (typeof fn !== 'function') throw new TypeError('not a function');
vendor: 4,160 bytes, lines 1155-1334
1155 /** @type {!number} */ 1156 this._state = 0; 1157 /** @type {!boolean} */ 1158 this._handled = false; 1159 /** @type {Promise|undefined} */ 1160 this._value = undefined; 1161 /** @type {!Array<!Function>} */ 1162 this._deferreds = []; 1163 1164 doResolve(fn, this); 1165} 1166 1167function handle(self, deferred) { 1168 while (self._state === 3) { 1169 self = self._value; 1170 } 1171 if (self._state === 0) { 1172 self._deferreds.push(deferred); 1173 return; 1174 } 1175 self._handled = true; 1176 Promise._immediateFn(function() { 1177 var cb = self._state === 1 ? deferred.onFulfilled : deferred.onRejected; 1178 if (cb === null) { 1179 (self._state === 1 ? resolve : reject)(deferred.promise, self._value); 1180 return; 1181 } 1182 var ret; 1183 try { 1184 ret = cb(self._value); 1185 } catch (e) { 1186 reject(deferred.promise, e); 1187 return; 1188 } 1189 resolve(deferred.promise, ret); 1190 }); 1191} 1192 1193function resolve(self, newValue) { 1194 try { 1195 // Promise Resolution Procedure: https://github.com/promises-aplus/promises-spec#the-promise-resolution-procedure 1196 if (newValue === self) 1197 throw new TypeError('A promise cannot be resolved with itself.'); 1198 if ( 1199 newValue && 1200 (typeof newValue === 'object' || typeof newValue === 'function') 1201 ) { 1202 var then = newValue.then; 1203 if (newValue instanceof Promise) { 1204 self._state = 3; 1205 self._value = newValue; 1206 finale(self); 1207 return; 1208 } else if (typeof then === 'function') { 1209 doResolve(bind(then, newValue), self); 1210 return; 1211 } 1212 } 1213 self._state = 1; 1214 self._value = newValue; 1215 finale(self); 1216 } catch (e) { 1217 reject(self, e); 1218 } 1219} 1220 1221function reject(self, newValue) { 1222 self._state = 2; 1223 self._value = newValue; 1224 finale(self); 1225} 1226 1227function finale(self) { 1228 if (self._state === 2 && self._deferreds.length === 0) { 1229 Promise._immediateFn(function() { 1230 if (!self._handled) { 1231 Promise._unhandledRejectionFn(self._value); 1232 } 1233 }); 1234 } 1235 1236 for (var i = 0, len = self._deferreds.length; i < len; i++) { 1237 handle(self, self._deferreds[i]); 1238 } 1239 self._deferreds = null; 1240} 1241 1242/** 1243 * @constructor 1244 */ 1245function Handler(onFulfilled, onRejected, promise) { 1246 this.onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : null; 1247 this.onRejected = typeof onRejected === 'function' ? onRejected : null; 1248 this.promise = promise; 1249} 1250 1251/** 1252 * Take a potentially misbehaving resolver function and make sure 1253 * onFulfilled and onRejected are only called once. 1254 * 1255 * Makes no guarantees about asynchrony. 1256 */ 1257function doResolve(fn, self) { 1258 var done = false; 1259 try { 1260 fn( 1261 function(value) { 1262 if (done) return; 1263 done = true; 1264 resolve(self, value); 1265 }, 1266 function(reason) { 1267 if (done) return; 1268 done = true; 1269 reject(self, reason); 1270 } 1271 ); 1272 } catch (ex) { 1273 if (done) return; 1274 done = true; 1275 reject(self, ex); 1276 } 1277} 1278 1279Promise.prototype['catch'] = function(onRejected) { 1280 return this.then(null, onRejected); 1281}; 1282 1283Promise.prototype.then = function(onFulfilled, onRejected) { 1284 // @ts-ignore 1285 var prom = new this.constructor(noop); 1286 1287 handle(this, new Handler(onFulfilled, onRejected, prom)); 1288 return prom; 1289}; 1290 1291Promise.prototype['finally'] = finallyConstructor; 1292 1293Promise.all = function(arr) { 1294 return new Promise(function(resolve, reject) { 1295 if (!isArray(arr)) { 1296 return reject(new TypeError('Promise.all accepts an array')); 1297 } 1298 1299 var args = Array.prototype.slice.call(arr); 1300 if (args.length === 0) return resolve([]); 1301 var remaining = args.length; 1302 1303 function res(i, val) { 1304 try { 1305 if (val && (typeof val === 'object' || typeof val === 'function')) { 1306 var then = val.then; 1307 if (typeof then === 'function') { 1308 then.call( 1309 val, 1310 function(val) { 1311 res(i, val); 1312 }, 1313 reject 1314 ); 1315 return; 1316 } 1317 } 1318 args[i] = val; 1319 if (--remaining === 0) { 1320 resolve(args); 1321 } 1322 } catch (ex) { 1323 reject(ex); 1324 } 1325 } 1326 1327 for (var i = 0; i < args.length; i++) { 1328 res(i, args[i]); 1329 } 1330 }); 1331}; 1332 1333Promise.any = any; 1334
1335Promise.allSettled = allSettled; 1336 1337Promise.resolve = function(value) { 1338 if (value && typeof value === 'object' && value.constructor === Promise) { 1339 return value; 1340 } 1341 1342 return new Promise(function(resolve) { 1343 resolve(value); 1344 }); 1345}; 1346 1347Promise.reject = function(value) { 1348 return new Promise(function(resolve, reject) { 1349 reject(value); 1350 }); 1351}; 1352 1353Promise.race = function(arr) { 1354 return new Promise(function(resolve, reject) { 1355 if (!isArray(arr)) { 1356 return reject(new TypeError('Promise.race accepts an array')); 1357 } 1358 1359 for (var i = 0, len = arr.length; i < len; i++) { 1360 Promise.resolve(arr[i]).then(resolve, reject); 1361 } 1362 }); 1363}; 1364 1365// Use polyfill for setImmediate for performance gains 1366Promise._immediateFn = 1367 // @ts-ignore 1368 (typeof setImmediate === 'function' && 1369 function(fn) { 1370 // @ts-ignore 1371 setImmediate(fn); 1372 }) || 1373 function(fn) { 1374 setTimeoutFunc(fn, 0); 1375 }; 1376 1377Promise._unhandledRejectionFn = function _unhandledRejectionFn(err) { 1378 if (typeof console !== 'undefined' && console) { 1379 console.warn('Possible Unhandled Promise Rejection:', err); // eslint-disable-line no-console 1380 } 1381}; 1382 1383module.exports = Promise; 1384 1385}).call(this)}).call(this,require("timers").setImmediate) 1386},{"timers":13}],13:[function(require,module,exports){ 1387(function (setImmediate,clearImmediate){(function (){ 1388var nextTick = require('process/browser.js').nextTick; 1389var apply = Function.prototype.apply; 1390var slice = Array.prototype.slice; 1391var immediateIds = {}; 1392var nextImmediateId = 0; 1393 1394// DOM APIs, for completeness 1395 1396exports.setTimeout = function() { 1397 return new Timeout(apply.call(setTimeout, window, arguments), clearTimeout); 1398}; 1399exports.setInterval = function() { 1400 return new Timeout(apply.call(setInterval, window, arguments), clearInterval); 1401}; 1402exports.clearTimeout = 1403exports.clearInterval = function(timeout) { timeout.close(); }; 1404 1405function Timeout(id, clearFn) { 1406 this._id = id; 1407 this._clearFn = clearFn; 1408} 1409Timeout.prototype.unref = Timeout.prototype.ref = function() {}; 1410Timeout.prototype.close = function() { 1411 this._clearFn.call(window, this._id); 1412}; 1413 1414// Does not start the time, just sets up the members needed. 1415exports.enroll = function(item, msecs) { 1416 clearTimeout(item._idleTimeoutId); 1417 item._idleTimeout = msecs; 1418}; 1419 1420exports.unenroll = function(item) { 1421 clearTimeout(item._idleTimeoutId); 1422 item._idleTimeout = -1; 1423}; 1424 1425exports._unrefActive = exports.active = function(item) { 1426 clearTimeout(item._idleTimeoutId); 1427 1428 var msecs = item._idleTimeout; 1429 if (msecs >= 0) { 1430 item._idleTimeoutId = setTimeout(function onTimeout() { 1431 if (item._onTimeout) 1432 item._onTimeout(); 1433 }, msecs); 1434 } 1435}; 1436 1437// That's not how node.js implements it but the exposed api is the same. 1438exports.setImmediate = typeof setImmediate === "function" ? setImmediate : function(fn) { 1439 var id = nextImmediateId++; 1440 var args = arguments.length < 2 ? false : slice.call(arguments, 1); 1441 1442 immediateIds[id] = true; 1443 1444 nextTick(function onNextTick() { 1445 if (immediateIds[id]) { 1446 // fn.call() is faster so we optimize for the common use-case 1447 // @see http://jsperf.com/call-apply-segu 1448 if (args) { 1449 fn.apply(null, args); 1450 } else { 1451 fn.call(null); 1452 } 1453 // Prevent ids from leaking 1454 exports.clearImmediate(id); 1455 } 1456 }); 1457 1458 return id; 1459}; 1460 1461exports.clearImmediate = typeof clearImmediate === "function" ? clearImmediate : function(id) { 1462 delete immediateIds[id]; 1463}; 1464}).call(this)}).call(this,require("timers").setImmediate,require("timers").clearImmediate) 1465},{"process/browser.js":11,"timers":13}],"BaseController":[function(require,module,exports){ 1466(function (global){(function (){ 1467"use strict"; 1468var mix = require('@icewarp/mix'); 1469var extend = require('@icewarp/extend'); 1470var Callback = require('@icewarp/callback'); 1471var EventTarget = require('./EventTarget.js'); 1472var Template = require('@icewarp/icebrace-runtime'); 1473var logger = require('@icewarp/logger'); 1474var escape_string = require('@icewarp/escape-string'); 1475var function_name = require('@icewarp/function-name'); 1476var Debugger = require('@icewarp/debugger'); 1477var Breakpoint = require('./Breakpoint.js'); 1478var Promise = window.Promise || (global || {}).Promise || require('promise-polyfill'); 1479 1480/** 1481 * @typedef {Object} StoredModelListener 1482 * @description Stored object of listener to model event. 1483 * @property {BaseModel} target - Target model 1484 * @property {string} type - type of event (name of the event) 1485 * @property {function} func - handler function, this function will be executed with `this` of this controller. 1486 */ 1487 1488/** 1489 * @typedef {Object} StoredGlobalListener 1490 * @description Stored object of listener to model event. 1491 * @property {BaseController} target - Target is always instance of controller which is adding this listener 1492 * @property {string} type - type of event (name of the event) 1493 * @property {function} func - handler function, this function will be executed with `this` of this controller. 1494 */ 1495 1496/** 1497 * @typedef {Object} StoredDOMListener 1498 * @description Stored object of listener to DOM Element. 1499 * @property {HTMLElement} target - Target DOM Element 1500 * @property {string} type - type of event (name of the event) 1501 * @property {function} func - handler function, this function will be executed with `this` of this controller. 1502 */ 1503 1504/* Privates */ 1505 1506/** 1507 * @summary Model listeners storage 1508 * @description Storage for model listeners. Every time `addModelListener` is called `StoredModelListener` is stored here and if `removeListeners` is called with this storage, it's emptied. 1509 * @type {Object} 1510 * @property {Object} [controller_name] 1511 * @property {StoredModelListener[]} [controller_name.listener_id] 1512 */ 1513var modelListeners = {}; 1514 1515/** 1516 * @summary global listeners storage 1517 * @description Storage for global listeners, every time `addGlobalListener` is called `StoredGlobalListener` is stored here and if `removeListeners` is called with this storage, it's emptied. 1518 * @type {Object} 1519 * @property {Object} [controller_name] 1520 * @property {StoredGlobalListener[]} [controller_name.listener_id] 1521 */ 1522var globalListeners = {}; 1523 1524/** 1525 * @summary DOM listeners storage 1526 * @description Storage for DOM listeners, every time `addDOMListener` or `addDelegatedDOMListener` is called `StoredGlobalListener` is stored here and if `removeListeners` is called with this storage, it's emptied. 1527 * @type {Object} 1528 * @property {Object} [controller_name] 1529 * @property {StoredDOMListener[]} [controller_name.listener_id] 1530 */ 1531var DOMListeners = {}; 1532 1533/** 1534 * @summary instances storage
1535 * @description Contains instances for all controllers stored by `class_name` and id. This is necessary to target existing instance by ID. 1536 * @type {Object} 1537 */ 1538var instances = {}; 1539 1540/** 1541 * @summary controllers storage 1542 * @description Storage for all controllers in application. Used as single entry point for creating and getting all controllers in application 1543 * @type {Object} 1544 */ 1545var controllers = {}; 1546 1547/** 1548 * IDs storage 1549 */ 1550var ids = {}; 1551 1552/** 1553 * @summary destructors storage 1554 * @description Contains destructors for all controllers stored by `class_name` and id. 1555 * @type {Object} 1556 */ 1557var destructors = {}; 1558 1559Callback.addMiddleware(Callback.SUCCESS, function () { 1560 return false; //cancel propagation of callbacks for controllers without dom 1561}, function () { 1562 return this instanceof BaseController && !this.DOMElement && !this.DOMShadowElement; 1563}); 1564 1565/** 1566 * Merge two objects 1567 * @param {object} target 1568 * @param {object} source 1569 * @returns {undefined} 1570 */ 1571function mergeData(target, source) { 1572 Object.keys(source).forEach(function (key) { 1573 target[key] = source[key]; 1574 }); 1575} 1576 1577/** 1578 * @description Flats mixed sync and async data into flat promise 1579 * @param {*} data 1580 * @param {number} depth 1581 * @param {array} entities 1582 * @returns {Promise} 1583 */ 1584function flatPromisedData(data, depth, entities) { 1585 depth = depth || 0; 1586 entities = entities || []; 1587 if (typeof data !== 'object' || data === null) { 1588 return data; 1589 } 1590 if (data instanceof Promise || (data && function_name(data.constructor) === 'Promise')) { 1591 return data.then(function (data) { 1592 return flatPromisedData(data, depth + 1, entities); 1593 }); 1594 } 1595 if (~entities.indexOf(data)) { 1596 return false; 1597 } 1598 entities.push(data); 1599 if (data instanceof Array) { 1600 return Promise.all(data.map(function (data) { 1601 if (depth > 300) { 1602 return new Promise(function (resolve) { 1603 setTimeout(function () { 1604 resolve(flatPromisedData(data, 0, entities.slice(0))); 1605 }); 1606 }); 1607 } 1608 return flatPromisedData(data, depth + 1, entities.slice(0)); 1609 })); 1610 } 1611 if (data instanceof BaseController) { 1612 return data.resolveHelper(depth + 1, entities); 1613 } 1614 return new Promise(function (resolve) { 1615 var resolved = {}; 1616 var promises = []; 1617 Object.keys(data).forEach(function (key) { 1618 var value; 1619 if (depth > 300) { 1620 value = new Promise(function (resolve) { 1621 setTimeout(function () { 1622 resolve(flatPromisedData(data[key], 0, entities.slice(0))); 1623 }); 1624 }); 1625 } else { 1626 value = flatPromisedData(data[key], depth + 1, entities.slice(0)); 1627 } 1628 if (value instanceof Promise || (value && function_name(value.constructor) === 'Promise')) { 1629 return promises.push(value.then(function (value) { 1630 resolved[key] = value; 1631 })); 1632 }
1633 resolved[key] = value; 1634 }); 1635 resolve(Promise.all(promises).then(function () { 1636 return resolved; 1637 })); 1638 }); 1639} 1640 1641/** 1642 * Convert camelcase to snake case 1643 * @param {string} camelcase 1644 * @returns {string} 1645 */ 1646function camelcaseToLowercaseWithDashes(camelcase) { 1647 return camelcase.replace(/([a-z])([A-Z])/g, '$1-$2').toLowerCase(); 1648} 1649 1650/** 1651 * Returns name of template used in Controller 1652 * @this {BaseController} 1653 * @returns {string} 1654 */ 1655function getTemplateName() { 1656 return camelcaseToLowercaseWithDashes(this.getClassname()).match(/((?:[a-zA-Z-]|_{2})+)/g)[0]; 1657} 1658/** 1659 * returns modifier string 1660 * @returns {string} 1661 */ 1662function getTemplateModifier() { 1663 return camelcaseToLowercaseWithDashes(this.getClassname()).match(/((?:[a-zA-Z-]|_{2})+)/g)[1]; 1664} 1665 1666/** 1667 * Remove bound listeners 1668 * @param {type} listeners 1669 * @returns {nm$_BaseController.prototype} 1670 */ 1671function removeListeners(listeners) { 1672 var listener; 1673 if (!listeners) { 1674 throw new Error('listeners to remove not specified'); 1675 } 1676 while (listeners[this._name] && listeners[this._name][this.id] && listeners[this._name][this.id].length) { 1677 listener = listeners[this._name][this.id].pop(); 1678 listener.target.removeEventListener(listener.type, listener.func); 1679 } 1680 return this; 1681} 1682 1683/** 1684 * Removes breakpoint listeners attached to the controller 1685 * @returns {nm$_BaseController.prototype} 1686 */ 1687function removeBreakpointListeners() { 1688 Breakpoint.removeListeners(this); 1689 return this; 1690} 1691 1692/** Push listener to listener storage 1693 * 1694 * @param {array} listeners listeners storage 1695 * @param {object} listener listener object {target,type,function} 1696 * @returns {BaseController.prototype} 1697 */ 1698function pushListener(listeners, listener) { 1699 if (!listeners[this._name]) { 1700 listeners[this._name] = {}; 1701 } 1702 if (!listeners[this._name][this.id]) { 1703 listeners[this._name][this.id] = []; 1704 } 1705 listeners[this._name][this.id].push(listener); 1706 return this; 1707} 1708 1709/** 1710 * 1711 * @param {function} fn 1712 * @param {object} data 1713 * @param {string} selector 1714 * @param {string} event_type 1715 * @param {boolean} once 1716 * @param {object} listeners 1717 * @param {Event} event 1718 * @returns {Array|undefined} 1719 */ 1720function eventHandler(fn, data, selector, event_type, once, listeners, event) { 1721 var elements; 1722 Debugger.logEvent(fn, data, selector, event_type, event, this); 1723 if (!fn) { 1724 return logger.error(this._name, this.id, 'Missing callback function for ' + selector); 1725 } 1726 elements = selector ? (typeof selector === 'string' ? this.selectAll(selector) : [selector]) : [this.DOMElement || this.DOMShadowElement]; 1727 if (!elements.length) { 1728 return logger.warning('No elements for selector "' + selector + '" found'); 1729 } 1730 if (event_type === 'clickoutside') { 1731 return [].forEach.call(elements, function (element) { 1732 if (element !== event.target && !element.contains(event.target)) { 1733 logger.groupCollapsed(selector + ' ' + event_type); 1734 logger.info(event, element); 1735 logger.groupEnd(); 1736 fn.call(this, event, data); 1737 if (once) { 1738 listeners[this._name][this.id] = listeners[this._name][this.id].filter(function (listener) { 1739 if (listener.fn === fn && listener.type === 'click') { 1740 listener.target.removeEventListener(listener.type, listener.func); 1741 } else { 1742 return true; 1743 } 1744 }); 1745 } 1746 } 1747 }, this); 1748 } 1749 [].forEach.call(elements, function (element) { 1750 if (element === event.target || element === window || element.contains(event.target)) { 1751 event.element = element; 1752 logger.groupCollapsed(selector + ' ' + event_type); 1753 logger.info(event, element); 1754 logger.groupEnd(); 1755 fn.call(this, event, data); 1756 if (once) { 1757 listeners[this._name][this.id] = listeners[this._name][this.id].filter(function (listener) { 1758 if (listener.fn === fn && listener.type === event_type) { 1759 listener.target.removeEventListener(listener.type, listener.func); 1760 } else { 1761 return true; 1762 } 1763 }); 1764 } 1765 } 1766 }, this); 1767} 1768 1769/** 1770 * 1771 * @param {Node} parent_element 1772 * @param {function} controller_callback 1773 * @returns {undefined} 1774 */ 1775function subcontrollersCallback(parent_element, controller_callback) { 1776 [].forEach.call(parent_element.querySelectorAll('[data-component]'), function (element) { 1777 controller_callback(this.getInstanceByElement(element), element); 1778 }, this); 1779} 1780 1781/** 1782 * Remove listeners, call beforeDestroy, unbind DOMElements if soft === false, call all destructors and call afterDestroy 1783 * @param {type} soft unbind DOMElements if soft === false 1784 * @returns {nm$_BaseController.prototype} 1785 */ 1786function destroy(soft) { 1787 if (!instances[this._name][this.id]) { 1788 return this; 1789 } 1790 1791 removeListeners.call(this, DOMListeners); 1792 removeListeners.call(this, globalListeners); 1793 removeListeners.call(this, modelListeners); 1794 removeBreakpointListeners.call(this); 1795 1796 this.beforeDestroy && this.beforeDestroy(soft); 1797 1798 destructors[this._name][this.id] = destructors[this._name][this.id].filter(function (destructor) { 1799 destructor.call(this); 1800 return false; 1801 }, this); 1802 1803 if (!soft) { 1804 this.DOMElement = null; 1805 this.DOMShadowElement = null; 1806 setTimeout(function () { 1807 if (!this.DOMElement) { 1808 delete instances[this._name][this.id]; 1809 } 1810 }.bind(this), 5); 1811 } 1812 1813 this.afterDestroy && this.afterDestroy(soft); 1814 1815 return this; 1816} 1817 1818/** Check if storage for class is already initialized 1819 * 1820 * @param {string} class_name 1821 * @returns {undefined} 1822 */ 1823function checkInstance(class_name) { 1824 if (!instances[class_name]) { 1825 instances[class_name] = {}; 1826 ids[class_name] = 0; 1827 } 1828} 1829 1830/** 1831 * 1832 * @param {Object} instance 1833 * @returns {undefined} 1834 */ 1835function set(instance) { 1836 var id; 1837 checkInstance(instance._name); 1838 id = ++ids[instance._name]; 1839 instances[instance._name][id] = instance; 1840 instance.setId(id); 1841} 1842 1843/* /Privates */ 1844 1845/** Control for view module 1846 * @class 1847 * 1848 * @param {object} context data to render module with 1849 * @returns {BaseController} 1850 */ 1851function BaseController(context) { 1852 this.data = context || this.data || {}; 1853 this._name = getTemplateName.call(this); 1854 this._mod = getTemplateModifier.call(this); 1855 this._resolved_helper = {}; 1856 1857 set(this); 1858 1859 destructors[this._name] = destructors[this._name] || {}; 1860 destructors[this._name][this.id] = destructors[this._name][this.id] || []; 1861 1862 EventTarget.call(this, true); 1863} 1864extend(EventTarget, BaseController); 1865 1866/** 1867 * Add BaseController instance to instances storage 1868 * @param {BaseController} instance 1869 * @returns {BaseController} 1870 */ 1871BaseController.reinstance = function (instance) { 1872 instances[instance._name][instance.id] = instance; 1873 return instance; 1874}; 1875 1876/** 1877 * @description Persistent data to be cloned on every rerender.
1878 * @type String[] 1879 */ 1880BaseController.PERSISTENT_DATA_KEYS = ['styleModifier']; 1881 1882/** Default function for adding listeners, this is called on every execute 1883 * To be overridden by child 1884 * 1885 * @returns {undefined} 1886 */ 1887BaseController.prototype.addListeners = function () {}; 1888 1889/** Function called before render, To be overridden by child 1890 * 1891 * @returns {undefined} 1892 */ 1893BaseController.prototype.beforeRender = function () {}; 1894 1895/** Function called befor destroy, To be overridden by child 1896 * 1897 * @returns {undefined} 1898 */ 1899BaseController.prototype.beforeDestroy = function () {}; 1900 1901/** function called after render, To be overridden by child 1902 * 1903 * @returns {undefined} 1904 */ 1905BaseController.prototype.afterRender = function () {}; 1906 1907/** Function called after destroy. To be overridden by child 1908 * 1909 * @returns {undefined} 1910 */ 1911BaseController.prototype.afterDestroy = function () {}; 1912 1913/** 1914 * 1915 * @param {number|string} id 1916 * @returns {BaseController.prototype} 1917 */ 1918BaseController.prototype.setId = function (id) { 1919 this.id = id; 1920 return this; 1921}; 1922 1923/** 1924 * 1925 * @param {DOMElement|string} element - element or selector 1926 * @returns {BaseController} 1927 */ 1928BaseController.prototype.getInstanceByElement = function (element) { 1929 var parts, id; 1930 if (!element) { 1931 return null; 1932 } 1933 parts = (typeof element === 'string' ? this.select(element) : element).getAttribute('data-component'); 1934 if (!parts) { 1935 return null; 1936 } 1937 parts = parts.split('-'); 1938 id = parts.pop(); 1939 return instances[parts.join('-').split('~')[0]][id]; 1940}; 1941 1942/** 1943 * Return parent controller 1944 * @param {string} name - controller name 1945 * @param {function} [callback] 1946 * @returns {BaseController|null} parent controller or null in case no parent matched 1947 */ 1948BaseController.prototype.getParent = function (name, callback) { 1949 var result; 1950 var parent = this.DOMElement || this.DOMShadowElement; 1951 parent && (parent = parent.parentNode); 1952 while ( 1953 parent !== null && !( 1954 parent.hasAttribute('data-component') && 1955 (!name || parent.getAttribute('data-component').match(new RegExp(name + '\\b'))) 1956 ) 1957 ) { 1958 parent = parent.parentNode; 1959 if (parent.classList === void 0) { 1960 return null; 1961 } 1962 } 1963 result = this.getInstanceByElement(parent); 1964 callback && result && callback(result); 1965 return result; 1966}; 1967 1968/** 1969 * 1970 * @param {string} name - controller name 1971 * @param {function} [callback] 1972 * @returns {array} array of child controllers 1973 */ 1974BaseController.prototype.getChildren = function (name, callback) { 1975 var selector; 1976 name && !Array.isArray(name) && (name = [name]); 1977 selector = name ? name.map(function (name) { 1978 return '[data-component^="' + name + '-"], [data-component^="' + name + '~"]'; 1979 }).join(',') : '[data-component]'; 1980 if (callback) { 1981 return this.selectAll(selector, function (children) { 1982 callback(children.map(this.getInstanceByElement).filter(Boolean)); 1983 }.bind(this)); 1984 } 1985 return this.selectAll(selector).map(this.getInstanceByElement).filter(Boolean); 1986}; 1987/** 1988 * 1989 * @param {Function|String} constructor 1990 * @param {function} [callback] 1991 * @returns {BaseController[]} 1992 */ 1993BaseController.prototype.getChildrenByClass = function (constructor, callback) { 1994 if (callback) { 1995 return this.getChildren(false, function (children) { 1996 callback(children.filter(function (instance) { 1997 return instance instanceof constructor || (instance.mixes && !!~instance.mixes.indexOf(function_name(constructor))); 1998 })); 1999 }); 2000 } 2001 return this.getChildren().filter(function (instance) { 2002 return instance instanceof constructor || (instance.mixes && !!~instance.mixes.indexOf(function_name(constructor))); 2003 }); 2004}; 2005 2006/** 2007 * 2008 * @returns {String} 2009 */ 2010BaseController.prototype.getClassname = function () { 2011 return function_name(this.constructor); 2012}; 2013 2014/** 2015 * Extract persistent data from this.data property 2016 * @returns {undefined} 2017 */ 2018BaseController.prototype.getPersistentData = function () { 2019 var persistent = {}; 2020 if (this.data && typeof this.data === 'object') { 2021 BaseController.PERSISTENT_DATA_KEYS.forEach(function (KEY) { 2022 if (this.data[KEY] === void 0) { 2023 return; 2024 } 2025 persistent[KEY] = this.data[KEY]; 2026 }, this); 2027 } 2028 return persistent; 2029}; 2030 2031/** 2032 * Returns proper parent element tag name (eg. table for tr, tr for td, div otherwise) 2033 * @param {String} tag_name tag name 2034 * @returns {String} parent tag name 2035 */ 2036function chooseParentElementTagName(tag_name) { 2037 return { 2038 thead: 'table', 2039 tbody: 'table', 2040 tr: 'tbody', 2041 td: 'tr' 2042 } [tag_name] || 'div'; 2043} 2044 2045/** 2046 * Execute template function, parse HTML to DOM and setup listeners 2047 * @param {Object} data 2048 * @returns {Promise} 2049 */ 2050BaseController.prototype.execute = function (data) { 2051 var template = getTemplateName.call(this); 2052 var template_data, html, first_tag; 2053 var persistent_data = this.getPersistentData(); 2054 if (!Template.t(template)) { 2055 throw new Error(template, 'template not set'); 2056 } 2057 this.data = data || this.data || {}; 2058 return this.resolveHelper().then(function () { 2059 template_data = this.getView(); 2060 mergeData(this.data, persistent_data); 2061 mergeData(template_data, persistent_data); 2062 html = Template.t(template)()(template_data); 2063 first_tag = (html.match(/<([\w-]+)/) || [])[1]; 2064 this.DOMShadowElement = document.createElement(chooseParentElementTagName(first_tag)); 2065 this.DOMShadowElement.insertAdjacentHTML('afterbegin', html); 2066 this.DOMShadowElement.normalize(); 2067 if (this.DOMShadowElement.firstElementChild) { 2068 this.DOMShadowElement = this.DOMShadowElement.firstElementChild; 2069 } 2070 this.DOMShadowElement.setAttribute('data-component', this._name + '-' + this.id); 2071 this.DOMShadowElement.classList.add(this._name); 2072 template !== this._name && this.DOMShadowElement.classList.add(template); 2073 this.addListeners && this.addListeners(); 2074 subcontrollersCallback.call(this, this.DOMShadowElement, function (controller, element) { 2075 controller.DOMShadowElement = element; 2076 controller.addListeners && controller.addListeners(); 2077 }); 2078 return this; 2079 }.bind(this)); 2080 2081}; 2082 2083/** 2084 * 2085 * @description Add listener to BaseController global context. Listening to all event across all BaseController instances. 2086 * @param {string} event_type - type of event to listen to 2087 * @param {function} fn - event handler 2088 * @param {boolean} once - remove after first trigger 2089 * @returns {BaseController} 2090 */ 2091BaseController.prototype.addGlobalListener = function (event_type, fn, once) { 2092 var func = fn.bind(this); 2093 this.on(event_type, func, this, false, once); 2094 return pushListener.call(this, globalListeners, { 2095 target: this, 2096 type: event_type, 2097 func: func 2098 }); 2099}; 2100 2101/** 2102 * @description Add destructor function to controller if not already added to be called on destroy. 2103 * @param {function} fn - destructor function 2104 * @returns {BaseController} 2105 */ 2106BaseController.prototype.addDestructor = function (fn) { 2107 !~destructors[this._name][this.id].indexOf(fn) && destructors[this._name][this.id].push(fn); 2108 return this; 2109};
2110 2111/** 2112 * @description Add a delegated listener on elements specified by selector, Listener is attached to controller root element and triggered if selector is matched in bubbling phase. This can be used for triggering actions from dynamically changed parts of component. 2113 * 2114 * @param {string|DOMElement} selector 2115 * @param {string|string[]} event_type - type of event to listen to; multiple event types as array or space delimited string 2116 * @param {function} fn function to be executed on event 2117 * @param {object} [data] optional data for event callback 2118 * @returns {BaseController} 2119 */ 2120BaseController.prototype.addDelegatedDOMListener = function (selector, event_type, fn, data) { 2121 var eventFn; 2122 if (Array.isArray(event_type) || (event_type.split(' ').length > 1 && (event_type = event_type.split(' ')))) { 2123 return event_type.forEach(function (event_type) { 2124 this.addDelegatedDOMListener(selector, event_type, fn, data); 2125 }, this); 2126 } 2127 2128 eventFn = eventHandler.bind(this, fn, data, selector, event_type, false, void 0); 2129 this.DOMShadowElement.addEventListener(event_type, eventFn); 2130 return pushListener.call(this, DOMListeners, { 2131 target: this.DOMShadowElement, 2132 type: event_type, 2133 func: eventFn 2134 }); 2135}; 2136/** 2137 * @description Shortcut for adding delegated listener on data-hook, same as delegatedDOMListener, but selector is created dynamically using hook. Hook selector is matched in bubbling phase. This can be used for triggering actions from dynamically changed parts of component. 2138 * 2139 * @param {string} hook - name of the hook 2140 * @param {string} event_type 2141 * @param {function} fn function to be executed on event 2142 * @param {object} [data] optional data for event callback 2143 * @returns {BaseController.prototype} 2144 */ 2145BaseController.prototype.addDelegatedHookListener = function (hook, event_type, fn, data) { 2146 return this.addDelegatedDOMListener('[data-hook="' + hook + '"]', event_type, fn, data); 2147}; 2148/** 2149 * @description Adding delegated listener on namespaced hook. More on listening on delegated events on addDelegatedHookListener. Namespaced hook is hook created by createNSHook() function, it's hook prefixed by name of the controller. 2150 * @param {string} hook - hook name 2151 * @param {string} event_type - type of event 2152 * @param {function} fn - function to be executed on event trigger 2153 * @param {object} [data] - optional data to be passed to event handler 2154 * @returns {BaseController} 2155 */ 2156BaseController.prototype.addDelegatedNSHookListener = function (hook, event_type, fn, data) { 2157 return this.addDelegatedDOMListener('[data-hook="' + function_name(this.constructor) + '-' + hook + '"]', event_type, fn, data); 2158}; 2159 2160BaseController.prototype.addDelegatedPartialListener = function (name, event_type, fn, data) { 2161 return this.addDelegatedDOMListener('[data-component^="' + name + '-"], [data-component^="' + name + '~"]', event_type, fn, data); 2162}; 2163 2164/** 2165 * 2166 * @description Shortcut for adding listener on data-hook, selector is constructed automatically from hook name, Hook is data attribute create by createHook() function. This data attribute is used for marking some parts of component as controllable. 2167 * 2168 * @param {string} hook - name of the hook 2169 * @param {string} event_type 2170 * @param {function} fn function to be executed on event 2171 * @param {object} [data] optional data for event callback 2172 * @param {boolean} once fire listener only once 2173 * @returns {BaseController.prototype} 2174 */ 2175BaseController.prototype.addHookListener = function (hook, event_type, fn, data, once) { 2176 return this.addDOMListener('[data-hook="' + hook + '"]', event_type, fn, data, once); 2177}; 2178 2179/** 2180 * @description Shortcut for adding listener on namespaced data-hook, selector is constructed automatically from hook name and controller name, Namespaced Hook is data attribute create by createNSHook() function. 2181 * @param {string} hook 2182 * @param {string} event_type 2183 * @param {function} fn 2184 * @param {object} [data] 2185 * @param {boolean} [once] 2186 * @returns {BaseController} 2187 */ 2188BaseController.prototype.addNSHookListener = function (hook, event_type, fn, data, once) { 2189 return this.addDOMListener('[data-hook="' + function_name(this.constructor) + '-' + hook + '"]', event_type, fn, data, once); 2190};
2191 2192BaseController.prototype.addPartialListener = function (name, event_type, fn, data, once) { 2193 return this.addDOMListener('[data-component^="' + name + '-"], [data-component^="' + name + '~"]', event_type, fn, data, once); 2194}; 2195 2196/** 2197 * 2198 * @description Add a listener on elements specified by css selector. 2199 * 2200 * @param {string|DOMElement} selector 2201 * @param {string|string[]} event_type Event type, array of event types or space separated event types 2202 * @param {function} fn function to be executed on event 2203 * @param {object} [data] optional data for event callback 2204 * @param {boolean} once fire listener only once 2205 * @returns {BaseController.prototype} 2206 */ 2207BaseController.prototype.addDOMListener = function (selector, event_type, fn, data, once) { 2208 var eventFn, elements, i; 2209 if (Array.isArray(event_type) || (event_type.split(' ').length > 1 && (event_type = event_type.split(' ')))) { 2210 return event_type.forEach(function (event_type) { 2211 this.addDOMListener(selector, event_type, fn, data, once); 2212 }, this); 2213 } 2214 eventFn = eventHandler.bind(this, fn, data, selector, event_type, once, DOMListeners); 2215 elements = selector ? (typeof selector === 'string' ? this.selectAll(selector) : [selector]) : [this.DOMShadowElement]; 2216 if (!elements.length) { 2217 logger.groupCollapsed('Cannot bind listener to non-existing elements'); 2218 logger.error(selector, this); 2219 logger.groupEnd(); 2220 return this; 2221 } 2222 for (i in elements) { 2223 elements[i].addEventListener(event_type, eventFn); 2224 pushListener.call(this, DOMListeners, { 2225 target: elements[i], 2226 type: event_type, 2227 func: eventFn, 2228 fn: fn 2229 }); 2230 } 2231 return this; 2232}; 2233 2234/** Add click-outside listener on elements specified by selector 2235 * 2236 * @param {string|DOMElement} selector 2237 * @param {function} fn function to be executed on event 2238 * @param {object} [data] optional data for event callback 2239 * @param {boolean} once fire listener only once 2240 * @returns {BaseController.prototype} 2241 */ 2242BaseController.prototype.addClickOutsideListener = function (selector, fn, data, once) { 2243 var eventFn = eventHandler.bind(this, fn, data, selector, 'clickoutside', once, DOMListeners); 2244 document.body.addEventListener('click', eventFn); 2245 return pushListener.call(this, DOMListeners, { 2246 target: document.body, 2247 type: 'click', 2248 func: eventFn, 2249 fn: fn 2250 }); 2251}; 2252 2253/** Add listener to given model 2254 * 2255 * @param {BaseModel} model 2256 * @param {string} event_type 2257 * @param {function} fn 2258 * @param {boolean} once listen only once and delete listener 2259 * @returns {BaseController.prototype} 2260 */ 2261BaseController.prototype.addModelListener = function (model, event_type, fn, once) { 2262 if (Array.isArray(event_type) || (event_type.split(' ').length > 1 && (event_type = event_type.split(' ')))) { 2263 return event_type.forEach(function (event_type) { 2264 this.addModelListener(model, event_type, fn, once); 2265 }, this); 2266 } 2267 model.on(event_type, fn, this, false, once); 2268 return pushListener.call(this, modelListeners, { 2269 target: model, 2270 type: event_type, 2271 func: fn 2272 }); 2273}; 2274 2275/** 2276 * Add breakpoint listener 2277 * 2278 * @param {array} breakpoints 2279 * @param {function} fn 2280 * @returns {BaseController.prototype} 2281 */ 2282BaseController.prototype.addBreakpointListener = function (breakpoints, fn) { 2283 (Array.isArray(breakpoints) ? breakpoints : [breakpoints]).forEach(function (breakpoint) { 2284 Breakpoint.addListener(this, breakpoint, fn); 2285 }, this); 2286 return this; 2287}; 2288 2289/** Rerender this module if already rendered 2290 * 2291 * @param {object} [data] - New data that will replace current controller this.data 2292 * @returns {Promise} 2293 */ 2294BaseController.prototype.rerender = function (data) { 2295 if (!this.DOMElement && !this.DOMShadowElement) { 2296 return Promise.resolve(this); 2297 } 2298 this.remove(true); 2299 return this.execute(data).then(function (control) { 2300 control.render(control.DOMElement); 2301 return control; 2302 }); 2303}; 2304 2305/** 2306 * Renders executed controller to the page 2307 * @param {DOMElement} element 2308 * @param {string} render_type - [beforebegin | afterbegin | beforeend | afterend | replaceWith (default)] 2309 * @returns {BaseController.prototype} 2310 */ 2311BaseController.prototype.render = function (element, render_type) { 2312 var replaced_controller = null; 2313 var children = this.getChildren();
2314 2315 this.beforeRender && this.beforeRender(); 2316 subcontrollersCallback.call(this, this.DOMShadowElement, function (controller) { 2317 controller.beforeRender && controller.beforeRender(); 2318 }); 2319 switch (render_type) { 2320 case 'beforebegin': 2321 case 'afterbegin': 2322 case 'beforeend': 2323 case 'afterend': 2324 element.insertAdjacentElement(render_type, this.DOMShadowElement); 2325 break; 2326 default: 2327 subcontrollersCallback.call(this, element || this.DOMElement, function (controller) { 2328 if (!~children.indexOf(controller)) { 2329 destroy.call(controller); 2330 } 2331 }); 2332 (element || this.DOMElement).parentNode.replaceChild(this.DOMShadowElement, (element || this.DOMElement)); 2333 replaced_controller = this.getInstanceByElement(element); 2334 if (replaced_controller && replaced_controller !== this) { 2335 destroy.call(replaced_controller); 2336 } 2337 } 2338 this.DOMElement = this.DOMShadowElement; 2339 this.DOMShadowElement = null; 2340 subcontrollersCallback.call(this, this.DOMElement, function (controller) { 2341 controller.DOMElement = controller.DOMShadowElement; 2342 controller.DOMShadowElement = null; 2343 }); 2344 this.afterRender && this.afterRender(); 2345 subcontrollersCallback.call(this, this.DOMElement, function (controller) { 2346 controller.afterRender && controller.afterRender(); 2347 }); 2348 return this; 2349}; 2350 2351/** 2352 * 2353 * @description Select node inside this component by given css selector, Cannot be used for selecting component itself. 2354 * 2355 * @param {string} selector 2356 * @param {function} [callback] 2357 * @returns {Element} 2358 */ 2359BaseController.prototype.select = function (selector, callback) { 2360 var result = null; 2361 var element = this.DOMShadowElement || this.DOMElement; 2362 if (!element) { 2363 return result; 2364 } 2365 2366 result = selector ? element.querySelector(selector) : element; 2367 callback && result && callback(result); 2368 return result; 2369}; 2370 2371/** 2372 * @description Select nodes inside this component by given css selector. 2373 * 2374 * @param {string} selector 2375 * @param {function} [callback] 2376 * @returns {Array} 2377 */ 2378BaseController.prototype.selectAll = function (selector, callback) { 2379 var result = []; 2380 var element = this.DOMShadowElement || this.DOMElement; 2381 if (!element) { 2382 return result; 2383 } 2384 2385 result = [].slice.call(element.querySelectorAll(selector)); 2386 callback && result && callback(result); 2387 return result; 2388}; 2389 2390/** 2391 * Select data-hook="selector" 2392 * @param {String} selector 2393 * @param {function} [callback] 2394 * @returns {Element} 2395 */ 2396BaseController.prototype.hook = function (selector, callback) { 2397 return this.select('[data-hook="' + selector + '"]', callback); 2398}; 2399/** 2400 * Select data-hook="ns-selector" 2401 * @param {String} selector 2402 * @param {function} [callback] 2403 * @returns {Element} 2404 */ 2405BaseController.prototype.nsHook = function (selector, callback) { 2406 return this.select('[data-hook="' + escape_string(this.getClassname() + '-' + selector) + '"]', callback); 2407}; 2408 2409/** 2410 * Select all data-hook="selector" 2411 * @param {string} selector 2412 * @param {function} [callback] 2413 * @returns {Element[]} 2414 */ 2415BaseController.prototype.hooks = function (selector, callback) { 2416 return this.selectAll('[data-hook="' + selector + '"]', callback); 2417}; 2418 2419/** 2420 * Returns closest data-hook="selector" 2421 * @param {string} selector 2422 * @param {Element} element 2423 * @param {function} [callback] 2424 * @returns {Element} 2425 */ 2426BaseController.prototype.closestHook = function (selector, element, callback) { 2427 var result = null; 2428 element = element || this.DOMShadowElement || this.DOMElement; 2429 if (!element) { 2430 return result; 2431 } 2432 2433 result = element.closest('[data-hook="' + selector + '"]'); 2434 callback && result && callback(result); 2435 return result; 2436}; 2437 2438/** 2439 * Creates data-hook attribute 2440 * @param {String} hook 2441 * @returns {String} 2442 */ 2443BaseController.prototype.createHook = function (hook) { 2444 return ' data-hook="' + escape_string(hook) + '" '; 2445}; 2446 2447/** 2448 * Creates data-hook attribute in module namespace 2449 * @param {String} hook 2450 * @returns {String} 2451 */ 2452BaseController.prototype.createNSHook = function (hook) { 2453 return ' data-hook="' + escape_string(function_name(this.constructor) + '-' + hook) + '" '; 2454}; 2455
2456/** Default helper for all controllers, to be overridden in children 2457 * 2458 * @returns {object} 2459 */ 2460BaseController.prototype.helper = function () { 2461 return this.data; 2462}; 2463 2464/** 2465 * Provides custom modifications and adding mod flags for module data 2466 * @returns {object} 2467 */ 2468BaseController.prototype.getView = function () { 2469 var _data = this._resolved_helper; 2470 var parts = function_name(this.constructor).match(/((?:[a-zA-Z-]|_{2})+)/g); 2471 if (_data) { 2472 _data._mod = camelcaseToLowercaseWithDashes(parts[1] || ''); 2473 _data._name = camelcaseToLowercaseWithDashes(parts[0]); 2474 } 2475 this.view_data = _data; 2476 return _data; 2477}; 2478 2479/** 2480 * @description Resolves async data in helper 2481 * @param {number} [depth] 2482 * @param {array} [entities] 2483 * @returns {Promise} 2484 */ 2485BaseController.prototype.resolveHelper = function (depth, entities) { 2486 return flatPromisedData(this.helper(), depth, entities).then(function (data) { 2487 this._resolved_helper = data; 2488 return this; 2489 }.bind(this), function (error) { 2490 logger.error(error); 2491 this._resolved_helper = {}; 2492 return this; 2493 }.bind(this)); 2494}; 2495 2496/** 2497 * 2498 * @param {Object} data 2499 * @returns {BaseController} 2500 */ 2501BaseController.prototype.setViewData = function (data) { 2502 this.view_data = data; 2503 return this; 2504}; 2505 2506/** 2507 * Set controllers to work with 2508 * @param {Object} controllersToSet object with controllers {controller_name: controller return function} 2509 * @returns {undefined} 2510 */ 2511BaseController.setControllers = function (controllersToSet) { 2512 controllers = controllersToSet; 2513}; 2514 2515/** 2516 * Get controller from static_controllers 2517 * @param {String} class_name 2518 * @returns {BaseController} 2519 */ 2520BaseController.static = function (class_name) { 2521 class_name = camelcaseToLowercaseWithDashes(class_name); 2522 if (!controllers[class_name]) { 2523 logger.info('Creating non-existing controller ' + class_name); 2524 controllers[class_name] = function () { 2525 return BaseController.create(class_name.replace('~', '_').replace(/(?:^|-|\b)(\w)/g, function (match, $1) { 2526 return $1.toUpperCase(); 2527 })); 2528 }; 2529 } 2530 return controllers[class_name](); 2531}; 2532 2533/** 2534 * Create new instance of BaseController 2535 * @param {string} class_name - name of controller class 2536 * @param {Object} context - data context for inner usage 2537 * @returns {BaseController} 2538 */ 2539BaseController.new = function (class_name, context) { 2540 return new(this.static(class_name))(context); 2541}; 2542 2543/** 2544 * Creates a controller 2545 * @param {String} controller_name 2546 * @param {Object} extend_controller controller to inherit from 2547 * @param {Object} mixins controller or array of controllers to mix with the new controller 2548 * @returns {BaseController} a class with className as its name 2549 */ 2550 BaseController.create = function (controller_name, extend_controller, mixins) { 2551 var controller = new Function('BaseController', 'function ' + controller_name + '(){BaseController.apply(this,arguments);this.onCreate&&this.onCreate()}return ' + controller_name)(BaseController); 2552 extend(extend_controller || BaseController, controller); 2553 mixins && (Array.isArray(mixins) ? mixins : [mixins]).forEach(function (mixin) { 2554 controller.mixes = controller.mixes || []; 2555 controller.mixes.push(function_name(mixin)); 2556 mix(mixin, controller); 2557 }); 2558 return controller; 2559}; 2560 2561/** Remove element from 2562 * 2563 * @param {Boolean} soft Do not remove DOMElement 2564 * @returns {undefined} 2565 */ 2566BaseController.prototype.remove = function (soft) { 2567 this.DOMElement && subcontrollersCallback.call(this, this.DOMElement, function (controller) { 2568 destroy.call(controller, soft); 2569 }); 2570 !soft && (this.DOMElement || {}).parentNode && this.DOMElement.parentNode.removeChild(this.DOMElement); 2571 destroy.call(this, soft); 2572}; 2573 2574module.exports = BaseController; 2575 2576}).call(this)}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) 2577},{"./Breakpoint.js":"Breakpoint","./EventTarget.js":3,"@icewarp/callback":"Callback","@icewarp/debugger":"debugger","@icewarp/escape-string":2,"@icewarp/extend":"extend","@icewarp/function-name":"function-name","@icewarp/icebrace-runtime":"icebrace-runtime","@icewarp/logger":"logger","@icewarp/mix":"mix","promise-polyfill":12}],"BaseEvent":[function(require,module,exports){ 2578"use strict"; 2579/** Parent of all event models 2580 * @class 2581 * 2582 * @param {object} data data to store inside event 2583 * @returns {BaseEvent} 2584 */ 2585function BaseEvent(data) { 2586 this.data = data; 2587 this.immediatePropagationStopped = false; 2588} 2589/** Stop propagation 2590 * 2591 * @returns {undefined} 2592 */ 2593BaseEvent.prototype.stopImmediatePropagation = function () { 2594 this.immediatePropagationStopped = true; 2595}; 2596module.exports = BaseEvent; 2597 2598},{}],"BaseModel":[function(require,module,exports){ 2599"use strict"; 2600var extend = require('@icewarp/extend'); 2601var delayed = require('@icewarp/delayed'); 2602var mix = require('@icewarp/mix'); 2603var EventTarget = require('./EventTarget.js'); 2604var ModelData = require('./ModelData.js'); 2605var BaseEvent = require('./BaseEvent.js'); 2606var overtype = require('@icewarp/overtype'); 2607 2608var tmp_id = 0; 2609 2610 2611/* Privates */ 2612 2613 2614/** Instances Storage 2615 * 2616 */ 2617var instances = {}; 2618 2619/** Models storage, To be filled up in app 2620 * 2621 */ 2622var models = {}; 2623 2624/** 2625 * Storage for class_name route rules 2626 * @type Object 2627 */ 2628var name_route_rule = {}; 2629 2630/** 2631 * Storage for class_name routes 2632 * @type Object 2633 */ 2634var name_route = {}; 2635 2636 2637/** 2638 * 2639 * @param {object} instance 2640 * @returns {undefined} 2641 */ 2642var set = function (instance) { 2643 var class_name = instance.getClassname(); 2644 checkInstance(class_name); 2645 instances[class_name][instance.getId()] = instance; 2646}; 2647var checkInstance = function (class_name) { 2648 if (!instances[class_name]) { 2649 instances[class_name] = {}; 2650 } 2651}; 2652 2653/** 2654 * Generates auto incremental id for temporary models 2655 * @returns {string} 2656 */ 2657function getTmpID() { 2658 return '_tmp_' + ++tmp_id; 2659} 2660 2661/** 2662 * Set itself to working data in all references 2663 * @this BaseModel 2664 * @argument {boolean} [recursive] - propagate recursively in entire reference chain 2665 * @argument {BaseModel[]} [instances] - Array of instances that was already processed 2666 * @returns {undefined} 2667 */ 2668function propagateChange(recursive, instances) { 2669 var class_name, id, key; 2670 instances = instances || []; 2671 if (~instances.indexOf(this)) { 2672 return; 2673 } 2674 instances.push(this); 2675 for (class_name in this.references) { 2676 for (id in this.references[class_name]) { 2677 for (key in this.references[class_name][id]) { 2678 BaseModel.instance(class_name, id)[(this.references[class_name][id][key] & BaseModel.REFERENCE_MASK.IS_ARRAY) ? 'pushData' : 'setData'](key, this); 2679 if (recursive) { 2680 propagateChange.call(BaseModel.instance(class_name, id), recursive, instances); 2681 } 2682 } 2683 } 2684 } 2685} 2686 2687/** 2688 * Propagate changes in defined upstream path 2689 * @param {string[]} path - Array of class names defining upstream path 2690 * @returns {undefined} 2691 */ 2692function propagateChangeUpstreamPath(path) { 2693 var next_stop, id, key; 2694 if (!path.length) { 2695 return; 2696 } 2697 next_stop = path.shift(); 2698 if (!this.references[next_stop]) { 2699 return; 2700 } 2701 for (id in this.references[next_stop]) { 2702 for (key in this.references[next_stop][id]) { 2703 BaseModel.instance(next_stop, id)[(this.references[next_stop][id][key] & BaseModel.REFERENCE_MASK.IS_ARRAY) ? 'pushData' : 'setData'](key, this); 2704 propagateChangeUpstreamPath.call(BaseModel.instance(next_stop, id), path); 2705 } 2706 } 2707 2708} 2709 2710/* /Privates */ 2711 2712/** Parent of all models 2713 * @class 2714 * 2715 * @requires extend 2716 * 2717 * @param {number|string} id 2718 * @returns {BaseModel} 2719 */ 2720function BaseModel(id) { 2721 var data; 2722 EventTarget.call(this); 2723 data = new ModelData(); 2724 this.getId = function () { 2725 return id; 2726 }; 2727 this.setId = function (new_id) { 2728 if (new_id === this.getId()) { 2729 return; 2730 } 2731 if (instances[this.getClassname()][new_id]) {
2732 throw new Error('Model ' + this.getClassname() + ' with id ' + new_id + ' already exists'); 2733 } 2734 this.tmp = (typeof new_id === 'string' && !!~new_id.indexOf('_tmp_')); 2735 delete instances[this.getClassname()][id]; 2736 id = new_id; 2737 set.call(BaseModel, this); 2738 }; 2739 this.caller = data.caller.bind(data); 2740 this.tmp = (typeof id === 'string' && !!~id.indexOf('_tmp_')); 2741 this.references = {}; 2742 set.call(BaseModel, this); 2743} 2744extend(EventTarget, BaseModel); 2745BaseModel.prototype.callback = require('@icewarp/callback'); 2746 2747/** 2748 * @type Object 2749 * @property {number} IN_ARRAY - if property is array property 2750 * @property {number} IS_IN_SERVER_DATA - if property is in server data 2751 */ 2752BaseModel.REFERENCE_MASK = { 2753 IS_ARRAY: 1, 2754 IS_IN_SERVER_DATA: 2 2755}; 2756 2757 2758/** 2759 * Destructor 2760 * @description Clears references in models with references to this instance. 2761 * Removes instance from Instances Storage. 2762 * 2763 * @returns {undefined} 2764 */ 2765BaseModel.prototype.destroy = function () { 2766 this.caller('destroy'); 2767 this.clearReferences(); 2768 delete instances[this.getClassname()][this.getId()]; 2769}; 2770/** 2771 * Clear references to this object from other BaseModel object 2772 * @param {BaseModel} [reference] reference to clear 2773 * @param {String} [modeldata_key] key to clear from 2774 * @returns {BaseModel.prototype} 2775 */ 2776BaseModel.prototype.clearReferences = function (reference, modeldata_key) { 2777 var i, model, j, key, instance, tmp_instance; 2778 for (i in this.references) { 2779 model = this.references[i]; 2780 for (j in model) { 2781 instance = model[j]; 2782 for (key in instance) { 2783 if(modeldata_key && modeldata_key !== key) { 2784 continue; 2785 } 2786 if(reference && reference !== BaseModel.instance(i, j)) { 2787 continue; 2788 } 2789 tmp_instance = instance[key]; 2790 delete instance[key]; 2791 if (tmp_instance & BaseModel.REFERENCE_MASK.IS_ARRAY) { 2792 BaseModel.instance(i, j).spliceData(key, this, { 2793 server_data: tmp_instance & BaseModel.REFERENCE_MASK.IS_IN_SERVER_DATA 2794 }); 2795 } else { 2796 BaseModel.instance(i, j).unsetData(key, { 2797 server_data: tmp_instance & BaseModel.REFERENCE_MASK.IS_IN_SERVER_DATA 2798 }); 2799 } 2800 } 2801 if(!Object.keys(instance).length) { 2802 delete model[j]; 2803 } 2804 } 2805 if(!Object.keys(model).length) { 2806 delete this.references[i]; 2807 } 2808 } 2809 2810 return this; 2811}; 2812/** 2813 * @param {boolean} real - Return real class name, not overridden 2814 * @returns {String} 2815 */ 2816BaseModel.prototype.getClassname = function (real) { 2817 return this.constructor.getClassname(real); 2818}; 2819 2820BaseModel.getClassname = function (real) { 2821 if (!real && this.classNameOverride) { 2822 return this.classNameOverride; 2823 } 2824 return this['name'] || (/function (.*?)\(/.exec((this).toString())[1] || '').trim(); 2825}; 2826 2827/** 2828 * @type {string} 2829 * @description Can override actual class name of model, This is used when you need several models to share same ID namespace, for example Model A has two children Model B and Model C. But A, B and C has same ID line and you want to prevent duplications so you set classNameOverride for B and C to A. 2830 */ 2831BaseModel.classNameOverride = ''; 2832 2833/** 2834 * @type {array} 2835 * @description Array of class names which classes can this model overtype to self. 2836 */ 2837BaseModel.canOvertype = []; 2838 2839/** Getter for data, if exist working data of given key then it's value is returned otherwise server data of given key is returned 2840 * 2841 * @description gets value from model data by given key. 2842 * @param {string} key 2843 * @param {object} [options] 2844 * @param {boolean} [options.server_data] - return server data directly 2845 * @returns {*} - If no key is provided returned value will be false, If key is provided but there is undefined value in working_data value from server_data is returned, If there is undefined value in both server and working data, undefined is returned. 2846 */ 2847BaseModel.prototype.getData = function (key, options) { 2848 return this.caller('getData', key, options && options.server_data); 2849}; 2850 2851/** Getter for data array, if exist working data of given key then it's value is returned otherwise server data of given key is returned 2852 * 2853 * @param {string} key 2854 * @param {object} [options] 2855 * @param {boolean} [options.server_data] 2856 * @returns {*} 2857 */ 2858BaseModel.prototype.getArray = function (key, options) { 2859 return this.caller('getArray', key, options && options.server_data); 2860}; 2861 2862/** Inits an array if undefined 2863 * 2864 * @param {string} key 2865 * @param {object} [options] 2866 * @param {boolean} [options.server_data] (default value: true) 2867 * @returns {*} 2868 */ 2869BaseModel.prototype.initArray = function (key, options) { 2870 this.caller('initArray', key, (!options || options.server_data === undefined) ? true : options.server_data); 2871 return this; 2872};
2873 2874/** Setter for all data 2875 * 2876 * @param {string} key 2877 * @param {*} value 2878 * @param {object} [options] 2879 * @param {string} [options.type] 2880 * @param {boolean} [options.server_data] true if you want to set server data. Like to save response from server 2881 * @param {boolean} [options.propagate_change] - propagate change to the upper model 2882 * @param {boolean} [options.propagate_recursive] - propagate change all the way up 2883 * @param {boolean} [options.upstream_path] - propagate change by the specified upstream path 2884 * @returns {BaseModel} 2885 */ 2886BaseModel.prototype.setData = function (key, value, options) { 2887 var old_value; 2888 if (!key) { 2889 throw 'Undefined key for setData ' + this.getClassname(); 2890 } 2891 old_value = this.getData(key, options); 2892 if(old_value instanceof BaseModel && old_value !== value) { 2893 old_value.clearReferences(this, key); 2894 } 2895 if (options && options.type) { 2896 value = overtype(options.type, value); 2897 } 2898 if (value === undefined) { 2899 return this; 2900 } 2901 if (value instanceof BaseModel) { 2902 value.addReference(this, key); 2903 } 2904 if (options && options.propagate_change) { 2905 propagateChange.call(this, options && options.propagate_recursive); 2906 } 2907 if (options && options.upstream_path) { 2908 propagateChangeUpstreamPath.call(this, options && options.upstream_path); 2909 } 2910 this.caller('setData', key, value, options && options.server_data) && (old_value !== value) && this.trigger(key + '_set', new BaseEvent({ 2911 model: this, 2912 old_value: old_value, 2913 new_value: value 2914 })) && update.call(this, key); 2915 return this; 2916}; 2917/** Push new value to data array 2918 * 2919 * @param {string} key 2920 * @param {*} value 2921 * @param {object} [options] 2922 * @param {boolean} [options.unshift] 2923 * @param {boolean} [options.server_data] true if you want to set server data. Like to save response from server 2924 * @param {boolean} [options.propagate_change] - propagate change to the upper model 2925 * @param {boolean} [options.propagate_recursive] - propagate change all the way up 2926 * @param {boolean} [options.upstream_path] - propagate change by the specified upstream path 2927 * @returns {BaseModel} 2928 */ 2929BaseModel.prototype.pushData = function (key, value, options) { 2930 if (value instanceof BaseModel) { 2931 value.addReference(this, key, true); 2932 } 2933 if (options && options.propagate_change) { 2934 propagateChange.call(this, options && options.propagate_recursive); 2935 } 2936 if (options && options.upstream_path) { 2937 propagateChangeUpstreamPath.call(this, options.upstream_path); 2938 } 2939 this.caller('pushData', key, value, options && options.unshift, options && options.server_data) && this.trigger(key + '_pushed', new BaseEvent({ 2940 model: this, 2941 new_value: value 2942 })) && update.call(this, key); 2943 return this; 2944}; 2945/** remove value from array data 2946 * 2947 * @param {string} key 2948 * @param {*} value 2949 * @param {options} [options] 2950 * @param {boolean} [options.server_data] 2951 * @param {boolean} [options.propagate_change] - propagate change to the upper model 2952 * @param {boolean} [options.propagate_recursive] - propagate change all the way up 2953 * @param {boolean} [options.upstream_path] - propagate change by the specified upstream path 2954 * @returns {BaseModel} 2955 */ 2956BaseModel.prototype.spliceData = function (key, value, options) { 2957 if (options && options.propagate_change) { 2958 propagateChange.call(this, options && options.propagate_recursive); 2959 } 2960 if (options && options.upstream_path) { 2961 propagateChangeUpstreamPath.call(this, options && options.upstream_path); 2962 } 2963 this.caller('spliceData', key, value, options && options.server_data) && this.trigger(key + '_spliced', new BaseEvent({ 2964 model: this, 2965 old_value: value 2966 })) && update.call(this, key); 2967 if(value instanceof BaseModel) { 2968 value.clearReferences(this, key); 2969 } 2970 return this; 2971}; 2972 2973/** 2974 * Get difference object between server_data array and working_data array 2975 * @param {string} key - key which array to compare 2976 * @returns {Object} - returns object with added property containing items newly added to array and removed property with items removed from array 2977 */ 2978BaseModel.prototype.getDataDiff = function (key) { 2979 var i; 2980 var working = this.getArray(key); 2981 var server = this.getArray(key, { 2982 server_data: true 2983 }); 2984 var removed = []; 2985 var added = []; 2986 var length = (working.length > server.length ? working.length : server.length); 2987 for (i = 0; i < length; i++) { 2988 working[i] && !~server.indexOf(working[i]) && added.push(working[i]); 2989 server[i] && !~working.indexOf(server[i]) && removed.push(server[i]); 2990 } 2991 return { 2992 added: added, 2993 removed: removed 2994 }; 2995}; 2996 2997/** 2998 * remove model property 2999 * @param {string} key 3000 * @param {object} [options] 3001 * @param {boolean} [options.server_data] 3002 * @param {boolean} [options.propagate_change] - propagate change to the upper model 3003 * @param {boolean} [options.propagate_recursive] - propagate change all the way up 3004 * @param {boolean} [options.upstream_path] - propagate change by the specified upstream path 3005 * @returns {BaseModel} 3006 */ 3007BaseModel.prototype.unsetData = function (key, options) { 3008 if (options && options.propagate_change) {
3009 propagateChange.call(this, options && options.propagate_recursive); 3010 } 3011 if (options && options.upstream_path) { 3012 propagateChangeUpstreamPath.call(this, options && options.upstream_path); 3013 } 3014 this.getArray(key, options).forEach(function(value) { 3015 if(value instanceof BaseModel) { 3016 value.clearReferences(this, key); 3017 } 3018 }, this); 3019 this.caller('unsetData', key, options && options.server_data) && this.trigger(key + '_unset', new BaseEvent({ 3020 model: this 3021 })) && update.call(this, key); 3022 return this; 3023}; 3024 3025/** 3026 * Filter function to remove duplicity 3027 * @param {*} value 3028 * @param {number} index 3029 * @param {Array} self 3030 * @returns {Boolean} 3031 */ 3032function onlyUnique(value, index, self) { 3033 return self.indexOf(value) === index; 3034} 3035 3036/** 3037 * 3038 * Trigger update event on data change 3039 * @this {BaseModel} 3040 * @param {string} key 3041 * @returns {undefined} 3042 */ 3043function update(key) { 3044 this.keys = this.keys || []; 3045 this.keys.push(key); 3046 delayed(function () { 3047 this.trigger('update', new BaseEvent({ 3048 model: this, 3049 keys: this.keys.filter(onlyUnique) 3050 })); 3051 this.keys = []; 3052 }, this, 5, this.getClassname() + '_' + this.getId() + '_update'); 3053} 3054 3055/** 3056 * Add model to referential table 3057 * @param {BaseModel} reference_model 3058 * @param {string} key 3059 * @param {boolean} in_array 3060 * @param {boolean} server_data 3061 * @returns {BaseModel} 3062 */ 3063BaseModel.prototype.addReference = function (reference_model, key, in_array, server_data) { 3064 this.references = this.references || {}; 3065 this.references[reference_model.getClassname()] = this.references[reference_model.getClassname()] || {}; 3066 this.references[reference_model.getClassname()][reference_model.getId()] = this.references[reference_model.getClassname()][reference_model.getId()] || {}; 3067 this.references[reference_model.getClassname()][reference_model.getId()][key] = 0 + (in_array ? BaseModel.REFERENCE_MASK.IS_ARRAY : 0) + (server_data ? BaseModel.REFERENCE_MASK.IS_IN_SERVER_DATA : 0); 3068 return this; 3069}; 3070/** Propagate working data to server data 3071 * @param {object} [options] 3072 * @param {boolean} [options.recursive] - save recursively 3073 * @returns {BaseModel} 3074 */ 3075BaseModel.prototype.saveWorkingData = function (options) { 3076 var working_data, key; 3077 if (options && options.recursive) { 3078 options.saved = options.saved || []; 3079 if (~options.saved.indexOf(this)) { 3080 return this; 3081 } 3082 options.saved.push(this); 3083 working_data = this.getWorkingData(); 3084 for (key in working_data) { 3085 if (working_data[key] instanceof BaseModel) { 3086 working_data[key].saveWorkingData(options); 3087 } 3088 } 3089 } 3090 this.caller('saveWorkingData'); 3091 return this; 3092}; 3093/** Returns all working data 3094 * 3095 * @returns {object} 3096 */ 3097BaseModel.prototype.getWorkingData = function () { 3098 return this.caller('getWorkingData'); 3099}; 3100/** get keys of all working data 3101 * 3102 * @returns {array} 3103 */ 3104BaseModel.prototype.getWorkingDataKeys = function () { 3105 return this.caller('getWorkingDataKeys'); 3106}; 3107/** Flush all working data 3108 * @param {object} [options] 3109 * @param {boolean} [options.recursive] - save recursively 3110 * @returns {BaseModel} 3111 */ 3112BaseModel.prototype.flushWorkingData = function (options) { 3113 var key; 3114 var working_data = this.getWorkingData(); 3115 if (options && options.recursive) { 3116 options.flushed = options.flushed || []; 3117 if (~options.flushed.indexOf(this)) { 3118 return this; 3119 } 3120 options.flushed.push(this); 3121 for (key in working_data) { 3122 if (working_data[key] instanceof BaseModel) { 3123 working_data[key].flushWorkingData(options); 3124 } 3125 } 3126 } 3127 3128 this.caller('flushWorkingData'); 3129 3130 for (key in working_data) { 3131 this.trigger(key + '_set', new BaseEvent({ 3132 model: this, 3133 old_value: working_data[key], 3134 new_value: this.getData(key) 3135 })); 3136 } 3137 3138 return this; 3139}; 3140 3141/** 3142 * @description Overtype this to arg model, this function will go thur all references and adds new instance to all references. Calling destroy on old instance will remove model from all references in the end. 3143 * @param {BaseModel} model - static class of overtype target 3144 * @param {array} args - arguments for constructor 3145 * @returns {BaseModel} - returns overtype instance 3146 */ 3147BaseModel.prototype.overtypeTo = function (model, args) { 3148 var key, reference_classname, reference_id, new_instance, rm, rmi; 3149 var server_data = this.caller('getServerData'); 3150 var working_data = this.getWorkingData(); 3151 var references = JSON.parse(JSON.stringify(this.references)); 3152 this.destroy(); 3153 new_instance = new(model.bind.apply(model, args)); 3154 for (reference_classname in references) { 3155 rm = references[reference_classname]; 3156 for (reference_id in rm) { 3157 rmi = rm[reference_id]; 3158 for (key in rmi) { 3159 BaseModel.instance(reference_classname, reference_id)[rmi[key] & BaseModel.REFERENCE_MASK.IS_ARRAY ? 'pushData' : 'setData'](key, new_instance, { 3160 server_data: rmi[key] & BaseModel.REFERENCE_MASK.IS_IN_SERVER_DATA 3161 }); 3162 } 3163 } 3164 } 3165 for (key in server_data) { 3166 new_instance.setData(key, server_data[key], { 3167 server_data: true 3168 }); 3169 } 3170 for (key in working_data) { 3171 new_instance.setData(key, working_data[key]); 3172 } 3173 references = null; 3174 return new_instance; 3175}; 3176 3177/** Factory for Model instances 3178 * 3179 * @param {string} class_name name of the class you want to create 3180 * @param {string|number} [id] if there is no id given system generates tmp id based on timestamp, models like this are used for temporary data storage before saving on server.
3181 * @param {*} args any arguments will be passed to the constructor and to the onCreate function 3182 * @returns {BaseModel} 3183 */ 3184BaseModel.instance = function (class_name, id, args) { 3185 var model = this.static(class_name); 3186 var argumenty = [].slice.call(arguments); 3187 class_name = model.getClassname(); 3188 argumenty[1] = id = id !== void 0 ? id : model.singleton ? 0 : (getTmpID()); 3189 checkInstance(class_name); 3190 if (instances[class_name][id]) { 3191 if (model.getClassname(true) !== instances[class_name][id].getClassname(true) && ~model.canOvertype.indexOf(class_name)) { 3192 return instances[class_name][id].overtypeTo(model, argumenty); 3193 } 3194 return instances[class_name][id]; 3195 } 3196 return new(model.bind.apply(model, argumenty)); 3197}; 3198 3199BaseModel.instanceExists = function (class_name, id) { 3200 return !!(instances[class_name] && instances[class_name][id]); 3201}; 3202 3203/** 3204 * Returns whether passed instance is an instance of class_name 3205 * @param {object} instance 3206 * @param {String} class_name instance class_name to compare with 3207 * @returns {Boolean} 3208 */ 3209BaseModel.instanceof = function (instance, class_name) { 3210 return instance instanceof BaseModel && instance.instanceof(class_name); 3211}; 3212 3213/** 3214 * Returns whether model is instance of class_name 3215 * @param {String} class_name instance class_name to compare with 3216 * @returns {Boolean} 3217 */ 3218BaseModel.prototype.instanceof = function (class_name) { 3219 return this instanceof BaseModel.static(class_name); 3220}; 3221 3222BaseModel.modelExists = function (class_name) { 3223 return !!models[this.checkNameRoute(class_name)]; 3224}; 3225/** 3226 * Sets models to central storage 3227 * @param {object} modelsToSet 3228 * @returns {undefined} 3229 */ 3230BaseModel.setModels = function (modelsToSet) { 3231 if (Object.keys(models).length) { 3232 return Object.keys(modelsToSet).forEach(function (key) { 3233 models[key] = modelsToSet[key]; 3234 }); 3235 } 3236 models = modelsToSet; 3237}; 3238/** 3239 * Sets single model to global storage 3240 * @param {BaseModel} model 3241 * @returns {undefined} 3242 */ 3243BaseModel.setModel = function (model) { 3244 models[model.getClassname()] = function () { 3245 return model; 3246 }; 3247}; 3248 3249/** 3250 * @summary Check name_route for remapping to real class name 3251 * @description Check name_route storage for route to real class_name for this link, if there is no route, go thru all rules and test ling againts them. If there is match cache found link to name_route storage. 3252 * @param {String} link 3253 * @returns {unresolved} 3254 */ 3255BaseModel.checkNameRoute = function (link) { 3256 var result, match, source; 3257 if (name_route[link]) { 3258 return name_route[link]; 3259 } 3260 for (source in name_route_rule) { 3261 if ((result = link.match(name_route_rule[source]))) { 3262 match = source; //partial match 3263 if (result[0] === result.input) { 3264 return name_route[link] = source; //fullmatch 3265 } 3266 } 3267 } 3268 return match ? (name_route[link] = match) : link; 3269}; 3270/** 3271 * @summary Register classname routing 3272 * @description Register class_name link to ream class_name, if you register string you are creating direct link from one string to another. You can also register regular expression. Be carful with regular expression, because it will be evaluated against every class_name in eventy BaseModel static call, that may cause performance issues with many registered rules, or with badly written regexp. 3273 * @param {string|RegExp} link 3274 * @param {string} source 3275 * @returns {nm$_BaseModel.BaseModel} 3276 */ 3277BaseModel.registerNameRoute = function (link, source) { 3278 if (link instanceof RegExp) { 3279 name_route_rule[source] = link; 3280 return this; 3281 } 3282 name_route[link] = source; 3283 return this; 3284}; 3285 3286/** 3287 * Returns static object of class_name 3288 * @param {string} class_name 3289 * @returns {BaseModel} 3290 */ 3291BaseModel.static = function (class_name) { 3292 class_name = this.checkNameRoute(class_name); 3293 if (!this.modelExists(class_name)) { 3294 throw class_name + ' model doesn\'t exist'; 3295 } 3296 return models[class_name](); 3297}; 3298 3299/** 3300 * Creates a model 3301 * @param {type} modelName 3302 * @param {Object} mixins model or array of models to mix with the new model 3303 * @returns {BaseModel} 3304 */ 3305BaseModel.create = function (modelName, mixins) { 3306 var model = new Function('BaseModel', 'function ' + modelName + '(){BaseModel.apply(this,arguments);this.onCreate&&this.onCreate.apply(this, arguments)}return ' + modelName)(BaseModel); 3307 extend(this, model);
3308 mixins && (Array.isArray(mixins) ? mixins : [mixins]).forEach(function (mixin) { 3309 mix(mixin, model); 3310 }); 3311 return model; 3312}; 3313 3314/** 3315 * Get temporary instances by class_name 3316 * @param {string} class_name 3317 * @returns {BaseModel[]} 3318 */ 3319BaseModel.getTmpInstances = function (class_name) { 3320 return Object.keys((instances[class_name] || {})).map(function (id) { 3321 return BaseModel.instance(class_name, id); 3322 }).filter(function (instance) { 3323 return instance.tmp; 3324 }); 3325}; 3326 3327module.exports = BaseModel; 3328 3329},{"./BaseEvent.js":"BaseEvent","./EventTarget.js":3,"./ModelData.js":4,"@icewarp/callback":"Callback","@icewarp/delayed":"delayed","@icewarp/extend":"extend","@icewarp/mix":"mix","@icewarp/overtype":8}],"Breakpoint":[function(require,module,exports){ 3330"use strict"; 3331var functionName = require('@icewarp/function-name'); 3332var delayed = require('@icewarp/delayed'); 3333 3334var Breakpoint = { 3335 all: [] 3336}; 3337 3338var breakpoint_listeners = {}; 3339 3340// lower boundries 3341var breakpoints = { 3342 xs: [0, 543], 3343 sm: [544, 767], 3344 md: [768, 991], 3345 lg: [992, 1199], 3346 xl: [1200, 99999] 3347}; 3348 3349var i, listeners; 3350 3351for (i in breakpoints) { 3352 Breakpoint['all'].push(i); 3353 Breakpoint[i] = i; 3354 breakpoint_listeners[i] = []; 3355 'matchMedia' in window && matchMedia('(min-width: ' + breakpoints[i][0] + 'px) and (max-width: ' + breakpoints[i][1] + 'px)').addListener(function (breakpoint, event) { 3356 if (!event.matches) { 3357 return; 3358 } 3359 listeners = breakpoint_listeners[breakpoint].slice(); 3360 listeners.forEach(function (listener) { 3361 delayed(function () { 3362 if (~breakpoint_listeners[breakpoint].indexOf(listener)) { 3363 listener.fn ? listener.fn.call(listener.context, breakpoint, breakpoints[breakpoint]) : listener.context.rerender(); 3364 } 3365 }, this, 50, functionName(listener.context) + listener.context.id); 3366 }); 3367 }.bind(null, i)); 3368} 3369 3370Breakpoint.getCurrent = function () { 3371 var client_width = document.body.clientWidth; 3372 var i; 3373 for (i in breakpoints) { 3374 if (client_width >= breakpoints[i][0] && client_width <= breakpoints[i][1]) { 3375 return i; 3376 } 3377 } 3378 return i; 3379}; 3380 3381Breakpoint.addListener = function (context, breakpoint, fn) { 3382 breakpoint_listeners[breakpoint].push({ 3383 context: context, 3384 fn: fn 3385 }); 3386}; 3387 3388Breakpoint.removeListeners = function (self) { 3389 var breakpoint; 3390 for (breakpoint in breakpoint_listeners) { 3391 breakpoint_listeners[breakpoint] = breakpoint_listeners[breakpoint].filter(function (listener) { 3392 return listener.context !== self; 3393 }); 3394 } 3395}; 3396 3397module.exports = Breakpoint; 3398 3399},{"@icewarp/delayed":"delayed","@icewarp/function-name":"function-name"}],"Callback":[function(require,module,exports){ 3400"use strict"; 3401var Logger = require('@icewarp/logger'); 3402var defaults = { 3403 error: Logger.error 3404}; 3405/** 3406 * @type {Object} 3407 * @description Defined middlewares by type 3408 */ 3409var middlewares = { 3410 3411}; 3412 3413/** 3414 * @description Applying all middlewares in series 3415 * @param {function} cb - callback handler for given type 3416 * @param {string} type - type of callback 3417 * @param {Object} ctx - context of callback handler 3418 * @param {array} args - array of arguments 3419 * @returns {boolean} - true if is should stop propagation and false for continue 3420 */ 3421function applyMiddlewares(cb, type, ctx, args) { 3422 var mid_obj; 3423 if (!middlewares[type] || !middlewares[type].length) { 3424 return true; 3425 } 3426 for (var i = 0; i < middlewares[type].length; i++) { 3427 mid_obj = middlewares[type][i]; 3428 if (!mid_obj.condition || mid_obj.condition.apply(ctx, args)) { 3429 if (mid_obj.middleware.apply(ctx, args) === false) { 3430 return false; 3431 } 3432 } 3433 } 3434 return true; 3435} 3436/** 3437 * Function to call function by type if exists 3438 * @module Callback 3439 * @param {string} type 3440 * @param {function} callback_object 3441 * @param {*} [args] 3442 * @returns {undefined} 3443 */ 3444function Callback(type, callback_object) { 3445 var cb, ctx = null; 3446 var args = [].slice.call(arguments).splice(2); 3447 if (callback_object && typeof callback_object[type] === 'function') { 3448 cb = callback_object[type]; 3449 ctx = callback_object.context || null; 3450 if (!applyMiddlewares(cb, type, ctx, args)) { 3451 return; 3452 } 3453 } else if (typeof defaults[type] === 'function') { 3454 cb = defaults[type]; 3455 } 3456 cb && cb.apply(ctx, args); 3457} 3458Callback.SUCCESS = 'success'; 3459Callback.ERROR = 'error'; 3460Callback.DONE = 'done'; 3461 3462/** 3463 * Set default Callback[type] function 3464 * @param {String} type 3465 * @param {Function} fn 3466 * @return {Callback} 3467 */
3468Callback.setDefault = function (type, fn) { 3469 defaults[type] = fn; 3470 return this; 3471}; 3472 3473/** 3474 * @description Add middleware function before async action and callback execution. Middleware function will be executed with callback function context and can be controller via condition function. Condition function ex executed with context and arguments of callback function 3475 * @param {string} type - type of callback (success, error, done, etc...) 3476 * @param {function} middleware - middleware function to run before 3477 * @param {function} condition - function that returns boolean if middleware should be applied before callback 3478 * @return {Callback} 3479 */ 3480Callback.addMiddleware = function (type, middleware, condition) { 3481 middlewares[type] = middlewares[type] || []; 3482 middlewares[type].push({ 3483 condition: condition, 3484 middleware: middleware 3485 }); 3486 return this; 3487}; 3488 3489/** 3490 * @description Remove middleware by middleware function and condition function 3491 * @param {string} type - type of callback (success, error, done, etc...) 3492 * @param {function} middleware - middleware function to run before 3493 * @param {function} condition - function that returns boolean if middleware should be applied before callback 3494 * @return {Callback} 3495 */ 3496Callback.removeMiddleware = function (type, middleware, condition) { 3497 var index; 3498 if (!middlewares[type] || !middlewares[type].length) { 3499 return this; 3500 } 3501 middlewares[type].some(function (mid_obj, i) { 3502 if (mid_obj.middleware === middleware && (!mid_obj.condition || mid_obj.condition === condition)) { 3503 index = i; 3504 return true; 3505 } 3506 return false; 3507 }); 3508 middlewares[type].splice(index, 1); 3509 return this; 3510}; 3511 3512module.exports = Callback; 3513 3514},{"@icewarp/logger":"logger"}],"Library":[function(require,module,exports){ 3515"use strict"; 3516var Request = require('@icewarp/request'); 3517var Callback = require('@icewarp/callback'); 3518var Library = {}; 3519 3520var storage = {}; 3521var path = './libs/'; 3522 3523/** 3524 * Set new library path 3525 * @param {string} new_path 3526 * @returns {undefined} 3527 */ 3528Library.setPath = function (new_path) { 3529 path = new_path; 3530}; 3531 3532/** 3533 * Get library 3534 * @param {string} name 3535 * @param {@icewarp/callback} callback 3536 * @param {string} [custom_path] custom path only for this request 3537 * @param {object} lib_storage custom storage for required lib 3538 * @returns {unresolved} 3539 */ 3540Library.get = function (name, callback, custom_path, lib_storage) { 3541 var _storage = lib_storage || storage; 3542 var request; 3543 if (_storage[name]) { 3544 return Callback('success', callback, _storage[name]); 3545 } 3546 request = new Request({ 3547 url: (custom_path || path) + name + '.js', 3548 method: 'GET' 3549 }); 3550 request.on('load', function (event, response) { 3551 if (response.status === 200) { 3552 new Function('window', response.response)(_storage); 3553 return Callback('success', callback, _storage[name]); 3554 } 3555 Callback('error', callback, response); 3556 }); 3557 3558 request.on('error', function () { 3559 Callback('error', callback); 3560 }); 3561 request.on('abort', function () { 3562 Callback('error', callback); 3563 }); 3564 request.send(); 3565}; 3566 3567/** 3568 * Clean lib storage 3569 * @param {string} [name] 3570 * @returns {undefined} 3571 */ 3572Library.clean = function (name) { 3573 if (name) { 3574 delete storage[name]; 3575 } else { 3576 storage = {}; 3577 } 3578}; 3579 3580module.exports = Library; 3581 3582},{"@icewarp/callback":"Callback","@icewarp/request":"request"}],"debugger":[function(require,module,exports){ 3583"use strict"; 3584/** 3585 * Log storage 3586 * @type Array 3587 */ 3588var log = []; 3589/** 3590 * Actual log level 3591 * @type Number 3592 */ 3593var log_level = 0; 3594var MouseTracking = require('./MouseTracking'); 3595/** 3596 * Power of last level 3597 * @type Number 3598 */ 3599var power = 0; 3600/** 3601 * Dynamic Entry Classes Storage 3602 */ 3603var entries = {}; 3604 3605/** 3606 * 3607 * @param {string} name 3608 * @param {number} level 3609 * @returns {debug} 3610 */ 3611function entryFactory(name, level) { 3612 name = name.toLowerCase().split('_').map(function (part) { 3613 return part[0].toUpperCase() + part.slice(1); 3614 }).join(''); 3615 entries[level] = new Function("return function " + name + "Entry(data){this.data = data;this.data.stamp = Date.now();}")(); 3616 return this; 3617} 3618 3619function transform(element, x, y, unit) { 3620 unit = unit || 'px'; 3621 ['-webkit-', '-ms-', ''].forEach(function (prefix) { 3622 element.style[prefix + "transform"] = "translate(" + x + unit + ", " + y + unit + ")"; 3623 }); 3624} 3625 3626function rulerEventHandler(event) { 3627 transform(document.getElementById('ruler'), event.clientX, event.clientY); 3628 document.getElementById('rulerCoordinates').textContent = "X: " + event.clientX + " Y: " + event.clientY; 3629} 3630
3631/** 3632 * @class Debugger 3633 * class for logging errors and actions thru App for easier debugging 3634 */ 3635var Debugger = { 3636 logEvent: function (fn, data, selector, event_type, event, module) { 3637 this.logAction({module: module.getClassname()/*, fn: fn.toString()*/, data: data, selector: selector.toString(), event_type: event_type/*, event: event*/}, this.levels.EVENT); 3638 }, 3639 /** 3640 * Log action 3641 * @param {object} data 3642 * @param {number} type 3643 * @returns {Debugger} 3644 */ 3645 logAction: function (data, type) { 3646 if (log_level & type) { 3647 log.push(new entries[type](data)); 3648 if (log.length > this.log_length) { 3649 if (this.dump && this.dump.fn) { 3650 this.dump.fn.call(this.dump.context || this, 'mouse', JSON.stringify(log)); 3651 log = []; 3652 } else { 3653 log.shift(); 3654 } 3655 } 3656 } 3657 return this; 3658 }, 3659 /** 3660 * Disable js error handeling 3661 * @type boolean 3662 */ 3663 swallow: false, 3664 /** length of stored log 3665 * @type number 3666 */ 3667 log_length: 500, 3668 /** 3669 * @type object|boolean 3670 */ 3671 error_handler: false, 3672 /** 3673 * Set external error handler 3674 * @param {function} fn 3675 * @param {object} context 3676 * @returns {undefined} 3677 */ 3678 setErrorHandler: function (fn, context) { 3679 this.error_handler = {fn: fn, context: context}; 3680 return this; 3681 }, 3682 /** 3683 * Init Debugger 3684 * @param {object} options 3685 * @returns {Debugger} 3686 */ 3687 init: function (options) { 3688 log_level = options.level; 3689 this.swallow = options.swallow || false; 3690 this.log_length = options.log_length || 500; 3691 this.dump = options.dump || false; 3692 options.error_handler && this.setErrorHandler(options.error_handler, options.error_handler_context); 3693 (log_level & this.levels.MOUSE_TRACKING) && MouseTracking.initTracking(options.mouse_log_length, this.dump); 3694 return this; 3695 }, 3696 /** 3697 * Show Logs 3698 * @returns {undefined} 3699 */ 3700 show: function () { 3701 var data = {}; 3702 log.forEach(function (entry, i) { 3703 data[entry.data.stamp + "." + i] = entry; 3704 }); 3705 console.log(data); 3706 console.log(MouseTracking.getData()); 3707 }, 3708 /** 3709 * Play mouse movements 3710 * @returns {undefined} 3711 */ 3712 mousePlay: function () { 3713 MouseTracking.mousePlay(); 3714 }, 3715 /** 3716 * Dynamic levels storage 3717 */ 3718 levels: {}, 3719 /** 3720 * Add new log level to Debugger, This action will also creates new log entry class 3721 * @param {string} key 3722 * @returns {Debugger} 3723 */ 3724 addLogLevel: function (key) { 3725 if (this.levels[key]) { 3726 throw Error('Level ' + key + ' already exists'); 3727 } 3728 this.levels[key] = Math.pow(2, power++); 3729 return entryFactory.call(this, key, this.levels[key]); 3730 }, 3731 /** 3732 * enables ruller 3733 * @returns {Debugger} 3734 */ 3735 enableRuler: function () { 3736 if (document.getElementById('ruler')) { 3737 return; 3738 } 3739 3740 var ruler = document.createElement('i'); 3741 ruler.setAttribute('id', 'ruler'); 3742 var style = document.createElement('style'); 3743 style.textContent = "\ 3744 #ruler {\ 3745 position: absolute;\ 3746 top: 0;\ 3747 left: 0;\ 3748 will-change: transform;\ 3749 }\ 3750 #rulerCoordinates {\ 3751 position: static;\ 3752 opacity: 0.5;\ 3753 background-color: #000;\ 3754 color: #fff;\ 3755 padding: 2px 5px;\ 3756 }\ 3757 #ruler::after, #ruler::before {\ 3758 position: absolute;\ 3759 content: '';\ 3760 background-color: #00ff00;\ 3761 }\ 3762 #ruler::before {\ 3763 width:1px;\ 3764 height: 200vh;\ 3765 top: -100vh;\ 3766 }\ 3767 #ruler::after {\ 3768 height:1px;\ 3769 width: 200vw;\ 3770 left: -100vw;\ 3771 }\ 3772 body {\ 3773 overflow: hidden !important;\ 3774 }\ 3775 * {\ 3776 cursor: none !important;\ 3777 }\ 3778 "; 3779 ruler.appendChild(style); 3780 document.body.appendChild(ruler); 3781 3782 var rulerCoordinates = document.createElement('span'); 3783 rulerCoordinates.setAttribute('id', 'rulerCoordinates'); 3784 document.body.appendChild(rulerCoordinates); 3785 3786 document.body.addEventListener('mousemove', rulerEventHandler); 3787 return this; 3788 }, 3789 /** 3790 * disables ruler 3791 * @returns {Debugger} 3792 */ 3793 disableRuler: function () { 3794 document.body.removeEventListener('mousemove', rulerEventHandler); 3795 var ruler = document.getElementById('ruler'); 3796 ruler.parentNode.removeChild(ruler); 3797 return this; 3798 } 3799 3800}; 3801typeof window !== 'undefined' && (window.onerror = function (message, source, lineno, colno, error) { 3802 Debugger.logAction({message: message, source: source, lineno: lineno, colno: colno, error: error}, Debugger.levels.ERRORS); 3803 this.error_handler && this.error_handler.fn.apply(this.error_handler.context || this, arguments); 3804 if (Debugger.swallow) { 3805 return false;
3806 } 3807}); 3808 3809Debugger.addLogLevel("ERROR") 3810 .addLogLevel("XHR") 3811 .addLogLevel("WS") 3812 .addLogLevel("EVENT") 3813 .addLogLevel("MOUSE_TRACKING"); 3814module.exports = Debugger; 3815},{"./MouseTracking":1}],"delayed":[function(require,module,exports){ 3816"use strict"; 3817/** 3818 * stack of delayed functions 3819 * @type {object} 3820 */ 3821var list = {}; 3822/** 3823 * Function to delay function run 3824 * @param {function} func 3825 * @param {object} context 3826 * @param {number} delay 3827 * @param {string} ns - Namespace 3828 * @returns {undefined} 3829 */ 3830function delayed(func, context, delay, ns) { 3831 ns = ns || func.toString().replace(/\s/g, ""); 3832 list[ns] && clearTimeout(list[ns].timeout); 3833 list[ns] = { 3834 func: func, context: context, timeout: setTimeout(function () { 3835 func.call(context); 3836 delete list[ns]; 3837 }, delay || 1000) 3838 }; 3839 return list[ns].timeout; 3840} 3841 3842/** 3843 * @module @icewarp/delayed 3844 */ 3845module.exports = delayed; 3846 3847},{}],"extend":[function(require,module,exports){ 3848"use strict"; 3849function defineFunction(parent, propKey) { 3850 return function () { 3851 return parent[propKey].apply(this, arguments); 3852 }; 3853} 3854 3855/** Module for extending 3856 * @description Set child prototype to parent prototype and copy parents static properties to child 3857 * @module extend 3858 * @param {object} parent 3859 * @param {object} child 3860 * @returns {undefined} 3861 */ 3862module.exports = function (parent, child) { 3863 var _constructor = child.prototype.constructor; 3864 child.prototype = Object.create(parent.prototype); 3865 child.prototype.constructor = _constructor; 3866 /*for(var propKey in parent) { 3867 parent.hasOwnProperty(propKey) && Object.defineProperty(child, propKey, Object.getOwnPropertyDescriptor(parent, propKey)); 3868 };*/ 3869 for (var propKey in parent) { 3870 if (!parent.hasOwnProperty(propKey)) { 3871 continue; 3872 } 3873 if (typeof parent[propKey] === 'function') { 3874 child[propKey] = defineFunction(parent, propKey); 3875 } else { 3876 Object.defineProperty(child, propKey, Object.getOwnPropertyDescriptor(parent, propKey)); 3877 } 3878 } 3879}; 3880 3881},{}],"function-name":[function(require,module,exports){ 3882"use strict"; 3883/** 3884 * Module to return function name 3885 * @param {Object} object 3886 * @returns {String} 3887 */ 3888module.exports = function (object) { 3889 return object.name || function() { 3890 var funcNameRegex = /function\s+([^(]+)\s*\(/; 3891 var results = (funcNameRegex).exec(object.toString()); 3892 return (results && results.length > 1) ? results[1] : ""; 3893 }(); 3894}; 3895 3896},{}],"icebrace-runtime":[function(require,module,exports){ 3897"use strict"; 3898var Escape = require('@icewarp/escape-string'); 3899 3900/** 3901 * @class Template 3902 */ 3903var Template = { 3904 /** 3905 * object to store template functions 3906 */ 3907 cache: {}, 3908 /** 3909 * @param {string} string - String representation of the compiled template function 3910 * @returns {function} template function 3911 */ 3912 getFunction: function (string) { 3913 if (Template.cache[string]) { 3914 return Template.cache[string]; 3915 } 3916 return Template.cache[string] = new Function('s','c','v','T','return ' + string); 3917 }, 3918 /** 3919 * returns an object with value and context 3920 * @param {string[]} level array of keys 3921 * @param {object} data context 3922 * @param {object} current_data_level current context 3923 * @returns {object} object with value and context 3924 */ 3925 resolvePath: function (level, data, current_data_level) { 3926 var ret = data.c; 3927 for (var i = 0; i < level.length; i++) { 3928 if (ret.hasOwnProperty(level[i])) { 3929 ret = ret[level[i]]; 3930 } else if (data.p) { 3931 return Template.resolvePath(level, data.p, current_data_level); 3932 } else { 3933 return {v: '', c: current_data_level}; 3934 } 3935 } 3936 return {v: ret, c: current_data_level}; 3937 }, 3938 /** 3939 * 3940 * @param {object} context data 3941 * @param {*} current 3942 * @param {string} key 3943 * @returns {mixed} value of the key 3944 */ 3945 getVar: function (context, current, key) { 3946 if (key === '.') { 3947 return (typeof context.c === 'object' ? current : context.c); 3948 } 3949 var value = Template.resolvePath(key.split('.'), context, context.c); 3950 if (typeof value.v === 'function') { 3951 return value.v.call(value.c); 3952 } 3953 return value.v; 3954 }, 3955 /** 3956 * 3957 * @param {object} context 3958 * @param {*} value 3959 * @param {string} key 3960 * @returns {string} escaped string 3961 */ 3962 escapedString: function (context, value, key) { 3963 return Escape(toExport.u(context, value, key)); 3964 }, 3965 /** 3966 * 3967 * @param {object} context 3968 * @param {*} value 3969 * @param {string} key 3970 * @returns {string} non-escaped string 3971 */ 3972 unescapedString: function (context, value, key) { 3973 var variable = Template.getVar(context, value, key); 3974 return (variable !== null && typeof variable !== 'undefined') ? variable : ''; 3975 }, 3976 /** 3977 * positive condition 3978 * @param {object} strings 3979 * @param {object} context 3980 * @param {*} value 3981 * @param {string} key 3982 * @param {string} callback 3983 * @returns {string} 3984 */
3985 section: function (strings, context, value, key, callback) { 3986 var variable = Template.getVar(context, value, key), buffer; 3987 if (!variable) { 3988 return ''; 3989 } 3990 if (Array.isArray(variable)) { 3991 buffer = variable.map(function (c) { 3992 return Template.getFunction(callback)(strings, {c: c, p: {c: variable, p: context}}, c, toExport); 3993 }, this).join(''); 3994 } else if (typeof variable === 'string' || typeof variable === 'number' || typeof variable === 'boolean') { 3995 buffer = Template.getFunction(callback)(strings, context, variable, toExport); 3996 } else if (typeof variable === 'object' && variable !== null) { 3997 buffer = Template.getFunction(callback)(strings, {c: variable, p: context}, variable, toExport); 3998 } 3999 return buffer ? buffer : ''; 4000 }, 4001 /** 4002 * 4003 * @param {object} context 4004 * @param {string} name name of component 4005 * @returns {string} 4006 */ 4007 component: function (name, context) { 4008 return (Template.getTemplate(name, context)())(context); 4009 }, 4010 /** 4011 * else condition 4012 * @param {object} strings 4013 * @param {object} context 4014 * @param {*} value 4015 * @param {string} name 4016 * @param {string} callback 4017 * @returns {string} 4018 */ 4019 inverted: function (strings, context, value, name, callback) { 4020 var variable = this.getVar(context, value, name); 4021 return (!variable || (Array.isArray(variable) && !variable.length)) ? Template.getFunction(callback)(strings, context, value, toExport) : ''; 4022 }, 4023 getTemplate: function (name, context) { 4024 return name ? Template.templates[name] : name === void 0 ? Template.templates : false; 4025 } 4026}; 4027/** 4028 * object to store templates 4029 */ 4030Template.templates = {}; 4031 4032/** 4033 * @typedef {Function} Template~component Component function 4034 * @argument {string} name name of component 4035 * @argument {object} context context to be passed to component 4036 */ 4037 4038var toExport = { 4039 i: function () { 4040 return Template.inverted.apply(Template, arguments); 4041 }, 4042 s: function () { 4043 return Template.section.apply(Template, arguments); 4044 }, 4045 c: function () { 4046 return Template.component.apply(Template, arguments); 4047 }, 4048 u: function () { 4049 return Template.unescapedString.apply(Template, arguments); 4050 }, 4051 e: function () { 4052 return Template.escapedString.apply(Template, arguments); 4053 }, 4054 t: function (name) { 4055 return Template.getTemplate.call(Template, name); 4056 }, 4057 setTemplates: function (templates) { 4058 Template.templates = templates; 4059 }, 4060 /** 4061 * Replace component handler with new one for handeling custom template structures 4062 * @param {Template~component} fn 4063 * @returns {undefined} 4064 */ 4065 setComponentHandler: function (fn) { 4066 this.c = fn; 4067 } 4068}; 4069 4070/** 4071 * @module @icewarp/icebrace 4072 */ 4073module.exports = toExport; 4074},{"@icewarp/escape-string":2}],"logger":[function(require,module,exports){ 4075"use strict"; 4076/** 4077 * function to log arguments to console 4078 * @param {mixed} args 4079 * @param {string} type 4080 * @returns {undefined} 4081 */ 4082function log(args, type) { 4083 if (current_level & Logger[type]) { 4084 4085 if (current_group) { 4086 if (current_group.collapsed) { 4087 console.groupCollapsed(current_group.name); 4088 } else { 4089 console.group(current_group.name); 4090 } 4091 current_group = null; 4092 } 4093 4094 args = [].slice.call(args); 4095 if (!console[type.toLowerCase()]) { 4096 type = 'LOG'; 4097 } 4098 4099 if (enable_stack_trace) { 4100 console.groupCollapsed(new Date().toLocaleString() + ' ' + args[0]); 4101 } else { 4102 args.unshift(new Date().toLocaleString()); 4103 } 4104 4105 for (var i = 0; i < open_groups.length; i++) { 4106 args = args.map(function (arg) { 4107 return typeof arg === "string" ? " " + arg : arg; 4108 }); 4109 } 4110 4111 try { 4112 console[type.toLowerCase()].apply(console, args); 4113 } catch(e) { 4114 console[type.toLowerCase()](args); 4115 } 4116 4117 if (enable_stack_trace) { 4118 console.error('TRACE'); 4119 console.groupEnd(); 4120 } 4121 } 4122} 4123 4124/** 4125 * Variable to store open console groups if console.group is not defined 4126 * @type String[] 4127 */ 4128var open_groups = []; 4129 4130var current_group = null; 4131 4132var enable_stack_trace = false; 4133 4134/** 4135 * @class Logger 4136 */ 4137var Logger = { 4138 /** 4139 * Set logging level 4140 * @param {number} level 4141 * @returns {Logger} 4142 */ 4143 setLevel: function (level) { 4144 current_level = level; 4145 return this; 4146 }, 4147 /** 4148 * Enable stack trace in console 4149 * @param {Boolean} enable 4150 * @returns {Logger} 4151 */ 4152 enableStackTrace: function (enable) { 4153 enable_stack_trace = enable; 4154 return this; 4155 }, 4156 /** 4157 * Log log message 4158 * @returns {Logger} 4159 */ 4160 log: function () { 4161 log(arguments, "LOG"); 4162 return this; 4163 }, 4164 /** 4165 * Log info message 4166 * @returns {Logger} 4167 */ 4168 info: function () { 4169 log(arguments, "INFO"); 4170 return this; 4171 }, 4172 /** 4173 * Log warn message 4174 * @returns {Logger} 4175 */ 4176 warning: function () { 4177 log(arguments, "WARN"); 4178 return this; 4179 }, 4180 /** 4181 * Log error message 4182 * @returns {Logger} 4183 */ 4184 error: function () { 4185 log(arguments, "ERROR"); 4186 return this; 4187 }, 4188 /** 4189 * Start console group if console.group is defined 4190 * @param {String} groupname
4191 * @returns {Logger} 4192 */ 4193 group: function (groupname) { 4194 if (console.group) { 4195 current_group = { name: groupname }; 4196 } else { 4197 log([groupname + ' console group start'], "LOG"); 4198 open_groups.push(groupname); 4199 } 4200 return this; 4201 }, 4202 4203 /** 4204 * Start collapsed console group if console.group is defined 4205 * @param {String} groupname 4206 * @returns {Logger} 4207 */ 4208 groupCollapsed: function (groupname) { 4209 if (console.groupCollapsed) { 4210 current_group = { name: groupname, collapsed: true }; 4211 } else { 4212 log([groupname + ' console group start'], "LOG"); 4213 open_groups.push(groupname); 4214 } 4215 return this; 4216 }, 4217 4218 /** 4219 * End console group if console.group is defined 4220 * @returns {Logger} 4221 */ 4222 groupEnd: function () { 4223 if (console.groupEnd) { 4224 console.groupEnd(); 4225 } else { 4226 open_groups.shift(); 4227 } 4228 return this; 4229 }, 4230 4231 /** @const {number} 8 */ 4232 LOG: 8, 4233 /** @const {number} 4 */ 4234 INFO: 4, 4235 /** @const {number} 2 */ 4236 WARN: 2, 4237 /** @const {number} 1 */ 4238 ERROR: 1, 4239 /** @const {number} 0 */ 4240 NONE: 0, 4241 /** @const {number} 15 */ 4242 ALL: 15 4243}; 4244 4245/** 4246 * Variable to store current log level 4247 * @type Number 4248 */ 4249var current_level = Logger.ALL; 4250 4251console.log = console.log || function () { 4252 alert([].slice.call(arguments).join("\n")); 4253}; 4254console.info = console.info || console.log; 4255console.warn = console.warn || console.log; 4256console.error = console.error || console.log; 4257 4258/** 4259 * @module @icewarp/logger 4260 */ 4261module.exports = Logger; 4262 4263},{}],"mix":[function(require,module,exports){ 4264"use strict"; 4265var function_name = require('@icewarp/function-name'); 4266 4267function defineOwnFunction(mixin, propKey) { 4268 return function () { 4269 return mixin[propKey].apply(this, arguments); 4270 }; 4271} 4272 4273function definePrototypeFunction(mixin, propKey) { 4274 return function () { 4275 return mixin.prototype[propKey].apply(this, arguments); 4276 }; 4277} 4278 4279/** Module for mixins 4280 * @description Copy parents properties to child (both static and prototype functions, except for constructor) 4281 * @module mix 4282 * @param {object} mixin 4283 * @param {object} target 4284 * @returns {undefined} 4285 */ 4286module.exports = function (mixin, target) { 4287 for (var propKey in mixin) { 4288 if (!mixin.hasOwnProperty(propKey)) { 4289 continue; 4290 } 4291 if (typeof mixin[propKey] === 'function') { 4292 target[propKey] = defineOwnFunction(mixin, propKey); 4293 } else { 4294 Object.defineProperty(target, propKey, Object.getOwnPropertyDescriptor(mixin, propKey)); 4295 } 4296 } 4297 for (propKey in mixin.prototype) { 4298 if (propKey === 'constructor' || !mixin.prototype.hasOwnProperty(propKey)) { 4299 continue; 4300 } 4301 if (typeof mixin.prototype[propKey] === 'function') { 4302 target.prototype[propKey] = definePrototypeFunction(mixin, propKey); 4303 } else { 4304 Object.defineProperty(target.prototype, propKey, Object.getOwnPropertyDescriptor(mixin.prototype, propKey)); 4305 } 4306 } 4307 target.prototype.mixes = (target.prototype.mixes || []).concat([function_name(mixin)]); 4308}; 4309},{"@icewarp/function-name":"function-name"}],"request":[function(require,module,exports){ 4310"use strict"; 4311/** Allowed events to listen on 4312 * 4313 */ 4314var events = ['progress', 'load', 'error', 'abort', 'always']; 4315/** 4316 * @type MissingOptionException 4317 */ 4318var MissingOptionException = require('./missing_option_exception.js'); 4319var Debugger = require('@icewarp/debugger'); 4320 4321/** Actual XHR event handler 4322 * @listens progress 4323 * @listens load 4324 * @listens error 4325 * @listens abort 4326 * @param {object} e 4327 * @returns {void} 4328 */ 4329var eventHandler = function (e) { 4330 this.events[e.type] && this.events[e.type].func.call(this.events[e.type].context, e, this.xhr); 4331 ((e.type === 'load' || e.type === 'error') && this.events['always']) && this.events['always'].func.call(this.events['always'].context, e); 4332}; 4333 4334/** Check if all required options are present 4335 * 4336 * @param {object} options 4337 * @throws {MissingOptionException} 4338 * @throws {Error} 4339 * @returns {undefined} 4340 */ 4341var validateOptions = function (options) { 4342 var keys = Object.keys(options); 4343 required_options.forEach(function (key) { 4344 if (!~keys.indexOf(key)) { 4345 throw new MissingOptionException(key); 4346 } 4347 }); 4348}; 4349 4350/** Required options Array 4351 * @type string[] 4352 * 4353 */ 4354var required_options = ['url']; 4355 4356/** Request module for handeling XHR requests 4357 * @class 4358 * @param {object} options 4359 * @returns {Request} 4360 */
4361function Request(options) { 4362 validateOptions(options); 4363 /** Listeners storage 4364 * @private 4365 */ 4366 this.events = {}; 4367 /** 4368 * @private 4369 * @type XMLHttpRequest 4370 */ 4371 this.xhr = new XMLHttpRequest(); 4372 this.xhr.open(options.method || "GET", options.url, options.async === void 0 ? true : options.async, options.user || '', options.password || ''); 4373 events.forEach(function (event) { 4374 this.xhr.addEventListener(event, eventHandler.bind(this)); 4375 }, this); 4376 this.options = options; 4377 return this; 4378} 4379/** Add listener on XHR object 4380 * 4381 * @param {string} event 4382 * @param {function} callback 4383 * @param {object} context 4384 * @returns {Request} 4385 */ 4386Request.prototype.on = function (event, callback, context) { 4387 this.events[event] = {func: callback, context: context || this}; 4388 return this; 4389}; 4390/** Send XHR 4391 * 4392 * @param {object} payload 4393 * @returns {void} 4394 */ 4395Request.prototype.send = function (payload) { 4396 Debugger.logAction({options: this.options, payload: payload}, Debugger.levels.XHR); 4397 this.xhr.send(payload || null); 4398}; 4399 4400/** 4401 * @module Request 4402 * @requires MissingOptionException 4403 */ 4404module.exports = Request; 4405},{"./missing_option_exception.js":9,"@icewarp/debugger":"debugger"}],"socket":[function(require,module,exports){ 4406"use strict"; 4407var Connection = require('./connection.js'); 4408 4409 4410/** Object containing all open connections 4411 * @type Object 4412 */ 4413var connections = {}; 4414 4415/** Socket wrapper class for connection 4416 * @class 4417 * @returns {nm$_socket.Socket} 4418 */ 4419function Socket() { 4420} 4421/** 4422 * 4423 * @param {string} name 4424 * @param {object} options options to initialize connection with 4425 * @returns {Connection} 4426 */ 4427Socket.createConnection = function (name, options) { 4428 return (connections[name] = new Connection(options)); 4429}; 4430/** Getter for connection instance 4431 * 4432 * @param {string} name 4433 * @returns {Connection} 4434 */ 4435Socket.getConnection = function (name) { 4436 return connections[name]; 4437}; 4438 4439/** 4440 * @module Socket 4441 * @exports Socket 4442 */ 4443module.exports = Socket; 4444 4445},{"./connection.js":10}]},{},[7]);
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.