1 /*
  2   JWL - The JavaScript Widget Library version 0.8.7
  3   Copyright (c) 2016 - 2020 The Zonebuilder <zone.builder@gmx.com>
  4   http://sourceforge.net/projects/jwl-library/
  5   Licenses: GNU GPL2 or later; GNU LGPLv3 or later (http://sourceforge.net/p/jwl-library/wiki/License/)
  6  */
  7 /**
  8   @fileOverview  The JavaScript Widget Library (JWL) is a tool that allows you to build modern web applications by providing a simple way to create HTML components.
  9    JWL is based on JUL - The JavaScript UI Language module and it easily integrates with JUL Designer.
 10 */
 11 /* jshint browser: true, curly: true, eqeqeq: true, evil: true, expr: true, funcscope: true, immed: true, latedef: true, loopfunc: true,  
 12   onevar: true, newcap: true, noarg: true, node: true, strict: true, trailing: true, undef: true, unused: vars, wsh: true */
 13 /* globals JUL */
 14 
 15 (function(global, module) {
 16 'use strict';
 17 if (module && module.exports && typeof require === 'function') { require('jul'); }
 18 var jul = new JUL.Instance({nsRoot: module && module.exports ? {JWL: module.exports} : global || null});
 19 var JWL = jul.ns('JWL');
 20 
 21 /* generated by JCS version 1.5.8 */
 22 
 23 /**
 24   JWL global namespace
 25   @namespace  It holds properties and methods used by JWL
 26   @name  JWL
 27 */
 28 jul.ns('JWL');
 29 
 30 jul.apply(jul.get('JWL'), /** @lends JWL */ {
 31   /**
 32     JWL parser configuration
 33     @type  Object
 34   */
 35   parserConfig: {
 36     /**
 37       Default class of the parser - HTML elements
 38       @type  String
 39     */
 40     defaultClass: 'html',
 41      /**
 42       Order of component creation - parent before children
 43       @type  Boolean
 44     */
 45     topDown: true,
 46      /**
 47       The parser will use tha tag property to differentiate between components
 48       @type  Boolean
 49     */
 50     useTags: true,
 51      /**
 52       Special component factory that will do further processing compared to JUL.UI.createDom():
 53       <ul>
 54         <li>if the config object is not a JWL component, return JUL.UI.createDom(oConfig)</li>
 55         <li>call config/component pre-create callback with parent's scope</li>
 56         <li>distribute dotted attributes 'objectID.attribute' among descendants</li>
 57         <li>create element and recursively process its children</li>
 58         <li>call config/component post-create callback with element's scope</li>
 59       </ul>
 60       @param  {Object}  oConfig  Configuration object
 61       @returns  {Object}  Element instance
 62     */
 63     customFactory: function(oConfig) {
 64       var sTag = oConfig[this.tagProperty];
 65       if (oConfig[this.classProperty] !== this.defaultClass) { sTag = oConfig[this.classProperty] + ':' + sTag; } 
 66       var oComponent = JWL.components[sTag];
 67       if (!oComponent) {
 68         var fCreator = this._creator ? jul.get(this._creator) : null;
 69         return typeof fCreator === 'function' ? fCreator.call(this, oConfig) : this.createDom(oConfig);
 70       }
 71       oConfig._componentIndex = sTag;
 72       var fPreCreate = oConfig.preCreate || oComponent.preCreate;
 73       if (fPreCreate) { fPreCreate = jul.get(fPreCreate); }
 74       delete oConfig.preCreate;
 75       var fPostCreate = oConfig.postCreate || oComponent.postCreate;
 76       if (fPostCreate) { fPostCreate = jul.get(fPostCreate); }
 77       if (fPostCreate) { oConfig.postCreate = fPostCreate; }
 78       var oHost = oConfig[this.parentProperty] ? oConfig[this.parentProperty].host || oConfig[this.parentProperty] : null;
 79       if (oHost && oHost._componentName && oHost._derived) {
 80         oConfig[this.classProperty] = this.defaultClass;
 81         oConfig[this.tagProperty] = 'div';
 82       }
 83       else if (oComponent.ui) {
 84         oConfig[this.classProperty] = oComponent.ui[this.classProperty] || this.defaultClass;
 85         oConfig[this.tagProperty] = oComponent.ui[this.tagProperty];
 86       }
 87       if (typeof fPreCreate === 'function') {
 88         var bReturn = fPreCreate.call(oConfig[this.parentProperty],  oConfig, this);
 89         if (bReturn === false) { return null; }
 90       }
 91       fPostCreate = oConfig.postCreate;
 92       delete oConfig.postCreate;
 93       var oInit = oConfig;
 94       oConfig = JUL.apply({}, oConfig);
 95       delete oConfig._componentIndex;
 96       var oLogic = {};
 97       var sBinding = oComponent.ui ? oComponent.ui[this.bindingProperty] : '.component';
 98       if (!oComponent.ui) { oConfig[this.bindingProperty] = sBinding; }
 99       var oRootLogic = {};
100       oLogic[sBinding] = oRootLogic;
101       var sItem, nDot;
102       for (sItem in oConfig) {
103         if (oConfig.hasOwnProperty(sItem)) {
104            nDot = sItem.indexOf('.', 1);
105           if (nDot > 0 && nDot < sItem.length - 1) {
106             sBinding = sItem.slice(0, nDot);
107             oLogic[sBinding] = oLogic[sBinding] || {};
108             oLogic[sBinding][sItem.substr(nDot + 1)] = oConfig[sItem];
109             delete oConfig[sItem];
110           }
111         }
112       }
113       var oListeners = oConfig.listeners || {};
114       delete oConfig.listeners;
115       oRootLogic.listeners = oListeners;
116       for (sItem in oListeners) {
117         if (oListeners.hasOwnProperty(sItem)) {
118            nDot = sItem.indexOf('.', 1);
119           if (nDot > 0 && nDot < sItem.length - 1) {
120             sBinding = sItem.slice(0, nDot);
121             oLogic[sBinding] = oLogic[sBinding] || {};
122             oLogic[sBinding].listeners = oLogic[sBinding].listeners || {};
123             oLogic[sBinding].listeners[sItem.substr(nDot + 1)] = oListeners[sItem];
124             delete oListeners[sItem];
125           }
126         }
127       }
128       for (sItem in oConfig) {
129         if (oConfig.hasOwnProperty(sItem) &&
130           [this.classProperty, this.tagProperty,  this.idProperty, this.bindingProperty, this.parentProperty, this.cssProperty].indexOf(sItem) < 0) {
131           oRootLogic[sItem] = oConfig[sItem];
132           delete oConfig[sItem];
133         }
134       }
135       if (oComponent.ui) { oConfig[this.includeProperty] = oComponent.ui; }
136       if (oComponent.logic) { oLogic[this.includeProperty] = oComponent.logic; }
137       var oWidget = this.create(oConfig, oLogic, oConfig.parent);
138       if (typeof fPostCreate === 'function') { fPostCreate.call(oWidget, oInit, this); }
139       return oWidget;
140     },
141     /**
142       Use JSON prefixes when serializing objects
143       @type  Boolean
144       @private
145     */
146     _usePrefixes: true,
147      /**
148       Special merging callback for parser's include() method that will do further processing compared to JUL.apply():
149       <ul>
150         <li>if the object is not a component (binding ID doesn't start with a dot), call JUL.apply(oData, oApply)</li>
151         <li>attach object's listeners in cascade</li>
152         <li>append object's CSS class</li>
153         <li>call JUL.apply() on the other members</li>
154       </ul>
155       @param  {Object}  oData  Target object
156       @param  {Object}  oApply  Appended object
157       @param  {Boolean}  [bSkip]  For internal use, to process component's logic
158       @returns  {Object}  Target object with the resulting members
159       @private
160     */
161     _includeMerger: function(oData, oApply, bSkip) {
162       var oListeners = oData.listeners;
163       var sItem;
164       if (bSkip) {
165         JUL.apply(oData, oApply);
166       }
167       else {
168         for (sItem in oApply) {
169           if (oApply.hasOwnProperty(sItem)) {
170             if (sItem.substr(0, 1) === '.' && sItem.length > 1 && JUL.typeOf(oApply[sItem]) === 'Object' &&
171               oData[sItem] && JUL.typeOf(oData[sItem]) === 'Object') { this._includeMerger(oData[sItem], oApply[sItem], true); }
172             else {
173               if (sItem === this.cssProperty) { oData[sItem] = oApply[sItem] + (oData[sItem] ? ' ' + oData[sItem] : ''); }
174               else { oData[sItem] = oApply[sItem]; }
175             }
176           }
177         }
178       }
179       if (!oListeners || !oApply.listeners) { return oData; }
180       for (sItem in oApply.listeners) {
181         if (oApply.listeners.hasOwnProperty(sItem)) {
182           if (sItem !== 'scope' && oListeners[sItem]) {
183             oListeners[sItem] = [].concat(oListeners[sItem], oApply.listeners[sItem]);
184           }
185           else {
186             oListeners[sItem] = oApply.listeners[sItem];
187           }
188         }
189       }
190       oData.listeners = oListeners;
191       return oData;
192     },
193     /**
194       Callback for un-serializing objects. Use it in a safe data environment because of eval().
195       @param  {String}  sKey  Current member key
196       @param  {Mixed}  oValue  Current member value
197       @returns  {Mixed}  Member's processed value
198       @private
199     */
200     _jsonReviver: function(sKey, oValue) {
201       if (sKey && typeof oValue === 'string') {
202         var bPrefix = false;
203         for (var sItem in this._jsonPrefixes) {
204           if (this._jsonPrefixes.hasOwnProperty(sItem) &&
205             oValue.substr(0, this._jsonPrefixes[sItem].length) === this._jsonPrefixes[sItem]) {
206             bPrefix = true;
207             oValue = oValue.substr(this._jsonPrefixes[sItem].length).replace(/^\s+/, '');
208             break;
209           }
210         }
211         if (bPrefix) {
212           try {
213             return eval('(function(){return ' + oValue + '})()');
214           }
215           catch(e) {
216             return oValue;
217           }
218         }
219       }
220       return oValue;
221     }
222   },
223   /**
224     Default prefix for custom element tags
225     @type  String
226   */
227   registerPrefix: 'jwl',
228   /**
229     JWL version
230     @type  String
231   */
232   version: '0.8.5',
233   /**
234     Creates a new parser derived from JWL.parser
235     @class
236     @extends  JWL.parser
237     @param  {Object}  oConfig  Configuration object
238   */
239   Parser: function(oConfig) {
240     if (!(this instanceof JWL.Parser)) {
241       return new JWL.Parser(oConfig);
242     }
243     jul.ui.Parser.call(this, oConfig);
244   },
245   /**
246     Callback to be used as the JWL.Parser custom factory to self-register and to create custom HTML elements.
247     e.g. var oParser = new JWL.Parser({customFactory: 'JWL.custom'});
248     @param  {Object}  oConfig  Configuration object
249     @returns  {Object}  New element
250   */
251   custom: function(oConfig) {
252       var sName = oConfig[this.tagProperty];
253       if (oConfig[this.classProperty] !== this.defaultClass) { sName = oConfig[this.classProperty] + ':' + sName; }
254       var oComponent = JWL.components[sName];
255       if (oComponent) {
256         JWL._customCache = JWL._customCache || {};
257         var sKey = oConfig[this.classProperty] + ':' + oConfig[this.tagProperty];
258         if (typeof JWL._customCache[sKey] !== 'function') {
259           try {
260             JWL._customCache[sKey] = JWL.register(sName, false, '', this);
261           }
262           catch (e) {}
263         }
264         oConfig[this.tagProperty] = JWL.registerPrefix + '-' +
265           (oConfig[this.classProperty] === this.defaultClass ? '' : oConfig[this.classProperty] + '-') +
266           oConfig[this.tagProperty];
267         oConfig[this.classProperty] = this.defaultClass;
268       }
269       return this.createDom(oConfig);
270   },
271   /**
272     Callback to be used as the JWL.Parser custom factory to create element wrappers.
273     e.g. var oParser = new JWL.Parser({customFactory: 'JWL.factory'});
274     @param  {Object}  oConfig  Configuration object
275     @returns  {Object}  Element wrapper instance
276   */
277   factory: function(oConfig) {
278     var sName = oConfig[this.tagProperty];
279     var sNS = oConfig[this.classProperty];
280     var CNew = jul.get('JWL.' + sNS.toUpperCase() + '.' + sName[0].toUpperCase() + sName.substr(1));
281     if (typeof CNew !== 'function') { CNew = JWL.makeClass(sNS + ':' + sName, false, this); }
282     return new CNew(oConfig);
283   },
284   /**
285     Gets a wrapper object associated with an element
286     @param  {Object}  oEl  DOM element or element ID
287     @returns  {Object}  Element wrapper, component root element, of null if not found
288   */
289   get: function(oEl) {
290     if (typeof oEl === 'string') { oEl = document.getElementById(oEl); }
291     if (typeof JWL._Base_ === 'function'&& oEl instanceof JWL._Base_) { return oEl; }
292     if (oEl && typeof oEl.el === 'function') { oEl = oEl.el(); }
293     return oEl && typeof JWL._Base_ === 'function' ? JWL._Base_.get(oEl) || oEl : oEl || null;
294   },
295   /**
296     Loads component(s) from a string serialization
297     @param  {String}  sData  Parameter description
298     @param  {String}  [sWhat]  Name of a specific component to load
299     @param  {String}  [sRoot]  Dotted path to read the component from the un-serialized object
300     @returns  {Object}  Component configuration
301   */
302   load: function(sData, sWhat, sRoot) {
303     var oData = null;
304     try {
305       oData = JSON.parse(sData, JUL.makeCaller(this.parser, '_jsonReviver'));
306     }
307     catch (e) {}
308     if (oData && sRoot) { oData = JUL.get(sRoot, oData); }
309     if (!oData || typeof oData !== 'object') { return null; }
310     return jul.ns('JWL.components' + (sWhat ? '.' + sWhat : ''), oData);
311   },
312   /**
313     Loads external CSS for a component using XMLHttpRequest
314     @param  {String}  sComponent  Component name
315     @param  {Function}  [fCall]  If supplied, the CSS will be loaded asynchronously
316     @param  {Object}  [oScope]  Optional scope to run the callback in
317     @returns  {Array}  Array of CSS descriptors
318   */
319   loadCss: function(sComponent, fCall, oScope) {
320     var oComponent = this.components[sComponent] || {};
321     if (!oComponent.css) { return null; }
322     var bCall = typeof fCall === 'function';
323     this._cssCache = this._cssCache || {};
324     var aCss;
325     if (this._cssCache[sComponent]) {
326       aCss = this._cssCache[sComponent];
327       if (bCall) {
328         (oScope ? fCall.call(oScope, aCss) : fCall(aCss));
329       }
330       return aCss;
331     }
332     var oWatch = {
333       values: [],
334       total: 0,
335       count: 0,
336       ready: null,
337       scope: this,
338       set: function(nKey, oValue) {
339         var sUrl = '';
340         if (nKey >= 0) {
341           sUrl = this.values[nKey].style;
342           this.values[nKey].style = oValue;
343         }
344         this.count++;
345         if (this.count >= this.total && typeof this.ready === 'function') {
346           this.ready.call(this.scope);
347         }
348         if (sUrl && this.scope.__pending[sUrl]) {
349           var aCalls = this.scope.__pending[sUrl];
350           for (var i = 0; i < aCalls.length; i++) {
351             aCalls[i].watch.set(aCalls[i].key, oValue);
352           }
353           delete this.scope.__pending[sUrl];
354         }
355       }
356     };
357     this.__pending = this.__pending || {};
358     var fLoad = function(sUrl, nKey) {
359       if (this.__pending[sUrl]) {
360         this.__pending[sUrl].push({watch: oWatch, key: nKey});
361         return;
362       }
363       else {
364         this.__pending[sUrl] = [];
365       }
366       var oHttp;
367       try {
368         if (typeof window.XMLHttpRequest === 'function') {
369           oHttp = new XMLHttpRequest();
370           if (bCall) {
371             oHttp.addEventListener('load', function() {
372               oWatch.set(nKey, this.responseText || '');
373             });
374             oHttp.addEventListener('error', function() {
375               oWatch.set(nKey, '');
376             });
377           }
378           oHttp.open('GET', sUrl, bCall);
379           oHttp.setRequestHeader('Content-Type', 'text/css; charset=UTF-8');
380           oHttp.send(null);
381           if (!bCall) { oWatch.set(nKey, oHttp.responseText || ''); }
382         }
383         else {
384           oHttp = new ActiveXObject('WinHttp.WinHttpRequest.5.1');
385           oHttp.Open('GET', sUrl, false);
386           oHttp.SetRequestHeader('Content-Type', 'text/css; charset=UTF-8');
387           oHttp.Send();
388           oWatch.ser(nKey, oHttp.ResponseText || '');
389         }
390       }
391       catch (e) {
392         oWatch.set(nKey, '');
393       }
394     };
395     aCss = [].concat(oComponent.css);
396     oWatch.ready = function() {
397       for (var i = 0; i < aCss.length; i++) {
398         if (!aCss[i].style) {
399           aCss.splice(i, 1);
400           i--;
401         }
402       }
403       this._cssCache[sComponent] = aCss;
404       if (bCall) {
405         (oScope ? fCall.call(oScope, aCss) : fCall(aCss));
406       }
407     };
408     oWatch.total = aCss.length;
409     oWatch.values = aCss;
410     for (var i = 0; i < aCss.length; i++) {
411       if (typeof aCss[i] !== 'object') { aCss[i] = {style: aCss[i], media: ''}; }
412       var sUrl = encodeURI(JUL.trim(aCss[i].style.substr(0, 1024).split('\n')));
413       if (aCss[i].style && aCss[i].style.indexOf(';') < 0 && sUrl) {
414         fLoad.call(this, sUrl, i);
415       }
416       else {
417         oWatch.set(-1, '' );
418       }
419     }
420     return aCss;
421   },
422   /**
423     Creates an element wrapper class for a specific component
424     @param  {String}  sName  Component name or existing HTML tag
425     @param  {String}  [sNewNS]  Optional namespace under to put the class constructor, it defaults to 'JWL.<Name>
426     @param  {Object}  [oParser]  Custom instance of JUL.UI.Parser to use instead of the default JWL.parser
427     @returns  {Function}  Class constructor
428   */
429   makeClass: function(sName, sNewNS, oParser) {
430     oParser = oParser || this.parser;
431     if (sName.indexOf(oParser.defaultClass + ':') === 0) { sName = sName.substr(oParser.defaultClass.length + 1); }
432     var oComponent = this.components[sName] || {};
433     var sNS = oParser.defaultClass;
434     if (sName.indexOf(':') > -1) {
435       sNS = sName.split(':')[0];
436       sName = sName.substr(sNS.length + 1);
437     }
438     if (typeof JWL._Base_ !== 'function') {
439       JWL._Base_ = function() {};
440       JUL.apply(JWL._Base_.prototype, {
441         get: function(sItem) { return sItem in this ? this[sItem] : JWL._Base_.wrapUp(this._el[sItem]); },
442         set: function(sItem, oValue, bHost) { (bHost || sItem in this ? this : this._el)[sItem] =
443           !bHost && !(sItem in this) && JWL._Base_.onRe.test(sItem) && typeof oValue === 'function' ?
444           JUL.makeCaller(this, oValue) : oValue; },
445         el: function() { return this._el; },
446         config: function() { return this._config; }
447       });
448       JUL.apply(JWL._Base_, {
449         id: 1,
450         items: {},
451         attributeName: 'data-component-id',
452         onRe: /^on[a-z]+$/,
453         map: function(oComponent, sItem) {
454           var oEl = oComponent.el();
455           if (!oEl) { return; }
456           if (sItem && typeof sItem !== 'string') { sItem = sItem.getAttribute(this.attributeName); }
457           if (!sItem) { sItem = 'c-' + this.id++; }
458           this.items[sItem] = oComponent;
459           oEl.setAttribute(this.attributeName, sItem);
460         },
461         get: function(sId) {
462           if (sId && typeof sId !== 'string') { sId = sId.getAttribute(this.attributeName); }
463           return sId ? this.items[sId] || null : null;
464         },
465         cleanUp: function() {
466           if ((this.id - 1) % 4096) { return; }
467           var oItems = {};
468           var fClean = function(oNode) {
469             for (var i = 0; i < oNode.childNodes.length; i++) {
470               var oChild = oNode.childNodes[i];
471               if (oChild.nodeType !== 1) { continue; }
472               var sItem = oChild.getAttribute(this.attributeName);
473               if (sItem) { oItems[sItem] = this.items[sItem]; }
474               fClean.call(this, oChild);
475             }
476           };
477           fClean.call(this, document.body);
478           this.items = oItems;
479         },
480         wrapUp: function(oData) {
481           try {
482             if (!oData) { return oData; }
483             if (oData instanceof Element && oData.nodeType === 1) {
484               return oData.getAttribute(this.attributeName) ? this.get(oData) : oData;
485             }
486             if (typeof oData === 'object' && typeof oData.length && oData[0] instanceof Element) {
487               var aReturn = [];
488               for (var i = 0; i < oData.length; i++) {
489                 aReturn[i] = oData[i].nodeType === 1 && oData[i].getAttribute(this.attributeName) ? this.get(oData[i]) : oData[i];
490               }
491               return aReturn;
492             }
493           }
494           catch (e) {}
495           return oData;
496         }
497       });
498     }
499     var fClass = function(oConfig, oEl) {
500       oConfig = oConfig  || {};
501       this._config = JUL.apply({}, oConfig);
502       delete this._config[this._parser.parentProperty];
503       oConfig = JUL.apply({}, oConfig);
504       oConfig[this._parser.classProperty] = sNS;
505       oConfig[this._parser.tagProperty] = sName;
506       oConfig.listeners = JUL.apply({scope: this}, oConfig.listeners || {});
507       if (oEl) {
508         this._parser.createDom(oConfig, oEl);
509         this._el = oEl;
510       }
511       else {
512         this._el = JWL.parser.customFactory.call(this._parser, oConfig);
513         if (this._el instanceof JWL._Base_) {
514           oEl = this._el.el();
515           oEl.setAttribute('class', (oEl.getAttribute('class') || '') + ' ' + JWL.registerPrefix + '-' +
516             (sNS === this._parser.defaultClass ? '' : sNS + '-') +
517             ((oComponent.ui || {})[this._parser.cssProperty] || sName).split(' ').shift());
518           this._el = oEl;
519           JWL._Base_.map(this, oEl);
520           return;
521         }
522       }
523       JWL._Base_.map(this);
524       JWL._Base_.cleanUp();
525     };
526     fClass.prototype = new JWL._Base_();
527     fClass.prototype.constructor = fClass;
528     fClass.prototype._parser = oParser;
529     this._protoCache = this._protoCache || {};
530     var sItem, oProto;
531     var sCompNS = oComponent.ui ? oComponent.ui[oParser.classPrpperty] || oParser.defaultClass : sNS;
532     var sCompTag = oComponent.ui ? oComponent.ui[oParser.tagProperty] : sName;
533     var sTag = sCompNS + ':' + sCompTag;
534     if (!this._protoCache[sTag]) {
535       this._protoCache[sTag] = {attributes: false, baseURI: false, childNodes: false, className: false,  
536         dataset: false, firstChild: false, innerHTML: false, lastChild: false, localName: false, 
537         namespaceURI: false, nextSibling: false, nodeName: false, nodeType: false, nodeValue: false, 
538         ownerDocument: false, parentNode: false, prefix: false, previousSibling : false, style: false, 
539         tabIndex: false, tagName: false,
540         addEventListener: true, appendChild: true, blur: true, cloneNode: true, 
541         compareDocumentPosition: true, dispatchEvent: true, focus: true, getAttribute: true, 
542         getAttributeNode: true, getAttributeNodeNS: true, getAttributeNS: true, getBoundingClientRect: true, 
543         getElementsByTagName: true, getElementsByTagNameNS: true, hasAttribute: true, hasAttributeNS: true, 
544         hasAttributes: true, hasChildNodes: true, insertBefore: true, isDefaultNamespace: true, 
545         lookupNamespaceURI: true, lookupPrefix: true, normalize: true, querySelector: true, querySelectorAll: true, 
546         releaseCapture: true, removeAttribute: true, removeAttributeNode: true, removeAttributeNS: true, 
547         removeChild: true, removeEventListener: true, replaceChild: true, scrollIntoView: true, setAttribute: true, 
548         setAttributeNode: true, setAttributeNodeNS: true, setAttributeNS: true, setCapture: true};
549       var oFilter = /^[a-z]/;
550       var oProtoConfig = {};
551       oProtoConfig[oParser.classProperty] = sCompNS;
552       oProtoConfig[oParser.tagProperty] = sCompTag;
553       oProto = oParser.createDom(oProtoConfig);
554       for (sItem in oProto) {
555         if (!oFilter.test(sItem)) { continue; }
556         try {
557           this._protoCache[sTag][sItem] = typeof oProto[sItem] === 'function';
558         }
559         catch (e) {}
560       }
561     }
562     oProto = this._protoCache[sTag];
563     this._methodCache = this._methodCache || {getter: {}, setter: {}, other: {}};
564     for (sItem in oProto) {
565       if (oProto.hasOwnProperty(sItem)) {
566         if (oProto[sItem]) {
567           this._methodCache.other[sItem] = this._methodCache.other[sItem] || (function(sItem) {
568             return function() {
569               if (!this._el) { return undefined; }
570               var bEvent = sItem === 'addEventListener' || sItem === 'attachEvent';
571               var aArgs = [].slice.call(arguments);
572               for (var i = 0; i < aArgs.length; i++) {
573                 // re-scope event listeners at explicit assignment
574                 if (bEvent && typeof aArgs[i] === 'function') { aArgs[i] = JUL.makeCaller(this, aArgs[i]); }
575                 if (aArgs[i] instanceof JWL._Base_) { aArgs[i] = aArgs[i].el(); }
576               }
577               return JWL._Base_.wrapUp(this._el[sItem].apply(this._el, aArgs));
578             };
579           })(sItem);
580           fClass.prototype[sItem] = this._methodCache.other[sItem];
581         }
582         else {
583           this._methodCache.getter[sItem] = this._methodCache.getter[sItem] || (function(sItem) {
584             return function() {
585               return this._el ? JWL._Base_.wrapUp(this._el[sItem]) : undefined;
586             };
587           })(sItem);
588           this._methodCache.setter[sItem] = this._methodCache.setter[sItem] || (function(sItem) {
589             return function(oValue) {
590               if (oValue instanceof JWL._Base_) { oValue = oValue.el(); }
591               if (this._el) {
592                 // re-scope 'on' handler at direct assignment; careful not using a function expression with an 'on' attribute
593                 if (JWL._Base_.onRe.test(sItem) && typeof oValue === 'function') {
594                   oValue = JUL.makeCaller(this, oValue);
595                 }
596                 this._el[sItem] = oValue;
597               }
598             };
599           })(sItem);
600           try {
601             Object.defineProperty(fClass.prototype, sItem, {
602               configurable: true,
603               enumerable: true,
604               get: this._methodCache.getter[sItem],
605               set: this._methodCache.setter[sItem]
606             });
607           }
608           catch (e1) {}
609         }
610       }
611     }
612     JUL.apply(fClass.prototype, oComponent.prototype || {});
613     var sWhat = 'JWL.' + sNS.toUpperCase() + '.' + sName[0].toUpperCase() + sName.substr(1);
614     return jul.ns(sNewNS || sWhat, fClass);
615   },
616   /**
617     Registers a JWL component as a custom HTML element (W3C web components)
618     @param  {String}  sName  Component name
619     @param  {Boolean}  [bDerived]  Set it to true to register derived a custom HTML element
620     @param  {String}  [sNewName]  Optional new tag name instead of prepending 'jwl-' to the component name
621     @param  {Object}  [oParser]  Custom instance of JUL.UI.Parser to use instead of the default JWL.parser
622     @returns  {Function}  Registered element constructor
623   */
624   register: function(sName, bDerived, sNewName, oParser) {
625     oParser = oParser || this.parser;
626     if (sName.indexOf(oParser.defaultClass + ':') === 0) { sName = sName.substr(oParser.defaultClass.length + 1); }
627     var oComponent = this.components[sName] || {};
628     var oPrototype = JUL.apply({
629       _componentName: sName,
630       _derived: bDerived && true,
631       _parser: oParser,
632       el: function() {
633         return (this.shadowRoot || this).lastChild;
634       },
635       createdCallback: function() {
636         var oRoot = this;
637         if (this.shadowRoot) { oRoot = this.shadowRoot; }
638         else if (typeof this.createShadowRoot === 'function') {  oRoot = this.createShadowRoot(); }
639         var oComponent = JWL.components[this._componentName] || {};
640         if (oComponent.css) {
641           var n = [].concat(oComponent.css).length;
642           for (var i = 0; i < n; i++) {
643             var oStyle = document.createElement('style');
644             oStyle.setAttribute('type', 'text/css' );
645             oStyle.appendChild(document.createTextNode('noscript {}'));
646             oRoot.appendChild(oStyle);
647           }
648           JWL.loadCss(this._componentName, function(aCss) {
649             for (var i = 0; i < aCss.length; i++) {
650               var oStyle = document.createElement('style');
651               oStyle.setAttribute('type', 'text/css' );
652               if (aCss[i].media) { oStyle.setAttribute('media', aCss[i].media); }
653               oStyle.appendChild(document.createTextNode(aCss[i].style));
654               oRoot.replaceChild(oStyle, oRoot.childNodes[i]);
655             }
656           }, this);
657         }
658       },
659       connectedCallback: function() {
660         this.attachedCallback();
661       },
662       attachedCallback: function() {
663         var oRoot = this.shadowRoot || this;
664         if (oRoot.childNodes.length && oRoot.lastChild.nodeName.toLowerCase() !== 'style') { return; }
665         var oComponent = JWL.components[this._componentName] || {};
666         var sNS = this._parser.defaultClass;
667         var sName = this._componentName;
668         if (sName.indexOf(':') > -1) {
669           sNS = sName.split(':')[0];
670           sName = sName.substr(sNS.length + 1);
671         }
672         this.setAttribute('class', (this.getAttribute('class') || '') + ' ' + JWL.registerPrefix + '-' +
673           (sNS === this._parser.defaultClass ? '' : sNS + '-') +
674           ((oComponent.ui || {})[this._parser.cssProperty] || sName).split(' ').shift());
675         if (!oComponent.ui) { return; }
676         var oConfig = {};
677         oConfig[this._parser.classProperty] = sNS;
678         oConfig[this._parser.tagProperty] = sName;
679         oConfig[this._parser.parentProperty] = oRoot;
680         oConfig.listeners = JUL.apply({scope: this}, oConfig.listeners || {});
681         JWL.parser.customFactory.call(this._parser, oConfig);
682       }
683     }, oComponent.prototype || {});
684     var sNS = oParser.defaultClass;
685     if (sName.indexOf(':') > -1) {
686       sNS = sName.split(':')[0];
687       sName = sName.substr(sNS.length + 1);
688     }
689     var sTag = '';
690     if (bDerived) {
691       var sCompNS = oComponent.ui ? oComponent.ui[oParser.classPrpperty] || oParser.defaultClass : sNS;
692       var sCompTag = oComponent.ui ? oComponent.ui[oParser.tagProperty] : sName;
693       sTag = (sCompNS === oParser.defaultClass ? '' : sCompNS + ':') + sCompTag;
694       var oElConfig = {};
695       oElConfig[oParser.classProperty] = sCompNS;
696       oElConfig[oParser.tagProperty] = sCompTag;
697       var oEl = oParser.createDom(oElConfig);
698       oPrototype = JUL.apply(Object.create(oEl.constructor.prototype), oPrototype);
699     }
700     else {
701       oPrototype = JUL.apply(Object.create(HTMLElement.prototype), oPrototype);
702     }
703     sName = this.registerPrefix + '-' + (sNS === oParser.defaultClass ? '' : sNS + '-') + sName;
704     if (window.customElements && typeof window.customElements.define === 'function') {
705       var CC = function() {
706          var oEl = window.Reflect.construct(oPrototype.constructor, [].slice.call(arguments) , CC);
707            oEl.attachShadow({mode: 'open'});
708              oEl.createdCallback();
709          return oEl;
710       };
711       CC.prototype = oPrototype;
712       var oCE = window.customElements;
713       oCE.define.apply(oCE, [sName, CC].concat(bDerived ? {'extends': sTag} : []));
714       return CC;
715     }
716     return document.registerElement(sNewName || sName, bDerived ? 
717       {'extends': sTag, prototype: oPrototype} : {prototype: oPrototype});
718   },
719   /**
720     Saves component(s) into a JSON serialization
721     @param  {String}  [sWhat]  Component to serialize, if omitted all components are saved
722     @returns  {String}  JSON string containing serialized component(s)
723   */
724   save: function(sWhat) {
725     return this.parser.obj2str(sWhat ? this.components[sWhat] : this.components, true);
726   },
727   /**
728     Creates and triggers a custom DOM event
729     @param  {Object}  oTarget  Target element or element wrapper to trigger the event on
730     @param  {String}  sEvent  Event name
731     @param  {Object}  [oInit]  Hash of additional event properties
732     @returns  {Boolean}  The result of dispatching the event to its cascaded listeners
733   */
734   trigger: function(oTarget, sEvent, oInit) {
735     if (typeof JWL._Base_ === 'function' && oTarget instanceof JWL._Base_) { oTarget = oTarget.el(); }
736     oInit = JUL.apply({bubbles: true, cancelable: true, composed: true}, oInit || {});
737     var nSep = sEvent.indexOf(':');
738     var sClass = nSep < 0 ? 'Event' : sEvent.slice (0, nSep);
739     if (nSep > -1) { sEvent = sEvent.substr(nSep + 1); }
740     var oEvent = null;
741     if (typeof window[sClass] === 'function') {
742         oEvent = new window[sClass](sEvent, oInit);
743     }
744     else if (typeof document.createEvent === 'function') {
745         oEvent = document.createEvent(sClass );
746         var aArgs = [sEvent];
747         for (var sItem in oInit) {
748           if (oInit.hasOwnProperty(sItem)) { aArgs.push(oInit[sItem]); }
749         }
750         oEvent['init' + sClass].apply(oEvent, aArgs);
751     }
752     else {
753       oEvent = document.createEventObject();
754       JUL.apply(oEvent, oInit);
755       try {
756         return oTarget.fireEvent('on' + sEvent, oEvent);
757       }
758       catch (e1) { return false; }
759     }
760     return  oTarget.dispatchEvent(oEvent);
761   }
762 });
763 
764 jul.ns('JWL.components');
765 JWL.parser = new jul.ui.Parser(JWL.parserConfig);
766 JWL.Parser.prototype = JWL.parser;
767 
768 })(typeof global !== 'undefined' ? global : window, typeof module !== 'undefined' ? module : null);
769 
770 /* end JWL.js */
771