forked from fanruan/fineui
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
292 lines
10 KiB
292 lines
10 KiB
/** |
|
* Collection |
|
* |
|
* Created by GUY on 2016/1/15. |
|
* @class BI.Collection |
|
* @extends BI.Widget |
|
*/ |
|
BI.Collection = BI.inherit(BI.Widget, { |
|
_defaultConfig: function () { |
|
return BI.extend(BI.Collection.superclass._defaultConfig.apply(this, arguments), { |
|
baseCls: "bi-collection", |
|
width: 400, |
|
height: 300, |
|
overflowX: true, |
|
overflowY: true, |
|
cellSizeAndPositionGetter: BI.emptyFn, |
|
horizontalOverscanSize: 0, |
|
verticalOverscanSize: 0, |
|
scrollLeft: 0, |
|
scrollTop: 0, |
|
items: [] |
|
}); |
|
}, |
|
|
|
_init: function () { |
|
BI.Collection.superclass._init.apply(this, arguments); |
|
var self = this, o = this.options; |
|
this.renderedCells = []; |
|
this.renderedKeys = []; |
|
this._scrollLock = false; |
|
this._debounceRelease = BI.debounce(function () { |
|
self._scrollLock = false; |
|
}, 150); |
|
this.container = BI.createWidget({ |
|
type: "bi.absolute" |
|
}); |
|
this.element.scroll(function () { |
|
if (self._scrollLock === true) { |
|
return; |
|
} |
|
o.scrollLeft = self.element.scrollLeft(); |
|
o.scrollTop = self.element.scrollTop(); |
|
self._calculateChildrenToRender(); |
|
self.fireEvent(BI.Collection.EVENT_SCROLL, { |
|
scrollLeft: o.scrollLeft, |
|
scrollTop: o.scrollTop |
|
}); |
|
}); |
|
BI.createWidget({ |
|
type: "bi.vertical", |
|
element: this, |
|
scrollable: o.overflowX === true && o.overflowY === true, |
|
scrolly: o.overflowX === false && o.overflowY === true, |
|
scrollx: o.overflowX === true && o.overflowY === false, |
|
items: [this.container] |
|
}); |
|
if (o.items.length > 0) { |
|
this._calculateSizeAndPositionData(); |
|
this._populate(); |
|
} |
|
if (o.scrollLeft !== 0 || o.scrollTop !== 0) { |
|
BI.nextTick(function () { |
|
self.element.scrollTop(o.scrollTop); |
|
self.element.scrollLeft(o.scrollLeft); |
|
}); |
|
} |
|
}, |
|
|
|
_calculateSizeAndPositionData: function () { |
|
var o = this.options; |
|
var cellMetadata = []; |
|
var sectionManager = new BI.SectionManager(); |
|
var height = 0; |
|
var width = 0; |
|
|
|
for (var index = 0, len = o.items.length; index < len; index++) { |
|
var cellMetadatum = o.cellSizeAndPositionGetter(index); |
|
|
|
if ( |
|
cellMetadatum.height == null || isNaN(cellMetadatum.height) || |
|
cellMetadatum.width == null || isNaN(cellMetadatum.width) || |
|
cellMetadatum.x == null || isNaN(cellMetadatum.x) || |
|
cellMetadatum.y == null || isNaN(cellMetadatum.y) |
|
) { |
|
throw Error(); |
|
} |
|
|
|
height = Math.max(height, cellMetadatum.y + cellMetadatum.height); |
|
width = Math.max(width, cellMetadatum.x + cellMetadatum.width); |
|
|
|
cellMetadatum.index = index; |
|
cellMetadata[index] = cellMetadatum; |
|
sectionManager.registerCell(cellMetadatum, index); |
|
} |
|
|
|
this._cellMetadata = cellMetadata; |
|
this._sectionManager = sectionManager; |
|
this._height = height; |
|
this._width = width; |
|
}, |
|
|
|
_cellRenderers: function (height, width, x, y) { |
|
this._lastRenderedCellIndices = this._sectionManager.getCellIndices(height, width, x, y); |
|
return this._cellGroupRenderer() |
|
}, |
|
|
|
_cellGroupRenderer: function () { |
|
var self = this, o = this.options; |
|
var rendered = []; |
|
BI.each(this._lastRenderedCellIndices, function (i, index) { |
|
var cellMetadata = self._sectionManager.getCellMetadata(index); |
|
rendered.push(cellMetadata); |
|
}); |
|
return rendered; |
|
}, |
|
|
|
_calculateChildrenToRender: function () { |
|
var self = this, o = this.options; |
|
var scrollLeft = BI.clamp(o.scrollLeft, 0, this._getMaxScrollLeft()); |
|
var scrollTop = BI.clamp(o.scrollTop, 0, this._getMaxScrollTop()); |
|
var left = Math.max(0, scrollLeft - o.horizontalOverscanSize); |
|
var top = Math.max(0, scrollTop - o.verticalOverscanSize); |
|
var right = Math.min(this._width, scrollLeft + o.width + o.horizontalOverscanSize); |
|
var bottom = Math.min(this._height, scrollTop + o.height + o.verticalOverscanSize); |
|
var childrenToDisplay = this._cellRenderers(bottom - top, right - left, left, top); |
|
var renderedCells = [], renderedKeys = []; |
|
for (var i = 0, len = childrenToDisplay.length; i < len; i++) { |
|
var datum = childrenToDisplay[i]; |
|
var index = BI.deepIndexOf(this.renderedKeys, datum.index); |
|
if (index > -1) { |
|
if (datum.width !== this.renderedCells[index]._width) { |
|
this.renderedCells[index]._width = datum.width; |
|
this.renderedCells[index].el.setWidth(datum.width); |
|
} |
|
if (datum.height !== this.renderedCells[index]._height) { |
|
this.renderedCells[index]._height = datum.height; |
|
this.renderedCells[index].el.setHeight(datum.height); |
|
} |
|
if (this.renderedCells[index].left !== datum.x) { |
|
this.renderedCells[index].el.element.css("left", datum.x + "px"); |
|
} |
|
if (this.renderedCells[index].top !== datum.y) { |
|
this.renderedCells[index].el.element.css("top", datum.y + "px"); |
|
} |
|
renderedCells.push(this.renderedCells[index]); |
|
} else { |
|
var child = BI.createWidget(BI.extend({ |
|
type: "bi.label", |
|
width: datum.width, |
|
height: datum.height |
|
}, o.items[datum.index], { |
|
cls: (o.items[datum.index].cls || "") + " container-cell" + (datum.y === 0 ? " first-row" : "") + (datum.x === 0 ? " first-col" : ""), |
|
_left: datum.x, |
|
_top: datum.y |
|
})); |
|
renderedCells.push({ |
|
el: child, |
|
left: datum.x, |
|
top: datum.y, |
|
_width: datum.width, |
|
_height: datum.height |
|
}); |
|
} |
|
renderedKeys.push(datum.index); |
|
} |
|
//已存在的, 需要添加的和需要删除的 |
|
var existSet = {}, addSet = {}, deleteArray = []; |
|
BI.each(renderedKeys, function (i, key) { |
|
if (BI.deepContains(self.renderedKeys, key)) { |
|
existSet[i] = key; |
|
} else { |
|
addSet[i] = key; |
|
} |
|
}); |
|
BI.each(this.renderedKeys, function (i, key) { |
|
if (BI.deepContains(existSet, key)) { |
|
return; |
|
} |
|
if (BI.deepContains(addSet, key)) { |
|
return; |
|
} |
|
deleteArray.push(i); |
|
}); |
|
BI.each(deleteArray, function (i, index) { |
|
self.renderedCells[index].el.destroy(); |
|
}); |
|
var addedItems = []; |
|
BI.each(addSet, function (index) { |
|
addedItems.push(renderedCells[index]) |
|
}); |
|
this.container.addItems(addedItems); |
|
this.renderedCells = renderedCells; |
|
this.renderedKeys = renderedKeys; |
|
}, |
|
|
|
_getMaxScrollLeft: function () { |
|
return Math.max(0, this._width - this.options.width + (this.options.overflowX ? BI.DOM.getScrollWidth() : 0)); |
|
}, |
|
|
|
_getMaxScrollTop: function () { |
|
return Math.max(0, this._height - this.options.height + (this.options.overflowY ? BI.DOM.getScrollWidth() : 0)); |
|
}, |
|
|
|
_populate: function () { |
|
var o = this.options; |
|
if (o.items.length > 0) { |
|
this.container.setWidth(this._width); |
|
this.container.setHeight(this._height); |
|
|
|
this._calculateChildrenToRender(); |
|
this.element.scrollTop(o.scrollTop); |
|
this.element.scrollLeft(o.scrollLeft); |
|
} |
|
}, |
|
|
|
setScrollLeft: function (scrollLeft) { |
|
if (this.options.scrollLeft === scrollLeft) { |
|
return; |
|
} |
|
this._scrollLock = true; |
|
this.options.scrollLeft = BI.clamp(scrollLeft || 0, 0, this._getMaxScrollLeft()); |
|
this._debounceRelease(); |
|
this._calculateChildrenToRender(); |
|
this.element.scrollLeft(this.options.scrollLeft); |
|
}, |
|
|
|
setScrollTop: function (scrollTop) { |
|
if (this.options.scrollTop === scrollTop) { |
|
return; |
|
} |
|
this._scrollLock = true; |
|
this.options.scrollTop = BI.clamp(scrollTop || 0, 0, this._getMaxScrollTop()); |
|
this._debounceRelease(); |
|
this._calculateChildrenToRender(); |
|
this.element.scrollTop(this.options.scrollTop); |
|
}, |
|
|
|
setOverflowX: function (b) { |
|
var self = this; |
|
if (this.options.overflowX !== !!b) { |
|
this.options.overflowX = !!b; |
|
BI.nextTick(function () { |
|
self.element.css({overflowX: !!b ? "auto" : "hidden"}); |
|
}); |
|
} |
|
}, |
|
|
|
setOverflowY: function (b) { |
|
var self = this; |
|
if (this.options.overflowY !== !!b) { |
|
this.options.overflowY = !!b; |
|
BI.nextTick(function () { |
|
self.element.css({overflowY: !!b ? "auto" : "hidden"}); |
|
}); |
|
} |
|
}, |
|
|
|
getScrollLeft: function () { |
|
return this.options.scrollLeft; |
|
}, |
|
|
|
getScrollTop: function () { |
|
return this.options.scrollTop; |
|
}, |
|
|
|
getMaxScrollLeft: function () { |
|
return this._getMaxScrollLeft(); |
|
}, |
|
|
|
getMaxScrollTop: function () { |
|
return this._getMaxScrollTop(); |
|
}, |
|
|
|
restore: function () { |
|
BI.each(this.renderedCells, function (i, cell) { |
|
cell.el.destroy(); |
|
}); |
|
this.renderedCells = []; |
|
this.renderedKeys = []; |
|
this._scrollLock = false; |
|
}, |
|
|
|
populate: function (items) { |
|
if (items && items !== this.options.items) { |
|
this.options.items = items; |
|
this._calculateSizeAndPositionData(); |
|
} |
|
this._populate(); |
|
} |
|
}); |
|
BI.Collection.EVENT_SCROLL = "EVENT_SCROLL"; |
|
BI.shortcut('bi.collection_view', BI.Collection); |