UNPKG

bootstrap-table

Version:

An extended table to integration with some of the most widely used CSS frameworks. (Supports Bootstrap, Semantic UI, Bulma, Material Design, Foundation)

414 lines (346 loc) 14.8 kB
import Utils from '../utils/index.js' export default { initToolbar () { const opts = this.options let html = [] let timeoutId = 0 let $keepOpen let switchableCount = 0 if (this.$toolbar.find('.bs-bars').children().length) { $('body').append($(opts.toolbar)) } this.$toolbar.html('') if (typeof opts.toolbar === 'string' || typeof opts.toolbar === 'object') { $(Utils.sprintf('<div class="bs-bars %s-%s"></div>', this.constants.classes.pull, opts.toolbarAlign)) .appendTo(this.$toolbar) .append($(opts.toolbar)) } // showColumns, showToggle, showRefresh html = [`<div class="${[ 'columns', `columns-${opts.buttonsAlign}`, this.constants.classes.buttonsGroup, `${this.constants.classes.pull}-${opts.buttonsAlign}` ].join(' ')}">`] if (typeof opts.buttonsOrder === 'string') { opts.buttonsOrder = opts.buttonsOrder.replace(/\[|\]| |'/g, '').split(',') } this.buttons = Object.assign(this.buttons, { paginationSwitch: { text: opts.pagination ? opts.formatPaginationSwitchUp() : opts.formatPaginationSwitchDown(), icon: opts.pagination ? opts.icons.paginationSwitchDown : opts.icons.paginationSwitchUp, render: false, event: this.togglePagination, attributes: { 'aria-label': opts.formatPaginationSwitch(), title: opts.formatPaginationSwitch() } }, refresh: { text: opts.formatRefresh(), icon: opts.icons.refresh, render: false, event: this.refresh, attributes: { 'aria-label': opts.formatRefresh(), title: opts.formatRefresh() } }, toggle: { text: opts.formatToggleOn(), icon: opts.icons.toggleOff, render: false, event: this.toggleView, attributes: { 'aria-label': opts.formatToggleOn(), title: opts.formatToggleOn() } }, fullscreen: { text: opts.formatFullscreen(), icon: opts.icons.fullscreen, render: false, event: this.toggleFullscreen, attributes: { 'aria-label': opts.formatFullscreen(), title: opts.formatFullscreen() } }, columns: { render: false, html: () => { const html = [] html.push(`<div class="keep-open ${this.constants.classes.buttonsDropdown}"> <button class="${this.constants.buttonsClass} dropdown-toggle" type="button" ${this.constants.dataToggle}="dropdown" aria-label="${opts.formatColumns()}" ${opts.buttonsAttributeTitle}="${opts.formatColumns()}"> ${opts.showButtonIcons ? Utils.sprintf(this.constants.html.icon, opts.iconsPrefix, opts.icons.columns) : ''} ${opts.showButtonText ? opts.formatColumns() : ''} ${this.constants.html.dropdownCaret} </button> ${this.constants.html.toolbarDropdown[0]}`) if (opts.showColumnsSearch) { html.push( Utils.sprintf(this.constants.html.toolbarDropdownItem, Utils.sprintf('<input type="text" class="%s" name="columnsSearch" placeholder="%s" autocomplete="off">', this.constants.classes.input, opts.formatSearch()) ) ) html.push(this.constants.html.toolbarDropdownSeparator) } if (opts.showColumnsToggleAll) { const allFieldsVisible = this.getVisibleColumns().length === this.columns.filter(column => !this.isSelectionColumn(column)).length html.push( Utils.sprintf(this.constants.html.toolbarDropdownItem, Utils.sprintf('<input type="checkbox" class="toggle-all" %s> <span>%s</span>', allFieldsVisible ? 'checked="checked"' : '', opts.formatColumnsToggleAll()) ) ) html.push(this.constants.html.toolbarDropdownSeparator) } let visibleColumns = 0 this.columns.forEach(column => { if (column.visible) { visibleColumns++ } }) this.columns.forEach((column, i) => { if (this.isSelectionColumn(column)) { return } if (opts.cardView && !column.cardVisible) { return } const checked = column.visible ? ' checked="checked"' : '' const disabled = visibleColumns <= opts.minimumCountColumns && checked ? ' disabled="disabled"' : '' if (column.switchable) { html.push(Utils.sprintf(this.constants.html.toolbarDropdownItem, Utils.sprintf('<input type="checkbox" data-field="%s" value="%s"%s%s> <span>%s</span>', column.field, i, checked, disabled, column.switchableLabel || column.title))) switchableCount++ } }) html.push(this.constants.html.toolbarDropdown[1], '</div>') return html.join('') } } }) const buttonsHtml = {} for (const [buttonName, buttonConfig] of Object.entries(this.buttons)) { let buttonHtml if (buttonConfig.hasOwnProperty('html')) { if (typeof buttonConfig.html === 'function') { buttonHtml = buttonConfig.html() } else if (typeof buttonConfig.html === 'string') { buttonHtml = buttonConfig.html } } else { let buttonClass = this.constants.buttonsClass if (buttonConfig.hasOwnProperty('attributes') && buttonConfig.attributes.class) { buttonClass += ` ${buttonConfig.attributes.class}` } buttonHtml = `<button class="${buttonClass}" type="button" name="${buttonName}"` if (buttonConfig.hasOwnProperty('attributes')) { for (const [attributeName, value] of Object.entries(buttonConfig.attributes)) { if (attributeName === 'class') { continue } const attribute = attributeName === 'title' ? this.options.buttonsAttributeTitle : attributeName buttonHtml += ` ${attribute}="${value}"` } } buttonHtml += '>' if (opts.showButtonIcons && buttonConfig.hasOwnProperty('icon')) { buttonHtml += `${Utils.sprintf(this.constants.html.icon, opts.iconsPrefix, buttonConfig.icon)} ` } if (opts.showButtonText && buttonConfig.hasOwnProperty('text')) { buttonHtml += buttonConfig.text } buttonHtml += '</button>' } buttonsHtml[buttonName] = buttonHtml const optionName = `show${buttonName.charAt(0).toUpperCase()}${buttonName.substring(1)}` const showOption = opts[optionName] if (( !buttonConfig.hasOwnProperty('render') || buttonConfig.hasOwnProperty('render') && buttonConfig.render) && (showOption === undefined || showOption === true) ) { opts[optionName] = true } if (!opts.buttonsOrder.includes(buttonName)) { opts.buttonsOrder.push(buttonName) } } // Adding the button html to the final toolbar html when the showOption is true for (const button of opts.buttonsOrder) { const showOption = opts[`show${button.charAt(0).toUpperCase()}${button.substring(1)}`] if (showOption) { html.push(buttonsHtml[button]) } } html.push('</div>') // Fix #188: this.showToolbar is for extensions if (this.showToolbar || html.length > 2) { this.$toolbar.append(html.join('')) } for (const [buttonName, buttonConfig] of Object.entries(this.buttons)) { if (buttonConfig.hasOwnProperty('event')) { if (typeof buttonConfig.event === 'function' || typeof buttonConfig.event === 'string') { const event = typeof buttonConfig.event === 'string' ? window[buttonConfig.event] : buttonConfig.event this.$toolbar.find(`button[name="${buttonName}"]`) .off('click') .on('click', () => event.call(this)) continue } for (const [eventType, eventFunction] of Object.entries(buttonConfig.event)) { const event = typeof eventFunction === 'string' ? window[eventFunction] : eventFunction this.$toolbar.find(`button[name="${buttonName}"]`) .off(eventType) .on(eventType, () => event.call(this)) } } } if (opts.showColumns) { $keepOpen = this.$toolbar.find('.keep-open') const $checkboxes = $keepOpen.find('input[type="checkbox"]:not(".toggle-all")') const $toggleAll = $keepOpen.find('input[type="checkbox"].toggle-all') if (switchableCount <= opts.minimumCountColumns) { $keepOpen.find('input').prop('disabled', true) } $keepOpen.find('li, label').off('click').on('click', e => { e.stopImmediatePropagation() }) $checkboxes.off('click').on('click', ({ currentTarget }) => { const $this = $(currentTarget) this._toggleColumn($this.val(), $this.prop('checked'), false) this.trigger('column-switch', $this.data('field'), $this.prop('checked')) $toggleAll.prop('checked', $checkboxes.filter(':checked').length === this.columns.filter(column => !this.isSelectionColumn(column)).length) }) $toggleAll.off('click').on('click', ({ currentTarget }) => { this._toggleAllColumns($(currentTarget).prop('checked')) this.trigger('column-switch-all', $(currentTarget).prop('checked')) }) if (opts.showColumnsSearch) { const $columnsSearch = $keepOpen.find('[name="columnsSearch"]') const $listItems = $keepOpen.find('.dropdown-item-marker') $columnsSearch.on('keyup paste change', ({ currentTarget }) => { const $this = $(currentTarget) const searchValue = $this.val().toLowerCase() $listItems.show() $checkboxes.each((i, el) => { const $checkbox = $(el) const $listItem = $checkbox.parents('.dropdown-item-marker') const text = $listItem.text().toLowerCase() if (!text.includes(searchValue)) { $listItem.hide() } }) }) } } const handleInputEvent = $searchInput => { const eventTriggers = $searchInput.is('select') ? 'change' : 'keyup drop blur mouseup' $searchInput.off(eventTriggers).on(eventTriggers, event => { if (opts.searchOnEnterKey && event.keyCode !== 13) { return } if ([37, 38, 39, 40].includes(event.keyCode)) { return } clearTimeout(timeoutId) // doesn't matter if it's 0 timeoutId = setTimeout(() => { this.onSearch({ currentTarget: event.currentTarget }) }, opts.searchTimeOut) }) } // Fix #4516: this.showSearchClearButton is for extensions if ( (opts.search || this.showSearchClearButton) && typeof opts.searchSelector !== 'string' ) { html = [] const showSearchButton = Utils.sprintf(this.constants.html.searchButton, this.constants.buttonsClass, opts.formatSearch(), opts.showButtonIcons ? Utils.sprintf(this.constants.html.icon, opts.iconsPrefix, opts.icons.search) : '', opts.showButtonText ? opts.formatSearch() : '' ) const showSearchClearButton = Utils.sprintf(this.constants.html.searchClearButton, this.constants.buttonsClass, opts.formatClearSearch(), opts.showButtonIcons ? Utils.sprintf(this.constants.html.icon, opts.iconsPrefix, opts.icons.clearSearch) : '', opts.showButtonText ? opts.formatClearSearch() : '' ) const searchInputHtml = `<input class="${this.constants.classes.input} ${Utils.sprintf(' %s%s', this.constants.classes.inputPrefix, opts.iconSize)} search-input" type="search" aria-label="${opts.formatSearch()}" placeholder="${opts.formatSearch()}" autocomplete="off">` let searchInputFinalHtml = searchInputHtml if (opts.showSearchButton || opts.showSearchClearButton) { const buttonsHtml = (opts.showSearchButton ? showSearchButton : '') + (opts.showSearchClearButton ? showSearchClearButton : '') searchInputFinalHtml = opts.search ? Utils.sprintf(this.constants.html.inputGroup, searchInputHtml, buttonsHtml) : buttonsHtml } html.push(Utils.sprintf(` <div class="${this.constants.classes.pull}-${opts.searchAlign} search ${this.constants.classes.inputGroup}"> %s </div> `, searchInputFinalHtml)) this.$toolbar.append(html.join('')) const $searchInput = Utils.getSearchInput(this) if (opts.showSearchButton) { this.$toolbar.find('.search button[name=search]').off('click').on('click', () => { clearTimeout(timeoutId) // doesn't matter if it's 0 timeoutId = setTimeout(() => { this.onSearch({ currentTarget: $searchInput }) }, opts.searchTimeOut) }) if (opts.searchOnEnterKey) { handleInputEvent($searchInput) } } else { handleInputEvent($searchInput) } if (opts.showSearchClearButton) { this.$toolbar.find('.search button[name=clearSearch]').click(() => { this.resetSearch() }) } } else if (typeof opts.searchSelector === 'string') { handleInputEvent(Utils.getSearchInput(this)) } }, refresh (params) { if (params && params.url) { this.options.url = params.url } if (params && params.pageNumber) { this.options.pageNumber = params.pageNumber } if (params && params.pageSize) { this.options.pageSize = params.pageSize } if (params && params.query) { this.options.url = Utils.addQueryToUrl(this.options.url, params.query) } this.trigger('refresh', this.initServer(params && params.silent)) }, toggleView () { this.options.cardView = !this.options.cardView this.initHeader() const icon = this.options.showButtonIcons ? this.options.cardView ? this.options.icons.toggleOn : this.options.icons.toggleOff : '' const text = this.options.cardView ? this.options.formatToggleOff() : this.options.formatToggleOn() this.$toolbar.find('button[name="toggle"]') .html(`${Utils.sprintf(this.constants.html.icon, this.options.iconsPrefix, icon)} ${this.options.showButtonText ? text : ''}`) .attr('aria-label', text) .attr(this.options.buttonsAttributeTitle, text) this.initBody() this.trigger('toggle', this.options.cardView) }, toggleFullscreen () { this.$el.closest('.bootstrap-table').toggleClass('fullscreen') this.resetView() } }