UNPKG

nly-adminlte-vue

Version:
220 lines (212 loc) 7.5 kB
import identity from "../../../utils/identity"; import KeyCodes from "../../../utils/key-codes"; import startCase from "../../../utils/startcase"; import { getComponentConfig } from "../../../utils/config"; import { htmlOrText } from "../../../utils/html"; import { isUndefinedOrNull } from "../../../utils/inspect"; import filterEvent from "./filter-event"; import textSelectionActive from "./text-selection-active"; import { NlyThead } from "../thead"; import { NlyTfoot } from "../tfoot"; import { NlyTr } from "../tr"; import { NlyTh } from "../th"; export default { props: { headVariant: { type: String, // 'light', 'dark' or `null` (or custom) default: () => getComponentConfig("NlyTable", "headVariant") }, headRowVariant: { type: String, // Any Bootstrap theme variant (or custom) default: null }, theadClass: { type: [String, Array, Object] // default: undefined }, theadTrClass: { type: [String, Array, Object] // default: undefined } }, methods: { fieldClasses(field) { // Header field (<th>) classes return [ field.class ? field.class : "", field.thClass ? field.thClass : "" ]; }, headClicked(evt, field, isFoot) { if (this.stopIfBusy && this.stopIfBusy(evt)) { // If table is busy (via provider) then don't propagate return; } else if (filterEvent(evt)) { // Clicked on a non-disabled control so ignore return; } else if (textSelectionActive(this.$el)) { // User is selecting text, so ignore /* istanbul ignore next: JSDOM doesn't support getSelection() */ return; } evt.stopPropagation(); evt.preventDefault(); this.$emit("head-clicked", field.key, field, evt, isFoot); }, renderThead(isFoot = false) { const h = this.$createElement; const fields = this.computedFields || []; if (this.isStackedAlways || fields.length === 0) { // In always stacked mode, we don't bother rendering the head/foot // Or if no field headings (empty table) return h(); } // Reference to `selectAllRows` and `clearSelected()`, if table is selectable const selectAllRows = this.isSelectable ? this.selectAllRows : () => {}; const clearSelected = this.isSelectable ? this.clearSelected : () => {}; // Helper function to generate a field <th> cell const makeCell = (field, colIndex) => { let ariaLabel = null; if (!field.label.trim() && !field.headerTitle) { // In case field's label and title are empty/blank // We need to add a hint about what the column is about for non-sighted users /* istanbul ignore next */ ariaLabel = startCase(field.key); } const hasHeadClickListener = this.hasListener("head-clicked") || this.isSortable; const handlers = {}; if (hasHeadClickListener) { handlers.click = evt => { this.headClicked(evt, field, isFoot); }; handlers.keydown = evt => { const keyCode = evt.keyCode; if (keyCode === KeyCodes.ENTER || keyCode === KeyCodes.SPACE) { this.headClicked(evt, field, isFoot); } }; } const sortAttrs = this.isSortable ? this.sortTheadThAttrs(field.key, field, isFoot) : {}; const sortClass = this.isSortable ? this.sortTheadThClasses(field.key, field, isFoot) : null; const sortLabel = this.isSortable ? this.sortTheadThLabel(field.key, field, isFoot) : null; const data = { ref: field.ref, refInFor: true, key: field.key, class: [this.fieldClasses(field), sortClass], props: { variant: field.variant, stickyColumn: field.stickyColumn }, style: field.thStyle || {}, attrs: { // We only add a tabindex of 0 if there is a head-clicked listener tabindex: hasHeadClickListener ? "0" : null, abbr: field.headerAbbr || null, title: field.headerTitle || null, "aria-colindex": colIndex + 1, "aria-label": ariaLabel, ...this.getThValues( null, field.key, field.thAttr, isFoot ? "foot" : "head", {} ), ...sortAttrs }, on: handlers }; // Handle edge case where in-document templates are used with new // `v-slot:name` syntax where the browser lower-cases the v-slot's // name (attributes become lower cased when parsed by the browser) // We have replaced the square bracket syntax with round brackets // to prevent confusion with dynamic slot names let slotNames = [ `head(${field.key})`, `head(${field.key.toLowerCase()})`, "head()" ]; if (isFoot) { // Footer will fallback to header slot names slotNames = [ `foot(${field.key})`, `foot(${field.key.toLowerCase()})`, "foot()", ...slotNames ]; } const scope = { label: field.label, column: field.key, field, isFoot, // Add in row select methods selectAllRows, clearSelected }; const content = this.normalizeSlot(slotNames, scope) || (field.labelHtml ? h("div", { domProps: htmlOrText(field.labelHtml) }) : field.label); const srLabel = sortLabel ? h("span", { staticClass: "sr-only" }, ` (${sortLabel})`) : null; // Return the header cell return h(NlyTh, data, [content, srLabel].filter(identity)); }; // Generate the array of <th> cells const $cells = fields.map(makeCell).filter(identity); // Genrate the row(s) const $trs = []; if (isFoot) { const trProps = { variant: isUndefinedOrNull(this.footRowVariant) ? this.headRowVariant : this.footRowVariant }; $trs.push( h(NlyTr, { class: this.tfootTrClass, props: trProps }, $cells) ); } else { const scope = { columns: fields.length, fields: fields, // Add in row select methods selectAllRows, clearSelected }; $trs.push(this.normalizeSlot("thead-top", scope) || h()); $trs.push( h( NlyTr, { class: this.theadTrClass, props: { variant: this.headRowVariant } }, $cells ) ); } return h( isFoot ? NlyTfoot : NlyThead, { key: isFoot ? "nly-tfoot" : "nly-thead", class: (isFoot ? this.tfootClass : this.theadClass) || null, props: isFoot ? { footVariant: this.footVariant || this.headVariant || null } : { headVariant: this.headVariant || null } }, $trs ); } } };