1 /*
  2   JUL - The JavaScript UI Language version 1.6.8
  3   Copyright (c) 2012 - 2020 The Zonebuilder <zone.builder@gmx.com>
  4   http://sourceforge.net/projects/jul-javascript/
  5   Licenses: GNU GPL2 or later; GNU LGPLv3 or later (http://sourceforge.net/p/jul-javascript/wiki/License/)
  6  */
  7 /**
  8   @fileOverview  
  9   The JavaScript UI Language (JUL) is a configuration and instantiation module for the JavaScript frameworks. 
 10   It can be used with any framework that accepts a configuration object as a constructor parameter, 
 11   or with a custom factory for the other frameworks.<br />
 12   JUL parses a tree of configuration objects, and creates the runtime components in the expected order and membership. 
 13   For the most uses, after this step, you will have your application's user interface up and running.<br>
 14   <br>An example of the JUL tree for a generic 'FWK.Widgets' component library:
 15   <pre><code>var oUiConfig = {
 16       xclass: 'FWK.Widgets.DataView',
 17       id: 'APP.mainView',
 18       autoDraw: false,
 19       overflow: 'hidden',
 20       children: [{
 21           xclass: 'FWK.Widgets.VLayout',
 22           id:'VLayout0',
 23           children: [{
 24               xclass: 'FWK.Widgets.ToolStrip',
 25               id: 'ToolStrip0',
 26               visibilityMode: 'multiple'
 27           }, {
 28               xclass: 'FWK.Widgets.HLayout',
 29               id: 'HLayout0',
 30               children: [{
 31                   xclass: 'FWK.Widgets.VLayout',
 32                   id: 'Navigation',
 33                   width: 200,
 34                   showResizeBar: true
 35                   }, {
 36                   xclass: 'FWK.Widgets.TabSet',
 37                      id: 'TabSet1',
 38                   tabs: [{
 39                       xclass: 'FWK.Widgets.Tab',
 40                       title: 'Tab1',
 41                       id: 'Tab1'
 42                   }, {
 43                       xclass: 'FWK.Widgets.Tab',
 44                       title: 'Tab2',
 45                       id: 'Tab2'
 46                   }],
 47                   showTabScroller:true,
 48                   showTabPicker:true,
 49                   destroyPanes:false,
 50                   showEdges:false
 51               }]
 52           }]
 53       }],
 54       width: '100%',
 55       height: '100%'
 56   };
 57   var oParser = new JUL.UI.Parser({
 58       classProperty: 'xclass',
 59       childrenProperty: 'children',
 60       membersProperties: ['tabs'],
 61       idProperty: 'id'
 62   });
 63   oParser.create(oUiConfig);
 64   APP.mainView.render();</code></pre>
 65   Another example of the JUL tree for a XUL dialog:
 66   <pre><code>var oUiConfig = {
 67       tag: 'dialog',
 68       id: 'dialog-browse',
 69       title: 'Open',
 70       width: 500,
 71       height: 250,
 72       hidden: true,
 73       children: [
 74           {tag: 'listbox', id: 'listbox-browse', selType: 'single', 
 75               flex: 1, children: [
 76               {tag: 'listhead', children: [
 77                   {tag: 'listheader', label: 'Name', width: 300}
 78           ]},
 79               {tag: 'listbody', children: [
 80                   {tag: 'listitem', children: [
 81                       {tag: 'listcell', label: 'File 1'}
 82                   ]},
 83                   {tag: 'listitem', children: [
 84                       {tag: 'listcell', label: 'File 2'}
 85                   ]}
 86               ]}
 87           ]}
 88       ],
 89   };
 90   var oParser = new JUL.UI.Parser({
 91       defaultClass: 'xul',
 92       useTags: true,
 93       tagProperty: 'tag',
 94       customFactory: 'JUL.UI.createDom',
 95       topDown: true
 96   });
 97   var oDialog = oParser.create(oUiConfig);
 98   oDialog.show();</code></pre>
 99 */
