XObject.js
[gitlive] / XObject.js
1 //<script type="text/javascript">
2
3 /**
4  * XObject
5  * Yet another attempt to create a usable object construction library for seed..
6  *
7  * Extend this.. to use it's wonderful features..
8  * 
9  * 
10  * @arg xtype {String|Function} constructor or string.
11  * @arg xid {String}  (optional) id for registry
12  * @arg xns {String|Object}   (optional) namespace eg. Gtk or 'Gtk' - used with xtype.
13  * @arg items {Array}   (optional) list of child elements which will be constructed.. using XObject
14  * @arg listeners {Object}   (optional) map Gobject signals to functions
15  * @arg pack {Function|String|Array}   (optional) how this object gets added to it's parent
16  * @arg el {Object}   (optional) premade GObject
17  */
18
19 function XObject (cfg) {
20     // first apply cfg if set.
21     o =  {};
22     
23     cfg.items = cfg.items || [];
24     
25     XObject.extend(o, cfg); // copy everything into o.
26     
27     o.pack = typeof(o.pack) == 'undefined' ? 'add' : o.pack;
28     
29     XObject.extend(this, o);
30
31     // remove items.
32     
33     this.listeners = this.listeners || {}; 
34     this.items = [];
35     
36     // remove objects/functions from o, so they can be sent to the contructor.
37     for (var i in o) {
38         if ((typeof(o[i]) == 'object') || 
39             (typeof(o[i]) == 'function') || 
40             i == 'pack' ||
41             i == 'xid' ||
42             i == 'xtype' ||
43             i == 'xns'
44         ) {
45             delete o[i];
46         }
47     }
48     
49     // do we need to call 'beforeInit here?'
50      
51     // handle include?
52     //if ((this.xtype == 'Include')) {
53     //    o = this.pre_registry[cls];
54     //}
55     var isSeed = typeof(Seed) != 'undefined';
56      
57     // xtype= Gtk.Menu ?? what about c_new stuff?
58     print(this.xtype);
59     if (typeof(this.xtype) == 'function') {
60         this.el = this.el ||  this.xtype(o);
61     }
62     if (typeof(this.xtype) == 'object') {
63         print(XObject.keys(o).join(','));
64         this.el = this.el ||  new this.xtype(o);
65     }
66     print(this.el);
67     if (!this.el && o.xns) {
68         
69         var NS = imports.gi[o.xns];
70         if (!NS) {
71             Seed.print('Invalid xns: ' + o.xns);
72         }
73         constructor = NS[o.xtype];
74         if (!constructor) {
75             Seed.print('Invalid xtype: ' + o.xns + '.' + o.xtype);
76         }
77         this.el  =   isSeed ? new constructor(o) : new constructor();
78         if (!isSeed) {
79             // this might work for gjs!?
80             for (var i in o) {
81                 this.el[i] = o;
82             }
83         }
84     }
85     
86     // register it!
87     //if (o.xnsid  && o.xid) {
88      //   XObject.registry = XObject.registry || { };
89      //   XObject.registry[o.xnsid] = XObject.registry[o.xnsid] || {}; 
90      //   XObject.registry[o.xnsid][o.xid] = this;
91     //}
92     
93     cfg.items.forEach(this.addItem, this);
94     
95     for (var i in this.listeners) {
96         this.addListener(i, this.listeners[i]);
97     }
98     // delete this.listeners ?
99     
100     
101     // do we need to call 'init here?'
102     
103 }
104
105
106
107 XObject.prototype = {
108     /**
109      * @property el {GObject} the Gtk / etc. element.
110      */
111     el : false, 
112     /*
113      * @property items {Array} list of sub elements
114      */
115     /**
116      * @property parent {XObject} parent Element
117      */
118      /**
119       * @method addItem
120       * Adds an item to the object using a new XObject
121       * uses pack property to determine how to add it.
122       * @arg cfg {Object} same as XObject constructor.
123       */
124     addItem : function(o) {
125         var item = new XObject(o);
126         
127         this.items.push(item);
128         
129         if (item.pack===false) {  // no 
130             return;
131         }
132         if (typeof(item.pack) == 'function') {
133             // parent, child
134             item.pack.apply(o, [ o , o.items[i] ]);
135             item.parent = this;
136             return;
137         }
138         var args = [];
139         var pack_m  = false;
140         if (typeof(item.pack) == 'string') {
141             pack_m = item.pack;
142         } else {
143             pack_m = item.pack.shift();
144             args = item.pack;
145         }
146         
147         // handle error.
148         if (pack_m && typeof(this.el[pack_m]) == 'undefined') {
149             Seed.print('pack method not available : ' + this.xtype + '.' +  pack_m);
150             return;
151         }
152         
153         
154         Seed.print('Pack ' + this.el + '.'+ pack_m + '(' + item.el + ')');
155
156         args.unshift(item.el);
157         print('[' + args.join(',') +']');
158         //Seed.print('args: ' + args.length);
159         if (pack_m) {
160             this.el[pack_m].apply(item.el, args);
161         }
162         
163         item.parent = this;
164         
165     },
166     /**
167       * @method addListener
168       * Connects a method to a signal. (gjs/Seed aware)
169       * 
170       * @arg sig  {String} name of signal
171       * @arg fn  {Function} handler.
172       */
173     addListener  : function(sig, fn) 
174     {
175  
176         Seed.print("Add signal " + sig);
177  
178         var _li = XObject.createDelegate(fn,this);
179         // private listeners that are not copied to GTk.
180         
181         if (typeof(Seed) != 'undefined') {
182           //   Seed.print(typeof(_li));
183             this.el.signal[sig].connect(_li);
184         } else {
185             this.el.connect( sig, _li);
186         }
187              
188         
189     },
190      /**
191       * @method get
192       * Finds an object in the child elements using xid of object.
193       * 
194       * @arg name  {String} name of signal
195       * @return   {XObject|false} the object if found.
196       */
197     get : function(xid)
198     {
199         var ret=  false;
200         this.items.forEach(function(ch) {
201             if (ch.xid == xid) {
202                 ret = ch;
203                 return true;
204             }
205         })
206         if (ret) {
207             return ret;
208         }
209         // iterate children.
210         this.items.forEach(function(ch) {
211             ret = ch.get(xid);
212             if (ret) {
213                 return true;
214             }
215         })
216         return ret;
217     }
218       
219       
220
221          
222         
223 /**
224  * Copies all the properties of config to obj.
225  *
226  * Pretty much the same as JQuery/Prototype..
227  * @param {Object} obj The receiver of the properties
228  * @param {Object} config The source of the properties
229  * @param {Object} defaults A different object that will also be applied for default values
230  * @return {Object} returns obj
231  * @member XObject extend
232  */
233
234
235 XObject.extend = function(o, c, defaults){
236     if(defaults){
237         // no "this" reference for friendly out of scope calls
238         XObject.extend(o, defaults);
239     }
240     if(o && c && typeof c == 'object'){
241         for(var p in c){
242             o[p] = c[p];
243         }
244     }
245     return o;
246 };
247
248 XObject.extend(XObject,
249 {
250     /**
251      * Copies all the properties of config to obj, if the do not exist.
252      * @param {Object} obj The receiver of the properties
253      * @param {Object} config The source of the properties
254      * @return {Object} returns obj
255      * @member Object extendIf
256      */
257
258
259     extendIf : function(o, c){
260
261         if(!o || !c || typeof c != 'object'){
262             return o;
263         }
264         for(var p in c){
265             if (typeof(o[p]) != 'undefined') {
266                 continue;
267             }
268             o[p] = c[p];
269         }
270         return o;
271     },
272
273  
274
275     /**
276      * Extends one class with another class and optionally overrides members with the passed literal. This class
277      * also adds the function "override()" to the class that can be used to override
278      * members on an instance.
279      *
280      * usage:
281      * MyObject = Object.define(
282      *     function(...) {
283      *          ....
284      *     },
285      *     parentClass, // or Object
286      *     {
287      *        ... methods and properties.
288      *     }
289      * });
290      * @param {Function} constructor The class inheriting the functionality
291      * @param {Object} superclass The class being extended
292      * @param {Object} overrides (optional) A literal with members
293      * @return {Function} constructor (eg. class
294      * @method define
295      */
296     define : function(){
297         // inline overrides
298         var io = function(o){
299             for(var m in o){
300                 this[m] = o[m];
301             }
302         };
303         return function(sb, sp, overrides) {
304             if (typeof(sp) == 'undefined') {
305                 // error condition - try and dump..
306                 throw "Missing superclass: when applying: " + sb
307             }
308
309             var F = function(){}, sbp, spp = sp.prototype;
310             F.prototype = spp;
311             sbp = sb.prototype = new F();
312             sbp.constructor=sb;
313             sb.superclass=spp;
314
315             // extends Object.
316             if(spp.constructor == Object.prototype.constructor){
317                 spp.constructor=sp;
318             }
319             
320             sb.override = function(o){
321                 Object.extend(sb.prototype, o);
322             };
323             sbp.override = io;
324             Object.extend(sb.prototype, overrides);
325             return sb;
326         };
327     }(),
328
329          
330     /**
331      * returns a list of keys of the object.
332      * @param {Object} obj object to inspect
333      * @return {Array} returns list of kyes
334      * @member XObject keys
335      */
336     keys : function(o)
337     {
338         var ret = [];
339         for(var i in o) {
340             ret.push[i];
341         }
342         return ret;
343     },
344       
345     /**
346      * @member XObject createDelegate
347      * creates a delage metdhod
348      * @param {Function} method to wrap
349      * @param {Object} scope 
350      * @param {Array} args to add
351      * @param {Boolean|Number} append arguments or replace after N arguments.
352      * @return {Function} returns the delegate
353      */
354
355     createDelegate : function(method, obj, args, appendArgs){
356         
357         return function() {
358             var callArgs = args || arguments;
359             if(appendArgs === true){
360                 callArgs = Array.prototype.slice.call(arguments, 0);
361                 callArgs = callArgs.concat(args);
362             }else if(typeof appendArgs == "number"){
363                 callArgs = Array.prototype.slice.call(arguments, 0); // copy arguments first
364                     var applyArgs = [appendArgs, 0].concat(args); // create method call params
365                     Array.prototype.splice.apply(callArgs, applyArgs); // splice them in
366                 }
367                 return method.apply(obj || window, callArgs);
368             };
369     }
370     
371 });