OSDN Git Service

Version 0.6.149, fix X.Audio & X.UI.
[pettanr/clientJs.git] / 0.6.x / js / 20_ui / 08_Box.js
1 \r
2 var XUI_Layout_Canvas = X[ 'UI' ][ 'Layout' ][ 'Canvas' ] = XUI_createLayout( {\r
3         name : 'CanvasLayout',\r
4         \r
5         overrideAttrsForSelf : {\r
6                 selectable  : false,\r
7                 role        : [ 0, XUI_Dirty.CLEAN, XUI_Attr_USER.UINODE, XUI_Attr_Type.INIT_ONLY | XUI_Attr_Type.LIST, 'none,chrome,container' ],\r
8                 \r
9                 width       : [ '100%',         XUI_Dirty.LAYOUT, XUI_Attr_USER.LAYOUT, XUI_Attr_Type.LENGTH | XUI_Attr_Type.PERCENT ],\r
10                 maxWidth    : [ XUI_Attr_AUTO, XUI_Dirty.LAYOUT, XUI_Attr_USER.LAYOUT, XUI_Attr_Type.LENGTH | XUI_Attr_Type.PERCENT ],\r
11                 height      : [ 0,              XUI_Dirty.LAYOUT, XUI_Attr_USER.LAYOUT, XUI_Attr_Type.LENGTH | XUI_Attr_Type.PERCENT ],\r
12                 maxHeight   : [ XUI_Attr_AUTO, XUI_Dirty.LAYOUT, XUI_Attr_USER.LAYOUT, XUI_Attr_Type.LENGTH | XUI_Attr_Type.PERCENT ]\r
13         },\r
14         \r
15         overrideAttrsForChild : {\r
16                 left   : true,\r
17                 top    : true,\r
18                 bottom : true,\r
19                 right  : true\r
20         },\r
21         \r
22         calculate : function( data, isNeedsDetection, x, y, w, h ){\r
23                 var uinodes, l, i, _x, _y, _w, _h, node;\r
24 \r
25                 data.preMesure( w, h );\r
26                 \r
27                 if( isNeedsDetection && ( data.boxWidth === XUI_Attr_AUTO || data.boxHeight === XUI_Attr_AUTO ) ) return false;\r
28                 \r
29                 _x = data.contentL;\r
30                 _y = data.contentT;\r
31                 _w = data.contentWidth;\r
32                 _h = data.contentHeight;\r
33 \r
34                 if( ( uinodes = data.uinodes ) && ( l = uinodes.length ) ){\r
35                         for( i = 0; i < l; ++i ){\r
36                                 node = uinodes[ i ];\r
37                                 node.calculate( false, _x, _y, _w, _h );\r
38                         };\r
39                 } else\r
40                 if( data.contentHeight === XUI_Attr_AUTO ){\r
41                         data.contentHeight = data.minContentHeight !== XUI_Attr_AUTO ? data.minContentHeight : 0;\r
42                 };\r
43                 \r
44                 data.postMesure();\r
45 \r
46                 if( !isNeedsDetection ){\r
47                         data.boxX += x;\r
48                         data.boxY += y;                 \r
49                 };\r
50                 return true;\r
51         }\r
52 });\r
53 \r
54 \r
55 var XUI_Box = XUI_AbstractUINode.inherits(\r
56         'X.UI._Box',\r
57         X_Class.NONE,\r
58         {\r
59                 supportAttrs    : XUI_Attr_createAttrDef( XUI_AbstractUINode.prototype.supportAttrs, XUI_Layout_Canvas.overrideAttrsForSelf ),\r
60                 \r
61                 layout          : null,\r
62                 uinodes         : null,\r
63                 xnodes          : null,\r
64                 \r
65                 hitChildData    : null,\r
66                 pointerChildren : true,\r
67                 through         : false,\r
68 \r
69                 scrollingX      : 0, // TODO 現在のスクロール位置\r
70                 scrollingY      : 0, // TODO \r
71 \r
72                 Constructor : function( user, layout, args ){\r
73                         var i = 0,\r
74                                 l = args.length || 1,\r
75                                 j = -1,\r
76                                 uinodes, arg, _data, attrs, support, p;\r
77                         \r
78                         //if( !args.length ) args = [ args ];\r
79                         \r
80                         if( !user[ 'instanceOf' ]( X.UI.Box ) ){\r
81                                 //throw new Error( 'Box を継承したインスタンスだけが _Box のオーナーになれます' );\r
82                         };                      \r
83                         \r
84                         this.User   = user;\r
85                         \r
86                         this.xnode  = X_Doc_create( 'div' );\r
87                         \r
88                         // すでに定義されていればそちらを採用\r
89                         // supportAttrs や attrClass が、layout を元に上書きされているため\r
90                         this.layout = this.layout || layout;\r
91                         \r
92                         for( ; i < l; ++i ){\r
93                                 arg = args[ i ];\r
94                                 if( arg[ 'instanceOf' ] && arg[ 'instanceOf' ]( X.UI.AbstractUINode ) ){\r
95                                         _data = X_Pair_get( arg );\r
96                                         if( !uinodes ) this.uinodes = uinodes = [];\r
97                                         uinodes[ ++j ] = _data;\r
98                                         if( _data.parent ){\r
99                                                 //throw new Error( 'インスタンスはすでに親に追加されています ' + arg );\r
100                                         };\r
101                                 } else\r
102                                 if( arg[ 'instanceOf' ] && arg[ 'instanceOf' ]( Node ) ){\r
103                                         //this.layout = arg;\r
104                                 } else\r
105                                 if( arg[ 'instanceOf' ] && arg[ 'instanceOf' ]( XUI_LayoutBase ) ){\r
106                                         //this.layout = arg;\r
107                                 } else\r
108                                 if( X_Type_isObject( arg ) ){\r
109                                         if( attrs ){\r
110                                                 attrs = X_Class_override( attrs, arg );\r
111                                         } else {\r
112                                                 attrs = arg;\r
113                                         };\r
114                                 } else {\r
115                                         //throw new Error( 'AbstractUINode を継承したインスタンスを渡してください ' + arg );\r
116                                 };\r
117                         };\r
118                         \r
119                         for( p in attrs ){\r
120                                 if( X_EMPTY_OBJECT[ p ] ) continue;\r
121                                 ( support = this.supportAttrs[ p ] ) && this.setAttr( p, support, attrs[ p ] );\r
122                         };\r
123                 },\r
124         /* Rellay */\r
125                 initialize : function( root, rootData, parent, parentData ){\r
126                         var uinodes = this.uinodes,\r
127                                 i       = uinodes && uinodes.length;\r
128                         this.root       = root;\r
129                         this.rootData   = rootData;\r
130                         this.parent     = parent;\r
131                         this.parentData = parentData;\r
132                         //this.xnode      = X_Doc_create( 'div' );\r
133                         \r
134                         if( i ){\r
135                                 for( ; i; ){\r
136                                         uinodes[ --i ].initialize( root, rootData, this.User, this );\r
137                                 };                              \r
138                         };\r
139                         \r
140                         this.phase = 1;\r
141                         this.User[ 'dispatch' ]( { type : XUI_Event.INIT } );\r
142                 },\r
143                 \r
144                 addToParent : function( parentXNode ){\r
145                         var uinodes = this.uinodes,\r
146                                 l       = uinodes && uinodes.length,\r
147                                 i;\r
148 \r
149                         parentXNode && parentXNode[ 'append' ]( this.xnode );\r
150                         \r
151                         if( l ){\r
152                                 for( i = 0; i < l; ++i ){\r
153                                         uinodes[ i ].addToParent( this.xnode );\r
154                                 };\r
155                         };\r
156                         \r
157                         this.phase = 2;\r
158                         this.User[ 'dispatch' ]( { type : XUI_Event.ADDED } );\r
159                 },\r
160                 \r
161         /* Rellay */\r
162                 creationComplete : function(){\r
163                         var uinodes = this.uinodes,\r
164                                 i       = uinodes && uinodes.length;\r
165                         if( i ){\r
166                                 for( ; i; ){\r
167                                         uinodes[ --i ].creationComplete();\r
168                                 };                              \r
169                         };\r
170                         \r
171                         XUI_AbstractUINode.prototype.creationComplete.apply( this, arguments );\r
172                 },\r
173                 \r
174                 calculate : function( isNeedsDetection, x, y, w, h ){\r
175                         var ret = this.layout.calculate( this, isNeedsDetection, x, y, w, h );                  \r
176                         this.phase = 4;\r
177                         return ret;\r
178                 },\r
179         \r
180                 updateLayout : function(){\r
181                         var uinodes = this.uinodes, i, l;\r
182 \r
183                         if( uinodes && ( l = uinodes.length ) ){\r
184                                 for( i = 0; i < l; ++i ){\r
185                                         uinodes[ i ].updateLayout();\r
186                                 };      \r
187                         };\r
188                         XUI_AbstractUINode.prototype.updateLayout.call( this );\r
189                 },\r
190                 \r
191                 capcher : function( x, y ){\r
192                         var uinodes, child, _x, _y, hit, i;\r
193                         if( this.pointerDisabled ) return false;\r
194                         delete this.hitChildData;\r
195                         x -= this.boxX;\r
196                         y -= this.boxY;\r
197                         if( this.pointerChildren && ( uinodes = this.uinodes ) && ( i = uinodes.length ) ){\r
198                                 _x = x - this.scrollingX;\r
199                                 _y = y - this.scrollingY;\r
200                                 for( ; i; ){\r
201                                         child = uinodes[ --i ];\r
202                                         if( !child.pointerDisabled && child.boxX <= _x && _x < child.boxX + child.boxWidth && child.boxY <= _y && _y < child.boxY + child.boxHeight && child.capcher( _x, _y ) ){\r
203                                                 //console.log( 'hit child ' + _x + ' ' + _y + ' boxX:' + child.boxX + ' boxY:' + child.boxY );\r
204                                                 this.hitChildData = child;\r
205                                                 break;\r
206                                         };\r
207                                 };\r
208                         };\r
209                         if( this.through ){\r
210                                 this.hitChildData && !this.hovering && ( this.rootData.hoverList[ this.rootData.hoverList.length ] = this );\r
211                                 return !!this.hitChildData;\r
212                         };\r
213                         hit = 0 <= x && x < this.boxWidth && 0 <= y && y < this.boxHeight;\r
214                         ( this.hitChildData || hit ) && !this.hovering && ( this.rootData.hoverList[ this.rootData.hoverList.length ] = this );\r
215                         if( hit && this.hitChildData === null ) this.rootData.targetNodeData = this;\r
216                         return hit || !!this.hitChildData;\r
217                 },\r
218                 \r
219                 addAt : function( index, _uinodes ){\r
220                         //console.log( '# AddAt ' + this.phase )\r
221                         var uinodes = this.uinodes,\r
222                                 num     = uinodes.length,\r
223                                 p1      = 1 <= this.phase,\r
224                                 p2      = 2 <= this.phase,\r
225                                 p3      = 3 <= this.phase,\r
226                                 i       = 0,\r
227                                 _p1, _p2,\r
228                                 l, data;\r
229 \r
230                         //console.log( '### AddAt ' + this.phase )\r
231                         for( l = _uinodes.length; i < l; ++i ){\r
232                                 data = X_Pair_get( _uinodes[ i ] );\r
233                                 _p1  = p1 && data.phase < 1;\r
234                                 _p2  = p2 && data.phase < 2;\r
235                                 _p1 && data.initialize( this.root, this.rootData, this.User, this );\r
236                                 if( index <= num ){\r
237                                         // _p2 && this.xnode.insertBefore( data.xnode, uinodes[ index + i ].xnode );\r
238                                         _p2 && uinodes[ index + i ].xnode[ 'prev' ]( data.xnode );\r
239                                         _p2 && data.addToParent( this.xnode );\r
240                                         uinodes.splice( index + i, 0, data );\r
241                                 } else {\r
242                                         _p2 && data.addToParent( this.xnode );\r
243                                         uinodes[ uinodes.length ] = data;       \r
244                                 };\r
245                                 p3 && data.phase < 3 && data.creationComplete();\r
246                         };\r
247                         4 <= this.phase && this.rootData.reserveCalc();\r
248                 },\r
249                 \r
250                 remove : function( _uinodes ){\r
251                         //console.log( '# AddAt ' + this.phase )\r
252                         var uinodes = this.uinodes,\r
253                                 i       = _uinodes.length,\r
254                                 n, data;\r
255 \r
256                         //console.log( '### AddAt ' + this.phase )\r
257                         for( ; i; ){\r
258                                 data = X_Pair_get( _uinodes[ --i ] );\r
259                                 if( ( n = uinodes.indexOf( data ) ) !== -1 ){\r
260                                         uinodes.splice( n, 1 );\r
261                                         data._remove();\r
262                                 };\r
263                         };\r
264                         4 <= this.phase && this.rootData.reserveCalc();\r
265                 },\r
266                 \r
267                 removeAt : function( from, length ){\r
268                         var uinodes = this.uinodes,\r
269                                 i       = uinodes.length,\r
270                                 to      = from + ( X_Type_isNumber( length ) && 1 <= length ? length : 1 ),\r
271                                 node;\r
272                         for( ; i; ){\r
273                                 node = uinodes[ --i ];\r
274                                 if( from <= i && i < to ){\r
275                                         uinodes.splice( i, 1 );\r
276                                         node._remove();\r
277                                 };\r
278                         };\r
279                         4 <= this.phase && this.rootData.reserveCalc();\r
280                 },\r
281                 \r
282                 _remove : function(){\r
283                         var uinodes = this.uinodes,\r
284                                 i       = uinodes.length;\r
285                         for( ; i; ){ uinodes[ --i ]._remove(); };\r
286                                         \r
287                         switch( this.phase ){\r
288                                 case 4:\r
289                                 case 3:\r
290                                 case 2:\r
291                                         this.xnode[ 'remove' ]();\r
292                                 case 1:\r
293                                         delete this.root;\r
294                                         delete this.rootData;\r
295                                         delete this.parent;\r
296                                         delete this.parentData;\r
297                                         delete this.xnode;\r
298                         };\r
299                         delete this.phase;\r
300                 }\r
301         }\r
302 );\r
303 \r
304 X.UI.Box = X.UI.AbstractUINode.inherits(\r
305         'Box',\r
306         X_Class.NONE,\r
307         {\r
308                 Constructor : function(){\r
309                         X_Pair_create( this, XUI_Box( this, XUI_Layout_Canvas, arguments ) );\r
310                 },\r
311                 \r
312                 add : function( node /* , node, node ... */ ){\r
313                         X_Pair_get( this ).addAt( this.numNodes() + 1, Array.prototype.slice.call( arguments ) );\r
314                         return this;\r
315                 },\r
316                 addAt : function( index, node /* , node, node ... */ ){\r
317                         if( index < 0 ) index = 0;\r
318                         X_Pair_get( this ).addAt( arguments[ 0 ], Array.prototype.slice.call( arguments, 1 ) );\r
319                         return this;\r
320                 },\r
321                 remove : function( node /* , node, node ... */ ){\r
322                         X_Pair_get( this )[ 'remove' ]( Array.prototype.slice.call( arguments ) );\r
323                         return this;\r
324                 },\r
325                 removeAt : function( from, length ){\r
326                         X_Pair_get( this ).removeAt( from, length );\r
327                         return this;\r
328                 },\r
329                 getNodesByClass : function( klass ){\r
330                         var ret     = [],\r
331                                 uinodes = X_Pair_get( this ).uinodes,\r
332                                 i, l, node;\r
333                         if( !uinodes || uinodes.length === 0 ) return ret;\r
334                         for( i = 0, l = uinodes.length; i < l; ++i ){\r
335                                 node = uinodes[ i ].User;\r
336                                 if( node[ 'instanceOf' ]( klass ) ) ret[ ret.length ] = node;\r
337                         };\r
338                         return ret;\r
339                 },\r
340                 getFirstChild : function(){\r
341                         return this.getNodeAt( 0 );\r
342                 },\r
343                 getLastChild : function(){\r
344                         var uinodes = X_Pair_get( this ).uinodes;\r
345                         return uinodes && uinodes.length && uinodes[ uinodes.length - 1 ].User || null;\r
346                 },\r
347                 getNodeAt : function( index ){\r
348                         if( index < 0 ) return null;\r
349                         var uinodes = X_Pair_get( this ).uinodes;\r
350                         return uinodes && uinodes[ index ].User || null;\r
351                 },\r
352                 numNodes : function(){\r
353                         var uinodes = X_Pair_get( this ).uinodes;\r
354                         return uinodes && uinodes.length || 0;\r
355                 }\r
356         }\r
357 );\r
358 \r
359 /*\r
360  * layout が設定されている Box のサブクラスに対して、layout を指定できない.\r
361  * \r
362  */\r
363 X.UI.Box.presets = function(){\r
364         var args   = arguments,\r
365                 i      = 0,\r
366                 l      = args.length,   \r
367                 shadow = X_Class_getClassDef( this ).privateClass,\r
368                 layout = shadow.prototype.layout,\r
369                 arg, attrs, supports, klass, klassDef, privateKlass, boxName;\r
370                         \r
371         for( ; i < l; ++i ){\r
372                 arg = args[ i ];\r
373                 if( !arg ) continue;\r
374                 // レイアウトの preset ができるのは layout が未定義な Box だけ\r
375                 if( !shadow.prototype.layout && arg[ 'instanceOf' ] && arg[ 'instanceOf' ]( XUI_LayoutBase ) ){\r
376                         layout = arg;\r
377                 } else\r
378                 if( ( klassDef = X_Class_getClassDef( arg ) ) && klassDef.isPrivate ){\r
379                         privateKlass = arg;\r
380                         layout = privateKlass.prototype.layout;\r
381                 } else\r
382                 if( X_Type_isObject( arg ) ){\r
383                         if( attrs ){\r
384                                 X_Class_override( attrs, arg, true );\r
385                         } else {\r
386                                 attrs = arg;\r
387                         };\r
388                 } else\r
389                 if( X_Type_isString( arg ) ){\r
390                         boxName = arg;\r
391                 };\r
392         };\r
393         \r
394         if( privateKlass ){\r
395                 /*\r
396                  * スーパークラスの属性定義リストをレイアウトの持つ属性定義で上書きした新しい属性定義リストを作る。\r
397                  */\r
398                 supports = XUI_Attr_createAttrDef( privateKlass.prototype.supportAttrs, layout.overrideAttrsForSelf );\r
399                 \r
400                 klass = this.inherits( privateKlass );\r
401                 privateKlass.prototype.supportAttrs = supports;\r
402                 privateKlass.prototype.attrClass    = XUI_Attr_preset( privateKlass.prototype.attrClass, supports, attrs );\r
403         } else {\r
404                 supports = XUI_Attr_createAttrDef( shadow.prototype.supportAttrs, layout.overrideAttrsForSelf );\r
405                 \r
406                 klass = this.inherits(\r
407                         boxName,\r
408                         shadow.inherits(\r
409                                 {\r
410                                         layout       : layout,\r
411                                         supportAttrs : supports,\r
412                                         attrClass    : XUI_Attr_preset( shadow.prototype.attrClass, supports, attrs )\r
413                                 }\r
414                         )\r
415                 );              \r
416         };\r
417 \r
418         klass.presets = this.presets || X.UI.Box.presets;\r
419         \r
420         return klass;\r
421 };\r