100 /* jshint browser: true, curly: true, eqeqeq: true, expr: true, funcscope: true, immed: true, latedef: true, 
101   onevar: true, newcap: true, noarg: true, node: true, strict: true, trailing: true, undef: true, unused: vars, wsh: true */
102 /* globals JUL: true */
103 
104 (function(global) {
105 'use strict';
106 /* initialize JUL global namespace */
107 global.JUL = {};
108 
109 /* generated by JCS version 1.5.8 */
110 
111 /**
112   JUL global namespace
113   @namespace  It holds the utility methods used by JUL
114 */
115 JUL = {
116   /**
117     This allows setting a default root namespace instead of the global one
118     @type  Object
119   */
120   nsRoot: null,
121   /**
122     JUL version
123     @type  String
124   */
125   version: '1.6.8',
126   /**
127     Creates instances of the JUL global, which can be used as local variables.
128     E.g. <code>var oInstance = new JUL.Instance({nsRoot: myLocalVar});</code>
129     Special members of an instance:<ul>
130     <li>ui - instance of JUL.UI.Parser with JUL.UI defaults applied</li>
131     <li>ref - the same as JUL.Ref() factory</li>
132     <li>parser - shortcut to this.ui.Parser() factory</li></ul>
133     @class  A class for creating instances of the main JUL object
134     @param  {Object}  [oConfig]  Configuration object or an object to use as 'nsRoot'
135   */
136   Instance: function (oConfig) {
137     if (!(this instanceof JUL.Instance)) { return new JUL.Instance(oConfig); }
138     JUL.apply(this, oConfig || {});
139     var oThis = this;
140     var fInstance = function() { return oThis; };
141     var FRef = function(oRef, sKey) {
142       if (!(this instanceof FRef)) { return new FRef(oRef, sKey); }
143       JUL.Ref.call(this, oRef, sKey);
144     };
145     FRef. prototype = new JUL.Ref();
146     FRef.prototype.constructor = FRef;
147     FRef.prototype._getJulInstance = fInstance;
148     this.ref = FRef;
149     this.ui = new JUL.UI.Parser();
150     this.ui._getJulInstance = fInstance;
151     this.parser = this.ui.Parser;
152   },
153   /**
154     Applies an object or an array of objects to a given object
155     @param  {Object}  oSource  The source object to apply to
156     @param  {Object}  oAdd  An Object or array of Objects to apply
157     @param  {Boolean}  bDontReplace  Set it to true to don't replace existing members
158     @param  {Array}  [aFilterOut]  If not null, the keys in this array will not be applied over
159     @param  {Array}  [aFilterIn]  If not null, only the keys in this array will be applied over
160     @returns  {Object}  The source object with the applied members
161   */
162   apply: function (oSource, oAdd, bDontReplace, aFilterOut, aFilterIn) {
163     if (!oAdd || typeof oAdd !== 'object') { return oSource; }
164     if (aFilterOut) { aFilterOut = [].concat(aFilterOut); }
165     if (aFilterIn) { aFilterIn = [].concat(aFilterIn); }
166     var oNew = bDontReplace ? {} : oSource;
167     var aMembers = [].concat(oAdd);
168     for (var i = 0; i < aMembers.length; i++) {
169       oAdd = aMembers[i];
170       for (var sItem in oAdd) {
171         if (oAdd.hasOwnProperty(sItem) &&
172           (!aFilterOut || aFilterOut.indexOf(sItem) < 0) && (!aFilterIn || aFilterIn.indexOf(sItem) > -1)) {
173           oNew[sItem] = oAdd[sItem];
174         }
175       }
176     }
177     if (!bDontReplace) { return oSource; }
178     for (sItem in oNew) {
179       if (oNew.hasOwnProperty(sItem) && typeof oSource[sItem] === 'undefined') { oSource[sItem] = oNew[sItem]; }
180     }
181     return oSource;
182   },
183   /**
184     Retrieves a member specified by a dotted path
185     @param  {String}  sPath  The dotted path or object reference to retrieve
186     @param  {Object}  [oRoot]  An optional object where to start the search from
187     @returns  {Object}  The requested member or undefined if not found
188   */
189   get: function (sPath, oRoot) {
190     var oCurrent = oRoot || this.nsRoot || global;
191     if (!sPath) { return oCurrent; }
192     if (typeof sPath !== 'string') { return sPath; }
193     var aNames = this._square2dots(sPath, ':::::').split('.');
194     if (!oRoot && aNames.length > 1 && ('window' === aNames[0] || 'global' === aNames[0])) {
195       aNames.shift();
196       oCurrent = global;
197     }
198     var sItem = '';
199     while (aNames.length) {
200       sItem = aNames.shift().replace(/:{5}/g, '.');
201       if (!sItem) { continue; }
202       if (typeof oCurrent[sItem] === 'undefined') { return oCurrent[sItem]; }
203       oCurrent = oCurrent[sItem];
204     }
205     return oCurrent;
206   },
207   /**
208     Gets the JUL instance associated with a child object (e.g. a parser, a reference)
209     @param  {Object}  oChild  Child object
210     @returns  {Object}  JUL instance or null if not available
211   */
212   getInstance: function (oChild) {
213     if (oChild instanceof JUL.Ref || oChild instanceof JUL.UI.Parser) {
214       return oChild._getJulInstance ? oChild._getJulInstance() : JUL;
215     }
216     else {
217       return oChild === JUL.UI ? JUL : null;
218     }
219   },
220   /**
221     Creates a wrapper that will call a certain function in a specific scope.
222     Useful for ensuring that a callback will get the desired scope.
223     @param  {Object}  oScope  The scope to call the given function in
224     @param  {Mixed}  fCall  The function to be called. If a string or an index, it will be the oScope method with that name.
225     @param  {Boolean}  [bAppendThis]  If true, the actual calling context will be added as the last parameter of the called function
226     @returns  {Function}  The caller function
227   */
228   makeCaller: function (oScope, fCall, bAppendThis) {
229     if (!oScope || (!fCall && fCall !== 0)) { return null; }
230     if (typeof fCall !== 'function') {
231       fCall = oScope[fCall];
232       if (typeof fCall !== 'function') { return null; }
233     }
234     bAppendThis = (bAppendThis || false) && true;
235     /* try checking for duplicates */
236     this._callers = this._callers || [];
237     for (var i = 0; i < this._callers.length; i++) {
238       if (oScope === this._callers[i][0] && fCall === this._callers[i][1] && bAppendThis === this._callers[i][2]) { return this._callers[i][3]; }
239     }
240     var fCaller = bAppendThis ? function() { return fCall.apply(oScope, [].slice.call(arguments).concat([this])); } :
241       function() { return fCall.apply(oScope, [].slice.call(arguments)); };
242     if (this._callers.length > 16383) { this._callers = this._callers.slice(1024, 16384); }
243     this._callers.push([oScope, fCall, bAppendThis, fCaller]);
244     return fCaller;
245   },
246   /**
247     Creates the specified namespace, and optionally initializes it
248     @param  {String}  sPath  The dotted path for the namespace
249     @param  {Object}  [oInit]  An optional initializer
250     @param  {Object}  [oRoot]  The root object where to start from
251     @returns  {Object}  The created or existing namespace
252   */
253   ns: function (sPath, oInit, oRoot) {
254     var aNames = sPath ? this._square2dots(sPath, ':::::').split('.') : [];
255     var sItem = '';
256     var oRe = /^(\d|[1-9]\d+)$/;
257     var oCurrent = oRoot || this.nsRoot || global;
258     if (!oRoot && aNames.length > 1 && ('window' === aNames[0] || 'global' === aNames[0])) {
259       aNames.shift();
260       oCurrent = global;
261     }
262     while (aNames.length) {
263       sItem = aNames.shift().replace(/:{5}/g, '.');
264       if (!sItem) { continue; }
265       if (typeof oCurrent[sItem] === 'undefined') { oCurrent[sItem] = aNames.length && oRe.test(aNames[0]) ? [] : {}; }
266         if (!aNames.length && typeof oInit !== 'undefined') { oCurrent[sItem] = oInit; }
267       oCurrent = oCurrent[sItem];
268     }
269     return oCurrent;
270   },
271   /**
272     Trims a string at one or both ends
273     @param  {String}  sText  The string to trim
274     @param  {String}  [sWhat]  String pattern to match at the ends, it defaults to whitespace
275     @param  {Boolean}  [bLeftOrRight]  If true trims left, if false trims right, if not specified trims at both ends
276     @returns  {String}  Trimmed string
277   */
278   trim: function (sText, sWhat, bLeftOrRight) {
279     if (typeof sText !== 'string') { sText = sText.toString(); }
280     if (!sText) { return sText; }
281     var bUndef = typeof bLeftOrRight === 'undefined';
282     if (!(bUndef || bLeftOrRight === true || bLeftOrRight === false)  || (bUndef && !(sWhat || sWhat === 0))) {
283       if (typeof String.prototype.trim === 'function') {
284         return sText.trim();
285       }
286       else {
287         return sText.replace(/\s+$/, '').replace(/^\s+/, '');
288       }
289     }
290     else {
291       if (!(sWhat || sWhat === 0)) {
292         if (bLeftOrRight) { return sText.replace(/^\s+/, ''); }
293         else { return sText.replace(/\s+$/, ''); }
294       }
295       if (typeof sWhat !== 'string') { sWhat = sWhat.toString(); }
296       if (bUndef || bLeftOrRight === false) {
297         var nEnd = sText.length;
298         while (nEnd >= sWhat.length && sText.slice(nEnd - sWhat.length, nEnd) === sWhat) { nEnd = nEnd - sWhat.length; }
299         if (nEnd < sText.length) { sText = sText.slice(0, nEnd); }
300       }
301       if (sText.length < sWhat.length) { return sText; }
302       if (bUndef || bLeftOrRight === true) {
303         var nStart = 0;
304         while (nStart <= sText.length - sWhat.length && sText.slice(nStart, nStart + sWhat.length) === sWhat) { nStart = nStart + sWhat.length; }
305         if (nStart) { sText = sText.substr(nStart); }
306       }
307       return sText;
308     }
309   },
310   /**
311     Returns the name of the object's native constructor
312     @param  {Mixed}  oData  An object to get the native constructor name from
313     @returns  {String}  The native constructor name
314   */
315   typeOf: function (oData) {
316     return ({}).toString.call(oData).match(/\w+/g)[1];
317   },
318   /**
319     Gets the JUL instance getter function for a given namespace root, with caching
320     @param  {Object}  [oNSRoot]  Namespace root
321     @returns  {Function}  Instance getter
322     @private
323   */
324   _getAutoInstance: function (oNSRoot) {
325     oNSRoot = oNSRoot || null;
326     if (oNSRoot === this.nsRoot) { return this; }
327     this._autoInstances = this._autoInstances || [];
328     for (var i = 0; i < this._autoInstances.length; i++) {
329       if (oNSRoot === this._autoInstances[i].nsRoot) { return this._autoInstances[i].getInstance; }
330     }
331     var oInstance = new JUL.Instance({nsRoot: oNSRoot});
332     var fInstance = function() { return oInstance; };
333     if (this._autoInstances.length > 1023) { this._autoInstances = this._autoInstances.slice(64, 1024); }
334     this._autoInstances.push({nsRoot: oNSRoot, getInstance: fInstance});
335     return fInstance;
336   },
337   /**
338     Converts a path with square brackets into a dotted path.
339     Use a backslash to escape a square bracket inside segments.
340     @param  {String}  sNS  Input path
341     @param  {String}  [sDotEsc]  If specified, the escaped dots will be replaced with this string
342     @returns  {String}  Output path
343     @private
344   */
345   _square2dots: function (sNS, sDotEsc) {
346     sNS = sNS.replace(/\\\./g, sDotEsc || ':::::').replace(/\\\[/g, ';;;;;1').replace(/\\\]/g, ';;;;;2');
347     sNS = sNS.replace(/(\[|\])+/g, '.').replace(/\.+/g, '.');
348     sNS = this.trim(sNS, '.', false).replace(/;{5}2/g, ']').replace(/;{5}1/g, '[');
349     return sDotEsc ? sNS : sNS.replace(/:{5}/g, '\\.');
350   }
351 };
352 
353 /* add 'indexOf' Array method, if not present */
354 if (typeof Array.prototype.indexOf !== 'function') {
355   Array.prototype.indexOf = function(oSearch, nStart) {
356     for (var i = nStart || 0; i < this.length; i++) {
357       if (this[i] === oSearch) { return i; }
358     }
359     return -1;
360   };
361 }
362 
363 /* add 'map' Array method, if not present */
364 if (typeof Array.prototype.map !== 'function') {
365   Array.prototype.map = function(fMap, oScope) {
366     if (typeof fMap !== 'function') { return null; }
367     var aResult = [];
368     for (var i = 0; i < this.length; i++) {
369       aResult.push(oScope ? fMap.call(oScope, this[i], i, this) : fMap(this[i], i, this));
370     }
371     return aResult;
372   };
373 }
374 
375 /* make JUL.Instance to inherit the JUL members */
376 JUL.apply(JUL.Instance.prototype, JUL, false, ['Instance', 'Ref', 'UI', 'version', '_getAutoInstance']);
377 
378 })(typeof global !== 'undefined' ? global : window);
379 
380 /* end JUL.js */
381