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)

428 lines (359 loc) 15.2 kB
import Utils from '../utils/index.js' export default { initToolbar () { const opts = this.options let html let timeoutId 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.getCheckboxHtml({ name: 'toggle-all', checked: allFieldsVisible, label: opts.formatColumnsToggleAll(), extraClass: 'toggle-all', centered: false, withLabel: true })) 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) { const checkboxHtml = Utils.getDropdownColumnCheckboxHtml({ dataField: column.field, value: i, checked: !!checked, disabled: !!disabled, label: column.switchableLabel || column.title }) // Bootstrap 3/4 needs to be wrapped with toolbarDropdownItem if (Utils.getBootstrapVersion() === 5) { html.push(checkboxHtml) } else { html.push(Utils.sprintf(this.constants.html.toolbarDropdownItem, checkboxHtml)) } 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) const $searchInput = $(searchInput) 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() } }