UNPKG

framework7

Version:

Full featured mobile HTML framework for building iOS & Android apps

333 lines (330 loc) 10.5 kB
import $ from '../../shared/dom7.js'; import { extend, deleteProps } from '../../shared/utils.js'; import Framework7Class from '../../shared/class.js'; import { getSupport } from '../../shared/get-support.js'; class ListIndex extends Framework7Class { constructor(app, params) { if (params === void 0) { params = {}; } super(params, [app]); const index = this; const defaults = { el: null, // where to render indexes listEl: null, // list el to generate indexes indexes: 'auto', // or array of indexes iosItemHeight: 14, mdItemHeight: 14, scrollList: true, label: false, // eslint-disable-next-line renderItem(itemContent, itemIndex) { return ` <li>${itemContent}</li> `.trim(); }, renderSkipPlaceholder() { return '<li class="list-index-skip-placeholder"></li>'; }, on: {} }; // Extend defaults with modules params index.useModulesParams(defaults); index.params = extend(defaults, params); let $el; let $listEl; let $pageContentEl; let $ul; if (index.params.el) { $el = $(index.params.el); } else { return index; } if ($el[0].f7ListIndex) { return $el[0].f7ListIndex; } $ul = $el.find('ul'); if ($ul.length === 0) { $ul = $('<ul></ul>'); $el.append($ul); } if (index.params.listEl) { $listEl = $(index.params.listEl); } if (index.params.indexes === 'auto' && !$listEl) { return index; } if ($listEl) { $pageContentEl = $listEl.parents('.page-content').eq(0); } else { $pageContentEl = $el.siblings('.page-content').eq(0); if ($pageContentEl.length === 0) { $pageContentEl = $el.parents('.page').eq(0).find('.page-content').eq(0); } } $el[0].f7ListIndex = index; extend(index, { app, $el, el: $el && $el[0], $ul, ul: $ul && $ul[0], $listEl, listEl: $listEl && $listEl[0], $pageContentEl, pageContentEl: $pageContentEl && $pageContentEl[0], indexes: params.indexes, height: 0, skipRate: 0 }); // Install Modules index.useModules(); // Attach events function handleResize() { const height = { index }; index.calcSize(); if (height !== index.height) { index.render(); } } function handleClick(e) { const $clickedLi = $(e.target).closest('li'); if (!$clickedLi.length) return; let itemIndex = $clickedLi.index(); if (index.skipRate > 0) { const percentage = itemIndex / ($clickedLi.siblings('li').length - 1); itemIndex = Math.round((index.indexes.length - 1) * percentage); } const itemContent = index.indexes[itemIndex]; index.$el.trigger('listindex:click', { content: itemContent, index: itemIndex }); index.emit('local::click listIndexClick', index, itemContent, itemIndex); index.$el.trigger('listindex:select', { content: itemContent, index: itemIndex }); index.emit('local::select listIndexSelect', index, itemContent, itemIndex); if (index.$listEl && index.params.scrollList) { index.scrollListToIndex(itemContent, itemIndex); } } const touchesStart = {}; let isTouched; let isMoved; let topPoint; let bottomPoint; let $labelEl; let previousIndex = null; function handleTouchStart(e) { const $children = $ul.children(); if (!$children.length) return; topPoint = $children[0].getBoundingClientRect().top; bottomPoint = $children[$children.length - 1].getBoundingClientRect().top + $children[0].offsetHeight; touchesStart.x = e.type === 'touchstart' ? e.targetTouches[0].pageX : e.pageX; touchesStart.y = e.type === 'touchstart' ? e.targetTouches[0].pageY : e.pageY; isTouched = true; isMoved = false; previousIndex = null; } function handleTouchMove(e) { if (!isTouched) return; if (!isMoved && index.params.label) { $labelEl = $('<span class="list-index-label"></span>'); $el.append($labelEl); } isMoved = true; const pageY = e.type === 'touchmove' ? e.targetTouches[0].pageY : e.pageY; e.preventDefault(); let percentage = (pageY - topPoint) / (bottomPoint - topPoint); percentage = Math.min(Math.max(percentage, 0), 1); const itemIndex = Math.round((index.indexes.length - 1) * percentage); const itemContent = index.indexes[itemIndex]; const ulHeight = bottomPoint - topPoint; const bubbleBottom = (index.height - ulHeight) / 2 + (1 - percentage) * ulHeight; if (itemIndex !== previousIndex) { if (index.params.label) { $labelEl.html(itemContent).transform(`translateY(-${bubbleBottom}px)`); } if (index.$listEl && index.params.scrollList) { index.scrollListToIndex(itemContent, itemIndex); } } previousIndex = itemIndex; index.$el.trigger('listindex:select'); index.emit('local::select listIndexSelect', index, itemContent, itemIndex); } function handleTouchEnd() { if (!isTouched) return; isTouched = false; isMoved = false; if (index.params.label) { if ($labelEl) $labelEl.remove(); $labelEl = undefined; } } const passiveListener = getSupport().passiveListener ? { passive: true } : false; index.attachEvents = function attachEvents() { $el.parents('.tab').on('tab:show', handleResize); $el.parents('.page').on('page:reinit', handleResize); $el.parents('.panel').on('panel:open', handleResize); $el.parents('.sheet-modal, .actions-modal, .popup, .popover, .login-screen, .dialog, .toast').on('modal:open', handleResize); app.on('resize', handleResize); $el.on('click', handleClick); $el.on(app.touchEvents.start, handleTouchStart, passiveListener); app.on('touchmove:active', handleTouchMove); app.on('touchend:passive', handleTouchEnd); }; index.detachEvents = function attachEvents() { $el.parents('.tab').off('tab:show', handleResize); $el.parents('.page').off('page:reinit', handleResize); $el.parents('.panel').off('panel:open', handleResize); $el.parents('.sheet-modal, .actions-modal, .popup, .popover, .login-screen, .dialog, .toast').off('modal:open', handleResize); app.off('resize', handleResize); $el.off('click', handleClick); $el.off(app.touchEvents.start, handleTouchStart, passiveListener); app.off('touchmove:active', handleTouchMove); app.off('touchend:passive', handleTouchEnd); }; // Init index.init(); return index; } // eslint-disable-next-line scrollListToIndex(itemContent, itemIndex) { const index = this; const { $listEl, $pageContentEl, app } = index; if (!$listEl || !$pageContentEl || $pageContentEl.length === 0) return index; let $scrollToEl; $listEl.find('.list-group-title').each(el => { if ($scrollToEl) return; const $el = $(el); if ($el.text() === itemContent) { $scrollToEl = $el; } }); if (!$scrollToEl || $scrollToEl.length === 0) return index; const parentTop = $scrollToEl.parent().offset().top; let paddingTop = parseInt($pageContentEl.css('padding-top'), 10); const scrollTop = $pageContentEl[0].scrollTop; const scrollToElTop = $scrollToEl.offset().top; if ($pageContentEl.parents('.page-with-navbar-large').length) { const navbarInnerEl = app.navbar.getElByPage($pageContentEl.parents('.page-with-navbar-large').eq(0)); const $titleLargeEl = $(navbarInnerEl).find('.title-large'); if ($titleLargeEl.length) { paddingTop -= $titleLargeEl[0].offsetHeight || 0; } } if (parentTop <= paddingTop) { $pageContentEl.scrollTop(parentTop + scrollTop - paddingTop); } else { $pageContentEl.scrollTop(scrollToElTop + scrollTop - paddingTop); } return index; } renderSkipPlaceholder() { const index = this; return index.params.renderSkipPlaceholder.call(index); } renderItem(itemContent, itemIndex) { const index = this; return index.params.renderItem.call(index, itemContent, itemIndex); } render() { const index = this; const { $ul, indexes, skipRate } = index; let wasSkipped; const html = indexes.map((itemContent, itemIndex) => { if (itemIndex % skipRate !== 0 && skipRate > 0) { wasSkipped = true; return ''; } let itemHtml = index.renderItem(itemContent, itemIndex); if (wasSkipped) { itemHtml = index.renderSkipPlaceholder() + itemHtml; } wasSkipped = false; return itemHtml; }).join(''); $ul.html(html); return index; } calcSize() { const index = this; const { app, params, el, indexes } = index; const height = el.offsetHeight; const itemHeight = params[`${app.theme}ItemHeight`]; const maxItems = Math.floor(height / itemHeight); const items = indexes.length; let skipRate = 0; if (items > maxItems) { skipRate = Math.ceil((items * 2 - 1) / maxItems); } index.height = height; index.skipRate = skipRate; return index; } calcIndexes() { const index = this; if (index.params.indexes === 'auto') { index.indexes = []; index.$listEl.find('.list-group-title').each(el => { const elContent = $(el).text(); if (index.indexes.indexOf(elContent) < 0) { index.indexes.push(elContent); } }); } else { index.indexes = index.params.indexes; } return index; } update() { const index = this; index.calcIndexes(); index.calcSize(); index.render(); return index; } init() { const index = this; index.calcIndexes(); index.calcSize(); index.render(); index.attachEvents(); } destroy() { let index = this; index.$el.trigger('listindex:beforedestroy', index); index.emit('local::beforeDestroy listIndexBeforeDestroy'); index.detachEvents(); if (index.$el[0]) { index.$el[0].f7ListIndex = null; delete index.$el[0].f7ListIndex; } deleteProps(index); index = null; } } export default ListIndex;