UNPKG

26.8 kBJavaScriptView Raw
1"use strict";
2
3var Finder = require("../lib/dependencies-finder");
4
5jasmine.DEFAULT_TIMEOUT_INTERVAL = 3600000;
6
7
8describe('Module "dependencies-finder"', function() {
9 var check = function(file, requires) {
10 it('should find requires in ' + file, function() {
11 expect( Finder(FILES[file]).requires ).toEqual( requires );
12 });
13 };
14 describe('should find requires', function() {
15 check( "x-widget", ['dom', 'tfw.data-binding'] );
16 //check( "strings", ["A", "C'est", "EF"] );
17 check( "comments", ['YoMan'] );
18 check( "tp4.wdg-event", [
19 'dom', 'tfw.data-binding', 'wdg.text', 'wdg.flex',
20 'tp4.button.edit-intl'
21 ]);
22 check( "tfw.binding", ['tfw.binding.converters', 'tfw.binding.property-manager'] );
23 check( "dom", ['$', 'polyfill.classList', 'tfw.pointer-events'] );
24 });
25});
26
27
28
29var FILES = {
30 "strings": `// Prout
31require("A");
32require('C\'est');
33require("E\"F")`,
34 "comments": `
35/**
36 * @example
37 * var Toto = require("Alright");
38 */
39var Titi = require("YoMan");
40`,
41"tp4.wdg-event": `"use strict";
42
43var $ = require("dom");
44var DB = require("tfw.data-binding");
45var Text = require( "wdg.text" );
46var Flex = require( "wdg.flex" );
47var Description = require( "tp4.button.edit-intl" );
48
49
50/**
51 * @class Event
52 *
53 * @param {boolean} opts.visible - Set the visiblity of the component.
54 *
55 * @example
56 * var Tp.Wdg.Event = require("tp.wdg.event");
57 * var instance = new Tp.Wdg.Event({visible: false});
58 */
59var Event = function(opts) {
60 var inpName = new Text({
61 label: _("name"),
62 width: "320px"
63 });
64 var inpCode = new Text({
65 label: _("code"),
66 width: "120px"
67 });
68 var inpDesc = new Description({
69 text: _("desc"), html: true
70 });
71 var elem = $.elem( this, 'div', [
72 new Flex({
73 justify: "between",
74 content: [inpName, inpCode]
75 }),
76 inpDesc
77 ]);
78
79 DB.propRemoveClass( this, 'visible', 'hide' );
80 DB.propWidget( this, "focus", inpName );
81 DB.propWidget( this, "name", inpName, "value" );
82 DB.propWidget( this, "code", inpCode, "value" );
83 DB.propWidget( this, "desc", inpDesc, "value" );
84
85 opts = DB.extend({
86 visible: true,
87 name: "",
88 code: "",
89 desc: ""
90 }, opts, this);
91};
92
93
94module.exports = Event;
95`,
96 "tfw.binding": `/** @module tfw.binding */require( 'tfw.binding', function(require, module, exports) { var _=function(){return ''}; "use strict";
97
98var Converters = require("tfw.binding.converters");
99var PropertyManager = require('tfw.binding.property-manager');
100
101
102exports.defProps = function( obj, props ) {
103 var propertyName;
104 for( propertyName in props ) {
105 exports.defProp( obj, propertyName, props[propertyName] );
106 }
107};
108
109
110/**
111 * @param {function(v)} opts.cast
112 */
113exports.defProp = function( obj, name, opts ) {
114 if( typeof opts === 'undefined' ) opts = {};
115 var pm = PropertyManager( obj );
116 pm.converter( name, exports.createConverter( opts.cast ) );
117
118 Object.defineProperty( obj, name, {
119 set: pm.change.bind( pm, name ),
120 get: pm.get.bind( pm, name ),
121 configurable: false,
122 enumerable: true
123 });
124};
125
126
127exports.createConverter = function( arg ) {
128 var type = typeof arg;
129 switch( type ) {
130 case 'function':
131 return arg;
132 case 'string':
133 return Converters.get( arg );
134 default:
135 return undefined;
136 }
137};
138
139
140
141module.exports._ = _;
142});
143`,
144 "dom": `/** @module dom */require( 'dom', function(require, module, exports) { var _=function(){var D={"en":{}},X=require("$").intl;function _(){return X(D,arguments);}_.all=D;return _}();
145 /**
146 * @module dom
147 *
148 * @description
149 * Functions which facilitate DOm manipulations.
150 * Included __interact.js__. You can find documentation for it here:
151 * [http://interactjs.io/docs/]
152 *
153 * @example
154 * var mod = require('dom');
155 */
156require("polyfill.classList");
157var PointerEvents = require("tfw.pointer-events");
158
159var $ = function(dom) {
160 if (typeof dom === 'string') {
161 var elem = document.getElementById( dom );
162 if (!elem) {
163 console.error( "[dom] There is no DOM element with this ID: \`" + dom + "\`" );
164 }
165 return elem;
166 }
167 if (!dom) {
168 debugger;
169 throw Error("\`dom\` is not a valid element!", dom);
170 }
171 if (typeof dom.element === 'function') return dom.element();
172 if (dom.element) return dom.element;
173 return dom;
174};
175
176module.exports = $;
177
178
179// Used to store data on the DOM element without colliding with existing attributes.
180var SYMBOL = '@dom' + Date.now();
181
182var RX_ENTITY = /^&(#[0-9]+|[a-zA-Z0-9]+);$/;
183
184$.tagNS = tagNS;
185$.svgRoot = tagNS.bind( undefined, "http://www.w3.org/2000/svg", "svg", {
186 version: '1.1',
187 'xmlns:svg': 'http://www.w3.org/2000/svg',
188 xmlns: 'http://www.w3.org/2000/svg',
189 'xmlns:xlink': 'http://www.w3.org/1999/xlink'
190});
191$.svg = tagNS.bind( undefined, "http://www.w3.org/2000/svg" );
192$.tag = tagNS.bind( undefined, "http://www.w3.org/1999/xhtml" );
193$.div = tagNS.bind( undefined, "http://www.w3.org/1999/xhtml", "div" );
194$.txt = window.document.createTextNode.bind( window.document );
195$.textOrHtml = textOrHtml;
196$.get = get;
197/**
198 * Add a readonly \`element\` property to \`obj\` and return it.
199 */
200$.elem = elem;
201/**
202 * Apply css rules on \`element\`.
203 *
204 * @return \`element\`.
205 *
206 * @example
207 * var $ = require('dom');
208 * $.css( element, { width: '800px'. height: '600px' });
209 */
210$.css = css;
211$.att = att;
212$.removeAtt = removeAtt;
213$.addClass = addClass;
214$.hasClass = hasClass;
215$.removeClass = removeClass;
216$.toggleClass = toggleClass;
217$.saveStyle = saveStyle;
218$.restoreStyle = restoreStyle;
219/**
220 * @param newElem {Element} - Replacement element.
221 * @param oldElem {Element} - Element to replace.
222 */
223$.replace = replace;
224/**
225 * Remove element from its parent.
226 * @param element {Element} - Element to detach from its parent.
227 * @return The parent element.
228 */
229$.detach = detach;
230/**
231 * Add event handlers to one or many elements.
232 *
233 * @param {object|array} element - list of elements on which apply
234 * events handlers.
235 *
236 * @param {object|function} slots - If a function is given, it is
237 * considered as a slot for the event \`tap\`. Otherwise, the object is
238 * a map between events' names (the key) and function to handle the
239 * event (the value).
240 * Events' names are:
241 * * __tap__: When the element is pressed and released in less than
242 900 ms and without too much sliding.
243 * * __doubletap__
244 * * __dragmove__
245 *
246 * @param {boolean} capture - If \`true\` events are captured before they reach the children.
247 *
248 * @example
249 * DOM.on( [screen, button], function() {...} );
250 * DOM.on( body, null ); // Do nothing, but stop propagation.
251 * DOM.on( element, { tap: function() {...} } );
252 */
253$.on = on;
254$.off = off;
255/**
256 * Append all the \`children\` to \`element\`.
257 * @param element
258 * @param ...children
259 */
260$.add = add;
261/**
262 * Add the attribute \`element\` and the following functions to \`obj\`:
263 * * __css__
264 * * __addClass__
265 * * __removeClass__
266 * * __toggleClass__
267 */
268$.wrap = wrap;
269/**
270 * Remove all children of the \`element\`.
271 * @param element {Element} - Element from which remove all the children.
272 */
273$.clear = clear;
274
275function wrap( obj, element, nomethods ) {
276 Object.defineProperty( obj, 'element', {
277 value: element, writable: false, configurable: false, enumerable: true
278 });
279 if( nomethods ) return obj;
280
281 obj.on = on.bind( obj, element );
282 obj.css = css.bind( obj, element );
283 obj.add = add.bind( obj, element );
284 obj.att = att.bind( obj, element );
285 obj.addClass = addClass.bind( obj, element );
286 obj.hasClass = hasClass.bind( obj, element );
287 obj.removeClass = removeClass.bind( obj, element );
288 obj.toggleClass = toggleClass.bind( obj, element );
289 return obj;
290}
291
292function replace( newElem, oldElem ) {
293 newElem = $(newElem);
294 oldElem = $(oldElem);
295 oldElem.parentNode.replaceChild( newElem, oldElem );
296 return newElem;
297}
298
299function css( element, styles ) {
300 element = $(element);
301 var key, val;
302 for( key in styles ) {
303 val = styles[key];
304 element.style[key] = val;
305 }
306 return element;
307}
308
309function att( element, attribs, value ) {
310 element = $(element);
311 var key, val;
312 if (typeof attribs === 'string') {
313 key = attribs;
314 attribs = {};
315 attribs[key] = value;
316 }
317 for( key in attribs ) {
318 val = attribs[key];
319 element.setAttribute( key, val );
320 }
321 return element;
322}
323
324function removeAtt( element, attrib ) {
325 element = $(element);
326 element.removeAttribute( attrib );
327 return element;
328}
329
330function add( element ) {
331 element = $(element);
332 try {
333 var i, child;
334 for (i = 1 ; i < arguments.length ; i++) {
335 child = arguments[i];
336 if( typeof child === 'string' || typeof child === 'number' ) {
337 child = '' + child;
338 if( child.substr( 0, 6 ) == '<html>' ) {
339 var html = child.substr( 6 );
340 child = $.tag('span');
341 child.innerHTML = html;
342 }
343 else if( RX_ENTITY.test( child ) ) {
344 var text = child;
345 child = $.tag('span');
346 child.innerHTML = text;
347 }
348 else {
349 child = document.createTextNode( child );
350 }
351 }
352 else if( typeof child.element === 'function' ) {
353 // Backward compatibility with Widgets.
354 child = child.element();
355 }
356 else if( typeof child.element !== 'undefined' ) {
357 child = child.element;
358 }
359 element.appendChild( child );
360 }
361 return element;
362 }
363 catch( ex ) {
364 console.error( "[DOM.add] arguments=", [].slice.call( arguments ) );
365 throw Error( "[DOM.add] " + ex );
366 }
367}
368
369function off( element ) {
370 if( Array.isArray( element ) ) {
371 element.forEach(function ( elem ) {
372 off( elem );
373 });
374 return element;
375 }
376
377 if( typeof element[SYMBOL] === 'undefined' ) return element;
378 var pe = element[SYMBOL].events;
379 if( typeof pe === 'undefined' ) return element;
380 pe.off();
381 delete element[SYMBOL].events;
382}
383
384function on( element, slots ) {
385 // If only a function is passed, we consider this is a Tap event.
386 if( typeof slots === 'function' || slots === null ) slots = { tap: slots };
387
388 if( Array.isArray( element ) ) {
389 element.forEach(function ( elem ) {
390 on( elem, slots );
391 });
392 return element;
393 }
394
395 element = $(element);
396 if( typeof element[SYMBOL] === 'undefined' ) element[SYMBOL] = {};
397 if( typeof element[SYMBOL].events === 'undefined' ) {
398 element[SYMBOL].events = new PointerEvents( element );
399 }
400
401 var key, val, preview;
402 for( key in slots ) {
403 val = slots[key];
404 if (key.charAt(0) == '!') {
405 key = key.substr(1);
406 preview = true;
407 } else {
408 preview = false;
409 }
410 if (key == 'keydown' || key == 'keyup') {
411 element.addEventListener( key, val, preview );
412 } else {
413 element[SYMBOL].events.on( key, val, preview );
414 }
415 }
416
417 return element;
418}
419
420function tagNS( ns, name ) {
421 try {
422 var e = document.createElementNS( ns, name );
423 var i, arg, key, val;
424 for (i = 2 ; i < arguments.length ; i++) {
425 arg = arguments[i];
426 if( Array.isArray(arg) ) {
427 // Arrays are for children.
428 arg.forEach(function (child) {
429 switch( typeof child ) {
430 case 'string':
431 case 'number':
432 case 'boolean':
433 child = '' + child;
434 if( child.substr( 0, 6 ) == '<html>' ) {
435 var html = child.substr( 6 );
436 child = $.tag('span');
437 child.innerHTML = html;
438 } else {
439 child = document.createTextNode( child );
440 }
441 break;
442 }
443 add( e, child );
444 });
445 } else {
446 switch( typeof arg ) {
447 case "string":
448 arg.split( ' ' ).forEach(function ( item ) {
449 if( item.length > 0 ) {
450 addClass(e, item);
451 }
452 });
453 break;
454 case "object":
455 for( key in arg ) {
456 val = arg[key];
457 e.setAttribute( key, val );
458 }
459 break;
460 default:
461 throw Error("[dom.tag] Error creating <" + name + ">: Invalid argument #" + i + "!");
462 }
463 }
464 }
465 return e;
466 }
467 catch (ex) {
468 console.error("[dom.tagNS] Error with \`ns\` = ", ns, " and \`name\` = ", name);
469 console.error(ex);
470 }
471};
472
473
474function addClass(elem) {
475 var args = [].slice.call( arguments, 1 );
476 if( Array.isArray( elem ) ) {
477 // Loop on each element.
478 args.unshift( null );
479 elem.forEach(function ( child ) {
480 args[0] = child;
481 addClass.apply( undefined, args );
482 });
483 return elem;
484 }
485 elem = $( elem );
486 args.forEach(function (className) {
487 if (typeof className !== 'string') return;
488 className = className.trim();
489 if( className.length == 0 ) return;
490 try {
491 if( elem.classList )
492 elem.classList.add( className );
493 }
494 catch( ex ) {
495 console.error( "[dom.addClass] Invalid class name: ", className );
496 console.error( ex );
497 }
498 });
499 return elem;
500}
501
502
503function hasClass( elem, className ) {
504 elem = $( elem );
505 if( !elem.classList ) return false;
506 return elem.classList.contains( className );
507}
508
509
510function removeClass(elem) {
511 var args = [].slice.call( arguments, 1 );
512 if( Array.isArray( elem ) ) {
513 // Loop on each element.
514 args.unshift( null );
515 elem.forEach(function ( child ) {
516 args[0] = child;
517 removeClass.apply( undefined, args );
518 });
519 return elem;
520 }
521 elem = $( elem );
522 args.forEach(function (className) {
523 if (typeof className !== 'string') return;
524 try {
525 if( elem.classList )
526 elem.classList.remove( className );
527 }
528 catch( ex ) {
529 console.error( "[dom.removeClass] Invalid class name: ", className );
530 console.error( ex );
531 }
532 });
533 return elem;
534}
535
536
537function toggleClass(elem) {
538 var args = [].slice.call( arguments, 1 );
539 args.forEach(function( className ) {
540 if( hasClass( elem, className ) ) {
541 removeClass( elem, className );
542 } else {
543 addClass( elem, className );
544 }
545 });
546 return elem;
547}
548
549
550function clear( element ) {
551 // (!) On préfère retirer les éléments un par un du DOM plutôt que d'utiliser simplement
552 // this.html("").
553 // En effet, le code simplifié a des conséquences inattendues dans IE9 et IE10 au moins.
554 // Le bug des markers qui disparaissaients sur les cartes de Trail-Passion 4 a été corrigé
555 // avec cette modification.
556 element = $(element);
557 var e = element;
558 while(e.firstChild){
559 e.removeChild(e.firstChild);
560 }
561 var args = [].slice.call( arguments );
562 if( args.length > 1 ) {
563 add.apply( this, args );
564 }
565 return element;
566}
567
568function get( element, query ) {
569 element = $(element);
570 if( typeof query === 'undefined' ) {
571 query = element;
572 element = window.document;
573 }
574 return element.querySelector( query );
575}
576
577function detach( element ) {
578 element = $(element);
579 var parent = element.parentElement;
580 if( !parent ) return parent;
581 parent.removeChild( element );
582 return parent;
583}
584
585function elem( target ) {
586 var args = [].slice.call( arguments );
587 args.shift();
588 if (args.length == 0) args = ['div'];
589 args.push('dom', 'custom');
590 var e;
591 if (typeof args[0].element !== 'undefined') {
592 e = args[0].element;
593 addClass( e, 'dom', 'custom' );
594 } else if (typeof args[0].appendChild === 'function') {
595 e = args[0];
596 addClass( e, 'dom', 'custom' );
597 } else {
598 e = $.tag.apply( $, args );
599 }
600 Object.defineProperty( target, 'element', {
601 value: e, writable: false, configurable: false, enumerable: true
602 });
603 return e;
604}
605
606function textOrHtml( element, content ) {
607 if( typeof content === 'undefined' ) content = '';
608 if (content === null) content = '';
609 if (typeof content !== 'string') content = JSON.stringify( content );
610 if (content.substr(0, 6) == '<html>') {
611 element.innerHTML = content.substr(6);
612 } else {
613 element.textContent = content;
614 }
615 return element;
616}
617
618function saveStyle( elements ) {
619 if( !Array.isArray( elements ) ) return saveStyle( Array.prototype.slice.call( arguments ) );
620 elements.forEach(function (elem) {
621 elem = $( elem );
622 if( typeof elem[SYMBOL] === 'undefined' ) elem[SYMBOL] = {};
623 if( !Array.isArray( elem[SYMBOL].style ) ) elem[SYMBOL].style = [];
624 elem[SYMBOL].style.push( JSON.stringify( elem.style ) );
625 });
626}
627
628function restoreStyle( elements ) {
629 if( !Array.isArray( elements ) ) return restoreStyle( Array.prototype.slice.call( arguments ) );
630 elements.forEach(function (elem) {
631 elem = $( elem );
632 if( typeof elem[SYMBOL] === 'undefined' || !Array.isArray( elem[SYMBOL].style ) ) throw Error(
633 "[dom.restoreStyle] \`saveStyle()\` has never been used on this element!");
634 if( elem[SYMBOL].style.length == 0 ) throw Error(
635 "[dom.restoreStyle] more \`restore\` than \`save\`!");
636 var styles = JSON.parse( elem[SYMBOL].style.pop() );
637 var k, v;
638 for( k in styles ) {
639 v = styles[k];
640 if( typeof v !== 'undefined' ) {
641 elem.style[k] = v;
642 }
643 }
644 });
645}
646
647
648
649module.exports._ = _;
650/**
651 * @module dom
652 * @see module:$
653 * @see module:tfw.pointer-events
654
655 */
656});`,
657"x-widget": `/**
658 * @example
659 *
660 * var W = require("x-widget");
661 * W({
662 * elem: "div",
663 * attr: {"class": "black"},
664 * prop: {"$key": "menu"},
665 * children: [
666 * "This is the ",
667 * W({
668 * elem: "b",
669 * children: ["menu"]
670 * }),
671 * "..."
672 * ]
673 * });
674 */
675"use strict";
676
677var $ = require("dom");
678var DB = require("tfw.data-binding");
679
680var widgets = {};
681// Used for \`onWidgetCreation()\`.
682var slots = {};
683
684
685var Widget = function(id, modName, args, attribs) {
686 if (typeof id === 'string') return Widget1.call( this, id, modName, args, attribs );
687 else return Widget2.call( this, id );
688};
689
690function Widget1(id, modName, args, attribs ) {
691 if( typeof attribs === 'undefined' ) attribs = {};
692
693 try {
694 var module = require( modName );
695 var wdg = new module( args );
696 var elem = typeof wdg.element === 'function' ? wdg.element() : wdg.element;
697 var dst = document.getElementById( id );
698 if (dst) {
699 // This widget does exist in the current DOM.
700 // We have to replace it.
701 dst.parentNode.replaceChild( elem, dst );
702 }
703 elem.setAttribute( 'id', id );
704 // Add classes defined in the containing element (\`dst\`).
705 $.addClass( elem, attribs.class || "" );
706 register( id, wdg );
707 return wdg;
708 }
709 catch (ex) {
710 console.error("[x-widget] Unable to create widget \`" + modName + "\`!");
711 console.error("[x-widget] id = ", id, ", args = ", args);
712 throw Error(ex);
713 }
714};
715
716function Widget2(args) {
717 var id;
718 var elem = $.tag( args.elem );
719 if (args.attr) {
720 // Adding DOM element attributes.
721 $.att( elem, args.attr );
722 id = args.attr.id;
723 }
724
725 if (Array.isArray( args.children )) {
726 // Adding DOM element children.
727 args.children.forEach(function (child) {
728 $.add( elem, child );
729 });
730 }
731 // Converting into a widget.
732 var key, val;
733 var wdg = {};
734
735 if (args.prop) {
736 // Adding READ-ONLY properties to the widget.
737 for( key in args.prop ) {
738 val = args.prop[key];
739 Object.defineProperty( wdg, key, {
740 value: val, writable: false, configurable: false, enumerable: true
741 });
742 }
743 }
744 // Assigning the element to the widget.
745 Object.defineProperty( wdg, 'element', {
746 value: elem, writable: false, configurable: false, enumerable: true
747 });
748
749 if( typeof id !== 'undefined' ) {
750 // Registering the widget only if it as got an id.
751 register( id, wdg );
752 }
753 return wdg;
754}
755
756Widget.template = function( attribs ) {
757 var key, val, id, name = '', args = {};
758 for( key in attribs ) {
759 val = attribs[key];
760 if( key == 'name' ) {
761 name = val;
762 }
763 else if( key == 'id' ) {
764 id = val;
765 }
766 else if( key.charAt(0)=='$' ) {
767 args[key.substr( 1 )] = val;
768 }
769 }
770 var module = require( name );
771 var wdg = new module( args );
772 if( id ) {
773 register( id, wdg );
774 }
775
776 return typeof wdg.element === 'function' ? wdg.element() : (wdg.element || wdg);
777};
778
779function register( id, wdg ) {
780 widgets[id] = wdg;
781 var mySlots = slots[id];
782 if( typeof mySlots !== 'undefined' ) {
783 window.setTimeout(function() {
784 mySlots.forEach(function (slot) {
785 slot( wdg );
786 });
787 delete slots[id];
788 });
789 }
790 return typeof wdg.element === 'function' ? wdg.element : (wdg.element || wdg);
791};
792
793Widget.getById = function( id ) {
794 if( !widgets[id] ) throw Error( "[x-widget.getById()] ID not found: " + id + "!" );
795 return widgets[id];
796};
797
798Widget.onWidgetCreation = function( id, slot ) {
799 if( typeof widgets[id] === 'undefined' ) {
800 if( typeof slots[id] === 'undefined' ) slots[id] = [slot];
801 else slots[id].push( slot );
802 } else {
803 // Asynchronous call to the slot
804 window.setTimeout(
805 function() {
806 slot( widgets[id] );
807 }
808 );
809 }
810};
811
812/**
813 * @example
814 * var W = require("x-widget");
815 * W.bind('wdg.layout-stack0',{"value":{"B":[["btnNewTask","action"],["btnCancel","action"]]}});
816 */
817Widget.bind = function( id, attribs ) {
818 // Destination object: the one on the attributes of which we want to bind.
819 var dstObj = widgets[id];
820 // Destination attribute name.
821 var dstAtt;
822 // Temporary variables to hold source object and attributes.
823 var srcObj, srcAtt;
824 // @example
825 // ["btnNewTask","action","btnCancel","action"]
826 var bindings;
827 var slots;
828 // Index used to parse multiple bindings.
829 var idx;
830 for( dstAtt in attribs ) {
831 bindings = attribs[dstAtt].B;
832 if (Array.isArray( bindings )) {
833 // \`binding\` is an array of arrays.
834 // Subarrays have 2 or 3 elements.
835 // * ID if the source object
836 // * attribute to bind on
837 // * [optional] value to use as a constant. This is the
838 // * case where we just want to set a constant value as
839 // * soon as the source's attribute has changed.
840 bindings.forEach(function (binding) {
841 srcObj = widgets[binding[0]];
842 if( typeof srcObj === 'undefined' ) {
843 console.error( "[x-widget:bind(" + id + ")] Trying to bind attribute \""
844 + dstAtt
845 + "\" of widget \"" + id + "\" to the unexisting widget \""
846 + binding[0] + "\"!");
847 return;
848 }
849 srcAtt = binding[1];
850 try {
851 if (binding.length == 2) {
852 DB.bind( srcObj, srcAtt, dstObj, dstAtt );
853 } else {
854 var value = binding[2];
855 DB.bind( srcObj, srcAtt, function() {
856 dstObj[dstAtt] = value;
857 });
858 }
859 } catch( ex ) {
860 console.error("Binding error for widget \`" + id + "\`!", {
861 ex: ex,
862 binding: binding
863 });
864 }
865 });
866 }
867
868 slots = attribs[dstAtt].S;
869 if (Array.isArray( slots )) {
870 // Each item is the name of a function to call when the value of this attribute changes.
871 // If the item is a \`string\`, the function is from the global \`APP\` object.
872 // Otherwise, the item must be an array with two children:
873 // the first one is the module's name and the second one
874 // id the name of the function.
875 // The slots are called with two arguments:
876 // * the value and
877 // * the object the attribute belongs.
878 slots.forEach(function (slot) {
879 var mod = APP;
880 var fct = slot;
881 if (Array.isArray( slot )) {
882 try {
883 mod = require(slot[0]);
884 } catch( ex ) {
885 console.error("[x-widget:bind] Widget \`" + id + "\` can't require unexistent \`"
886 + slot[0] + "\`: ", ex);
887 throw( ex );
888 }
889 fct = slot[1];
890 }
891 fct = mod[fct];
892 if (typeof fct !== 'function') {
893 if( Array.isArray(slot) ) {
894 throw Error("[x-widget:bind] Widget \`" + id + "\` use unexisting slot \`"
895 + slot[1] + "\` of module \`" + slot[0] + "\`!");
896 } else {
897 throw Error("[x-widget:bind] Widget \`" + id + "\` use unexisting slot \`"
898 + slot + "\` of main module \`APP\`!");
899 }
900 } else {
901 try {
902 DB.bind( dstObj, dstAtt, fct );
903 } catch( ex ) {
904 console.error("Binding error for widget \`" + id + "\`!", {
905 ex: ex,
906 dstObj: dstObj,
907 dstAtt: dstAtt,
908 fct: fct,
909 slot: slot
910 });
911 }
912 }
913 });
914
915 }
916 }
917};
918
919module.exports = Widget;
920`};