1 /****************************************************************************
  2  Copyright (c) 2008-2010 Ricardo Quesada
  3  Copyright (c) 2011-2012 cocos2d-x.org
  4  Copyright (c) 2013-2014 Chukong Technologies Inc.
  5  Copyright (c) 2010 Sangwoo Im
  6 
  7  http://www.cocos2d-x.org
  8 
  9  Permission is hereby granted, free of charge, to any person obtaining a copy
 10  of this software and associated documentation files (the "Software"), to deal
 11  in the Software without restriction, including without limitation the rights
 12  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 13  copies of the Software, and to permit persons to whom the Software is
 14  furnished to do so, subject to the following conditions:
 15 
 16  The above copyright notice and this permission notice shall be included in
 17  all copies or substantial portions of the Software.
 18 
 19  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 20  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 21  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 22  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 23  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 24  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 25  THE SOFTWARE.
 26  ****************************************************************************/
 27 
 28 /**
 29  * The constant value of the fill style from top to bottom for cc.TableView
 30  * @constant
 31  * @type {number}
 32  */
 33 cc.TABLEVIEW_FILL_TOPDOWN = 0;
 34 
 35 /**
 36  * The constant value of the fill style from bottom to top for cc.TableView
 37  * @constant
 38  * @type {number}
 39  */
 40 cc.TABLEVIEW_FILL_BOTTOMUP = 1;
 41 
 42 /**
 43  * Abstract class for SWTableView cell node
 44  * @class
 45  * @abstract
 46  * @extends cc.Node
 47  *
 48  * @property {Number}   objectId    - The index used internally by SWTableView and its subclasses
 49  */
 50 cc.TableViewCell = cc.Node.extend(/** @lends cc.TableViewCell# */{
 51     _idx:0,
 52     _className:"TableViewCell",
 53 
 54     /**
 55      * The index used internally by SWTableView and its subclasses
 56      */
 57     getIdx:function () {
 58         return this._idx;
 59     },
 60     setIdx:function (idx) {
 61         this._idx = idx;
 62     },
 63 
 64     /**
 65      * Cleans up any resources linked to this cell and resets <code>idx</code> property.
 66      */
 67     reset:function () {
 68         this._idx = cc.INVALID_INDEX;
 69     },
 70 
 71     setObjectID:function (idx) {
 72         this._idx = idx;
 73     },
 74     getObjectID:function () {
 75         return this._idx;
 76     }
 77 });
 78 
 79 var _p = cc.TableViewCell.prototype;
 80 
 81 /** @expose */
 82 _p.objectId;
 83 cc.defineGetterSetter(_p, "objectId", _p.getObjectID, _p.setObjectID);
 84 
 85 _p = null;
 86 
 87 /**
 88  * Sole purpose of this delegate is to single touch event in this version.
 89  */
 90 cc.TableViewDelegate = cc.ScrollViewDelegate.extend(/** @lends cc.TableViewDelegate# */{
 91     /**
 92      * Delegate to respond touch event
 93      *
 94      * @param {cc.TableView} table table contains the given cell
 95      * @param {cc.TableViewCell} cell  cell that is touched
 96      */
 97     tableCellTouched:function (table, cell) {
 98     },
 99 
100     /**
101      * Delegate to respond a table cell press event.
102      *
103      * @param {cc.TableView} table table contains the given cell
104      * @param {cc.TableViewCell} cell  cell that is pressed
105      */
106     tableCellHighlight:function(table, cell){
107     },
108 
109     /**
110      * Delegate to respond a table cell release event
111      *
112      * @param {cc.TableView} table table contains the given cell
113      * @param {cc.TableViewCell} cell  cell that is pressed
114      */
115     tableCellUnhighlight:function(table, cell){
116 
117     },
118 
119     /**
120      * <p>
121      * Delegate called when the cell is about to be recycled. Immediately                     <br/>
122      * after this call the cell will be removed from the scene graph and                      <br/>
123      * recycled.
124      * </p>
125      * @param table table contains the given cell
126      * @param cell  cell that is pressed
127      */
128     tableCellWillRecycle:function(table, cell){
129 
130     }
131 });
132 
133 /**
134  * Data source that governs table backend data.
135  */
136 cc.TableViewDataSource = cc.Class.extend(/** @lends cc.TableViewDataSource# */{
137     /**
138      * cell size for a given index
139      * @param {cc.TableView} table table to hold the instances of Class
140      * @param {Number} idx the index of a cell to get a size
141      * @return {cc.Size} size of a cell at given index
142      */
143     tableCellSizeForIndex:function(table, idx){
144         return this.cellSizeForTable(table);
145     },
146     /**
147      * cell height for a given table.
148      *
149      * @param {cc.TableView} table table to hold the instances of Class
150      * @return {cc.Size} cell size
151      */
152     cellSizeForTable:function (table) {
153         return cc.size(0,0);
154     },
155 
156     /**
157      * a cell instance at a given index
158      * @param {cc.TableView} table table to hold the instances of Class
159      * @param idx index to search for a cell
160      * @return {cc.TableView} cell found at idx
161      */
162     tableCellAtIndex:function (table, idx) {
163         return null;
164     },
165 
166     /**
167      * Returns number of cells in a given table view.
168      * @param {cc.TableView} table table to hold the instances of Class
169      * @return {Number} number of cells
170      */
171     numberOfCellsInTableView:function (table) {
172         return 0;
173     }
174 });
175 
176 /**
177  * UITableView counterpart for cocos2d for iphone.
178  * this is a very basic, minimal implementation to bring UITableView-like component into cocos2d world.
179  *
180  * @class
181  * @extends cc.ScrollView
182  *
183  * @property {cc.TableViewDataSource}   dataSource          - The data source of the table view
184  * @property {cc.TableViewDelegate}     delegate            - The event delegate of the table view
185  * @property {Number}                   verticalFillOrder   - The index to determine how cell is ordered and filled in the view
186  *
187  */
188 cc.TableView = cc.ScrollView.extend(/** @lends cc.TableView# */{
189     _vOrdering:null,
190     _indices:null,
191     _cellsFreed:null,
192     _dataSource:null,
193     _tableViewDelegate:null,
194     _oldDirection:null,
195     _cellsPositions:null,                       //vector with all cell positions
196     _touchedCell:null,
197 
198     /**
199      * The
200      * @param dataSource
201      * @param size
202      * @param container
203      */
204     ctor:function (dataSource, size, container) {
205         cc.ScrollView.prototype.ctor.call(this);
206         this._oldDirection = cc.SCROLLVIEW_DIRECTION_NONE;
207         this._cellsPositions = [];
208 
209         this.initWithViewSize(size, container);
210         this.setDataSource(dataSource);
211         this._updateCellPositions();
212         this._updateContentSize();
213     },
214 
215     __indexFromOffset:function (offset) {
216         var low = 0;
217         var high = this._dataSource.numberOfCellsInTableView(this) - 1;
218         var search;
219         switch (this.getDirection()) {
220             case cc.SCROLLVIEW_DIRECTION_HORIZONTAL:
221                 search = offset.x;
222                 break;
223             default:
224                 search = offset.y;
225                 break;
226         }
227 
228         var locCellsPositions = this._cellsPositions;
229         while (high >= low){
230             var index = 0|(low + (high - low) / 2);
231             var cellStart = locCellsPositions[index];
232             var cellEnd = locCellsPositions[index + 1];
233 
234             if (search >= cellStart && search <= cellEnd){
235                 return index;
236             } else if (search < cellStart){
237                 high = index - 1;
238             }else {
239                 low = index + 1;
240             }
241         }
242 
243         if (low <= 0)
244             return 0;
245         return -1;
246     },
247 
248     _indexFromOffset:function (offset) {
249         var locOffset = {x: offset.x, y: offset.y};
250         var locDataSource = this._dataSource;
251         var maxIdx = locDataSource.numberOfCellsInTableView(this) - 1;
252 
253         if (this._vOrdering === cc.TABLEVIEW_FILL_TOPDOWN)
254             locOffset.y = this.getContainer().getContentSize().height - locOffset.y;
255 
256         var index = this.__indexFromOffset(locOffset);
257         if (index !== -1) {
258             index = Math.max(0, index);
259             if (index > maxIdx)
260                 index = cc.INVALID_INDEX;
261         }
262         return index;
263     },
264 
265     __offsetFromIndex:function (index) {
266         var offset;
267         switch (this.getDirection()) {
268             case cc.SCROLLVIEW_DIRECTION_HORIZONTAL:
269                 offset = cc.p(this._cellsPositions[index], 0);
270                 break;
271             default:
272                 offset = cc.p(0, this._cellsPositions[index]);
273                 break;
274         }
275 
276         return offset;
277     },
278 
279     _offsetFromIndex:function (index) {
280         var offset = this.__offsetFromIndex(index);
281 
282         var cellSize = this._dataSource.tableCellSizeForIndex(this, index);
283         if (this._vOrdering === cc.TABLEVIEW_FILL_TOPDOWN)
284             offset.y = this.getContainer().getContentSize().height - offset.y - cellSize.height;
285 
286         return offset;
287     },
288 
289     _updateCellPositions:function(){
290         var cellsCount = this._dataSource.numberOfCellsInTableView(this);
291         var locCellsPositions = this._cellsPositions;
292 
293         if (cellsCount > 0){
294             var currentPos = 0;
295             var cellSize, locDataSource = this._dataSource;
296             for (var i=0; i < cellsCount; i++) {
297                 locCellsPositions[i] = currentPos;
298                 cellSize = locDataSource.tableCellSizeForIndex(this, i);
299                 switch (this.getDirection()) {
300                     case cc.SCROLLVIEW_DIRECTION_HORIZONTAL:
301                         currentPos += cellSize.width;
302                         break;
303                     default:
304                         currentPos += cellSize.height;
305                         break;
306                 }
307             }
308             this._cellsPositions[cellsCount] = currentPos;//1 extra value allows us to get right/bottom of the last cell
309         }
310     },
311 
312     _updateContentSize:function () {
313         var size = cc.size(0, 0);
314 
315         var cellsCount = this._dataSource.numberOfCellsInTableView(this);
316 
317         if(cellsCount > 0){
318             var maxPosition = this._cellsPositions[cellsCount];
319             switch (this.getDirection()) {
320                 case cc.SCROLLVIEW_DIRECTION_HORIZONTAL:
321                     size = cc.size(maxPosition, this._viewSize.height);
322                     break;
323                 default:
324                     size = cc.size(this._viewSize.width, maxPosition);
325                     break;
326             }
327         }
328 
329         this.setContentSize(size);
330 
331         if (this._oldDirection !== this._direction) {
332             if (this._direction === cc.SCROLLVIEW_DIRECTION_HORIZONTAL) {
333                 this.setContentOffset(cc.p(0, 0));
334             } else {
335                 this.setContentOffset(cc.p(0, this.minContainerOffset().y));
336             }
337             this._oldDirection = this._direction;
338         }
339     },
340 
341     _moveCellOutOfSight:function (cell) {
342         if(this._tableViewDelegate && this._tableViewDelegate.tableCellWillRecycle)
343             this._tableViewDelegate.tableCellWillRecycle(this, cell);
344 
345         this._cellsFreed.addObject(cell);
346         this._cellsUsed.removeSortedObject(cell);
347         cc.arrayRemoveObject(this._indices, cell.getIdx());
348 
349         cell.reset();
350         if (cell.getParent() === this.getContainer()) {
351             this.getContainer().removeChild(cell, true);
352         }
353     },
354 
355     _setIndexForCell:function (index, cell) {
356         cell.setAnchorPoint(0, 0);
357         cell.setPosition(this._offsetFromIndex(index));
358         cell.setIdx(index);
359     },
360 
361     _addCellIfNecessary:function (cell) {
362         if (cell.getParent() !== this.getContainer()) {
363             this.getContainer().addChild(cell);
364         }
365         this._cellsUsed.insertSortedObject(cell);
366         var locIndices = this._indices, addIdx = cell.getIdx();
367         if(locIndices.indexOf(addIdx) === -1){
368             locIndices.push(addIdx);
369             //sort
370             locIndices.sort(function(a,b){return a-b;});
371         }
372     },
373 
374     /**
375      * data source
376      */
377     getDataSource:function () {
378         return this._dataSource;
379     },
380     setDataSource:function (source) {
381         this._dataSource = source;
382     },
383 
384     /**
385      * delegate
386      */
387     getDelegate:function () {
388         return this._tableViewDelegate;
389     },
390 
391     setDelegate:function (delegate) {
392         this._tableViewDelegate = delegate;
393     },
394 
395     /**
396      * determines how cell is ordered and filled in the view.
397      */
398     setVerticalFillOrder:function (fillOrder) {
399         if (this._vOrdering !== fillOrder) {
400             this._vOrdering = fillOrder;
401             if (this._cellsUsed.count() > 0) {
402                 this.reloadData();
403             }
404         }
405     },
406     getVerticalFillOrder:function () {
407         return this._vOrdering;
408     },
409 
410     initWithViewSize:function (size, container) {
411         if (cc.ScrollView.prototype.initWithViewSize.call(this, size, container)) {
412             this._cellsUsed = new cc.ArrayForObjectSorting();
413             this._cellsFreed = new cc.ArrayForObjectSorting();
414             this._indices = [];
415             this._tableViewDelegate = null;
416             this._vOrdering = cc.TABLEVIEW_FILL_BOTTOMUP;
417             this.setDirection(cc.SCROLLVIEW_DIRECTION_VERTICAL);
418 
419             cc.ScrollView.prototype.setDelegate.call(this, this);
420             return true;
421         }
422         return false;
423     },
424 
425     /**
426      * Updates the content of the cell at a given index.
427      *
428      * @param idx index to find a cell
429      */
430     updateCellAtIndex:function (idx) {
431         if (idx === cc.INVALID_INDEX || idx > this._dataSource.numberOfCellsInTableView(this) - 1)
432             return;
433 
434         var cell = this.cellAtIndex(idx);
435         if (cell)
436             this._moveCellOutOfSight(cell);
437 
438         cell = this._dataSource.tableCellAtIndex(this, idx);
439         this._setIndexForCell(idx, cell);
440         this._addCellIfNecessary(cell);
441     },
442 
443     /**
444      * Inserts a new cell at a given index
445      *
446      * @param idx location to insert
447      */
448     insertCellAtIndex:function (idx) {
449         if (idx === cc.INVALID_INDEX || idx > this._dataSource.numberOfCellsInTableView(this) - 1)
450             return;
451 
452         var newIdx, locCellsUsed = this._cellsUsed;
453         var cell = locCellsUsed.objectWithObjectID(idx);
454         if (cell) {
455             newIdx = locCellsUsed.indexOfSortedObject(cell);
456             for (var i = newIdx; i < locCellsUsed.count(); i++) {
457                 cell = locCellsUsed.objectAtIndex(i);
458                 this._setIndexForCell(cell.getIdx() + 1, cell);
459             }
460         }
461 
462         //insert a new cell
463         cell = this._dataSource.tableCellAtIndex(this, idx);
464         this._setIndexForCell(idx, cell);
465         this._addCellIfNecessary(cell);
466 
467         this._updateCellPositions();
468         this._updateContentSize();
469     },
470 
471     /**
472      * Removes a cell at a given index
473      *
474      * @param idx index to find a cell
475      */
476     removeCellAtIndex:function (idx) {
477         if (idx === cc.INVALID_INDEX || idx > this._dataSource.numberOfCellsInTableView(this) - 1)
478             return;
479 
480         var cell = this.cellAtIndex(idx);
481         if (!cell)
482             return;
483 
484         var locCellsUsed = this._cellsUsed;
485         var newIdx = locCellsUsed.indexOfSortedObject(cell);
486 
487         //remove first
488         this._moveCellOutOfSight(cell);
489         cc.arrayRemoveObject(this._indices, idx);
490         this._updateCellPositions();
491 
492         for (var i = locCellsUsed.count() - 1; i > newIdx; i--) {
493             cell = locCellsUsed.objectAtIndex(i);
494             this._setIndexForCell(cell.getIdx() - 1, cell);
495         }
496     },
497 
498     /**
499      * reloads data from data source.  the view will be refreshed.
500      */
501     reloadData:function () {
502         this._oldDirection = cc.SCROLLVIEW_DIRECTION_NONE;
503         var locCellsUsed = this._cellsUsed, locCellsFreed = this._cellsFreed, locContainer = this.getContainer();
504         for (var i = 0, len = locCellsUsed.count(); i < len; i++) {
505             var cell = locCellsUsed.objectAtIndex(i);
506 
507             if(this._tableViewDelegate && this._tableViewDelegate.tableCellWillRecycle)
508                 this._tableViewDelegate.tableCellWillRecycle(this, cell);
509 
510             locCellsFreed.addObject(cell);
511             cell.reset();
512             if (cell.getParent() === locContainer)
513                 locContainer.removeChild(cell, true);
514         }
515 
516         this._indices = [];
517         this._cellsUsed = new cc.ArrayForObjectSorting();
518 
519         this._updateCellPositions();
520         this._updateContentSize();
521         if (this._dataSource.numberOfCellsInTableView(this) > 0)
522             this.scrollViewDidScroll(this);
523     },
524 
525     /**
526      * Dequeues a free cell if available. nil if not.
527      *
528      * @return {TableViewCell} free cell
529      */
530     dequeueCell:function () {
531         if (this._cellsFreed.count() === 0) {
532             return null;
533         } else {
534             var cell = this._cellsFreed.objectAtIndex(0);
535             this._cellsFreed.removeObjectAtIndex(0);
536             return cell;
537         }
538     },
539 
540     /**
541      * Returns an existing cell at a given index. Returns nil if a cell is nonexistent at the moment of query.
542      *
543      * @param idx index
544      * @return {cc.TableViewCell} a cell at a given index
545      */
546     cellAtIndex:function (idx) {
547         var i = this._indices.indexOf(idx);
548         if (i === -1)
549             return null;
550         return this._cellsUsed.objectWithObjectID(idx);
551     },
552 
553     scrollViewDidScroll:function (view) {
554         var locDataSource = this._dataSource;
555         var countOfItems = locDataSource.numberOfCellsInTableView(this);
556         if (0 === countOfItems)
557             return;
558 
559         if (this._tableViewDelegate !== null && this._tableViewDelegate.scrollViewDidScroll)
560             this._tableViewDelegate.scrollViewDidScroll(this);
561 
562         var  idx = 0, locViewSize = this._viewSize, locContainer = this.getContainer();
563         var offset = this.getContentOffset();
564         offset.x *= -1;
565         offset.y *= -1;
566 
567         var maxIdx = Math.max(countOfItems-1, 0);
568 
569         if (this._vOrdering === cc.TABLEVIEW_FILL_TOPDOWN)
570             offset.y = offset.y + locViewSize.height/locContainer.getScaleY();
571         var startIdx = this._indexFromOffset(offset);
572         if (startIdx === cc.INVALID_INDEX)
573             startIdx = countOfItems - 1;
574 
575         if (this._vOrdering === cc.TABLEVIEW_FILL_TOPDOWN)
576             offset.y -= locViewSize.height/locContainer.getScaleY();
577         else
578             offset.y += locViewSize.height/locContainer.getScaleY();
579         offset.x += locViewSize.width/locContainer.getScaleX();
580 
581         var endIdx = this._indexFromOffset(offset);
582         if (endIdx === cc.INVALID_INDEX)
583             endIdx = countOfItems - 1;
584 
585         var cell, locCellsUsed = this._cellsUsed;
586         if (locCellsUsed.count() > 0) {
587             cell = locCellsUsed.objectAtIndex(0);
588             idx = cell.getIdx();
589             while (idx < startIdx) {
590                 this._moveCellOutOfSight(cell);
591                 if (locCellsUsed.count() > 0) {
592                     cell = locCellsUsed.objectAtIndex(0);
593                     idx = cell.getIdx();
594                 } else
595                     break;
596             }
597         }
598 
599         if (locCellsUsed.count() > 0) {
600             cell = locCellsUsed.lastObject();
601             idx = cell.getIdx();
602             while (idx <= maxIdx && idx > endIdx) {
603                 this._moveCellOutOfSight(cell);
604                 if (locCellsUsed.count() > 0) {
605                     cell = locCellsUsed.lastObject();
606                     idx = cell.getIdx();
607                 } else
608                     break;
609             }
610         }
611 
612         var locIndices = this._indices;
613         for (var i = startIdx; i <= endIdx; i++) {
614             if (locIndices.indexOf(i) !== -1)
615                 continue;
616             this.updateCellAtIndex(i);
617         }
618     },
619 
620     scrollViewDidZoom:function (view) {
621     },
622 
623     onTouchEnded:function (touch, event) {
624         if (!this.isVisible())
625             return;
626 
627         if (this._touchedCell){
628             var bb = this.getBoundingBox();
629             var tmpOrigin = cc.p(bb.x, bb.y);
630             tmpOrigin = this._parent.convertToWorldSpace(tmpOrigin);
631             bb.x = tmpOrigin.x;
632             bb.y = tmpOrigin.y;
633             var locTableViewDelegate = this._tableViewDelegate;
634             if (cc.rectContainsPoint(bb, touch.getLocation()) && locTableViewDelegate !== null){
635                 if(locTableViewDelegate.tableCellUnhighlight)
636                     locTableViewDelegate.tableCellUnhighlight(this, this._touchedCell);
637                 if(locTableViewDelegate.tableCellTouched)
638                     locTableViewDelegate.tableCellTouched(this, this._touchedCell);
639             }
640             this._touchedCell = null;
641         }
642         cc.ScrollView.prototype.onTouchEnded.call(this, touch, event);
643     },
644 
645     onTouchBegan:function(touch, event){
646         if (!this.isVisible())
647             return false;
648 
649         var touchResult = cc.ScrollView.prototype.onTouchBegan.call(this, touch, event);
650 
651         if(this._touches.length === 1) {
652             var index, point;
653 
654             point = this.getContainer().convertTouchToNodeSpace(touch);
655 
656             index = this._indexFromOffset(point);
657             if (index === cc.INVALID_INDEX)
658                 this._touchedCell = null;
659             else
660                 this._touchedCell  = this.cellAtIndex(index);
661 
662             if (this._touchedCell && this._tableViewDelegate !== null && this._tableViewDelegate.tableCellHighlight)
663                 this._tableViewDelegate.tableCellHighlight(this, this._touchedCell);
664         } else if(this._touchedCell) {
665             if(this._tableViewDelegate !== null && this._tableViewDelegate.tableCellUnhighlight)
666                 this._tableViewDelegate.tableCellUnhighlight(this, this._touchedCell);
667             this._touchedCell = null;
668         }
669 
670         return touchResult;
671     },
672 
673     onTouchMoved: function(touch, event){
674         cc.ScrollView.prototype.onTouchMoved.call(this, touch, event);
675 
676         if (this._touchedCell && this.isTouchMoved()) {
677             if(this._tableViewDelegate !== null && this._tableViewDelegate.tableCellUnhighlight)
678                 this._tableViewDelegate.tableCellUnhighlight(this, this._touchedCell);
679             this._touchedCell = null;
680         }
681     },
682 
683     onTouchCancelled: function(touch, event){
684         cc.ScrollView.prototype.onTouchCancelled.call(this, touch, event);
685 
686         if (this._touchedCell) {
687             if(this._tableViewDelegate !== null && this._tableViewDelegate.tableCellUnhighlight)
688                 this._tableViewDelegate.tableCellUnhighlight(this, this._touchedCell);
689             this._touchedCell = null;
690         }
691     }
692 });
693 
694 var _p = cc.TableView.prototype;
695 
696 /** @expose */
697 _p.dataSource;
698 cc.defineGetterSetter(_p, "dataSource", _p.getDataSource, _p.setDataSource);
699 /** @expose */
700 _p.delegate;
701 cc.defineGetterSetter(_p, "delegate", _p.getDelegate, _p.setDelegate);
702 /** @expose */
703 _p.verticalFillOrder;
704 cc.defineGetterSetter(_p, "verticalFillOrder", _p.getVerticalFillOrder, _p.setVerticalFillOrder);
705 
706 _p = null;
707 
708 /**
709  * An initialized table view object
710  * @deprecated
711  * @param {cc.TableViewDataSource} dataSource data source;
712  * @param {cc.Size} size view size
713  * @param {cc.Node} [container] parent object for cells
714  * @return {cc.TableView} table view
715  */
716 cc.TableView.create = function (dataSource, size, container) {
717     return new cc.TableView(dataSource, size, container);
718 };
719