diff --git a/bi/base.css b/bi/base.css
index a470b9f270..9a756c5503 100644
--- a/bi/base.css
+++ b/bi/base.css
@@ -633,38 +633,6 @@ li.CodeMirror-hint-active {
cursor: text;
font-size: 14px;
}
-/* max-height - the only parameter in this file that needs to be edited.
- * Change it to suit your needs. The rest is recommended to leave as is.
- */
-.clusterize-scroll {
- overflow: auto;
-}
-/**
- * Avoid vertical margins for extra tags
- * Necessary for correct calculations when rows have nonzero vertical margins
- */
-.clusterize-extra-row {
- margin-top: 0 !important;
- margin-bottom: 0 !important;
-}
-/* By default extra tag .clusterize-keep-parity added to keep parity of rows.
- * Useful when used :nth-child(even/odd)
- */
-.clusterize-extra-row.clusterize-keep-parity {
- display: none;
-}
-/* During initialization clusterize adds tabindex to force the browser to keep focus
- * on the scrolling list, see issue #11
- * Outline removes default browser's borders for focused elements.
- */
-.clusterize-content {
- outline: 0;
-}
-/* Centering message that appears when no data provided
- */
-.clusterize-no-data td {
- text-align: center;
-}
/****添加计算宽度的--运算符直接需要space****/
/****** common color(常用颜色,可用于普遍场景) *****/
/**** custom color(自定义颜色,用于特定场景) ****/
diff --git a/bi/base.js b/bi/base.js
index cace48d533..40ab66d6f0 100644
--- a/bi/base.js
+++ b/bi/base.js
@@ -2530,8 +2530,8 @@ BI.CollectionView = BI.inherit(BI.Widget, {
_defaultConfig: function () {
return BI.extend(BI.CollectionView.superclass._defaultConfig.apply(this, arguments), {
baseCls: "bi-collection",
- // width: 400,
- // height: 300,
+ // width: 400, //必设
+ // height: 300, //必设
overflowX: true,
overflowY: true,
cellSizeAndPositionGetter: BI.emptyFn,
@@ -14671,16 +14671,16 @@ BI.GridView = BI.inherit(BI.Widget, {
_defaultConfig: function () {
return BI.extend(BI.GridView.superclass._defaultConfig.apply(this, arguments), {
baseCls: "bi-grid-view",
- // width: 400,
- // height: 300,
+ // width: 400, //必设
+ // height: 300, //必设
overflowX: true,
overflowY: true,
overscanColumnCount: 0,
overscanRowCount: 0,
- rowHeightGetter: BI.emptyFn,
- columnWidthGetter: BI.emptyFn,
- // estimatedColumnSize: 100,
- // estimatedRowSize: 30,
+ rowHeightGetter: BI.emptyFn, //number类型或function类型
+ columnWidthGetter: BI.emptyFn, //number类型或function类型
+ // estimatedColumnSize: 100, //columnWidthGetter为function时必设
+ // estimatedRowSize: 30, //rowHeightGetter为function时必设
scrollLeft: 0,
scrollTop: 0,
items: []
@@ -15455,335 +15455,7 @@ BI.SearcherView = BI.inherit(BI.Pane, {
});
BI.SearcherView.EVENT_CHANGE = "EVENT_CHANGE";
-BI.shortcut("bi.searcher_view", BI.SearcherView);/*! Clusterize.js - v0.17.6 - 2017-03-05
- * http://NeXTs.github.com/Clusterize.js/
- * Copyright (c) 2015 Denis Lukov; Licensed GPLv3 */
-
-;(function(name, definition) {
- if (typeof module != 'undefined') module.exports = definition();
- else if (typeof define == 'function' && typeof define.amd == 'object') define(definition);
- else this[name] = definition();
-}('Clusterize', function() {
- "use strict"
-
- // detect ie9 and lower
- // https://gist.github.com/padolsey/527683#comment-786682
- var ie = (function(){
- for( var v = 3,
- el = document.createElement('b'),
- all = el.all || [];
- el.innerHTML = '',
- all[0];
- ){}
- return v > 4 ? v : document.documentMode;
- }()),
- is_mac = navigator.platform.toLowerCase().indexOf('mac') + 1;
- var Clusterize = function(data) {
- if( ! (this instanceof Clusterize))
- return new Clusterize(data);
- var self = this;
-
- var defaults = {
- rows_in_block: 50,
- blocks_in_cluster: 4,
- tag: null,
- show_no_data_row: true,
- no_data_class: 'clusterize-no-data',
- no_data_text: 'No data',
- keep_parity: true,
- callbacks: {}
- }
-
- // public parameters
- self.options = {};
- var options = ['rows_in_block', 'blocks_in_cluster', 'show_no_data_row', 'no_data_class', 'no_data_text', 'keep_parity', 'tag', 'callbacks'];
- for(var i = 0, option; option = options[i]; i++) {
- self.options[option] = typeof data[option] != 'undefined' && data[option] != null
- ? data[option]
- : defaults[option];
- }
-
- var elems = ['scroll', 'content'];
- for(var i = 0, elem; elem = elems[i]; i++) {
- self[elem + '_elem'] = data[elem + 'Id']
- ? document.getElementById(data[elem + 'Id'])
- : data[elem + 'Elem'];
- if( ! self[elem + '_elem'])
- throw new Error("Error! Could not find " + elem + " element");
- }
-
- // tabindex forces the browser to keep focus on the scrolling list, fixes #11
- if( ! self.content_elem.hasAttribute('tabindex'))
- self.content_elem.setAttribute('tabindex', 0);
-
- // private parameters
- var rows = isArray(data.rows)
- ? data.rows
- : self.fetchMarkup(),
- cache = {},
- scroll_top = self.scroll_elem.scrollTop;
-
- // append initial data
- self.insertToDOM(rows, cache);
-
- // restore the scroll position
- self.scroll_elem.scrollTop = scroll_top;
-
- // adding scroll handler
- var last_cluster = false,
- scroll_debounce = 0,
- pointer_events_set = false,
- scrollEv = function() {
- // fixes scrolling issue on Mac #3
- if (is_mac) {
- if( ! pointer_events_set) self.content_elem.style.pointerEvents = 'none';
- pointer_events_set = true;
- clearTimeout(scroll_debounce);
- scroll_debounce = setTimeout(function () {
- self.content_elem.style.pointerEvents = 'auto';
- pointer_events_set = false;
- }, 50);
- }
- if (last_cluster != (last_cluster = self.getClusterNum()))
- self.insertToDOM(rows, cache);
- if (self.options.callbacks.scrollingProgress)
- self.options.callbacks.scrollingProgress(self.getScrollProgress());
- },
- resize_debounce = 0,
- resizeEv = function() {
- clearTimeout(resize_debounce);
- resize_debounce = setTimeout(self.refresh, 100);
- }
- on('scroll', self.scroll_elem, scrollEv);
- on('resize', window, resizeEv);
-
- // public methods
- self.destroy = function(clean) {
- off('scroll', self.scroll_elem, scrollEv);
- off('resize', window, resizeEv);
- self.html((clean ? self.generateEmptyRow() : rows).join(''));
- }
- self.refresh = function(force) {
- if(self.getRowsHeight(rows) || force) self.update(rows);
- }
- self.update = function(new_rows) {
- rows = isArray(new_rows)
- ? new_rows
- : [];
- var scroll_top = self.scroll_elem.scrollTop;
- // fixes #39
- if(rows.length * self.options.item_height < scroll_top) {
- self.scroll_elem.scrollTop = 0;
- last_cluster = 0;
- }
- self.insertToDOM(rows, cache);
- self.scroll_elem.scrollTop = scroll_top;
- }
- self.clear = function() {
- self.update([]);
- }
- self.getRowsAmount = function() {
- return rows.length;
- }
- self.getScrollProgress = function() {
- return this.options.scroll_top / (rows.length * this.options.item_height) * 100 || 0;
- }
-
- var add = function(where, _new_rows) {
- var new_rows = isArray(_new_rows)
- ? _new_rows
- : [];
- if( ! new_rows.length) return;
- rows = where == 'append'
- ? rows.concat(new_rows)
- : new_rows.concat(rows);
- self.insertToDOM(rows, cache);
- }
- self.append = function(rows) {
- add('append', rows);
- }
- self.prepend = function(rows) {
- add('prepend', rows);
- }
- }
-
- Clusterize.prototype = {
- constructor: Clusterize,
- // fetch existing markup
- fetchMarkup: function() {
- var rows = [], rows_nodes = this.getChildNodes(this.content_elem);
- while (rows_nodes.length) {
- rows.push(rows_nodes.shift().outerHTML);
- }
- return rows;
- },
- // get tag name, content tag name, tag height, calc cluster height
- exploreEnvironment: function(rows, cache) {
- var opts = this.options;
- opts.content_tag = this.content_elem.tagName.toLowerCase();
- if( ! rows.length) return;
- if(ie && ie <= 9 && ! opts.tag) opts.tag = rows[0].match(/<([^>\s/]*)/)[1].toLowerCase();
- if(this.content_elem.children.length <= 1) cache.data = this.html(rows[0] + rows[0] + rows[0]);
- if( ! opts.tag) opts.tag = this.content_elem.children[0].tagName.toLowerCase();
- this.getRowsHeight(rows);
- },
- getRowsHeight: function(rows) {
- var opts = this.options,
- prev_item_height = opts.item_height;
- opts.cluster_height = 0;
- if( ! rows.length) return;
- var nodes = this.content_elem.children;
- var node = nodes[Math.floor(nodes.length / 2)];
- opts.item_height = node.offsetHeight;
- // consider table's border-spacing
- if(opts.tag == 'tr' && getStyle('borderCollapse', this.content_elem) != 'collapse')
- opts.item_height += parseInt(getStyle('borderSpacing', this.content_elem), 10) || 0;
- // consider margins (and margins collapsing)
- if(opts.tag != 'tr') {
- var marginTop = parseInt(getStyle('marginTop', node), 10) || 0;
- var marginBottom = parseInt(getStyle('marginBottom', node), 10) || 0;
- opts.item_height += Math.max(marginTop, marginBottom);
- }
- opts.block_height = opts.item_height * opts.rows_in_block;
- opts.rows_in_cluster = opts.blocks_in_cluster * opts.rows_in_block;
- opts.cluster_height = opts.blocks_in_cluster * opts.block_height;
- return prev_item_height != opts.item_height;
- },
- // get current cluster number
- getClusterNum: function () {
- this.options.scroll_top = this.scroll_elem.scrollTop;
- return Math.floor(this.options.scroll_top / (this.options.cluster_height - this.options.block_height)) || 0;
- },
- // generate empty row if no data provided
- generateEmptyRow: function() {
- var opts = this.options;
- if( ! opts.tag || ! opts.show_no_data_row) return [];
- var empty_row = document.createElement(opts.tag),
- no_data_content = document.createTextNode(opts.no_data_text), td;
- empty_row.className = opts.no_data_class;
- if(opts.tag == 'tr') {
- td = document.createElement('td');
- // fixes #53
- td.colSpan = 100;
- td.appendChild(no_data_content);
- }
- empty_row.appendChild(td || no_data_content);
- return [empty_row.outerHTML];
- },
- // generate cluster for current scroll position
- generate: function (rows, cluster_num) {
- var opts = this.options,
- rows_len = rows.length;
- if (rows_len < opts.rows_in_block) {
- return {
- top_offset: 0,
- bottom_offset: 0,
- rows_above: 0,
- rows: rows_len ? rows : this.generateEmptyRow()
- }
- }
- var items_start = Math.max((opts.rows_in_cluster - opts.rows_in_block) * cluster_num, 0),
- items_end = items_start + opts.rows_in_cluster,
- top_offset = Math.max(items_start * opts.item_height, 0),
- bottom_offset = Math.max((rows_len - items_end) * opts.item_height, 0),
- this_cluster_rows = [],
- rows_above = items_start;
- if(top_offset < 1) {
- rows_above++;
- }
- for (var i = items_start; i < items_end; i++) {
- rows[i] && this_cluster_rows.push(rows[i]);
- }
- return {
- top_offset: top_offset,
- bottom_offset: bottom_offset,
- rows_above: rows_above,
- rows: this_cluster_rows
- }
- },
- renderExtraTag: function(class_name, height) {
- var tag = document.createElement(this.options.tag),
- clusterize_prefix = 'clusterize-';
- tag.className = [clusterize_prefix + 'extra-row', clusterize_prefix + class_name].join(' ');
- height && (tag.style.height = height + 'px');
- return tag.outerHTML;
- },
- // if necessary verify data changed and insert to DOM
- insertToDOM: function(rows, cache) {
- // explore row's height
- if( ! this.options.cluster_height) {
- this.exploreEnvironment(rows, cache);
- }
- var data = this.generate(rows, this.getClusterNum()),
- this_cluster_rows = data.rows.join(''),
- this_cluster_content_changed = this.checkChanges('data', this_cluster_rows, cache),
- top_offset_changed = this.checkChanges('top', data.top_offset, cache),
- only_bottom_offset_changed = this.checkChanges('bottom', data.bottom_offset, cache),
- callbacks = this.options.callbacks,
- layout = [];
-
- if(this_cluster_content_changed || top_offset_changed) {
- if(data.top_offset) {
- this.options.keep_parity && layout.push(this.renderExtraTag('keep-parity'));
- layout.push(this.renderExtraTag('top-space', data.top_offset));
- }
- layout.push(this_cluster_rows);
- data.bottom_offset && layout.push(this.renderExtraTag('bottom-space', data.bottom_offset));
- callbacks.clusterWillChange && callbacks.clusterWillChange();
- this.html(layout.join(''));
- this.options.content_tag == 'ol' && this.content_elem.setAttribute('start', data.rows_above);
- callbacks.clusterChanged && callbacks.clusterChanged();
- } else if(only_bottom_offset_changed) {
- this.content_elem.lastChild.style.height = data.bottom_offset + 'px';
- }
- },
- // unfortunately ie <= 9 does not allow to use innerHTML for table elements, so make a workaround
- html: function(data) {
- var content_elem = this.content_elem;
- if(ie && ie <= 9 && this.options.tag == 'tr') {
- var div = document.createElement('div'), last;
- div.innerHTML = '
';
- while((last = content_elem.lastChild)) {
- content_elem.removeChild(last);
- }
- var rows_nodes = this.getChildNodes(div.firstChild.firstChild);
- while (rows_nodes.length) {
- content_elem.appendChild(rows_nodes.shift());
- }
- } else {
- content_elem.innerHTML = data;
- }
- },
- getChildNodes: function(tag) {
- var child_nodes = tag.children, nodes = [];
- for (var i = 0, ii = child_nodes.length; i < ii; i++) {
- nodes.push(child_nodes[i]);
- }
- return nodes;
- },
- checkChanges: function(type, value, cache) {
- var changed = value != cache[type];
- cache[type] = value;
- return changed;
- }
- }
-
- // support functions
- function on(evt, element, fnc) {
- return element.addEventListener ? element.addEventListener(evt, fnc, false) : element.attachEvent("on" + evt, fnc);
- }
- function off(evt, element, fnc) {
- return element.removeEventListener ? element.removeEventListener(evt, fnc, false) : element.detachEvent("on" + evt, fnc);
- }
- function isArray(arr) {
- return Object.prototype.toString.call(arr) === '[object Array]';
- }
- function getStyle(prop, elem) {
- return window.getComputedStyle ? window.getComputedStyle(elem)[prop] : elem.currentStyle[prop];
- }
-
- return Clusterize;
-}));/**
+BI.shortcut("bi.searcher_view", BI.SearcherView);/**
* 表示当前对象
*
* Created by GUY on 2015/9/7.
@@ -15793,39 +15465,161 @@ BI.shortcut("bi.searcher_view", BI.SearcherView);/*! Clusterize.js - v0.17.6 - 2
BI.VirtualList = BI.inherit(BI.Widget, {
props: function () {
return {
- baseCls: "bi-virtual-list clusterize-scroll",
+ baseCls: "bi-virtual-list",
+ overscanHeight: 100,
+ blockSize: 10,
+ scrollTop: 0,
+ items: []
};
},
+
+ init: function () {
+ this.renderedIndex = -1;
+ this.cache = {};
+ },
+
render: function () {
var self = this, o = this.options;
return {
- type: "bi.default",
+ type: "bi.vertical",
items: [{
type: "bi.layout",
ref: function () {
- self.contentEl = this;
- },
- cls: "clusterize-content"
- }]
+ self.topBlank = this;
+ }
+ }, {
+ type: "bi.vertical",
+ scrolly: false,
+ ref: function () {
+ self.container = this;
+ }
+ }, {
+ type: "bi.layout",
+ ref: function () {
+ self.bottomBlank = this;
+ }
+ }],
+ element: this
}
},
mounted: function () {
- var data = [];
- for (var i = 0; i < 10000; i++) {
- data.push("" + i + "
");
- }
- new Clusterize({
- rows: data,
- scrollElem: this.element[0],
- contentElem: this.contentEl.element[0]
- })
+ var self = this, o = this.options;
+ this._populate();
+ this.element.scroll(function (e) {
+ o.scrollTop = self.element.scrollTop();
+ self._calculateBlocksToRender();
+ });
+ BI.ResizeDetector.addResizeListener(this, function () {
+ self._renderMoreIf();
+ });
},
- populate: function () {
+ _renderMoreIf: function () {
+ var o = this.options;
+ var height = this.element.height();
+ var minContentHeight = o.scrollTop + height + o.overscanHeight;
+ var index = (this.cache[this.renderedIndex] && (this.cache[this.renderedIndex].index + o.blockSize)) || 0,
+ cnt = this.renderedIndex + 1;
+ var lastHeight;
+ while ((lastHeight = this.container.element.height()) < minContentHeight && index < o.items.length) {
+ var items = o.items.slice(index, index + o.blockSize);
+ this.container.addItems(items);
+ var addedHeight = this.container.element.height() - lastHeight;
+ this.cache[cnt] = {
+ index: index,
+ height: addedHeight
+ };
+ this.tree.set(cnt, addedHeight);
+ this.renderedIndex = cnt;
+ cnt++;
+ index += o.blockSize;
+ }
+ },
+
+ _calculateBlocksToRender: function () {
+ var o = this.options;
+ this._renderMoreIf();
+ // var height = this.element.height();
+ // var minContentHeightFrom = o.scrollTop - o.overscanHeight;
+ // var minContentHeightTo = o.scrollTop + height + o.overscanHeight;
+ // var start = this.tree.greatestLowerBound(minContentHeightFrom);
+ // var end = this.tree.leastUpperBound(minContentHeightTo);
+ // var summaryTopHeight = 0;
+ // this.topBlank.setHeight(0);
+ // this.bottomBlank.setHeight(0);
+ // var needDestroyed = [];
+ // for (var i = 0; i < start; i++) {
+ // var index = this.cache[i].index;
+ // summaryTopHeight += this.cache[i].height;
+ // if (!this.cache[i].destroyed) {
+ // for (var j = index; j < index + o.blockSize && j < o.items.length; j++) {
+ // needDestroyed.push(this.container._children[j]);
+ // this.container._children[j] = null;
+ // }
+ // this.cache[i].destroyed = true;
+ // // this.topBlank.setHeight(summaryTopHeight);
+ // }
+ // }
+ // summaryTopHeight = 0;
+ // for (var i = end + 1; i <= this.renderedIndex; i++) {
+ // var index = this.cache[i].index;
+ // summaryTopHeight += this.cache[i].height;
+ // if (!this.cache[i].destroyed) {
+ // for (var j = index; j < index + o.blockSize && j < o.items.length; j++) {
+ // needDestroyed.push(this.container._children[j]);
+ // this.container._children[j] = null;
+ // }
+ // this.cache[i].destroyed = true;
+ // // this.bottomBlank.setHeight(summaryTopHeight);
+ // }
+ // }
+ // var firstFragment = document.createDocumentFragment(), lastFragment = document.createDocumentFragment();
+ // var currentFragment = firstFragment;
+ // for (var i = (start < 0 ? 0 : start); i <= end && i <= this.renderedIndex; i++) {
+ // var index = this.cache[i].index;
+ // if (!this.cache[i].destroyed) {
+ // currentFragment = lastFragment;
+ // }
+ // if (this.cache[i].destroyed === true) {
+ // for (var j = index; j < index + o.blockSize && j < o.items.length; j++) {
+ // var w = this.container._children[j] = BI.createWidget(BI.extend({
+ // root: true
+ // }, BI.stripEL(o.items[j])));
+ // currentFragment.appendChild(w.element[0]);
+ // }
+ // this.cache[i].destroyed = false;
+ // }
+ // }
+ // this.container.element.prepend(firstFragment);
+ // this.container.element.append(lastFragment);
+ // BI.each(needDestroyed, function (i, child) {
+ // child && child._destroy();
+ // });
+ },
+
+ _populate: function () {
+ var o = this.options;
+ this.tree = BI.PrefixIntervalTree.empty(Math.ceil(o.items.length / o.blockSize));
+ this._calculateBlocksToRender();
+ this.element.scrollTop(o.scrollTop);
+ },
+
+ restore: function () {
+ this.renderedIndex = -1;
+ this.cache = {};
+ },
+
+ populate: function (items) {
+
+ },
+
+ destroyed: function () {
+ this.restore();
}
});
-BI.shortcut('bi.virtual_list', BI.VirtualList);/**
+BI.shortcut('bi.virtual_list', BI.VirtualList);
+/**
* 分页控件
*
* Created by GUY on 2015/8/31.
diff --git a/bi/core.js b/bi/core.js
index de5f6d5d1f..746f642b87 100644
--- a/bi/core.js
+++ b/bi/core.js
@@ -9657,7 +9657,7 @@ $.extend(BI, {
return new BI.PrefixIntervalTree(xs);
};
- BI.PrefixIntervalTree.empty = function () {
+ BI.PrefixIntervalTree.empty = function (size) {
return BI.PrefixIntervalTree.uniform(size, 0);
};
diff --git a/demo/js/core/abstract/demo.collection_view.js b/demo/js/core/abstract/demo.collection_view.js
index 2867e1ed9a..ab175423ff 100644
--- a/demo/js/core/abstract/demo.collection_view.js
+++ b/demo/js/core/abstract/demo.collection_view.js
@@ -13,6 +13,8 @@ Demo.Func = BI.inherit(BI.Widget, {
}
var grid = BI.createWidget({
type: "bi.collection_view",
+ width: 400,
+ height: 300,
items: items,
cellSizeAndPositionGetter: function (index) {
return {
diff --git a/demo/js/core/abstract/demo.grid_view.js b/demo/js/core/abstract/demo.grid_view.js
index 141b77bb59..bea89520b0 100644
--- a/demo/js/core/abstract/demo.grid_view.js
+++ b/demo/js/core/abstract/demo.grid_view.js
@@ -16,6 +16,10 @@ Demo.Func = BI.inherit(BI.Widget, {
}
var grid = BI.createWidget({
type: "bi.grid_view",
+ width: 400,
+ height: 300,
+ estimatedRowSize: 30,
+ estimatedColumnSize: 100,
items: items,
scrollTop: 100,
rowHeightGetter: function () {
diff --git a/demo/js/core/abstract/demo.virtual_list.js b/demo/js/core/abstract/demo.virtual_list.js
index 792a5d8288..1a8a754d81 100644
--- a/demo/js/core/abstract/demo.virtual_list.js
+++ b/demo/js/core/abstract/demo.virtual_list.js
@@ -4,7 +4,14 @@ Demo.Func = BI.inherit(BI.Widget, {
},
render: function () {
return {
- type: "bi.virtual_list"
+ type: "bi.virtual_list",
+ items: BI.map(BI.makeArray(200, 0), function (i, item) {
+ return {
+ type: "bi.label",
+ height: 30,
+ text: i
+ };
+ })
}
}
});
diff --git a/docs/base.css b/docs/base.css
index a470b9f270..9a756c5503 100644
--- a/docs/base.css
+++ b/docs/base.css
@@ -633,38 +633,6 @@ li.CodeMirror-hint-active {
cursor: text;
font-size: 14px;
}
-/* max-height - the only parameter in this file that needs to be edited.
- * Change it to suit your needs. The rest is recommended to leave as is.
- */
-.clusterize-scroll {
- overflow: auto;
-}
-/**
- * Avoid vertical margins for extra tags
- * Necessary for correct calculations when rows have nonzero vertical margins
- */
-.clusterize-extra-row {
- margin-top: 0 !important;
- margin-bottom: 0 !important;
-}
-/* By default extra tag .clusterize-keep-parity added to keep parity of rows.
- * Useful when used :nth-child(even/odd)
- */
-.clusterize-extra-row.clusterize-keep-parity {
- display: none;
-}
-/* During initialization clusterize adds tabindex to force the browser to keep focus
- * on the scrolling list, see issue #11
- * Outline removes default browser's borders for focused elements.
- */
-.clusterize-content {
- outline: 0;
-}
-/* Centering message that appears when no data provided
- */
-.clusterize-no-data td {
- text-align: center;
-}
/****添加计算宽度的--运算符直接需要space****/
/****** common color(常用颜色,可用于普遍场景) *****/
/**** custom color(自定义颜色,用于特定场景) ****/
diff --git a/docs/base.js b/docs/base.js
index cace48d533..40ab66d6f0 100644
--- a/docs/base.js
+++ b/docs/base.js
@@ -2530,8 +2530,8 @@ BI.CollectionView = BI.inherit(BI.Widget, {
_defaultConfig: function () {
return BI.extend(BI.CollectionView.superclass._defaultConfig.apply(this, arguments), {
baseCls: "bi-collection",
- // width: 400,
- // height: 300,
+ // width: 400, //必设
+ // height: 300, //必设
overflowX: true,
overflowY: true,
cellSizeAndPositionGetter: BI.emptyFn,
@@ -14671,16 +14671,16 @@ BI.GridView = BI.inherit(BI.Widget, {
_defaultConfig: function () {
return BI.extend(BI.GridView.superclass._defaultConfig.apply(this, arguments), {
baseCls: "bi-grid-view",
- // width: 400,
- // height: 300,
+ // width: 400, //必设
+ // height: 300, //必设
overflowX: true,
overflowY: true,
overscanColumnCount: 0,
overscanRowCount: 0,
- rowHeightGetter: BI.emptyFn,
- columnWidthGetter: BI.emptyFn,
- // estimatedColumnSize: 100,
- // estimatedRowSize: 30,
+ rowHeightGetter: BI.emptyFn, //number类型或function类型
+ columnWidthGetter: BI.emptyFn, //number类型或function类型
+ // estimatedColumnSize: 100, //columnWidthGetter为function时必设
+ // estimatedRowSize: 30, //rowHeightGetter为function时必设
scrollLeft: 0,
scrollTop: 0,
items: []
@@ -15455,335 +15455,7 @@ BI.SearcherView = BI.inherit(BI.Pane, {
});
BI.SearcherView.EVENT_CHANGE = "EVENT_CHANGE";
-BI.shortcut("bi.searcher_view", BI.SearcherView);/*! Clusterize.js - v0.17.6 - 2017-03-05
- * http://NeXTs.github.com/Clusterize.js/
- * Copyright (c) 2015 Denis Lukov; Licensed GPLv3 */
-
-;(function(name, definition) {
- if (typeof module != 'undefined') module.exports = definition();
- else if (typeof define == 'function' && typeof define.amd == 'object') define(definition);
- else this[name] = definition();
-}('Clusterize', function() {
- "use strict"
-
- // detect ie9 and lower
- // https://gist.github.com/padolsey/527683#comment-786682
- var ie = (function(){
- for( var v = 3,
- el = document.createElement('b'),
- all = el.all || [];
- el.innerHTML = '',
- all[0];
- ){}
- return v > 4 ? v : document.documentMode;
- }()),
- is_mac = navigator.platform.toLowerCase().indexOf('mac') + 1;
- var Clusterize = function(data) {
- if( ! (this instanceof Clusterize))
- return new Clusterize(data);
- var self = this;
-
- var defaults = {
- rows_in_block: 50,
- blocks_in_cluster: 4,
- tag: null,
- show_no_data_row: true,
- no_data_class: 'clusterize-no-data',
- no_data_text: 'No data',
- keep_parity: true,
- callbacks: {}
- }
-
- // public parameters
- self.options = {};
- var options = ['rows_in_block', 'blocks_in_cluster', 'show_no_data_row', 'no_data_class', 'no_data_text', 'keep_parity', 'tag', 'callbacks'];
- for(var i = 0, option; option = options[i]; i++) {
- self.options[option] = typeof data[option] != 'undefined' && data[option] != null
- ? data[option]
- : defaults[option];
- }
-
- var elems = ['scroll', 'content'];
- for(var i = 0, elem; elem = elems[i]; i++) {
- self[elem + '_elem'] = data[elem + 'Id']
- ? document.getElementById(data[elem + 'Id'])
- : data[elem + 'Elem'];
- if( ! self[elem + '_elem'])
- throw new Error("Error! Could not find " + elem + " element");
- }
-
- // tabindex forces the browser to keep focus on the scrolling list, fixes #11
- if( ! self.content_elem.hasAttribute('tabindex'))
- self.content_elem.setAttribute('tabindex', 0);
-
- // private parameters
- var rows = isArray(data.rows)
- ? data.rows
- : self.fetchMarkup(),
- cache = {},
- scroll_top = self.scroll_elem.scrollTop;
-
- // append initial data
- self.insertToDOM(rows, cache);
-
- // restore the scroll position
- self.scroll_elem.scrollTop = scroll_top;
-
- // adding scroll handler
- var last_cluster = false,
- scroll_debounce = 0,
- pointer_events_set = false,
- scrollEv = function() {
- // fixes scrolling issue on Mac #3
- if (is_mac) {
- if( ! pointer_events_set) self.content_elem.style.pointerEvents = 'none';
- pointer_events_set = true;
- clearTimeout(scroll_debounce);
- scroll_debounce = setTimeout(function () {
- self.content_elem.style.pointerEvents = 'auto';
- pointer_events_set = false;
- }, 50);
- }
- if (last_cluster != (last_cluster = self.getClusterNum()))
- self.insertToDOM(rows, cache);
- if (self.options.callbacks.scrollingProgress)
- self.options.callbacks.scrollingProgress(self.getScrollProgress());
- },
- resize_debounce = 0,
- resizeEv = function() {
- clearTimeout(resize_debounce);
- resize_debounce = setTimeout(self.refresh, 100);
- }
- on('scroll', self.scroll_elem, scrollEv);
- on('resize', window, resizeEv);
-
- // public methods
- self.destroy = function(clean) {
- off('scroll', self.scroll_elem, scrollEv);
- off('resize', window, resizeEv);
- self.html((clean ? self.generateEmptyRow() : rows).join(''));
- }
- self.refresh = function(force) {
- if(self.getRowsHeight(rows) || force) self.update(rows);
- }
- self.update = function(new_rows) {
- rows = isArray(new_rows)
- ? new_rows
- : [];
- var scroll_top = self.scroll_elem.scrollTop;
- // fixes #39
- if(rows.length * self.options.item_height < scroll_top) {
- self.scroll_elem.scrollTop = 0;
- last_cluster = 0;
- }
- self.insertToDOM(rows, cache);
- self.scroll_elem.scrollTop = scroll_top;
- }
- self.clear = function() {
- self.update([]);
- }
- self.getRowsAmount = function() {
- return rows.length;
- }
- self.getScrollProgress = function() {
- return this.options.scroll_top / (rows.length * this.options.item_height) * 100 || 0;
- }
-
- var add = function(where, _new_rows) {
- var new_rows = isArray(_new_rows)
- ? _new_rows
- : [];
- if( ! new_rows.length) return;
- rows = where == 'append'
- ? rows.concat(new_rows)
- : new_rows.concat(rows);
- self.insertToDOM(rows, cache);
- }
- self.append = function(rows) {
- add('append', rows);
- }
- self.prepend = function(rows) {
- add('prepend', rows);
- }
- }
-
- Clusterize.prototype = {
- constructor: Clusterize,
- // fetch existing markup
- fetchMarkup: function() {
- var rows = [], rows_nodes = this.getChildNodes(this.content_elem);
- while (rows_nodes.length) {
- rows.push(rows_nodes.shift().outerHTML);
- }
- return rows;
- },
- // get tag name, content tag name, tag height, calc cluster height
- exploreEnvironment: function(rows, cache) {
- var opts = this.options;
- opts.content_tag = this.content_elem.tagName.toLowerCase();
- if( ! rows.length) return;
- if(ie && ie <= 9 && ! opts.tag) opts.tag = rows[0].match(/<([^>\s/]*)/)[1].toLowerCase();
- if(this.content_elem.children.length <= 1) cache.data = this.html(rows[0] + rows[0] + rows[0]);
- if( ! opts.tag) opts.tag = this.content_elem.children[0].tagName.toLowerCase();
- this.getRowsHeight(rows);
- },
- getRowsHeight: function(rows) {
- var opts = this.options,
- prev_item_height = opts.item_height;
- opts.cluster_height = 0;
- if( ! rows.length) return;
- var nodes = this.content_elem.children;
- var node = nodes[Math.floor(nodes.length / 2)];
- opts.item_height = node.offsetHeight;
- // consider table's border-spacing
- if(opts.tag == 'tr' && getStyle('borderCollapse', this.content_elem) != 'collapse')
- opts.item_height += parseInt(getStyle('borderSpacing', this.content_elem), 10) || 0;
- // consider margins (and margins collapsing)
- if(opts.tag != 'tr') {
- var marginTop = parseInt(getStyle('marginTop', node), 10) || 0;
- var marginBottom = parseInt(getStyle('marginBottom', node), 10) || 0;
- opts.item_height += Math.max(marginTop, marginBottom);
- }
- opts.block_height = opts.item_height * opts.rows_in_block;
- opts.rows_in_cluster = opts.blocks_in_cluster * opts.rows_in_block;
- opts.cluster_height = opts.blocks_in_cluster * opts.block_height;
- return prev_item_height != opts.item_height;
- },
- // get current cluster number
- getClusterNum: function () {
- this.options.scroll_top = this.scroll_elem.scrollTop;
- return Math.floor(this.options.scroll_top / (this.options.cluster_height - this.options.block_height)) || 0;
- },
- // generate empty row if no data provided
- generateEmptyRow: function() {
- var opts = this.options;
- if( ! opts.tag || ! opts.show_no_data_row) return [];
- var empty_row = document.createElement(opts.tag),
- no_data_content = document.createTextNode(opts.no_data_text), td;
- empty_row.className = opts.no_data_class;
- if(opts.tag == 'tr') {
- td = document.createElement('td');
- // fixes #53
- td.colSpan = 100;
- td.appendChild(no_data_content);
- }
- empty_row.appendChild(td || no_data_content);
- return [empty_row.outerHTML];
- },
- // generate cluster for current scroll position
- generate: function (rows, cluster_num) {
- var opts = this.options,
- rows_len = rows.length;
- if (rows_len < opts.rows_in_block) {
- return {
- top_offset: 0,
- bottom_offset: 0,
- rows_above: 0,
- rows: rows_len ? rows : this.generateEmptyRow()
- }
- }
- var items_start = Math.max((opts.rows_in_cluster - opts.rows_in_block) * cluster_num, 0),
- items_end = items_start + opts.rows_in_cluster,
- top_offset = Math.max(items_start * opts.item_height, 0),
- bottom_offset = Math.max((rows_len - items_end) * opts.item_height, 0),
- this_cluster_rows = [],
- rows_above = items_start;
- if(top_offset < 1) {
- rows_above++;
- }
- for (var i = items_start; i < items_end; i++) {
- rows[i] && this_cluster_rows.push(rows[i]);
- }
- return {
- top_offset: top_offset,
- bottom_offset: bottom_offset,
- rows_above: rows_above,
- rows: this_cluster_rows
- }
- },
- renderExtraTag: function(class_name, height) {
- var tag = document.createElement(this.options.tag),
- clusterize_prefix = 'clusterize-';
- tag.className = [clusterize_prefix + 'extra-row', clusterize_prefix + class_name].join(' ');
- height && (tag.style.height = height + 'px');
- return tag.outerHTML;
- },
- // if necessary verify data changed and insert to DOM
- insertToDOM: function(rows, cache) {
- // explore row's height
- if( ! this.options.cluster_height) {
- this.exploreEnvironment(rows, cache);
- }
- var data = this.generate(rows, this.getClusterNum()),
- this_cluster_rows = data.rows.join(''),
- this_cluster_content_changed = this.checkChanges('data', this_cluster_rows, cache),
- top_offset_changed = this.checkChanges('top', data.top_offset, cache),
- only_bottom_offset_changed = this.checkChanges('bottom', data.bottom_offset, cache),
- callbacks = this.options.callbacks,
- layout = [];
-
- if(this_cluster_content_changed || top_offset_changed) {
- if(data.top_offset) {
- this.options.keep_parity && layout.push(this.renderExtraTag('keep-parity'));
- layout.push(this.renderExtraTag('top-space', data.top_offset));
- }
- layout.push(this_cluster_rows);
- data.bottom_offset && layout.push(this.renderExtraTag('bottom-space', data.bottom_offset));
- callbacks.clusterWillChange && callbacks.clusterWillChange();
- this.html(layout.join(''));
- this.options.content_tag == 'ol' && this.content_elem.setAttribute('start', data.rows_above);
- callbacks.clusterChanged && callbacks.clusterChanged();
- } else if(only_bottom_offset_changed) {
- this.content_elem.lastChild.style.height = data.bottom_offset + 'px';
- }
- },
- // unfortunately ie <= 9 does not allow to use innerHTML for table elements, so make a workaround
- html: function(data) {
- var content_elem = this.content_elem;
- if(ie && ie <= 9 && this.options.tag == 'tr') {
- var div = document.createElement('div'), last;
- div.innerHTML = '';
- while((last = content_elem.lastChild)) {
- content_elem.removeChild(last);
- }
- var rows_nodes = this.getChildNodes(div.firstChild.firstChild);
- while (rows_nodes.length) {
- content_elem.appendChild(rows_nodes.shift());
- }
- } else {
- content_elem.innerHTML = data;
- }
- },
- getChildNodes: function(tag) {
- var child_nodes = tag.children, nodes = [];
- for (var i = 0, ii = child_nodes.length; i < ii; i++) {
- nodes.push(child_nodes[i]);
- }
- return nodes;
- },
- checkChanges: function(type, value, cache) {
- var changed = value != cache[type];
- cache[type] = value;
- return changed;
- }
- }
-
- // support functions
- function on(evt, element, fnc) {
- return element.addEventListener ? element.addEventListener(evt, fnc, false) : element.attachEvent("on" + evt, fnc);
- }
- function off(evt, element, fnc) {
- return element.removeEventListener ? element.removeEventListener(evt, fnc, false) : element.detachEvent("on" + evt, fnc);
- }
- function isArray(arr) {
- return Object.prototype.toString.call(arr) === '[object Array]';
- }
- function getStyle(prop, elem) {
- return window.getComputedStyle ? window.getComputedStyle(elem)[prop] : elem.currentStyle[prop];
- }
-
- return Clusterize;
-}));/**
+BI.shortcut("bi.searcher_view", BI.SearcherView);/**
* 表示当前对象
*
* Created by GUY on 2015/9/7.
@@ -15793,39 +15465,161 @@ BI.shortcut("bi.searcher_view", BI.SearcherView);/*! Clusterize.js - v0.17.6 - 2
BI.VirtualList = BI.inherit(BI.Widget, {
props: function () {
return {
- baseCls: "bi-virtual-list clusterize-scroll",
+ baseCls: "bi-virtual-list",
+ overscanHeight: 100,
+ blockSize: 10,
+ scrollTop: 0,
+ items: []
};
},
+
+ init: function () {
+ this.renderedIndex = -1;
+ this.cache = {};
+ },
+
render: function () {
var self = this, o = this.options;
return {
- type: "bi.default",
+ type: "bi.vertical",
items: [{
type: "bi.layout",
ref: function () {
- self.contentEl = this;
- },
- cls: "clusterize-content"
- }]
+ self.topBlank = this;
+ }
+ }, {
+ type: "bi.vertical",
+ scrolly: false,
+ ref: function () {
+ self.container = this;
+ }
+ }, {
+ type: "bi.layout",
+ ref: function () {
+ self.bottomBlank = this;
+ }
+ }],
+ element: this
}
},
mounted: function () {
- var data = [];
- for (var i = 0; i < 10000; i++) {
- data.push("" + i + "
");
- }
- new Clusterize({
- rows: data,
- scrollElem: this.element[0],
- contentElem: this.contentEl.element[0]
- })
+ var self = this, o = this.options;
+ this._populate();
+ this.element.scroll(function (e) {
+ o.scrollTop = self.element.scrollTop();
+ self._calculateBlocksToRender();
+ });
+ BI.ResizeDetector.addResizeListener(this, function () {
+ self._renderMoreIf();
+ });
},
- populate: function () {
+ _renderMoreIf: function () {
+ var o = this.options;
+ var height = this.element.height();
+ var minContentHeight = o.scrollTop + height + o.overscanHeight;
+ var index = (this.cache[this.renderedIndex] && (this.cache[this.renderedIndex].index + o.blockSize)) || 0,
+ cnt = this.renderedIndex + 1;
+ var lastHeight;
+ while ((lastHeight = this.container.element.height()) < minContentHeight && index < o.items.length) {
+ var items = o.items.slice(index, index + o.blockSize);
+ this.container.addItems(items);
+ var addedHeight = this.container.element.height() - lastHeight;
+ this.cache[cnt] = {
+ index: index,
+ height: addedHeight
+ };
+ this.tree.set(cnt, addedHeight);
+ this.renderedIndex = cnt;
+ cnt++;
+ index += o.blockSize;
+ }
+ },
+
+ _calculateBlocksToRender: function () {
+ var o = this.options;
+ this._renderMoreIf();
+ // var height = this.element.height();
+ // var minContentHeightFrom = o.scrollTop - o.overscanHeight;
+ // var minContentHeightTo = o.scrollTop + height + o.overscanHeight;
+ // var start = this.tree.greatestLowerBound(minContentHeightFrom);
+ // var end = this.tree.leastUpperBound(minContentHeightTo);
+ // var summaryTopHeight = 0;
+ // this.topBlank.setHeight(0);
+ // this.bottomBlank.setHeight(0);
+ // var needDestroyed = [];
+ // for (var i = 0; i < start; i++) {
+ // var index = this.cache[i].index;
+ // summaryTopHeight += this.cache[i].height;
+ // if (!this.cache[i].destroyed) {
+ // for (var j = index; j < index + o.blockSize && j < o.items.length; j++) {
+ // needDestroyed.push(this.container._children[j]);
+ // this.container._children[j] = null;
+ // }
+ // this.cache[i].destroyed = true;
+ // // this.topBlank.setHeight(summaryTopHeight);
+ // }
+ // }
+ // summaryTopHeight = 0;
+ // for (var i = end + 1; i <= this.renderedIndex; i++) {
+ // var index = this.cache[i].index;
+ // summaryTopHeight += this.cache[i].height;
+ // if (!this.cache[i].destroyed) {
+ // for (var j = index; j < index + o.blockSize && j < o.items.length; j++) {
+ // needDestroyed.push(this.container._children[j]);
+ // this.container._children[j] = null;
+ // }
+ // this.cache[i].destroyed = true;
+ // // this.bottomBlank.setHeight(summaryTopHeight);
+ // }
+ // }
+ // var firstFragment = document.createDocumentFragment(), lastFragment = document.createDocumentFragment();
+ // var currentFragment = firstFragment;
+ // for (var i = (start < 0 ? 0 : start); i <= end && i <= this.renderedIndex; i++) {
+ // var index = this.cache[i].index;
+ // if (!this.cache[i].destroyed) {
+ // currentFragment = lastFragment;
+ // }
+ // if (this.cache[i].destroyed === true) {
+ // for (var j = index; j < index + o.blockSize && j < o.items.length; j++) {
+ // var w = this.container._children[j] = BI.createWidget(BI.extend({
+ // root: true
+ // }, BI.stripEL(o.items[j])));
+ // currentFragment.appendChild(w.element[0]);
+ // }
+ // this.cache[i].destroyed = false;
+ // }
+ // }
+ // this.container.element.prepend(firstFragment);
+ // this.container.element.append(lastFragment);
+ // BI.each(needDestroyed, function (i, child) {
+ // child && child._destroy();
+ // });
+ },
+
+ _populate: function () {
+ var o = this.options;
+ this.tree = BI.PrefixIntervalTree.empty(Math.ceil(o.items.length / o.blockSize));
+ this._calculateBlocksToRender();
+ this.element.scrollTop(o.scrollTop);
+ },
+
+ restore: function () {
+ this.renderedIndex = -1;
+ this.cache = {};
+ },
+
+ populate: function (items) {
+
+ },
+
+ destroyed: function () {
+ this.restore();
}
});
-BI.shortcut('bi.virtual_list', BI.VirtualList);/**
+BI.shortcut('bi.virtual_list', BI.VirtualList);
+/**
* 分页控件
*
* Created by GUY on 2015/8/31.
diff --git a/docs/core.js b/docs/core.js
index 4b80066049..8d2d7eb6c2 100644
--- a/docs/core.js
+++ b/docs/core.js
@@ -18115,7 +18115,7 @@ $.extend(BI, {
return new BI.PrefixIntervalTree(xs);
};
- BI.PrefixIntervalTree.empty = function () {
+ BI.PrefixIntervalTree.empty = function (size) {
return BI.PrefixIntervalTree.uniform(size, 0);
};
diff --git a/docs/demo.js b/docs/demo.js
index 7542faa5b0..0c590a5639 100644
--- a/docs/demo.js
+++ b/docs/demo.js
@@ -3325,6 +3325,8 @@ BI.shortcut("demo.button_tree", Demo.Func);Demo.Func = BI.inherit(BI.Widget, {
}
var grid = BI.createWidget({
type: "bi.collection_view",
+ width: 400,
+ height: 300,
items: items,
cellSizeAndPositionGetter: function (index) {
return {
@@ -3366,6 +3368,10 @@ BI.shortcut("demo.collection_view", Demo.Func);Demo.Func = BI.inherit(BI.Widget,
}
var grid = BI.createWidget({
type: "bi.grid_view",
+ width: 400,
+ height: 300,
+ estimatedRowSize: 30,
+ estimatedColumnSize: 100,
items: items,
scrollTop: 100,
rowHeightGetter: function () {
@@ -3482,7 +3488,14 @@ BI.shortcut("demo.virtual_group_item", Demo.Item);Demo.Func = BI.inherit(BI.Widg
},
render: function () {
return {
- type: "bi.virtual_list"
+ type: "bi.virtual_list",
+ items: BI.map(BI.makeArray(200, 0), function (i, item) {
+ return {
+ type: "bi.label",
+ height: 30,
+ text: i
+ };
+ })
}
}
});
diff --git a/src/base/collection/collection.js b/src/base/collection/collection.js
index ab942f7bcf..039b02ca4a 100644
--- a/src/base/collection/collection.js
+++ b/src/base/collection/collection.js
@@ -9,8 +9,8 @@ BI.CollectionView = BI.inherit(BI.Widget, {
_defaultConfig: function () {
return BI.extend(BI.CollectionView.superclass._defaultConfig.apply(this, arguments), {
baseCls: "bi-collection",
- // width: 400,
- // height: 300,
+ // width: 400, //必设
+ // height: 300, //必设
overflowX: true,
overflowY: true,
cellSizeAndPositionGetter: BI.emptyFn,
diff --git a/src/base/grid/grid.js b/src/base/grid/grid.js
index 3ff3ff30fd..556040c048 100644
--- a/src/base/grid/grid.js
+++ b/src/base/grid/grid.js
@@ -9,16 +9,16 @@ BI.GridView = BI.inherit(BI.Widget, {
_defaultConfig: function () {
return BI.extend(BI.GridView.superclass._defaultConfig.apply(this, arguments), {
baseCls: "bi-grid-view",
- // width: 400,
- // height: 300,
+ // width: 400, //必设
+ // height: 300, //必设
overflowX: true,
overflowY: true,
overscanColumnCount: 0,
overscanRowCount: 0,
- rowHeightGetter: BI.emptyFn,
- columnWidthGetter: BI.emptyFn,
- // estimatedColumnSize: 100,
- // estimatedRowSize: 30,
+ rowHeightGetter: BI.emptyFn, //number类型或function类型
+ columnWidthGetter: BI.emptyFn, //number类型或function类型
+ // estimatedColumnSize: 100, //columnWidthGetter为function时必设
+ // estimatedRowSize: 30, //rowHeightGetter为function时必设
scrollLeft: 0,
scrollTop: 0,
items: []
diff --git a/src/base/list/clusterize.js b/src/base/list/clusterize.js
deleted file mode 100644
index 63c59e2baf..0000000000
--- a/src/base/list/clusterize.js
+++ /dev/null
@@ -1,329 +0,0 @@
-/*! Clusterize.js - v0.17.6 - 2017-03-05
- * http://NeXTs.github.com/Clusterize.js/
- * Copyright (c) 2015 Denis Lukov; Licensed GPLv3 */
-
-;(function(name, definition) {
- if (typeof module != 'undefined') module.exports = definition();
- else if (typeof define == 'function' && typeof define.amd == 'object') define(definition);
- else this[name] = definition();
-}('Clusterize', function() {
- "use strict"
-
- // detect ie9 and lower
- // https://gist.github.com/padolsey/527683#comment-786682
- var ie = (function(){
- for( var v = 3,
- el = document.createElement('b'),
- all = el.all || [];
- el.innerHTML = '',
- all[0];
- ){}
- return v > 4 ? v : document.documentMode;
- }()),
- is_mac = navigator.platform.toLowerCase().indexOf('mac') + 1;
- var Clusterize = function(data) {
- if( ! (this instanceof Clusterize))
- return new Clusterize(data);
- var self = this;
-
- var defaults = {
- rows_in_block: 50,
- blocks_in_cluster: 4,
- tag: null,
- show_no_data_row: true,
- no_data_class: 'clusterize-no-data',
- no_data_text: 'No data',
- keep_parity: true,
- callbacks: {}
- }
-
- // public parameters
- self.options = {};
- var options = ['rows_in_block', 'blocks_in_cluster', 'show_no_data_row', 'no_data_class', 'no_data_text', 'keep_parity', 'tag', 'callbacks'];
- for(var i = 0, option; option = options[i]; i++) {
- self.options[option] = typeof data[option] != 'undefined' && data[option] != null
- ? data[option]
- : defaults[option];
- }
-
- var elems = ['scroll', 'content'];
- for(var i = 0, elem; elem = elems[i]; i++) {
- self[elem + '_elem'] = data[elem + 'Id']
- ? document.getElementById(data[elem + 'Id'])
- : data[elem + 'Elem'];
- if( ! self[elem + '_elem'])
- throw new Error("Error! Could not find " + elem + " element");
- }
-
- // tabindex forces the browser to keep focus on the scrolling list, fixes #11
- if( ! self.content_elem.hasAttribute('tabindex'))
- self.content_elem.setAttribute('tabindex', 0);
-
- // private parameters
- var rows = isArray(data.rows)
- ? data.rows
- : self.fetchMarkup(),
- cache = {},
- scroll_top = self.scroll_elem.scrollTop;
-
- // append initial data
- self.insertToDOM(rows, cache);
-
- // restore the scroll position
- self.scroll_elem.scrollTop = scroll_top;
-
- // adding scroll handler
- var last_cluster = false,
- scroll_debounce = 0,
- pointer_events_set = false,
- scrollEv = function() {
- // fixes scrolling issue on Mac #3
- if (is_mac) {
- if( ! pointer_events_set) self.content_elem.style.pointerEvents = 'none';
- pointer_events_set = true;
- clearTimeout(scroll_debounce);
- scroll_debounce = setTimeout(function () {
- self.content_elem.style.pointerEvents = 'auto';
- pointer_events_set = false;
- }, 50);
- }
- if (last_cluster != (last_cluster = self.getClusterNum()))
- self.insertToDOM(rows, cache);
- if (self.options.callbacks.scrollingProgress)
- self.options.callbacks.scrollingProgress(self.getScrollProgress());
- },
- resize_debounce = 0,
- resizeEv = function() {
- clearTimeout(resize_debounce);
- resize_debounce = setTimeout(self.refresh, 100);
- }
- on('scroll', self.scroll_elem, scrollEv);
- on('resize', window, resizeEv);
-
- // public methods
- self.destroy = function(clean) {
- off('scroll', self.scroll_elem, scrollEv);
- off('resize', window, resizeEv);
- self.html((clean ? self.generateEmptyRow() : rows).join(''));
- }
- self.refresh = function(force) {
- if(self.getRowsHeight(rows) || force) self.update(rows);
- }
- self.update = function(new_rows) {
- rows = isArray(new_rows)
- ? new_rows
- : [];
- var scroll_top = self.scroll_elem.scrollTop;
- // fixes #39
- if(rows.length * self.options.item_height < scroll_top) {
- self.scroll_elem.scrollTop = 0;
- last_cluster = 0;
- }
- self.insertToDOM(rows, cache);
- self.scroll_elem.scrollTop = scroll_top;
- }
- self.clear = function() {
- self.update([]);
- }
- self.getRowsAmount = function() {
- return rows.length;
- }
- self.getScrollProgress = function() {
- return this.options.scroll_top / (rows.length * this.options.item_height) * 100 || 0;
- }
-
- var add = function(where, _new_rows) {
- var new_rows = isArray(_new_rows)
- ? _new_rows
- : [];
- if( ! new_rows.length) return;
- rows = where == 'append'
- ? rows.concat(new_rows)
- : new_rows.concat(rows);
- self.insertToDOM(rows, cache);
- }
- self.append = function(rows) {
- add('append', rows);
- }
- self.prepend = function(rows) {
- add('prepend', rows);
- }
- }
-
- Clusterize.prototype = {
- constructor: Clusterize,
- // fetch existing markup
- fetchMarkup: function() {
- var rows = [], rows_nodes = this.getChildNodes(this.content_elem);
- while (rows_nodes.length) {
- rows.push(rows_nodes.shift().outerHTML);
- }
- return rows;
- },
- // get tag name, content tag name, tag height, calc cluster height
- exploreEnvironment: function(rows, cache) {
- var opts = this.options;
- opts.content_tag = this.content_elem.tagName.toLowerCase();
- if( ! rows.length) return;
- if(ie && ie <= 9 && ! opts.tag) opts.tag = rows[0].match(/<([^>\s/]*)/)[1].toLowerCase();
- if(this.content_elem.children.length <= 1) cache.data = this.html(rows[0] + rows[0] + rows[0]);
- if( ! opts.tag) opts.tag = this.content_elem.children[0].tagName.toLowerCase();
- this.getRowsHeight(rows);
- },
- getRowsHeight: function(rows) {
- var opts = this.options,
- prev_item_height = opts.item_height;
- opts.cluster_height = 0;
- if( ! rows.length) return;
- var nodes = this.content_elem.children;
- var node = nodes[Math.floor(nodes.length / 2)];
- opts.item_height = node.offsetHeight;
- // consider table's border-spacing
- if(opts.tag == 'tr' && getStyle('borderCollapse', this.content_elem) != 'collapse')
- opts.item_height += parseInt(getStyle('borderSpacing', this.content_elem), 10) || 0;
- // consider margins (and margins collapsing)
- if(opts.tag != 'tr') {
- var marginTop = parseInt(getStyle('marginTop', node), 10) || 0;
- var marginBottom = parseInt(getStyle('marginBottom', node), 10) || 0;
- opts.item_height += Math.max(marginTop, marginBottom);
- }
- opts.block_height = opts.item_height * opts.rows_in_block;
- opts.rows_in_cluster = opts.blocks_in_cluster * opts.rows_in_block;
- opts.cluster_height = opts.blocks_in_cluster * opts.block_height;
- return prev_item_height != opts.item_height;
- },
- // get current cluster number
- getClusterNum: function () {
- this.options.scroll_top = this.scroll_elem.scrollTop;
- return Math.floor(this.options.scroll_top / (this.options.cluster_height - this.options.block_height)) || 0;
- },
- // generate empty row if no data provided
- generateEmptyRow: function() {
- var opts = this.options;
- if( ! opts.tag || ! opts.show_no_data_row) return [];
- var empty_row = document.createElement(opts.tag),
- no_data_content = document.createTextNode(opts.no_data_text), td;
- empty_row.className = opts.no_data_class;
- if(opts.tag == 'tr') {
- td = document.createElement('td');
- // fixes #53
- td.colSpan = 100;
- td.appendChild(no_data_content);
- }
- empty_row.appendChild(td || no_data_content);
- return [empty_row.outerHTML];
- },
- // generate cluster for current scroll position
- generate: function (rows, cluster_num) {
- var opts = this.options,
- rows_len = rows.length;
- if (rows_len < opts.rows_in_block) {
- return {
- top_offset: 0,
- bottom_offset: 0,
- rows_above: 0,
- rows: rows_len ? rows : this.generateEmptyRow()
- }
- }
- var items_start = Math.max((opts.rows_in_cluster - opts.rows_in_block) * cluster_num, 0),
- items_end = items_start + opts.rows_in_cluster,
- top_offset = Math.max(items_start * opts.item_height, 0),
- bottom_offset = Math.max((rows_len - items_end) * opts.item_height, 0),
- this_cluster_rows = [],
- rows_above = items_start;
- if(top_offset < 1) {
- rows_above++;
- }
- for (var i = items_start; i < items_end; i++) {
- rows[i] && this_cluster_rows.push(rows[i]);
- }
- return {
- top_offset: top_offset,
- bottom_offset: bottom_offset,
- rows_above: rows_above,
- rows: this_cluster_rows
- }
- },
- renderExtraTag: function(class_name, height) {
- var tag = document.createElement(this.options.tag),
- clusterize_prefix = 'clusterize-';
- tag.className = [clusterize_prefix + 'extra-row', clusterize_prefix + class_name].join(' ');
- height && (tag.style.height = height + 'px');
- return tag.outerHTML;
- },
- // if necessary verify data changed and insert to DOM
- insertToDOM: function(rows, cache) {
- // explore row's height
- if( ! this.options.cluster_height) {
- this.exploreEnvironment(rows, cache);
- }
- var data = this.generate(rows, this.getClusterNum()),
- this_cluster_rows = data.rows.join(''),
- this_cluster_content_changed = this.checkChanges('data', this_cluster_rows, cache),
- top_offset_changed = this.checkChanges('top', data.top_offset, cache),
- only_bottom_offset_changed = this.checkChanges('bottom', data.bottom_offset, cache),
- callbacks = this.options.callbacks,
- layout = [];
-
- if(this_cluster_content_changed || top_offset_changed) {
- if(data.top_offset) {
- this.options.keep_parity && layout.push(this.renderExtraTag('keep-parity'));
- layout.push(this.renderExtraTag('top-space', data.top_offset));
- }
- layout.push(this_cluster_rows);
- data.bottom_offset && layout.push(this.renderExtraTag('bottom-space', data.bottom_offset));
- callbacks.clusterWillChange && callbacks.clusterWillChange();
- this.html(layout.join(''));
- this.options.content_tag == 'ol' && this.content_elem.setAttribute('start', data.rows_above);
- callbacks.clusterChanged && callbacks.clusterChanged();
- } else if(only_bottom_offset_changed) {
- this.content_elem.lastChild.style.height = data.bottom_offset + 'px';
- }
- },
- // unfortunately ie <= 9 does not allow to use innerHTML for table elements, so make a workaround
- html: function(data) {
- var content_elem = this.content_elem;
- if(ie && ie <= 9 && this.options.tag == 'tr') {
- var div = document.createElement('div'), last;
- div.innerHTML = '';
- while((last = content_elem.lastChild)) {
- content_elem.removeChild(last);
- }
- var rows_nodes = this.getChildNodes(div.firstChild.firstChild);
- while (rows_nodes.length) {
- content_elem.appendChild(rows_nodes.shift());
- }
- } else {
- content_elem.innerHTML = data;
- }
- },
- getChildNodes: function(tag) {
- var child_nodes = tag.children, nodes = [];
- for (var i = 0, ii = child_nodes.length; i < ii; i++) {
- nodes.push(child_nodes[i]);
- }
- return nodes;
- },
- checkChanges: function(type, value, cache) {
- var changed = value != cache[type];
- cache[type] = value;
- return changed;
- }
- }
-
- // support functions
- function on(evt, element, fnc) {
- return element.addEventListener ? element.addEventListener(evt, fnc, false) : element.attachEvent("on" + evt, fnc);
- }
- function off(evt, element, fnc) {
- return element.removeEventListener ? element.removeEventListener(evt, fnc, false) : element.detachEvent("on" + evt, fnc);
- }
- function isArray(arr) {
- return Object.prototype.toString.call(arr) === '[object Array]';
- }
- function getStyle(prop, elem) {
- return window.getComputedStyle ? window.getComputedStyle(elem)[prop] : elem.currentStyle[prop];
- }
-
- return Clusterize;
-}));
\ No newline at end of file
diff --git a/src/base/list/virtuallist.js b/src/base/list/virtuallist.js
index aca28e1979..2b164bd6bc 100644
--- a/src/base/list/virtuallist.js
+++ b/src/base/list/virtuallist.js
@@ -8,36 +8,157 @@
BI.VirtualList = BI.inherit(BI.Widget, {
props: function () {
return {
- baseCls: "bi-virtual-list clusterize-scroll",
+ baseCls: "bi-virtual-list",
+ overscanHeight: 100,
+ blockSize: 10,
+ scrollTop: 0,
+ items: []
};
},
+
+ init: function () {
+ this.renderedIndex = -1;
+ this.cache = {};
+ },
+
render: function () {
var self = this, o = this.options;
return {
- type: "bi.default",
+ type: "bi.vertical",
items: [{
type: "bi.layout",
ref: function () {
- self.contentEl = this;
- },
- cls: "clusterize-content"
- }]
+ self.topBlank = this;
+ }
+ }, {
+ type: "bi.vertical",
+ scrolly: false,
+ ref: function () {
+ self.container = this;
+ }
+ }, {
+ type: "bi.layout",
+ ref: function () {
+ self.bottomBlank = this;
+ }
+ }],
+ element: this
}
},
mounted: function () {
- var data = [];
- for (var i = 0; i < 10000; i++) {
- data.push("" + i + "
");
+ var self = this, o = this.options;
+ this._populate();
+ this.element.scroll(function (e) {
+ o.scrollTop = self.element.scrollTop();
+ self._calculateBlocksToRender();
+ });
+ BI.ResizeDetector.addResizeListener(this, function () {
+ self._renderMoreIf();
+ });
+ },
+
+ _renderMoreIf: function () {
+ var o = this.options;
+ var height = this.element.height();
+ var minContentHeight = o.scrollTop + height + o.overscanHeight;
+ var index = (this.cache[this.renderedIndex] && (this.cache[this.renderedIndex].index + o.blockSize)) || 0,
+ cnt = this.renderedIndex + 1;
+ var lastHeight;
+ while ((lastHeight = this.container.element.height()) < minContentHeight && index < o.items.length) {
+ var items = o.items.slice(index, index + o.blockSize);
+ this.container.addItems(items);
+ var addedHeight = this.container.element.height() - lastHeight;
+ this.cache[cnt] = {
+ index: index,
+ height: addedHeight
+ };
+ this.tree.set(cnt, addedHeight);
+ this.renderedIndex = cnt;
+ cnt++;
+ index += o.blockSize;
}
- new Clusterize({
- rows: data,
- scrollElem: this.element[0],
- contentElem: this.contentEl.element[0]
- })
},
- populate: function () {
+ _calculateBlocksToRender: function () {
+ var o = this.options;
+ this._renderMoreIf();
+ // var height = this.element.height();
+ // var minContentHeightFrom = o.scrollTop - o.overscanHeight;
+ // var minContentHeightTo = o.scrollTop + height + o.overscanHeight;
+ // var start = this.tree.greatestLowerBound(minContentHeightFrom);
+ // var end = this.tree.leastUpperBound(minContentHeightTo);
+ // var summaryTopHeight = 0;
+ // this.topBlank.setHeight(0);
+ // this.bottomBlank.setHeight(0);
+ // var needDestroyed = [];
+ // for (var i = 0; i < start; i++) {
+ // var index = this.cache[i].index;
+ // summaryTopHeight += this.cache[i].height;
+ // if (!this.cache[i].destroyed) {
+ // for (var j = index; j < index + o.blockSize && j < o.items.length; j++) {
+ // needDestroyed.push(this.container._children[j]);
+ // this.container._children[j] = null;
+ // }
+ // this.cache[i].destroyed = true;
+ // // this.topBlank.setHeight(summaryTopHeight);
+ // }
+ // }
+ // summaryTopHeight = 0;
+ // for (var i = end + 1; i <= this.renderedIndex; i++) {
+ // var index = this.cache[i].index;
+ // summaryTopHeight += this.cache[i].height;
+ // if (!this.cache[i].destroyed) {
+ // for (var j = index; j < index + o.blockSize && j < o.items.length; j++) {
+ // needDestroyed.push(this.container._children[j]);
+ // this.container._children[j] = null;
+ // }
+ // this.cache[i].destroyed = true;
+ // // this.bottomBlank.setHeight(summaryTopHeight);
+ // }
+ // }
+ // var firstFragment = document.createDocumentFragment(), lastFragment = document.createDocumentFragment();
+ // var currentFragment = firstFragment;
+ // for (var i = (start < 0 ? 0 : start); i <= end && i <= this.renderedIndex; i++) {
+ // var index = this.cache[i].index;
+ // if (!this.cache[i].destroyed) {
+ // currentFragment = lastFragment;
+ // }
+ // if (this.cache[i].destroyed === true) {
+ // for (var j = index; j < index + o.blockSize && j < o.items.length; j++) {
+ // var w = this.container._children[j] = BI.createWidget(BI.extend({
+ // root: true
+ // }, BI.stripEL(o.items[j])));
+ // currentFragment.appendChild(w.element[0]);
+ // }
+ // this.cache[i].destroyed = false;
+ // }
+ // }
+ // this.container.element.prepend(firstFragment);
+ // this.container.element.append(lastFragment);
+ // BI.each(needDestroyed, function (i, child) {
+ // child && child._destroy();
+ // });
+ },
+
+ _populate: function () {
+ var o = this.options;
+ this.tree = BI.PrefixIntervalTree.empty(Math.ceil(o.items.length / o.blockSize));
+ this._calculateBlocksToRender();
+ this.element.scrollTop(o.scrollTop);
+ },
+
+ restore: function () {
+ this.renderedIndex = -1;
+ this.cache = {};
+ },
+
+ populate: function (items) {
+
+ },
+
+ destroyed: function () {
+ this.restore();
}
});
-BI.shortcut('bi.virtual_list', BI.VirtualList);
\ No newline at end of file
+BI.shortcut('bi.virtual_list', BI.VirtualList);
diff --git a/src/core/utils/prefixIntervalTree.js b/src/core/utils/prefixIntervalTree.js
index 82e1a50a78..043aa668b9 100644
--- a/src/core/utils/prefixIntervalTree.js
+++ b/src/core/utils/prefixIntervalTree.js
@@ -170,7 +170,7 @@
return new BI.PrefixIntervalTree(xs);
};
- BI.PrefixIntervalTree.empty = function () {
+ BI.PrefixIntervalTree.empty = function (size) {
return BI.PrefixIntervalTree.uniform(size, 0);
};
diff --git a/src/css/base/list/clusterize.css b/src/css/base/list/clusterize.css
deleted file mode 100644
index 2b8d17ee55..0000000000
--- a/src/css/base/list/clusterize.css
+++ /dev/null
@@ -1,32 +0,0 @@
-/* max-height - the only parameter in this file that needs to be edited.
- * Change it to suit your needs. The rest is recommended to leave as is.
- */
-.clusterize-scroll {
- overflow: auto;
-}
-/**
- * Avoid vertical margins for extra tags
- * Necessary for correct calculations when rows have nonzero vertical margins
- */
-.clusterize-extra-row {
- margin-top: 0 !important;
- margin-bottom: 0 !important;
-}
-/* By default extra tag .clusterize-keep-parity added to keep parity of rows.
- * Useful when used :nth-child(even/odd)
- */
-.clusterize-extra-row.clusterize-keep-parity {
- display: none;
-}
-/* During initialization clusterize adds tabindex to force the browser to keep focus
- * on the scrolling list, see issue #11
- * Outline removes default browser's borders for focused elements.
- */
-.clusterize-content {
- outline: 0;
-}
-/* Centering message that appears when no data provided
- */
-.clusterize-no-data td {
- text-align: center;
-}
diff --git a/src/less/base/list/clusterize.less b/src/less/base/list/clusterize.less
deleted file mode 100644
index 6aafca8652..0000000000
--- a/src/less/base/list/clusterize.less
+++ /dev/null
@@ -1,36 +0,0 @@
-/* max-height - the only parameter in this file that needs to be edited.
- * Change it to suit your needs. The rest is recommended to leave as is.
- */
-.clusterize-scroll{
- overflow: auto;
-}
-
-/**
- * Avoid vertical margins for extra tags
- * Necessary for correct calculations when rows have nonzero vertical margins
- */
-.clusterize-extra-row{
- margin-top: 0 !important;
- margin-bottom: 0 !important;
-}
-
-/* By default extra tag .clusterize-keep-parity added to keep parity of rows.
- * Useful when used :nth-child(even/odd)
- */
-.clusterize-extra-row.clusterize-keep-parity{
- display: none;
-}
-
-/* During initialization clusterize adds tabindex to force the browser to keep focus
- * on the scrolling list, see issue #11
- * Outline removes default browser's borders for focused elements.
- */
-.clusterize-content{
- outline: 0;
-}
-
-/* Centering message that appears when no data provided
- */
-.clusterize-no-data td{
- text-align: center;
-}
\ No newline at end of file