UNPKG

vuikit

Version:

A responsive Vue UI library for web site interfaces based on UIkit

747 lines (725 loc) 19.5 kB
/** * 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 };