bootstrap-vue
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
314 lines (277 loc) • 10.9 kB
JavaScript
function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; }
function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; }
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
import stableSort from '../../../utils/stable-sort';
import { arrayIncludes } from '../../../utils/array';
import { isFunction, isUndefinedOrNull } from '../../../utils/inspect';
import { trim } from '../../../utils/string';
import defaultSortCompare from './default-sort-compare';
export default {
props: {
sortBy: {
type: String,
default: ''
},
sortDesc: {
// TODO: Make this tri-state: true, false, null
type: Boolean,
default: false
},
sortDirection: {
// This prop is named incorrectly
// It should be `initialSortDirection` as it is a bit misleading
// (not to mention it screws up the ARIA label on the headers)
type: String,
default: 'asc',
validator: function validator(direction) {
return arrayIncludes(['asc', 'desc', 'last'], direction);
}
},
sortCompare: {
type: Function // default: null
},
sortCompareOptions: {
// Supported localCompare options, see `options` section of:
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/localeCompare
type: Object,
default: function _default() {
return {
numeric: true
};
}
},
sortCompareLocale: {
// String: locale code
// Array: array of Locale strings
type: [String, Array] // default: undefined
},
sortNullLast: {
// Sort null and undefined to appear last
type: Boolean,
default: false
},
noSortReset: {
// Another prop that should have had a better name.
// It should be noSortClear (on non-sortable headers).
// We will need to make sure the documentation is clear on what
// this prop does (as well as in the code for future reference)
type: Boolean,
default: false
},
labelSortAsc: {
type: String,
default: 'Click to sort Ascending'
},
labelSortDesc: {
type: String,
default: 'Click to sort Descending'
},
labelSortClear: {
type: String,
default: 'Click to clear sorting'
},
noLocalSorting: {
type: Boolean,
default: false
},
noFooterSorting: {
type: Boolean,
default: false
},
sortIconLeft: {
// Place the sorting icon on the left of the header cells
type: Boolean,
default: false
}
},
data: function data() {
return {
localSortBy: this.sortBy || '',
localSortDesc: this.sortDesc || false
};
},
computed: {
localSorting: function localSorting() {
return this.hasProvider ? !!this.noProviderSorting : !this.noLocalSorting;
},
isSortable: function isSortable() {
return this.computedFields.some(function (f) {
return f.sortable;
});
},
sortedItems: function sortedItems() {
// Sorts the filtered items and returns a new array of the sorted items
// or the original items array if not sorted.
var items = (this.filteredItems || this.localItems || []).slice();
var sortBy = this.localSortBy;
var sortDesc = this.localSortDesc;
var sortCompare = this.sortCompare;
var localSorting = this.localSorting;
var sortOptions = _objectSpread(_objectSpread({}, this.sortCompareOptions), {}, {
usage: 'sort'
});
var sortLocale = this.sortCompareLocale || undefined;
var nullLast = this.sortNullLast;
if (sortBy && localSorting) {
var field = this.computedFieldsObj[sortBy] || {};
var sortByFormatted = field.sortByFormatted;
var formatter = isFunction(sortByFormatted) ?
/* istanbul ignore next */
sortByFormatted : sortByFormatted ? this.getFieldFormatter(sortBy) : undefined; // `stableSort` returns a new array, and leaves the original array intact
return stableSort(items, function (a, b) {
var result = null;
if (isFunction(sortCompare)) {
// Call user provided sortCompare routine
result = sortCompare(a, b, sortBy, sortDesc, formatter, sortOptions, sortLocale);
}
if (isUndefinedOrNull(result) || result === false) {
// Fallback to built-in defaultSortCompare if sortCompare
// is not defined or returns null/false
result = defaultSortCompare(a, b, sortBy, sortDesc, formatter, sortOptions, sortLocale, nullLast);
} // Negate result if sorting in descending order
return (result || 0) * (sortDesc ? -1 : 1);
});
}
return items;
}
},
watch: {
/* istanbul ignore next: pain in the butt to test */
isSortable: function isSortable(newVal)
/* istanbul ignore next: pain in the butt to test */
{
if (newVal) {
if (this.isSortable) {
this.$on('head-clicked', this.handleSort);
}
} else {
this.$off('head-clicked', this.handleSort);
}
},
sortDesc: function sortDesc(newVal) {
if (newVal === this.localSortDesc) {
/* istanbul ignore next */
return;
}
this.localSortDesc = newVal || false;
},
sortBy: function sortBy(newVal) {
if (newVal === this.localSortBy) {
/* istanbul ignore next */
return;
}
this.localSortBy = newVal || '';
},
// Update .sync props
localSortDesc: function localSortDesc(newVal, oldVal) {
// Emit update to sort-desc.sync
if (newVal !== oldVal) {
this.$emit('update:sortDesc', newVal);
}
},
localSortBy: function localSortBy(newVal, oldVal) {
if (newVal !== oldVal) {
this.$emit('update:sortBy', newVal);
}
}
},
created: function created() {
if (this.isSortable) {
this.$on('head-clicked', this.handleSort);
}
},
methods: {
// Handlers
// Need to move from thead-mixin
handleSort: function handleSort(key, field, evt, isFoot) {
var _this = this;
if (!this.isSortable) {
/* istanbul ignore next */
return;
}
if (isFoot && this.noFooterSorting) {
return;
} // TODO: make this tri-state sorting
// cycle desc => asc => none => desc => ...
var sortChanged = false;
var toggleLocalSortDesc = function toggleLocalSortDesc() {
var sortDirection = field.sortDirection || _this.sortDirection;
if (sortDirection === 'asc') {
_this.localSortDesc = false;
} else if (sortDirection === 'desc') {
_this.localSortDesc = true;
} else {// sortDirection === 'last'
// Leave at last sort direction from previous column
}
};
if (field.sortable) {
var sortKey = !this.localSorting && field.sortKey ? field.sortKey : key;
if (this.localSortBy === sortKey) {
// Change sorting direction on current column
this.localSortDesc = !this.localSortDesc;
} else {
// Start sorting this column ascending
this.localSortBy = sortKey; // this.localSortDesc = false
toggleLocalSortDesc();
}
sortChanged = true;
} else if (this.localSortBy && !this.noSortReset) {
this.localSortBy = '';
toggleLocalSortDesc();
sortChanged = true;
}
if (sortChanged) {
// Sorting parameters changed
this.$emit('sort-changed', this.context);
}
},
// methods to compute classes and attrs for thead>th cells
sortTheadThClasses: function sortTheadThClasses(key, field, isFoot) {
return {
// If sortable and sortIconLeft are true, then place sort icon on the left
'b-table-sort-icon-left': field.sortable && this.sortIconLeft && !(isFoot && this.noFooterSorting)
};
},
sortTheadThAttrs: function sortTheadThAttrs(key, field, isFoot) {
if (!this.isSortable || isFoot && this.noFooterSorting) {
// No attributes if not a sortable table
return {};
}
var sortable = field.sortable; // Assemble the aria-sort attribute value
var ariaSort = sortable && this.localSortBy === key ? this.localSortDesc ? 'descending' : 'ascending' : sortable ? 'none' : null; // Return the attribute
return {
'aria-sort': ariaSort
};
},
sortTheadThLabel: function sortTheadThLabel(key, field, isFoot) {
// A label to be placed in an `.sr-only` element in the header cell
if (!this.isSortable || isFoot && this.noFooterSorting) {
// No label if not a sortable table
return null;
}
var sortable = field.sortable; // The correctness of these labels is very important for screen-reader users.
var labelSorting = '';
if (sortable) {
if (this.localSortBy === key) {
// currently sorted sortable column.
labelSorting = this.localSortDesc ? this.labelSortAsc : this.labelSortDesc;
} else {
// Not currently sorted sortable column.
// Not using nested ternary's here for clarity/readability
// Default for ariaLabel
labelSorting = this.localSortDesc ? this.labelSortDesc : this.labelSortAsc; // Handle sortDirection setting
var sortDirection = this.sortDirection || field.sortDirection;
if (sortDirection === 'asc') {
labelSorting = this.labelSortAsc;
} else if (sortDirection === 'desc') {
labelSorting = this.labelSortDesc;
}
}
} else if (!this.noSortReset) {
// Non sortable column
labelSorting = this.localSortBy ? this.labelSortClear : '';
} // Return the sr-only sort label or null if no label
return trim(labelSorting) || null;
}
}
};