UNPKG

bootstrap-view

Version:

With more than 85 components, over 45 available plugins, several directives, and 1000+ icons, BootstrapVue provides one of the most comprehensive implementations of the Bootstrap v4 component and grid system available for Vue.js v2.6, complete with extens

344 lines (324 loc) 17.1 kB
function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); } function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; } function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; } function _defineProperty(e, r, t) { return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: !0, configurable: !0, writable: !0 }) : e[r] = t, e; } function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == _typeof(i) ? i : i + ""; } function _toPrimitive(t, r) { if ("object" != _typeof(t) || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != _typeof(i)) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); } function _toConsumableArray(r) { return _arrayWithoutHoles(r) || _iterableToArray(r) || _unsupportedIterableToArray(r) || _nonIterableSpread(); } function _nonIterableSpread() { throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } function _unsupportedIterableToArray(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0; } } function _iterableToArray(r) { if ("undefined" != typeof Symbol && null != r[Symbol.iterator] || null != r["@@iterator"]) return Array.from(r); } function _arrayWithoutHoles(r) { if (Array.isArray(r)) return _arrayLikeToArray(r); } function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; } import { extend, REF_FOR_KEY } from '../../../vue'; import { EVENT_NAME_ROW_CLICKED, EVENT_NAME_ROW_HOVERED, EVENT_NAME_ROW_UNHOVERED } from '../../../constants/events'; import { PROP_TYPE_ARRAY_OBJECT_STRING, PROP_TYPE_FUNCTION, PROP_TYPE_OBJECT_FUNCTION } from '../../../constants/props'; import { SLOT_NAME_ROW_DETAILS } from '../../../constants/slots'; import { useParentMixin } from '../../../mixins/use-parent'; import { get } from '../../../utils/get'; import { isFunction, isString, isUndefinedOrNull } from '../../../utils/inspect'; import { makeProp } from '../../../utils/props'; import { safeVueInstance } from '../../../utils/safe-vue-instance'; import { toString } from '../../../utils/string'; import { BTr } from '../tr'; import { BTd } from '../td'; import { BTh } from '../th'; import { FIELD_KEY_CELL_VARIANT, FIELD_KEY_ROW_VARIANT, FIELD_KEY_SHOW_DETAILS } from './constants'; // --- Props --- export var props = { detailsTdClass: makeProp(PROP_TYPE_ARRAY_OBJECT_STRING), tbodyTrAttr: makeProp(PROP_TYPE_OBJECT_FUNCTION), tbodyTrClass: makeProp([].concat(_toConsumableArray(PROP_TYPE_ARRAY_OBJECT_STRING), [PROP_TYPE_FUNCTION])) }; // --- Mixin --- // @vue/component export var tbodyRowMixin = extend({ mixins: [useParentMixin], props: props, methods: { // Methods for computing classes, attributes and styles for table cells getTdValues: function getTdValues(item, key, tdValue, defaultValue) { var bvParent = this.bvParent; if (tdValue) { var value = get(item, key, ''); if (isFunction(tdValue)) { return tdValue(value, key, item); } else if (isString(tdValue) && isFunction(bvParent[tdValue])) { return bvParent[tdValue](value, key, item); } return tdValue; } return defaultValue; }, getThValues: function getThValues(item, key, thValue, type, defaultValue) { var bvParent = this.bvParent; if (thValue) { var value = get(item, key, ''); if (isFunction(thValue)) { return thValue(value, key, item, type); } else if (isString(thValue) && isFunction(bvParent[thValue])) { return bvParent[thValue](value, key, item, type); } return thValue; } return defaultValue; }, // Method to get the value for a field getFormattedValue: function getFormattedValue(item, field) { var key = field.key; var formatter = this.getFieldFormatter(key); var value = get(item, key, null); if (isFunction(formatter)) { value = formatter(value, key, item); } return isUndefinedOrNull(value) ? '' : value; }, // Factory function methods toggleDetailsFactory: function toggleDetailsFactory(hasDetailsSlot, item) { var _this = this; // Returns a function to toggle a row's details slot return function () { if (hasDetailsSlot) { _this.$set(item, FIELD_KEY_SHOW_DETAILS, !item[FIELD_KEY_SHOW_DETAILS]); } }; }, // Row event handlers rowHovered: function rowHovered(event) { // `mouseenter` handler (non-bubbling) // `this.tbodyRowEventStopped` from tbody mixin if (!this.tbodyRowEventStopped(event)) { // `this.emitTbodyRowEvent` from tbody mixin this.emitTbodyRowEvent(EVENT_NAME_ROW_HOVERED, event); } }, rowUnhovered: function rowUnhovered(event) { // `mouseleave` handler (non-bubbling) // `this.tbodyRowEventStopped` from tbody mixin if (!this.tbodyRowEventStopped(event)) { // `this.emitTbodyRowEvent` from tbody mixin this.emitTbodyRowEvent(EVENT_NAME_ROW_UNHOVERED, event); } }, // Renders a TD or TH for a row's field renderTbodyRowCell: function renderTbodyRowCell(field, colIndex, item, rowIndex) { var _this2 = this; var isStacked = this.isStacked; var key = field.key, label = field.label, isRowHeader = field.isRowHeader; var h = this.$createElement; var hasDetailsSlot = this.hasNormalizedSlot(SLOT_NAME_ROW_DETAILS); var formatted = this.getFormattedValue(item, field); var stickyColumn = !isStacked && (this.isResponsive || this.stickyHeader) && field.stickyColumn; // We only uses the helper components for sticky columns to // improve performance of BTable/BTableLite by reducing the // total number of vue instances created during render var cellTag = stickyColumn ? isRowHeader ? BTh : BTd : isRowHeader ? 'th' : 'td'; var cellVariant = item[FIELD_KEY_CELL_VARIANT] && item[FIELD_KEY_CELL_VARIANT][key] ? item[FIELD_KEY_CELL_VARIANT][key] : field.variant || null; var data = { // For the Vue key, we concatenate the column index and // field key (as field keys could be duplicated) // TODO: Although we do prevent duplicate field keys... // So we could change this to: `row-${rowIndex}-cell-${key}` class: [field.class ? field.class : '', this.getTdValues(item, key, field.tdClass, '')], props: {}, attrs: _objectSpread({ 'aria-colindex': String(colIndex + 1) }, isRowHeader ? this.getThValues(item, key, field.thAttr, 'row', {}) : this.getTdValues(item, key, field.tdAttr, {})), key: "row-".concat(rowIndex, "-cell-").concat(colIndex, "-").concat(key) }; if (stickyColumn) { // We are using the helper BTd or BTh data.props = { stackedHeading: isStacked ? label : null, stickyColumn: true, variant: cellVariant }; } else { // Using native TD or TH element, so we need to // add in the attributes and variant class data.attrs['data-label'] = isStacked && !isUndefinedOrNull(label) ? toString(label) : null; data.attrs.role = isRowHeader ? 'rowheader' : 'cell'; data.attrs.scope = isRowHeader ? 'row' : null; // Add in the variant class if (cellVariant) { data.class.push("".concat(this.dark ? 'bg' : 'table', "-").concat(cellVariant)); } } var slotScope = { item: item, index: rowIndex, field: field, unformatted: get(item, key, ''), value: formatted, toggleDetails: this.toggleDetailsFactory(hasDetailsSlot, item), detailsShowing: Boolean(item[FIELD_KEY_SHOW_DETAILS]) }; // If table supports selectable mode, then add in the following scope // this.supportsSelectableRows will be undefined if mixin isn't loaded if (safeVueInstance(this).supportsSelectableRows) { slotScope.rowSelected = this.isRowSelected(rowIndex); slotScope.selectRow = function () { return _this2.selectRow(rowIndex); }; slotScope.unselectRow = function () { return _this2.unselectRow(rowIndex); }; } // The new `v-slot` syntax doesn't like a slot name starting with // a square bracket and if using in-document HTML templates, the // v-slot attributes are lower-cased by the browser. // Switched to round bracket syntax to prevent confusion with // dynamic slot name syntax. // We look for slots in this order: `cell(${key})`, `cell(${key.toLowerCase()})`, 'cell()' // Slot names are now cached by mixin tbody in `this.$_bodyFieldSlotNameCache` // Will be `null` if no slot (or fallback slot) exists var slotName = this.$_bodyFieldSlotNameCache[key]; var $childNodes = slotName ? this.normalizeSlot(slotName, slotScope) : toString(formatted); if (this.isStacked) { // We wrap in a DIV to ensure rendered as a single cell when visually stacked! $childNodes = [h('div', [$childNodes])]; } // Render either a td or th cell return h(cellTag, data, [$childNodes]); }, // Renders an item's row (or rows if details supported) renderTbodyRow: function renderTbodyRow(item, rowIndex) { var _this3 = this; var _safeVueInstance = safeVueInstance(this), fields = _safeVueInstance.computedFields, striped = _safeVueInstance.striped, primaryKey = _safeVueInstance.primaryKey, currentPage = _safeVueInstance.currentPage, perPage = _safeVueInstance.perPage, tbodyTrClass = _safeVueInstance.tbodyTrClass, tbodyTrAttr = _safeVueInstance.tbodyTrAttr, hasSelectableRowClick = _safeVueInstance.hasSelectableRowClick; var h = this.$createElement; var hasDetailsSlot = this.hasNormalizedSlot(SLOT_NAME_ROW_DETAILS); var rowShowDetails = item[FIELD_KEY_SHOW_DETAILS] && hasDetailsSlot; var hasRowClickHandler = this.$listeners[EVENT_NAME_ROW_CLICKED] || hasSelectableRowClick; // We can return more than one TR if rowDetails enabled var $rows = []; // Details ID needed for `aria-details` when details showing // We set it to `null` when not showing so that attribute // does not appear on the element var detailsId = rowShowDetails ? this.safeId("_details_".concat(rowIndex, "_")) : null; // For each item data field in row var $tds = fields.map(function (field, colIndex) { return _this3.renderTbodyRowCell(field, colIndex, item, rowIndex); }); // Calculate the row number in the dataset (indexed from 1) var ariaRowIndex = null; if (currentPage && perPage && perPage > 0) { ariaRowIndex = String((currentPage - 1) * perPage + rowIndex + 1); } // Create a unique :key to help ensure that sub components are re-rendered rather than // re-used, which can cause issues. If a primary key is not provided we use the rendered // rows index within the tbody. // See: https://github.com/bootstrap-vue/bootstrap-vue/issues/2410 var primaryKeyValue = toString(get(item, primaryKey)) || null; var rowKey = primaryKeyValue || toString(rowIndex); // If primary key is provided, use it to generate a unique ID on each tbody > tr // In the format of '{tableId}__row_{primaryKeyValue}' var rowId = primaryKeyValue ? this.safeId("_row_".concat(primaryKeyValue)) : null; // Selectable classes and attributes var selectableClasses = safeVueInstance(this).selectableRowClasses ? this.selectableRowClasses(rowIndex) : {}; var selectableAttrs = safeVueInstance(this).selectableRowAttrs ? this.selectableRowAttrs(rowIndex) : {}; // Additional classes and attributes var userTrClasses = isFunction(tbodyTrClass) ? tbodyTrClass(item, 'row') : tbodyTrClass; var userTrAttrs = isFunction(tbodyTrAttr) ? /* istanbul ignore next */tbodyTrAttr(item, 'row') : tbodyTrAttr; // Add the item row $rows.push(h(BTr, _defineProperty({ class: [userTrClasses, selectableClasses, rowShowDetails ? 'b-table-has-details' : ''], props: { variant: item[FIELD_KEY_ROW_VARIANT] || null }, attrs: _objectSpread(_objectSpread({ id: rowId }, userTrAttrs), {}, { // Users cannot override the following attributes tabindex: hasRowClickHandler ? '0' : null, 'data-pk': primaryKeyValue || null, 'aria-details': detailsId, 'aria-owns': detailsId, 'aria-rowindex': ariaRowIndex }, selectableAttrs), on: { // Note: These events are not A11Y friendly! mouseenter: this.rowHovered, mouseleave: this.rowUnhovered }, key: "__b-table-row-".concat(rowKey, "__"), ref: 'item-rows' }, REF_FOR_KEY, true), $tds)); // Row Details slot if (rowShowDetails) { var detailsScope = { item: item, index: rowIndex, fields: fields, toggleDetails: this.toggleDetailsFactory(hasDetailsSlot, item) }; // If table supports selectable mode, then add in the following scope // this.supportsSelectableRows will be undefined if mixin isn't loaded if (safeVueInstance(this).supportsSelectableRows) { detailsScope.rowSelected = this.isRowSelected(rowIndex); detailsScope.selectRow = function () { return _this3.selectRow(rowIndex); }; detailsScope.unselectRow = function () { return _this3.unselectRow(rowIndex); }; } // Render the details slot in a TD var $details = h(BTd, { props: { colspan: fields.length }, class: this.detailsTdClass }, [this.normalizeSlot(SLOT_NAME_ROW_DETAILS, detailsScope)]); // Add a hidden row to keep table row striping consistent when details showing // Only added if the table is striped if (striped) { $rows.push( // We don't use `BTr` here as we don't need the extra functionality h('tr', { staticClass: 'd-none', attrs: { 'aria-hidden': 'true', role: 'presentation' }, key: "__b-table-details-stripe__".concat(rowKey) })); } // Add the actual details row var userDetailsTrClasses = isFunction(this.tbodyTrClass) ? /* istanbul ignore next */this.tbodyTrClass(item, SLOT_NAME_ROW_DETAILS) : this.tbodyTrClass; var userDetailsTrAttrs = isFunction(this.tbodyTrAttr) ? /* istanbul ignore next */this.tbodyTrAttr(item, SLOT_NAME_ROW_DETAILS) : this.tbodyTrAttr; $rows.push(h(BTr, { staticClass: 'b-table-details', class: [userDetailsTrClasses], props: { variant: item[FIELD_KEY_ROW_VARIANT] || null }, attrs: _objectSpread(_objectSpread({}, userDetailsTrAttrs), {}, { // Users cannot override the following attributes id: detailsId, tabindex: '-1' }), key: "__b-table-details__".concat(rowKey) }, [$details])); } else if (hasDetailsSlot) { // Only add the placeholder if a the table has a row-details slot defined (but not shown) $rows.push(h()); if (striped) { // Add extra placeholder if table is striped $rows.push(h()); } } // Return the row(s) return $rows; } } });