vuikit
Version:
A responsive Vue UI library for web site interfaces based on UIkit
747 lines (725 loc) • 19.5 kB
JavaScript
/**
* Vuikit 0.8.10
* (c) 2018 Miljan Aleksic
* @license MIT
**/
/* Substantial part of the code is adapted from UIkit,
Copyright (c) 2013-2018 YOOtheme GmbH, getuikit.com */
import { mergeData } from './util/vue';
import { assign, isFunction, isUndefined } from './util/lang';
import { get } from './util/misc';
import { warn } from './util/debug';
var ROW_ID = '__vkTable_rowId';
var ROW_LEVEL = '__vkTable_rowLevel';
var ROW_CHILDREN_COUNT = '__vkTable_rowChildrenCount';
var ROW_CLICK_PREVENTED = '__vkTable_rowClickPrevented';
var ON_CLICK_ROW = 'click-row';
var UPDATE_SORTEDBY = 'update:sortedBy';
var UPDATE_EXPANDEDROWS = 'update:expandedRows';
var UPDATE_SELECTEDROWS = 'update:selectedRows';
var constants = /*#__PURE__*/Object.freeze({
ROW_ID: ROW_ID,
ROW_LEVEL: ROW_LEVEL,
ROW_CHILDREN_COUNT: ROW_CHILDREN_COUNT,
ROW_CLICK_PREVENTED: ROW_CLICK_PREVENTED,
ON_CLICK_ROW: ON_CLICK_ROW,
UPDATE_SORTEDBY: UPDATE_SORTEDBY,
UPDATE_EXPANDEDROWS: UPDATE_EXPANDEDROWS,
UPDATE_SELECTEDROWS: UPDATE_SELECTEDROWS
});
var ElementTable = {
functional: true,
props: {
divided: {
type: Boolean,
default: true
},
narrowed: {
type: Boolean,
default: false
},
cellMiddle: {
type: Boolean,
default: false
},
striped: {
type: Boolean,
default: false
},
hoverable: {
type: Boolean,
default: false
},
justified: {
type: Boolean,
default: false
},
responsive: {
type: Boolean,
default: false
}
},
render: function render (h, ref) {
var data = ref.data;
var props = ref.props;
var children = ref.children;
return h('table', mergeData(data, {
class: ['uk-table', {
'uk-table-small': props.narrowed,
'uk-table-hover': props.hoverable,
'uk-table-middle': props.cellMiddle,
'uk-table-divider': props.divided,
'uk-table-striped': props.striped,
'uk-table-justify': props.justified,
'uk-table-responsive': props.responsive
}]
}), children)
}
}
var ElementTableTd = {
functional: true,
props: {
cellMiddle: {
type: Boolean,
default: false
},
shrinked: {
type: Boolean,
default: false
},
expanded: {
type: Boolean,
default: false
},
width: {
type: String,
default: ''
},
linked: {
type: Boolean,
default: false
},
truncated: {
type: Boolean,
default: false
},
unwrapped: {
type: Boolean,
default: false
}
},
render: function render (h, ref) {
var obj;
var data = ref.data;
var props = ref.props;
var children = ref.children;
var cellMiddle = props.cellMiddle;
var shrinked = props.shrinked;
var expanded = props.expanded;
var width = props.width;
var linked = props.linked;
var truncated = props.truncated;
var unwrapped = props.unwrapped;
return h('td', mergeData(data, {
class: ( obj = {
'uk-table-link': linked,
'uk-table-middle': cellMiddle,
'uk-table-shrink': shrinked,
'uk-table-expand': expanded,
'uk-text-nowrap': unwrapped,
'uk-text-truncate': truncated
}, obj[("uk-width-" + width)] = width, obj)
}), children)
}
}
var ElementTableTr = {
functional: true,
props: {
active: {
type: Boolean,
default: false
}
},
render: function render (h, ref) {
var data = ref.data;
var props = ref.props;
var children = ref.children;
var active = props.active;
return h('tr', mergeData(data, {
class: {
'uk-active': active
}
}), children)
}
}
var ElementTableTh = {
functional: true,
props: {
shrinked: {
type: Boolean,
default: false
},
expanded: {
type: Boolean,
default: false
}
},
render: function render (h, ref) {
var data = ref.data;
var props = ref.props;
var children = ref.children;
var shrinked = props.shrinked;
var expanded = props.expanded;
return h('th', mergeData(data, {
class: {
'uk-table-shrink': shrinked,
'uk-table-expand': expanded
}
}), children)
}
}
var ElementTableThSort = {
functional: true,
props: assign({}, ElementTableTh.props, {
order: {
type: String
}
}),
render: function render (h, ref) {
var data = ref.data;
var props = ref.props;
var children = ref.children;
var order = props.order;
return h(ElementTableTh, mergeData(data, {
class: 'vk-table-column-sort uk-visible-hover-inline'
}), [
h('div', {
class: 'uk-text-nowrap uk-position-relative'
}, [
children,
h('span', mergeData(data, {
class: ['vk-table-column-sort__arrow uk-position-absolute', {
'uk-invisible': !order,
'vk-table-column-sort__arrow--rotated': !order || order === 'asc'
}]
}))
])
])
}
}
var MixinSort = {
props: {
sortedBy: {
type: Object
}
}
}
var MixinSelect = {
props: {
selectedRows: {
type: Array,
default: function () { return []; }
},
rowSelectable: {
type: Boolean,
default: false
},
rowsSelectable: {
type: Boolean,
default: false
}
},
methods: {
selectRow: function selectRow (row) {
var id = row[ROW_ID];
if (this.rowSelectable) {
this.updateRowSelection([id]);
return
}
var selectedRows = [].concat( this.selectedRows );
selectedRows.push(id);
this.updateRowSelection(selectedRows);
},
unselectRow: function unselectRow (row) {
var id = row[ROW_ID];
var index = this.selectedRows.indexOf(id);
var selectedRows = [].concat( this.selectedRows );
selectedRows.splice(index, 1);
this.updateRowSelection(selectedRows);
},
toggleRowSelection: function toggleRowSelection (row) {
this.isRowSelected(row)
? this.unselectRow(row)
: this.selectRow(row);
},
toggleRowsSelection: function toggleRowsSelection () {
var selectedRows = [];
if (!this.allRowsSelected) {
selectedRows = this.rows.map(function (row) { return row[ROW_ID]; });
}
this.updateRowSelection(selectedRows);
},
isRowSelected: function isRowSelected (row) {
return Boolean(this.selectedRows
.filter(function (id) { return JSON.stringify(id) === JSON.stringify(row[ROW_ID]); }).length)
},
updateRowSelection: function updateRowSelection (selectedRows) {
this.$emit(UPDATE_SELECTEDROWS, selectedRows);
}
},
computed: {
allRowsSelected: function allRowsSelected () {
if (this.selectedRows && this.selectedRows.length < this.rows.length) {
return false
}
var selected = this.rows.filter(this.isRowSelected);
return selected.length === this.rows.length
}
},
created: function created () {
if (this.rowsSelectable || this.rowSelectable) {
this.$on(ON_CLICK_ROW, this.toggleRowSelection);
}
}
}
var Row = {
functional: true,
render: function render (h, ref) {
var data = ref.data;
var children = ref.children;
var parent = ref.parent;
var $row = data.$row;
return h(ElementTableTr, {
props: {
active: parent.isRowSelected($row)
},
class: resolveClass(parent.rowClass, $row),
on: {
click: function (e) {
var isPrevented = e[ROW_CLICK_PREVENTED];
var isIgnoredTag = /^(A|BUTTON)$/.test(e.target.tagName);
if (isPrevented || isIgnoredTag) {
return
}
parent.$emit(ON_CLICK_ROW, $row);
}
}
}, children)
}
};
function Render (h, ref) {
var rows = ref.rows;
var props = ref.props;
var columns = ref.columns;
var table = ref.table;
columns = columns.filter(function (node) {
var isValid = node.fnOptions && node.fnOptions.headRender && node.fnOptions.cellRender;
if (process.env.NODE_ENV !== 'production' && !isValid) {
warn('vk-table -> some of the columns were filtered out because they were missing a head or cell render.');
}
return isValid
});
var isHeadless = !columns.some(
function (node) { return node.children || get(node, 'data.props.title') || get(node, 'data.props.head'); }
);
return h(ElementTable, { props: props }, [
isHeadless || h('thead', [
h(ElementTableTr, columns.map(function (node) {
var fnOptions = node.fnOptions;
delete node.data.class;
return h({
functional: true,
render: fnOptions.headRender
}, node.data)
}))
]),
h('tbody', rows.map(function ($row, index) {
return h(Row, { $row: $row },
columns.map(function (node) {
var ref = node.data;
var props = ref.props;
var slots = ref.slots;
var scopedSlots = ref.scopedSlots;
var fnOptions = node.fnOptions;
if (process.env.NODE_ENV !== 'production' && !fnOptions) {
warn('vk-table -> column must be a functional component', table);
}
if (process.env.NODE_ENV !== 'production' && !fnOptions.cellRender) {
warn('vk-table -> column definition is missing cellRender', table);
}
return h({
functional: true,
render: fnOptions.cellRender
}, { $row: $row, props: props, slots: slots, scopedSlots: scopedSlots })
})
)
}))
])
}
function resolveClass (rowClass, row) {
return isFunction(rowClass)
? rowClass(row)
: rowClass
}
var Table = {
name: 'VkTable',
mixins: [ MixinSelect, MixinSort ],
inheritAttrs: false,
props: assign({}, ElementTable.props, {
data: {
type: Array,
required: true
},
rowKey: {
type: String,
default: 'id'
},
rowClass: {
type: Function
}
}),
computed: {
rows: function rows () {
var this$1 = this;
return this.data.map(function (_row, index) {
var row = assign({}, _row);
row[ROW_ID] = row[this$1.rowKey] || index;
return row
})
}
},
render: function render (h) {
var columns = get(this, '$slots.default', []).filter(function (n) { return n.tag; });
return Render(h, {
columns: columns,
table: this,
rows: this.rows,
props: this.$props
})
}
}
var tableTree = {
name: 'VkTableTree',
extends: Table,
props: {
expandedRows: {
type: Array,
default: function () { return []; }
},
childrenKey: {
type: String,
default: 'children'
}
},
computed: {
rows: function rows () {
var this$1 = this;
var rows = [];
var flatten = function (data, parent) {
if ( parent === void 0 ) parent = {};
var idCount = 0;
data.forEach(function (_row) {
var row = assign({}, _row);
var children = row[this$1.childrenKey];
var hasChildren = children && children.length;
row[ROW_LEVEL] = parent[ROW_LEVEL] !== undefined
? parent[ROW_LEVEL] + 1
: 0;
row[ROW_ID] = row[this$1.rowKey]
? row[this$1.rowKey]
: row[ROW_LEVEL] === 0
? ("" + (idCount++))
: ((parent[ROW_ID]) + "_" + (idCount++));
rows.push(row);
if (hasChildren && this$1.isExpanded(row)) {
flatten(children, row);
}
if (hasChildren) {
row[ROW_CHILDREN_COUNT] = children.length;
delete row[this$1.childrenKey];
}
});
};
flatten(this.data);
return rows
},
thereAreSubLevels: function thereAreSubLevels () {
return this.rows.some(function (row) { return row[ROW_CHILDREN_COUNT]; })
}
},
methods: {
isExpanded: function isExpanded (row) {
return Boolean(this.expandedRows
.filter(function (id) { return JSON.stringify(id) === JSON.stringify(row[ROW_ID]); }).length)
},
toggleExpand: function toggleExpand (row) {
var id = row[ROW_ID];
var expandedRows = [].concat( this.expandedRows );
var index = expandedRows.indexOf(id);
var isExpanded = index !== -1;
isExpanded
? expandedRows.splice(index, 1)
: expandedRows.push(id);
this.$emit(UPDATE_EXPANDEDROWS, expandedRows);
}
},
render: function render (h) {
var columns = (this.$slots.default || []).filter(function (n) { return n.tag; });
return Render(h, {
columns: columns,
table: this,
rows: this.rows,
props: this.$props
})
}
}
function RenderCell (h, ctx, defaultContent) {
var props = ctx.props;
var data = ctx.data;
var $row = data.$row;
var cell = props.cell;
var cellClass = props.cellClass;
var cellValue = get($row, cell);
var isEmpty = !isUndefined(cell) && isUndefined(cellValue);
var scope = getCellScope(ctx);
var slots = getCellSlots(ctx);
var slot = isEmpty && slots.empty
? slots.empty
: slots.default || defaultContent;
return h(ElementTableTd, {
props: props,
class: cellClass
}, [
slot(scope)
])
}
function getCellScope (ref) {
var data = ref.data;
var props = ref.props;
var parent = ref.parent;
var $row = data.$row;
var cell = props.cell;
var cellValue = get($row, cell);
var selected = parent.isRowSelected($row);
var allSelected = parent.allRowsSelected;
return { cell: cellValue, row: $row, selected: selected, allSelected: allSelected }
}
function getCellSlots (ref) {
var data = ref.data;
var defaultSlot = get(data, 'slots.default')
? function () { return get(data, 'slots.default'); }
: get(data, 'scopedSlots.default');
var emptySlot = get(data, 'slots.empty')
? function () { return get(data, 'slots.empty'); }
: get(data, 'scopedSlots.empty');
return {
default: defaultSlot,
empty: emptySlot
}
}
var Column = {
name: 'VkTableColumn',
functional: true,
props: assign({}, ElementTableTh.props, ElementTableTd.props, {
cell: String,
title: String,
cellClass: String
}),
render: function render (h, ref) {
var data = ref.data;
var props = ref.props;
var slots = ref.slots;
data.slots = slots();
return h('div', mergeData({}, data, { props: props }))
},
headRender: function headRender (h, ref) {
var data = ref.data;
var props = ref.props;
return h(ElementTableTh, mergeData({}, data, {
props: props,
class: 'vk-table-column'
}), props.title)
},
cellRender: function cellRender (h, ctx) {
return RenderCell(h, ctx, function (ref) {
var cell = ref.cell;
return cell;
})
}
}
var table_ColumnSort = {
name: 'VkTableColumnSort',
functional: true,
props: assign({}, Column.props, ElementTableThSort, {
cell: {
type: String,
required: true
}
}),
render: Column.render,
cellRender: Column.cellRender,
headRender: function headRender (h, ref) {
var data = ref.data;
var props = ref.props;
var children = ref.children;
var parent = ref.parent;
var title = props.title;
if (process.env.NODE_ENV !== 'production' && !parent.sortedBy) {
warn("vk-table-column-sort -> the table 'sortedBy' prop is required when using this column.", parent);
}
return h(ElementTableThSort, mergeData(data, {
props: assign({
order: get(parent, ("sortedBy." + (props.cell)))
}, props),
on: {
click: function (e) {
var sortedBy = getNewSortOrder(parent.sortedBy, props.cell, e.shiftKey);
parent.$emit(UPDATE_SORTEDBY, sortedBy);
}
}
}), title || children)
}
}
function getNewSortOrder (currentSort, by, multi) {
var sort = {};
var order = currentSort[by] === 'asc'
? 'desc'
: 'asc';
sort[by] = order;
return multi
? assign({}, currentSort, sort)
: sort
}
var ElementCheckbox = {
functional: true,
props: ['checked'],
render: function render (h, ref) {
var data = ref.data;
var props = ref.props;
var listeners = ref.listeners;
var def = {
staticClass: 'uk-checkbox',
attrs: {
type: 'checkbox'
},
domProps: {
checked: props.checked
},
on: {
change: function (e) {
e.target.checked = props.checked;
}
}
};
return h('input', mergeData(data, def))
}
}
var table_ColumnSelect = {
name: 'VkTableColumnSelect',
functional: true,
props: assign({}, ElementTableTh.props, {
cellClass: {
type: String
},
headless: {
type: Boolean,
default: false
},
shrinked: {
type: Boolean,
default: true
}
}),
render: Column.render,
headRender: function headRender (h, ref) {
var data = ref.data;
var props = ref.props;
var parent = ref.parent;
var content = props.headless || h('span', {
class: 'uk-form uk-text-center'
}, [
h(ElementCheckbox, {
props: {
checked: parent.allRowsSelected
},
on: {
click: function (e) { return parent.toggleRowsSelection(); }
}
})
]);
return h(ElementTableTh, mergeData(data, {
props: { shrinked: true },
class: 'vk-table-column-select'
}), [ content ])
},
cellRender: function cellRender (h, ctx) {
var parent = ctx.parent;
return RenderCell(h, ctx, function (ref) {
var row = ref.row;
var selected = ref.selected;
return h('span', {
class: 'uk-form uk-text-center'
}, [
h(ElementCheckbox, {
props: { checked: selected },
on: {
click: function (e) { return parent.toggleRowSelection(row); }
}
})
]);
})
}
}
var TreeArrow = {
functional: true,
props: ['rotated'],
render: function (h, ref) {
var listeners = ref.listeners;
var props = ref.props;
return h('span', {
on: listeners,
class: ['vk-table-column-tree__arrow', {
'vk-table-column-tree__arrow--rotated': props.rotated
}]
})
}
};
var TreeIndent = {
functional: true,
render: function (h, ref) {
var children = ref.children;
return h('span', { class: 'vk-table-column-tree__indent' }, children)
}
};
var table_ColumnTree = {
name: 'VkTableTreeColumn',
functional: true,
props: assign({}, Column.props),
render: Column.render,
headRender: Column.headRender,
cellRender: function cellRender (h, ctx) {
var parent = ctx.parent;
return RenderCell(h, ctx, function (ref) {
var row = ref.row;
var cell = ref.cell;
return [
Array(row[ROW_LEVEL]).fill(h(TreeIndent)),
parent.thereAreSubLevels && h(TreeIndent, [
row[ROW_CHILDREN_COUNT] && h(TreeArrow, {
props: {
rotated: parent.isExpanded(row)
},
on: {
click: function (e) {
e[ROW_CLICK_PREVENTED] = true;
parent.toggleExpand(row);
}
}
})
]),
h('span', cell)
];
})
}
}
export { constants, ElementTable, ElementTableTd, ElementTableTr, ElementTableTh, ElementTableThSort, Table, tableTree as TableTree, Column as TableColumn, table_ColumnSort as TableColumnSort, table_ColumnSelect as TableColumnSelect, table_ColumnTree as TableColumnTree };