OSDN Git Service

e709360de1d8c4d681d1903bdc234fcec463574f
[pettanr/clientJs.git] / 0.6.x / js / 20_ui / 16_Repeater.js
1 var X_UI_Repeater_SUPPORT_ATTRS = {\r
2                 dataSource   : [ null, XUI_Dirty.LAYOUT, XUI_Attr_USER.UINODE, XUI_Attr_Type.OBJECT ],\r
3                 itemRenderer : [ null, XUI_Dirty.LAYOUT, XUI_Attr_USER.UINODE, XUI_Attr_Type.OBJECT ]\r
4 };\r
5 \r
6 var XUI_Repeater = XUI_Box.inherits(\r
7         '_Repeater',\r
8         X_Class.NONE,\r
9         {\r
10                 layout       : XUI_Layout_Vertical,\r
11                 \r
12                 dataSource   : null, // Array.<object>, Array.<ItemData>\r
13                 \r
14                 itemRenderer     : null,\r
15                 \r
16                 itemNodes        : null,\r
17                 \r
18                 startIndex       : 0,\r
19                 startRenderIndex : 0,\r
20                 numItemsParPage  : 0,\r
21                 numItemsPrev     : 0,\r
22                 numItems         : 0,\r
23                 itemHeightLast   : 0,\r
24                 itemHeightLastEM : 0,\r
25                 \r
26                 Constructor : function( user, dataSource, itemRenderer, attr ){\r
27                         this.Super( user, null, [ attr ] );\r
28                         this.dataSource   = dataSource;\r
29                         this.itemRenderer = itemRenderer;\r
30                         this.itemNodes    = [];\r
31                         this.__item__     = X_Pair_get( itemRenderer );\r
32                 },\r
33                 \r
34                 initialize : function(){\r
35                         XUI_AbstractUINode.prototype.initialize.apply( this, arguments );\r
36                         \r
37                         this.parent[ 'listen' ]( XUI_Event.SCROLL_END, this );\r
38                 },\r
39                 \r
40                 /*\r
41                  * ここに来るのは、初描画とリサイズ\r
42                  */\r
43                 calculate : function( isNeedsDetection, x, y, allowedW, allowedH ){\r
44                         var dataSource = this[ 'dataSource' ];\r
45 \r
46                         if( allowedW + allowedH === XUI_Attr_AUTO ) return false;\r
47                 \r
48                         this.scrollPortWidth  = allowedW;\r
49                         this.scrollPortHeight = allowedH;                       \r
50                         \r
51                         this.preMesure( allowedW, allowedH );\r
52                         \r
53                         if( dataSource && dataSource.length ){\r
54                                 this.updateItemRenderer( this.contentWidth, allowedH );\r
55                         } else\r
56                         if( this.contentHeight === XUI_Attr_AUTO ){\r
57                                 this.contentHeight = this.contentHeightMin !== XUI_Attr_AUTO ? this.contentHeightMin : 0;\r
58                         };\r
59                         \r
60                         this.postMesure();\r
61         \r
62                         if( !isNeedsDetection ){\r
63                                 this.boxX += x;\r
64                                 this.boxY += y;\r
65                         };\r
66                         return true;\r
67                 },\r
68                 \r
69                 handleEvent : function( e ){\r
70                         var scrollBox, scrollY, dataSource, offsetY, startIndex, maxIndex, offset, itemNodes, ary, i, l;\r
71                         \r
72                         switch( e.type ){\r
73                                 case XUI_Event.SCROLL_END :\r
74                                         scrollBox  = this.parentData;\r
75                                         scrollY    = - scrollBox.scrollY;\r
76                                         dataSource = this[ 'dataSource' ];\r
77                                         itemNodes  = this.itemNodes;\r
78                                         itemH      = this.itemHeightLast;\r
79                                         \r
80                                         // transition Y を 0 付近に。\r
81                                 \r
82                                         \r
83                                         // startIndex の計算\r
84                                         startIndex = scrollY / itemH | 0;\r
85                                         \r
86                                         /*maxIndex   = dataSource.length <= this.numItems ? 0 : dataSource.length - this.numItems;\r
87                                         console.log( ' >>> ' + startIndex + ' ' + maxIndex );\r
88                                         \r
89                                         startIndex =\r
90                                                 startIndex < 0 ? 0 :\r
91                                                 maxIndex < startIndex ? maxIndex : startIndex; */\r
92                                         // アイテムの座標の修正とレンジ外のアイテムを配列内で再配置\r
93                                         offset = startIndex - this.startIndex; // visible な stratIndex renderStartIndex\r
94                                         this.startIndex = startIndex;\r
95                                         \r
96                                         console.log(  this.numItemsPrev + ' oo ' + offset )\r
97                                         \r
98                                         if( 0 < offset ){\r
99                                                 itemNodes.push.apply( itemNodes, itemNodes.splice( 0, offset ) );\r
100                                         } else\r
101                                         if( offset < - 0 ){\r
102                                                 itemNodes.unshift.apply( itemNodes, itemNodes.splice( itemNodes.length + offset ) );\r
103                                         };\r
104 \r
105                                         // 再配置されたアイテムにitemData のセット\r
106                                         this.updateItemRenderer( this.contentWidth, this.scrollPortHeight );\r
107                                         \r
108                                         \r
109                                         \r
110                                         offsetY  = scrollY % itemH;\r
111                                         offsetY  = offsetY === 0 ? 0 : ( offsetY - itemH );\r
112                                         offsetY += ( this.startRenderIndex - this.startIndex ) * itemH;\r
113                                         //console.log( ' ====> ' + this.startRenderIndex + ' -> ' + this.startIndex + ' scrollY:' + offsetY );\r
114 \r
115                                         //scrollBox.scrollTo( 0, - scrollY, 0, '', 0 ); // anime無し                                                  \r
116                                         //console.log( '  <==== ' );\r
117                                         break;\r
118                         };\r
119                 },\r
120                 \r
121                 updateItemRenderer : function( _w, _h ){\r
122                         var itemNodes  = this.itemNodes,\r
123                                 attrs      = this.attrObject || this.attrClass.prototype,\r
124                                 gapY       = XUI_AbstractUINode_calcValue( attrs[ this.usableAttrs.gapY.No ], _w ),\r
125                                 dataSource = this[ 'dataSource' ],\r
126                                 render     = this[ 'itemRenderer' ],\r
127                                 l          = dataSource.length,\r
128                                 start      = this.startIndex - this.numItemsPrev,\r
129                                 itemH      = this.itemHeightLastEM,\r
130                                 i, data, node, _y = 0, last, n;\r
131                         \r
132                         i = this.startRenderIndex = start = start < 0 ? 0 : start;\r
133                         \r
134                         _y = ( itemH + gapY ) * i;\r
135                         \r
136                         for( ; i < l; ++i ){\r
137                                 if( !( data = itemNodes[ i ] ) ){\r
138                                         node = render.clone( true );\r
139                                         this.addAt( i, [ node ] );\r
140                                         data = itemNodes[ i ] = X_Pair_get( node );\r
141                                         // init -> addToParent -> creationComplete\r
142                                 };\r
143                                 data.setItemData( dataSource[ i ] );\r
144                                 \r
145                                 data.calculate( false, 0, _y, _w, _h );\r
146                                 _y += ( itemH || data.boxHeight ) + gapY;\r
147                                 \r
148                                 // 一番最初のループ。ここでページあたりのアイテム数を計算\r
149                                 if( !itemH && i === start ){\r
150                                         itemH = _y - gapY;\r
151                                         this.itemHeightLastEM = itemH;\r
152                                         this.itemHeightLast   = itemH * X_ViewPort_baseFontSize,\r
153                                         // scroller の miniHeight は(例えば)親の高さの300% そこにいくつのアイテムを並べることが出来るか?端数切り上げ\r
154                                         this.numItemsParPage = _h / itemH + 0.999 | 0;\r
155                                         n    = this.numItems = ( _h * 3 ) / itemH + 0.999 | 0; // TODO boxHeight\r
156                                         this.numItemsPrev    = ( this.numItems - this.numItemsParPage ) / 2 | 0;\r
157                                         last = i + n;\r
158                                         // データの最後まで、または、開始位置から 3ページ分を生成する\r
159                                         l    = last < l ? last : l;\r
160                                 };\r
161                         };\r
162                         \r
163                         for( l = itemNodes.length; i < l; ++i ){\r
164                                 // itemNodes[ i ] hide\r
165                         };\r
166                         \r
167                         // TODO contentHeight は attr を無視する -> 未表示領域につくるアイテム数 GPU の有無で変わる\r
168                         this.contentHeight = dataSource.length * ( itemH + gapY ) - gapY;\r
169                 },\r
170                 \r
171                 onPropertyChange : function( name, newValue ){\r
172                         var itemNodes, i, l, uinode, dataList, from;\r
173                         \r
174                         switch( name ){\r
175                                 case 'itemRenderer' :\r
176                                         for( itemNodes = this.itemNodes, i = itemNodes && itemNodes.length; i; ){\r
177                                                 itemNodes[ --i ][ 'kill' ]();\r
178                                         };\r
179                                         \r
180                                 case 'dataSource' :\r
181                                         if( itemNodes = this.itemNodes ){\r
182                                                 i = itemNodes.length;\r
183                                                 l = this[ 'dataSource' ].length;\r
184                                                 while( l < i ){\r
185                                                         itemNodes[ --i ][ 'kill' ]();\r
186                                                         itemNodes.length = i;\r
187                                                 };                                              \r
188                                         };\r
189 \r
190                                         \r
191                                         break;\r
192                         };\r
193                 }\r
194         }\r
195 );\r
196 \r
197 X.UI.Repeater = X.UI.Box.inherits(\r
198         'Repeater',\r
199         X_Class.NONE,\r
200         {\r
201                 Constructor : function( dataSource, itemRenderer ){\r
202                         var supports;\r
203                         \r
204                         if( XUI_Repeater.prototype.usableAttrs === XUI_Box.prototype.usableAttrs ){\r
205                                 supports = XUI_Attr_createAttrDef( XUI_Attr_Support, X_UI_Repeater_SUPPORT_ATTRS );\r
206                                 XUI_Repeater.prototype.usableAttrs = supports = XUI_Attr_createAttrDef( supports, XUI_Layout_Vertical.overrideAttrsForSelf );\r
207                 \r
208                                 XUI_Repeater.prototype.attrClass   = XUI_Attr_preset( XUI_Box.prototype.attrClass, supports );\r
209                         };\r
210                         \r
211                         // dataProvider\r
212                         // itemBase parent に追加されている uinode は不可\r
213                         // minHeight=300% height=auto\r
214                         X_Pair_create( this,\r
215                                 XUI_Repeater(\r
216                                         this,\r
217                                         dataSource, itemRenderer,\r
218                                         {\r
219                                                 name      : 'ScrollBox-Scroller',\r
220                                                 role      : 'container',\r
221                                                 width     : 'auto',\r
222                                                 minWidth  : '100%',\r
223                                                 height    : 'auto',\r
224                                                 minHeight : '100%',\r
225                                 borderColor : 0x252527,\r
226                                 borderWidth : [ 0.15, 0, 0 ],\r
227                                 borderStyle : 'solid',\r
228                                 height      : 'auto',\r
229                                 bgColor     : 0x444643,\r
230                                 gapY        : 0.15\r
231                                         }));\r
232                 },\r
233                 \r
234                 getItemDataAt : function(){\r
235                         \r
236                 },\r
237                 \r
238                 add : function( /* node, node, node ... */ ){\r
239                 },\r
240                 addAt : function( index /* , node , node, node ... */ ){\r
241                 },\r
242                 remove : function( /* node, node, node ... */ ){\r
243                 },\r
244                 removeAt : function( from, length ){\r
245                 },\r
246                 getNodesByClass : function( klass ){\r
247                 },\r
248                 getFirstChild : function(){\r
249                 },\r
250                 getLastChild : function(){\r
251                 },\r
252                 getNodeAt : function( index ){\r
253                 },\r
254                 numNodes : function(){\r
255                         var uinodes = X_Pair_get( this ).uinodes;\r
256                         return uinodes && uinodes.length || 0;\r
257                 }\r
258 \r
259         }\r
260 );\r