UNPKG

framework7

Version:

Full featured mobile HTML framework for building iOS & Android apps

654 lines (520 loc) 19 kB
"use strict"; exports.__esModule = true; exports.default = void 0; var _ssrWindow = require("ssr-window"); var _dom = _interopRequireDefault(require("../../shared/dom7")); var _utils = require("../../shared/utils"); var _class = _interopRequireDefault(require("../../shared/class")); var _getDevice = require("../../shared/get-device"); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; } function _inheritsLoose(subClass, superClass) { subClass.prototype = Object.create(superClass.prototype); subClass.prototype.constructor = subClass; _setPrototypeOf(subClass, superClass); } function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); } var VirtualList = /*#__PURE__*/function (_Framework7Class) { _inheritsLoose(VirtualList, _Framework7Class); function VirtualList(app, params) { var _this; if (params === void 0) { params = {}; } _this = _Framework7Class.call(this, params, [app]) || this; var vl = _assertThisInitialized(_this); var device = (0, _getDevice.getDevice)(); var document = (0, _ssrWindow.getDocument)(); var defaultHeight; if (app.theme === 'md') { defaultHeight = 48; } else if (app.theme === 'ios') { defaultHeight = 44; } else if (app.theme === 'aurora') { defaultHeight = 38; } var defaults = { cols: 1, height: defaultHeight, cache: true, dynamicHeightBufferSize: 1, showFilteredItemsOnly: false, renderExternal: undefined, setListHeight: true, searchByItem: undefined, searchAll: undefined, ul: null, createUl: true, scrollableParentEl: undefined, renderItem: function renderItem(item) { return ("\n <li>\n <div class=\"item-content\">\n <div class=\"item-inner\">\n <div class=\"item-title\">" + item + "</div>\n </div>\n </div>\n </li>\n ").trim(); }, on: {} }; // Extend defaults with modules params vl.useModulesParams(defaults); vl.params = (0, _utils.extend)(defaults, params); if (vl.params.height === undefined || !vl.params.height) { vl.params.height = defaultHeight; } vl.$el = (0, _dom.default)(params.el); vl.el = vl.$el[0]; if (vl.$el.length === 0) return undefined || _assertThisInitialized(_this); vl.$el[0].f7VirtualList = vl; vl.items = vl.params.items; if (vl.params.showFilteredItemsOnly) { vl.filteredItems = []; } if (vl.params.renderItem) { vl.renderItem = vl.params.renderItem; } vl.$pageContentEl = vl.$el.parents('.page-content'); vl.pageContentEl = vl.$pageContentEl[0]; vl.$scrollableParentEl = vl.params.scrollableParentEl ? (0, _dom.default)(vl.params.scrollableParentEl).eq(0) : vl.$pageContentEl; if (!vl.$scrollableParentEl.length && vl.$pageContentEl.length) { vl.$scrollableParentEl = vl.$pageContentEl; } vl.scrollableParentEl = vl.$scrollableParentEl[0]; // Bad scroll if (typeof vl.params.updatableScroll !== 'undefined') { vl.updatableScroll = vl.params.updatableScroll; } else { vl.updatableScroll = true; if (device.ios && device.osVersion.split('.')[0] < 8) { vl.updatableScroll = false; } } // Append <ul> var ul = vl.params.ul; vl.$ul = ul ? (0, _dom.default)(vl.params.ul) : vl.$el.children('ul'); if (vl.$ul.length === 0 && vl.params.createUl) { vl.$el.append('<ul></ul>'); vl.$ul = vl.$el.children('ul'); } vl.ul = vl.$ul[0]; var $itemsWrapEl; if (!vl.ul && !vl.params.createUl) $itemsWrapEl = vl.$el;else $itemsWrapEl = vl.$ul; (0, _utils.extend)(vl, { $itemsWrapEl: $itemsWrapEl, itemsWrapEl: $itemsWrapEl[0], // DOM cached items domCache: {}, displayDomCache: {}, // Temporary DOM Element tempDomElement: document.createElement('ul'), // Last repain position lastRepaintY: null, // Fragment fragment: document.createDocumentFragment(), // Props pageHeight: undefined, rowsPerScreen: undefined, rowsBefore: undefined, rowsAfter: undefined, rowsToRender: undefined, maxBufferHeight: 0, listHeight: undefined, dynamicHeight: typeof vl.params.height === 'function' }); // Install Modules vl.useModules(); // Attach events var handleScrollBound = vl.handleScroll.bind(vl); var handleResizeBound = vl.handleResize.bind(vl); var $pageEl; var $tabEl; var $panelEl; var $popupEl; vl.attachEvents = function attachEvents() { $pageEl = vl.$el.parents('.page').eq(0); $tabEl = vl.$el.parents('.tab').filter(function (tabEl) { return (0, _dom.default)(tabEl).parent('.tabs').parent('.tabs-animated-wrap, .tabs-swipeable-wrap').length === 0; }).eq(0); $panelEl = vl.$el.parents('.panel').eq(0); $popupEl = vl.$el.parents('.popup').eq(0); vl.$scrollableParentEl.on('scroll', handleScrollBound); if ($pageEl.length) $pageEl.on('page:reinit', handleResizeBound); if ($tabEl.length) $tabEl.on('tab:show', handleResizeBound); if ($panelEl.length) $panelEl.on('panel:open', handleResizeBound); if ($popupEl.length) $popupEl.on('popup:open', handleResizeBound); app.on('resize', handleResizeBound); }; vl.detachEvents = function attachEvents() { vl.$scrollableParentEl.off('scroll', handleScrollBound); if ($pageEl.length) $pageEl.off('page:reinit', handleResizeBound); if ($tabEl.length) $tabEl.off('tab:show', handleResizeBound); if ($panelEl.length) $panelEl.off('panel:open', handleResizeBound); if ($popupEl.length) $popupEl.off('popup:open', handleResizeBound); app.off('resize', handleResizeBound); }; // Init vl.init(); return vl || _assertThisInitialized(_this); } var _proto = VirtualList.prototype; _proto.setListSize = function setListSize() { var vl = this; var items = vl.filteredItems || vl.items; vl.pageHeight = vl.$scrollableParentEl[0].offsetHeight; if (vl.dynamicHeight) { vl.listHeight = 0; vl.heights = []; for (var i = 0; i < items.length; i += 1) { var itemHeight = vl.params.height(items[i]); vl.listHeight += itemHeight; vl.heights.push(itemHeight); } } else { vl.listHeight = Math.ceil(items.length / vl.params.cols) * vl.params.height; vl.rowsPerScreen = Math.ceil(vl.pageHeight / vl.params.height); vl.rowsBefore = vl.params.rowsBefore || vl.rowsPerScreen * 2; vl.rowsAfter = vl.params.rowsAfter || vl.rowsPerScreen; vl.rowsToRender = vl.rowsPerScreen + vl.rowsBefore + vl.rowsAfter; vl.maxBufferHeight = vl.rowsBefore / 2 * vl.params.height; } if (vl.updatableScroll || vl.params.setListHeight) { vl.$itemsWrapEl.css({ height: vl.listHeight + "px" }); } }; _proto.render = function render(force, forceScrollTop) { var vl = this; if (force) vl.lastRepaintY = null; var scrollTop = -(vl.$el[0].getBoundingClientRect().top - vl.$scrollableParentEl[0].getBoundingClientRect().top); if (typeof forceScrollTop !== 'undefined') scrollTop = forceScrollTop; if (vl.lastRepaintY === null || Math.abs(scrollTop - vl.lastRepaintY) > vl.maxBufferHeight || !vl.updatableScroll && vl.$scrollableParentEl[0].scrollTop + vl.pageHeight >= vl.$scrollableParentEl[0].scrollHeight) { vl.lastRepaintY = scrollTop; } else { return; } var items = vl.filteredItems || vl.items; var fromIndex; var toIndex; var heightBeforeFirstItem = 0; var heightBeforeLastItem = 0; if (vl.dynamicHeight) { var itemTop = 0; var itemHeight; vl.maxBufferHeight = vl.pageHeight; for (var j = 0; j < vl.heights.length; j += 1) { itemHeight = vl.heights[j]; if (typeof fromIndex === 'undefined') { if (itemTop + itemHeight >= scrollTop - vl.pageHeight * 2 * vl.params.dynamicHeightBufferSize) fromIndex = j;else heightBeforeFirstItem += itemHeight; } if (typeof toIndex === 'undefined') { if (itemTop + itemHeight >= scrollTop + vl.pageHeight * 2 * vl.params.dynamicHeightBufferSize || j === vl.heights.length - 1) toIndex = j + 1; heightBeforeLastItem += itemHeight; } itemTop += itemHeight; } toIndex = Math.min(toIndex, items.length); } else { fromIndex = (parseInt(scrollTop / vl.params.height, 10) - vl.rowsBefore) * vl.params.cols; if (fromIndex < 0) { fromIndex = 0; } toIndex = Math.min(fromIndex + vl.rowsToRender * vl.params.cols, items.length); } var topPosition; var renderExternalItems = []; vl.reachEnd = false; var i; for (i = fromIndex; i < toIndex; i += 1) { var itemEl = void 0; // Define real item index var index = vl.items.indexOf(items[i]); if (i === fromIndex) vl.currentFromIndex = index; if (i === toIndex - 1) vl.currentToIndex = index; if (vl.filteredItems) { if (vl.items[index] === vl.filteredItems[vl.filteredItems.length - 1]) vl.reachEnd = true; } else if (index === vl.items.length - 1) vl.reachEnd = true; // Find items if (vl.params.renderExternal) { renderExternalItems.push(items[i]); } else if (vl.domCache[index]) { itemEl = vl.domCache[index]; itemEl.f7VirtualListIndex = index; } else { if (vl.renderItem) { vl.tempDomElement.innerHTML = vl.renderItem(items[i], index).trim(); } else { vl.tempDomElement.innerHTML = items[i].toString().trim(); } itemEl = vl.tempDomElement.childNodes[0]; if (vl.params.cache) vl.domCache[index] = itemEl; itemEl.f7VirtualListIndex = index; } // Set item top position if (i === fromIndex) { if (vl.dynamicHeight) { topPosition = heightBeforeFirstItem; } else { topPosition = i * vl.params.height / vl.params.cols; } } if (!vl.params.renderExternal) { itemEl.style.top = topPosition + "px"; // Before item insert vl.emit('local::itemBeforeInsert vlItemBeforeInsert', vl, itemEl, items[i]); // Append item to fragment vl.fragment.appendChild(itemEl); } } // Update list height with not updatable scroll if (!vl.updatableScroll) { if (vl.dynamicHeight) { vl.itemsWrapEl.style.height = heightBeforeLastItem + "px"; } else { vl.itemsWrapEl.style.height = i * vl.params.height / vl.params.cols + "px"; } } // Update list html if (vl.params.renderExternal) { if (items && items.length === 0) { vl.reachEnd = true; } } else { vl.emit('local::beforeClear vlBeforeClear', vl, vl.fragment); vl.itemsWrapEl.innerHTML = ''; vl.emit('local::itemsBeforeInsert vlItemsBeforeInsert', vl, vl.fragment); if (items && items.length === 0) { vl.reachEnd = true; if (vl.params.emptyTemplate) vl.itemsWrapEl.innerHTML = vl.params.emptyTemplate; } else { vl.itemsWrapEl.appendChild(vl.fragment); } vl.emit('local::itemsAfterInsert vlItemsAfterInsert', vl, vl.fragment); } if (typeof forceScrollTop !== 'undefined' && force) { vl.$scrollableParentEl.scrollTop(forceScrollTop, 0); } if (vl.params.renderExternal) { vl.params.renderExternal(vl, { fromIndex: fromIndex, toIndex: toIndex, listHeight: vl.listHeight, topPosition: topPosition, items: renderExternalItems }); } } // Filter ; _proto.filterItems = function filterItems(indexes, resetScrollTop) { if (resetScrollTop === void 0) { resetScrollTop = true; } var vl = this; vl.filteredItems = []; for (var i = 0; i < indexes.length; i += 1) { vl.filteredItems.push(vl.items[indexes[i]]); } if (resetScrollTop) { vl.$scrollableParentEl[0].scrollTop = 0; } vl.update(); }; _proto.resetFilter = function resetFilter() { var vl = this; if (vl.params.showFilteredItemsOnly) { vl.filteredItems = []; } else { vl.filteredItems = null; delete vl.filteredItems; } vl.update(); }; _proto.scrollToItem = function scrollToItem(index) { var vl = this; if (index > vl.items.length) return false; var itemTop = 0; if (vl.dynamicHeight) { for (var i = 0; i < index; i += 1) { itemTop += vl.heights[i]; } } else { itemTop = index * vl.params.height; } var listTop = vl.$el[0].offsetTop; vl.render(true, listTop + itemTop - parseInt(vl.$scrollableParentEl.css('padding-top'), 10)); return true; }; _proto.handleScroll = function handleScroll() { var vl = this; vl.render(); } // Handle resize event ; _proto.isVisible = function isVisible() { var vl = this; return !!(vl.el.offsetWidth || vl.el.offsetHeight || vl.el.getClientRects().length); }; _proto.handleResize = function handleResize() { var vl = this; if (vl.isVisible()) { vl.setListSize(); vl.render(true); } } // Append ; _proto.appendItems = function appendItems(items) { var vl = this; for (var i = 0; i < items.length; i += 1) { vl.items.push(items[i]); } vl.update(); }; _proto.appendItem = function appendItem(item) { var vl = this; vl.appendItems([item]); } // Replace ; _proto.replaceAllItems = function replaceAllItems(items) { var vl = this; vl.items = items; delete vl.filteredItems; vl.domCache = {}; vl.update(); }; _proto.replaceItem = function replaceItem(index, item) { var vl = this; vl.items[index] = item; if (vl.params.cache) delete vl.domCache[index]; vl.update(); } // Prepend ; _proto.prependItems = function prependItems(items) { var vl = this; for (var i = items.length - 1; i >= 0; i -= 1) { vl.items.unshift(items[i]); } if (vl.params.cache) { var newCache = {}; Object.keys(vl.domCache).forEach(function (cached) { newCache[parseInt(cached, 10) + items.length] = vl.domCache[cached]; }); vl.domCache = newCache; } vl.update(); }; _proto.prependItem = function prependItem(item) { var vl = this; vl.prependItems([item]); } // Move ; _proto.moveItem = function moveItem(from, to) { var vl = this; var fromIndex = from; var toIndex = to; if (fromIndex === toIndex) return; // remove item from array var item = vl.items.splice(fromIndex, 1)[0]; if (toIndex >= vl.items.length) { // Add item to the end vl.items.push(item); toIndex = vl.items.length - 1; } else { // Add item to new index vl.items.splice(toIndex, 0, item); } // Update cache if (vl.params.cache) { var newCache = {}; Object.keys(vl.domCache).forEach(function (cached) { var cachedIndex = parseInt(cached, 10); var leftIndex = fromIndex < toIndex ? fromIndex : toIndex; var rightIndex = fromIndex < toIndex ? toIndex : fromIndex; var indexShift = fromIndex < toIndex ? -1 : 1; if (cachedIndex < leftIndex || cachedIndex > rightIndex) newCache[cachedIndex] = vl.domCache[cachedIndex]; if (cachedIndex === leftIndex) newCache[rightIndex] = vl.domCache[cachedIndex]; if (cachedIndex > leftIndex && cachedIndex <= rightIndex) newCache[cachedIndex + indexShift] = vl.domCache[cachedIndex]; }); vl.domCache = newCache; } vl.update(); } // Insert before ; _proto.insertItemBefore = function insertItemBefore(index, item) { var vl = this; if (index === 0) { vl.prependItem(item); return; } if (index >= vl.items.length) { vl.appendItem(item); return; } vl.items.splice(index, 0, item); // Update cache if (vl.params.cache) { var newCache = {}; Object.keys(vl.domCache).forEach(function (cached) { var cachedIndex = parseInt(cached, 10); if (cachedIndex >= index) { newCache[cachedIndex + 1] = vl.domCache[cachedIndex]; } }); vl.domCache = newCache; } vl.update(); } // Delete ; _proto.deleteItems = function deleteItems(indexes) { var vl = this; var prevIndex; var indexShift = 0; var _loop = function _loop(i) { var index = indexes[i]; if (typeof prevIndex !== 'undefined') { if (index > prevIndex) { indexShift = -i; } } index += indexShift; prevIndex = indexes[i]; // Delete item var deletedItem = vl.items.splice(index, 1)[0]; // Delete from filtered if (vl.filteredItems && vl.filteredItems.indexOf(deletedItem) >= 0) { vl.filteredItems.splice(vl.filteredItems.indexOf(deletedItem), 1); } // Update cache if (vl.params.cache) { var newCache = {}; Object.keys(vl.domCache).forEach(function (cached) { var cachedIndex = parseInt(cached, 10); if (cachedIndex === index) { delete vl.domCache[index]; } else if (parseInt(cached, 10) > index) { newCache[cachedIndex - 1] = vl.domCache[cached]; } else { newCache[cachedIndex] = vl.domCache[cached]; } }); vl.domCache = newCache; } }; for (var i = 0; i < indexes.length; i += 1) { _loop(i); } vl.update(); }; _proto.deleteAllItems = function deleteAllItems() { var vl = this; vl.items = []; delete vl.filteredItems; if (vl.params.cache) vl.domCache = {}; vl.update(); }; _proto.deleteItem = function deleteItem(index) { var vl = this; vl.deleteItems([index]); } // Clear cache ; _proto.clearCache = function clearCache() { var vl = this; vl.domCache = {}; } // Update Virtual List ; _proto.update = function update(deleteCache) { var vl = this; if (deleteCache && vl.params.cache) { vl.domCache = {}; } vl.setListSize(); vl.render(true); }; _proto.init = function init() { var vl = this; vl.attachEvents(); vl.setListSize(); vl.render(); }; _proto.destroy = function destroy() { var vl = this; vl.detachEvents(); vl.$el[0].f7VirtualList = null; delete vl.$el[0].f7VirtualList; (0, _utils.deleteProps)(vl); vl = null; }; return VirtualList; }(_class.default); var _default = VirtualList; exports.default = _default;