diff --git a/src/scripts/js/es6/common/api/init.js b/src/scripts/js/es6/common/api/init.js index bbd9898d..dcb2cdb4 100644 --- a/src/scripts/js/es6/common/api/init.js +++ b/src/scripts/js/es6/common/api/init.js @@ -1 +1,3 @@ -export { thenMarkdownToHtml } from './markdown' \ No newline at end of file +export { thenMarkdownToHtml } from './markdown' +export { thenGetProject } from './projects' +export { thenGetNodes } from './nodes' diff --git a/src/scripts/js/es6/common/api/nodes.js b/src/scripts/js/es6/common/api/nodes.js new file mode 100644 index 00000000..053daf80 --- /dev/null +++ b/src/scripts/js/es6/common/api/nodes.js @@ -0,0 +1,8 @@ +function thenGetNodes(where, embedded={}) { + let encodedWhere = encodeURIComponent(JSON.stringify(where)); + let encodedEmbedded = encodeURIComponent(JSON.stringify(embedded)); + + return $.get(`/api/nodes?where=${encodedWhere}&embedded=${encodedEmbedded}`); +} + +export { thenGetNodes } diff --git a/src/scripts/js/es6/common/api/projects.js b/src/scripts/js/es6/common/api/projects.js new file mode 100644 index 00000000..2f813824 --- /dev/null +++ b/src/scripts/js/es6/common/api/projects.js @@ -0,0 +1,5 @@ +function thenGetProject(projectId) { + return $.get(`/api/projects/${projectId}`); +} + +export { thenGetProject } diff --git a/src/scripts/js/es6/common/events/Nodes.js b/src/scripts/js/es6/common/events/Nodes.js new file mode 100644 index 00000000..2be3dfe6 --- /dev/null +++ b/src/scripts/js/es6/common/events/Nodes.js @@ -0,0 +1,92 @@ +class EventName { + static parentCreated(parentId, node_type) { + return `pillar:node:${parentId}:created-${node_type}`; + } + + static globalCreated(node_type) { + return `pillar:node:created-${node_type}`; + } + + static updated(nodeId) { + return `pillar:node:${nodeId}:updated`; + } + + static deleted(nodeId) { + return `pillar:node:${nodeId}:deleted`; + } +} + +class Nodes { + static triggerCreated(node) { + if (node.parent) { + $('body').trigger( + EventName.parentCreated(node.parent, node.node_type), + node); + } + $('body').trigger( + EventName.globalCreated(node.node_type), + node); + } + + static onParentCreated(parentId, node_type, cb){ + $('body').on( + EventName.parentCreated(parentId, node_type), + cb); + } + + static offParentCreated(parentId, node_type, cb){ + $('body').off( + EventName.parentCreated(parentId, node_type), + cb); + } + + static onCreated(node_type, cb){ + $('body').on( + EventName.globalCreated(node_type), + cb); + } + + static offCreated(node_type, cb){ + $('body').off( + EventName.globalCreated(node_type), + cb); + } + + static triggerUpdated(node) { + $('body').trigger( + EventName.updated(node._id), + node); + } + + static onUpdated(nodeId, cb) { + $('body').on( + EventName.updated(nodeId), + cb); + } + + static offUpdated(nodeId, cb) { + $('body').off( + EventName.updated(nodeId), + cb); + } + + static triggerDeleted(nodeId) { + $('body').trigger( + EventName.deleted(nodeId), + nodeId); + } + + static onDeleted(nodeId, cb) { + $('body').on( + EventName.deleted(nodeId), + cb); + } + + static offDeleted(nodeId, cb) { + $('body').off( + EventName.deleted(nodeId), + cb); + } +} + +export { Nodes } diff --git a/src/scripts/js/es6/common/events/init.js b/src/scripts/js/es6/common/events/init.js new file mode 100644 index 00000000..36edc2ec --- /dev/null +++ b/src/scripts/js/es6/common/events/init.js @@ -0,0 +1 @@ +export {Nodes} from './Nodes' diff --git a/src/scripts/js/es6/common/templates/nodes/NodesBase.js b/src/scripts/js/es6/common/templates/nodes/NodesBase.js index 76ad9c17..53789c12 100644 --- a/src/scripts/js/es6/common/templates/nodes/NodesBase.js +++ b/src/scripts/js/es6/common/templates/nodes/NodesBase.js @@ -1,5 +1,4 @@ import { prettyDate } from '../../utils/prettydate'; -import { thenLoadImage } from '../utils'; import { ComponentCreatorInterface } from '../component/ComponentCreatorInterface' export class NodesBase extends ComponentCreatorInterface { @@ -20,7 +19,7 @@ export class NodesBase extends ComponentCreatorInterface { } else { $(window).trigger('pillar:workStart'); - thenLoadImage(node.picture) + pillar.utils.thenLoadImage(node.picture) .fail(warnNoPicture) .then((imgVariation) => { let img = $('') diff --git a/src/scripts/js/es6/common/templates/utils.js b/src/scripts/js/es6/common/templates/utils.js index 36e96d8c..a10abcf7 100644 --- a/src/scripts/js/es6/common/templates/utils.js +++ b/src/scripts/js/es6/common/templates/utils.js @@ -1,24 +1,5 @@ -function thenLoadImage(imgId, size = 'm') { - return $.get('/api/files/' + imgId) - .then((resp)=> { - var show_variation = null; - if (typeof resp.variations != 'undefined') { - for (var variation of resp.variations) { - if (variation.size != size) continue; - show_variation = variation; - break; - } - } - - if (show_variation == null) { - throw 'Image not found: ' + imgId + ' size: ' + size; - } - return show_variation; - }) -} - function thenLoadVideoProgress(nodeId) { return $.get('/api/users/video/' + nodeId + '/progress') } -export { thenLoadImage, thenLoadVideoProgress }; \ No newline at end of file +export { thenLoadVideoProgress }; diff --git a/src/scripts/js/es6/common/utils/files.js b/src/scripts/js/es6/common/utils/files.js new file mode 100644 index 00000000..2b2fe64d --- /dev/null +++ b/src/scripts/js/es6/common/utils/files.js @@ -0,0 +1,20 @@ +function thenLoadImage(imgId, size = 'm') { + return $.get('/api/files/' + imgId) + .then((resp)=> { + var show_variation = null; + if (typeof resp.variations != 'undefined') { + for (var variation of resp.variations) { + if (variation.size != size) continue; + show_variation = variation; + break; + } + } + + if (show_variation == null) { + throw 'Image not found: ' + imgId + ' size: ' + size; + } + return show_variation; + }) +} + +export { thenLoadImage } diff --git a/src/scripts/js/es6/common/utils/init.js b/src/scripts/js/es6/common/utils/init.js index 2f5e7b5b..18ef5307 100644 --- a/src/scripts/js/es6/common/utils/init.js +++ b/src/scripts/js/es6/common/utils/init.js @@ -1,6 +1,7 @@ export { transformPlaceholder } from './placeholder' export { prettyDate } from './prettydate' export { getCurrentUser, initCurrentUser } from './currentuser' +export { thenLoadImage } from './files' export function debounced(fn, delay=1000) { @@ -32,4 +33,4 @@ export function messageFromError(err){ // type xhr probably return xhrErrorResponseMessage(err); } -} \ No newline at end of file +} diff --git a/src/scripts/js/es6/common/utils/prettydate.js b/src/scripts/js/es6/common/utils/prettydate.js index 61a5b441..8438089d 100644 --- a/src/scripts/js/es6/common/utils/prettydate.js +++ b/src/scripts/js/es6/common/utils/prettydate.js @@ -13,7 +13,7 @@ export function prettyDate(time, detail=false) { let second_diff = Math.round((now - theDate) / 1000); let day_diff = Math.round(second_diff / 86400); // seconds per day (60*60*24) - + if ((day_diff < 0) && (theDate.getFullYear() !== now.getFullYear())) { // "Jul 16, 2018" pretty = theDate.toLocaleDateString('en-NL',{day: 'numeric', month: 'short', year: 'numeric'}); @@ -29,7 +29,7 @@ export function prettyDate(time, detail=false) { else pretty = "in " + week_count +" weeks"; } - else if (day_diff < -1) + else if (day_diff < 0) // "next Tuesday" pretty = 'next ' + theDate.toLocaleDateString('en-NL',{weekday: 'long'}); else if (day_diff === 0) { @@ -94,4 +94,4 @@ export function prettyDate(time, detail=false) { } return pretty; -} \ No newline at end of file +} diff --git a/src/scripts/js/es6/common/vuecomponents/customdirectives/click-outside.js b/src/scripts/js/es6/common/vuecomponents/customdirectives/click-outside.js new file mode 100644 index 00000000..1bfa4bca --- /dev/null +++ b/src/scripts/js/es6/common/vuecomponents/customdirectives/click-outside.js @@ -0,0 +1,17 @@ +// Code from https://stackoverflow.com/a/42389266 + +Vue.directive('click-outside', { + bind: function (el, binding, vnode) { + el.clickOutsideEvent = function (event) { + // here I check that click was outside the el and his childrens + if (!(el == event.target || el.contains(event.target))) { + // and if it did, call method provided in attribute value + vnode.context[binding.expression](event); + } + }; + document.body.addEventListener('click', el.clickOutsideEvent) + }, + unbind: function (el) { + document.body.removeEventListener('click', el.clickOutsideEvent) + }, + }); diff --git a/src/scripts/js/es6/common/vuecomponents/init.js b/src/scripts/js/es6/common/vuecomponents/init.js index 343dfa00..66bd1ca8 100644 --- a/src/scripts/js/es6/common/vuecomponents/init.js +++ b/src/scripts/js/es6/common/vuecomponents/init.js @@ -1 +1,38 @@ -import './comments/CommentTree' \ No newline at end of file +import './comments/CommentTree' +import './customdirectives/click-outside' +import { UnitOfWorkTracker } from './mixins/UnitOfWorkTracker' +import { PillarTable } from './table/Table' +import { CellPrettyDate } from './table/cells/renderer/CellPrettyDate' +import { CellDefault } from './table/cells/renderer/CellDefault' +import { ColumnBase } from './table/columns/ColumnBase' +import { ColumnFactoryBase } from './table/columns/ColumnFactoryBase' +import { RowObjectsSourceBase } from './table/rows/RowObjectsSourceBase' +import { RowBase } from './table/rows/RowObjectBase' +import { RowFilter } from './table/filter/RowFilter' + +let mixins = { + UnitOfWorkTracker +} + +let table = { + PillarTable, + columns: { + ColumnBase, + ColumnFactoryBase, + }, + cells: { + renderer: { + CellDefault, + CellPrettyDate + } + }, + rows: { + RowObjectsSourceBase, + RowBase + }, + filter: { + RowFilter + } +} + +export { mixins, table } diff --git a/src/scripts/js/es6/common/vuecomponents/menu/DropDown.js b/src/scripts/js/es6/common/vuecomponents/menu/DropDown.js new file mode 100644 index 00000000..e38d9e41 --- /dev/null +++ b/src/scripts/js/es6/common/vuecomponents/menu/DropDown.js @@ -0,0 +1,42 @@ +const TEMPLATE =` +
+
+ +
+
+ +
+
+`; + +let DropDown = Vue.component('pillar-dropdown', { + template: TEMPLATE, + data() { + return { + showMenu: false + } + }, + computed: { + buttonClasses() { + return {'is-open': this.showMenu}; + } + }, + methods: { + toggleShowMenu(event) { + event.preventDefault(); + event.stopPropagation(); + this.showMenu = !this.showMenu; + }, + closeMenu(event) { + this.showMenu = false; + } + }, +}); + +export { DropDown } diff --git a/src/scripts/js/es6/common/vuecomponents/mixins/UnitOfWorkTracker.js b/src/scripts/js/es6/common/vuecomponents/mixins/UnitOfWorkTracker.js index b1deeb4b..79743fdb 100644 --- a/src/scripts/js/es6/common/vuecomponents/mixins/UnitOfWorkTracker.js +++ b/src/scripts/js/es6/common/vuecomponents/mixins/UnitOfWorkTracker.js @@ -42,7 +42,15 @@ var UnitOfWorkTracker = { methods: { unitOfWork(promise) { this.unitOfWorkBegin(); - return promise.always(this.unitOfWorkDone); + if (promise.always) { + // jQuery Promise + return promise.always(this.unitOfWorkDone); + } + if (promise.finally) { + // Native js Promise + return promise.finally(this.unitOfWorkDone); + } + throw Error('Unsupported promise type'); }, unitOfWorkBegin() { this.unitOfWorkCounter++; @@ -56,4 +64,4 @@ var UnitOfWorkTracker = { } } -export { UnitOfWorkTracker } \ No newline at end of file +export { UnitOfWorkTracker } diff --git a/src/scripts/js/es6/common/vuecomponents/table/Table.js b/src/scripts/js/es6/common/vuecomponents/table/Table.js new file mode 100644 index 00000000..e97357d2 --- /dev/null +++ b/src/scripts/js/es6/common/vuecomponents/table/Table.js @@ -0,0 +1,89 @@ +import './rows/renderer/Head' +import './rows/renderer/Row' +import './filter/ColumnFilter' +import './filter/RowFilter' +import {UnitOfWorkTracker} from '../mixins/UnitOfWorkTracker' + +const TEMPLATE =` +
+
+ + + +
+
+ + + + +
+
+`; + +let PillarTable = Vue.component('pillar-table-base', { + template: TEMPLATE, + mixins: [UnitOfWorkTracker], + // columnFactory, + // rowsSource, + props: { + projectId: String + }, + data: function() { + return { + columns: [], + visibleColumns: [], + visibleRowObjects: [], + rowsSource: {} + } + }, + computed: { + rowObjects() { + return this.rowsSource.rowObjects || []; + } + }, + created() { + let columnFactory = new this.$options.columnFactory(this.projectId); + this.rowsSource = new this.$options.rowsSource(this.projectId); + this.unitOfWork( + Promise.all([ + columnFactory.thenGetColumns(), + this.rowsSource.thenInit() + ]) + .then((resp) => { + this.columns = resp[0]; + }) + ); + }, + methods: { + onVisibleColumnsChanged(visibleColumns) { + this.visibleColumns = visibleColumns; + }, + onVisibleRowObjectsChanged(visibleRowObjects) { + this.visibleRowObjects = visibleRowObjects; + }, + onSort(column, direction) { + function compareRows(r1, r2) { + return column.compareRows(r1, r2) * direction; + } + this.rowObjects.sort(compareRows); + }, + } +}); + +export { PillarTable } diff --git a/src/scripts/js/es6/common/vuecomponents/table/cells/renderer/CellDefault.js b/src/scripts/js/es6/common/vuecomponents/table/cells/renderer/CellDefault.js new file mode 100644 index 00000000..e3c433be --- /dev/null +++ b/src/scripts/js/es6/common/vuecomponents/table/cells/renderer/CellDefault.js @@ -0,0 +1,21 @@ +const TEMPLATE =` +
+ {{ cellValue }} +
+`; + +let CellDefault = Vue.component('pillar-cell-default', { + template: TEMPLATE, + props: { + column: Object, + rowObject: Object, + rawCellValue: Object + }, + computed: { + cellValue() { + return this.rawCellValue; + } + }, +}); + +export { CellDefault } diff --git a/src/scripts/js/es6/common/vuecomponents/table/cells/renderer/CellPrettyDate.js b/src/scripts/js/es6/common/vuecomponents/table/cells/renderer/CellPrettyDate.js new file mode 100644 index 00000000..f158d552 --- /dev/null +++ b/src/scripts/js/es6/common/vuecomponents/table/cells/renderer/CellPrettyDate.js @@ -0,0 +1,12 @@ +import { CellDefault } from './CellDefault' + +let CellPrettyDate = Vue.component('pillar-cell-pretty-date', { + extends: CellDefault, + computed: { + cellValue() { + return pillar.utils.prettyDate(this.rawCellValue); + } + } +}); + +export { CellPrettyDate } diff --git a/src/scripts/js/es6/common/vuecomponents/table/cells/renderer/CellProxy.js b/src/scripts/js/es6/common/vuecomponents/table/cells/renderer/CellProxy.js new file mode 100644 index 00000000..51570895 --- /dev/null +++ b/src/scripts/js/es6/common/vuecomponents/table/cells/renderer/CellProxy.js @@ -0,0 +1,34 @@ +const TEMPLATE =` + +`; + +let CellProxy = Vue.component('pillar-cell-proxy', { + template: TEMPLATE, + props: { + column: Object, + rowObject: Object + }, + computed: { + rawCellValue() { + return this.column.getRawCellValue(this.rowObject) || ''; + }, + cellRenderer() { + return this.column.getCellRenderer(this.rowObject); + }, + cellClasses() { + return this.column.getCellClasses(this.rawCellValue, this.rowObject); + }, + cellTitle() { + return this.column.getCellTitle(this.rawCellValue, this.rowObject); + } + }, +}); + +export { CellProxy } diff --git a/src/scripts/js/es6/common/vuecomponents/table/cells/renderer/HeadCell.js b/src/scripts/js/es6/common/vuecomponents/table/cells/renderer/HeadCell.js new file mode 100644 index 00000000..97facd37 --- /dev/null +++ b/src/scripts/js/es6/common/vuecomponents/table/cells/renderer/HeadCell.js @@ -0,0 +1,43 @@ +const TEMPLATE =` +
+
+ {{ column.displayName }} +
+ + +
+
+
+`; + +Vue.component('pillar-head-cell', { + template: TEMPLATE, + props: { + column: Object + }, + computed: { + cellClasses() { + return this.column.getHeaderCellClasses(); + } + }, + methods: { + onMouseEnter() { + this.column.highlightColumn(true); + }, + onMouseLeave() { + this.column.highlightColumn(false); + }, + }, +}); diff --git a/src/scripts/js/es6/common/vuecomponents/table/columns/ColumnBase.js b/src/scripts/js/es6/common/vuecomponents/table/columns/ColumnBase.js new file mode 100644 index 00000000..29cfa8f9 --- /dev/null +++ b/src/scripts/js/es6/common/vuecomponents/table/columns/ColumnBase.js @@ -0,0 +1,85 @@ +import { CellDefault } from '../cells/renderer/CellDefault' + +let nextColumnId = 0; +export class ColumnBase { + constructor(displayName, columnType) { + this._id = nextColumnId++; + this.displayName = displayName; + this.columnType = columnType; + this.isMandatory = false; + this.isSortable = true; + this.isHighLighted = 0; + } + + /** + * + * @param {*} rowObject + * @returns {String} Name of the Cell renderer component + */ + getCellRenderer(rowObject) { + return CellDefault.options.name; + } + + getRawCellValue(rowObject) { + // Should be overridden + throw Error('Not implemented'); + } + + /** + * Cell tooltip + * @param {Any} rawCellValue + * @param {RowObject} rowObject + * @returns {String} + */ + getCellTitle(rawCellValue, rowObject) { + // Should be overridden + return ''; + } + + /** + * Object with css classes to use on the header cell + * @returns {Any} Object with css classes + */ + getHeaderCellClasses() { + // Should be overridden + let classes = {} + classes[this.columnType] = true; + return classes; + } + + /** + * Object with css classes to use on the cell + * @param {*} rawCellValue + * @param {*} rowObject + * @returns {Any} Object with css classes + */ + getCellClasses(rawCellValue, rowObject) { + // Should be overridden + let classes = {} + classes[this.columnType] = true; + classes['highlight'] = !!this.isHighLighted; + return classes; + } + + /** + * Compare two rows to sort them. Can be overridden for more complex situations. + * + * @param {RowObject} rowObject1 + * @param {RowObject} rowObject2 + * @returns {Number} -1, 0, 1 + */ + compareRows(rowObject1, rowObject2) { + let rawCellValue1 = this.getRawCellValue(rowObject1); + let rawCellValue2 = this.getRawCellValue(rowObject2); + if (rawCellValue1 === rawCellValue2) return 0; + return rawCellValue1 < rawCellValue2 ? -1 : 1; + } + + /** + * + * @param {Boolean} + */ + highlightColumn(value) { + this.isHighLighted += !!value ? 1 : -1; + } +} diff --git a/src/scripts/js/es6/common/vuecomponents/table/columns/ColumnFactoryBase.js b/src/scripts/js/es6/common/vuecomponents/table/columns/ColumnFactoryBase.js new file mode 100644 index 00000000..18c1fa6a --- /dev/null +++ b/src/scripts/js/es6/common/vuecomponents/table/columns/ColumnFactoryBase.js @@ -0,0 +1,21 @@ +class ColumnFactoryBase{ + constructor(projectId) { + this.projectId = projectId; + this.projectPromise; + } + + // Override this + thenGetColumns() { + throw Error('Not implemented') + } + + thenGetProject() { + if (this.projectPromise) { + return this.projectPromise; + } + this.projectPromise = pillar.api.thenGetProject(this.projectId); + return this.projectPromise; + } +} + +export { ColumnFactoryBase } diff --git a/src/scripts/js/es6/common/vuecomponents/table/columns/renderer/Column.js b/src/scripts/js/es6/common/vuecomponents/table/columns/renderer/Column.js new file mode 100644 index 00000000..d22392bc --- /dev/null +++ b/src/scripts/js/es6/common/vuecomponents/table/columns/renderer/Column.js @@ -0,0 +1,10 @@ +const TEMPLATE =` +
+`; + +Vue.component('pillar-table-column', { + template: TEMPLATE, + props: { + column: Object + }, +}); diff --git a/src/scripts/js/es6/common/vuecomponents/table/filter/ColumnFilter.js b/src/scripts/js/es6/common/vuecomponents/table/filter/ColumnFilter.js new file mode 100644 index 00000000..222e9532 --- /dev/null +++ b/src/scripts/js/es6/common/vuecomponents/table/filter/ColumnFilter.js @@ -0,0 +1,80 @@ +import '../../menu/DropDown' + +const TEMPLATE =` +
+ + + +
    + Columns: +
  • + + {{ c.displayName }} +
  • +
+
+
+`; + +let Filter = Vue.component('pillar-table-column-filter', { + template: TEMPLATE, + props: { + columns: Array, + }, + data() { + return { + columnStates: [], + } + }, + computed: { + visibleColumns() { + return this.columns.filter((candidate) => { + return candidate.isMandatory || this.isColumnStateVisible(candidate); + }); + } + }, + watch: { + columns() { + this.columnStates = this.setColumnStates(); + }, + visibleColumns(visibleColumns) { + this.$emit('visibleColumnsChanged', visibleColumns); + } + }, + created() { + this.$emit('visibleColumnsChanged', this.visibleColumns); + }, + methods: { + setColumnStates() { + return this.columns.reduce((states, c) => { + if (!c.isMandatory) { + states.push({ + _id: c._id, + displayName: c.displayName, + isVisible: true, + }); + } + return states; + }, []) + }, + isColumnStateVisible(column) { + for (let state of this.columnStates) { + if (state._id === column._id) { + return state.isVisible; + } + } + return false; + }, + }, +}); + +export { Filter } diff --git a/src/scripts/js/es6/common/vuecomponents/table/filter/RowFilter.js b/src/scripts/js/es6/common/vuecomponents/table/filter/RowFilter.js new file mode 100644 index 00000000..098627a2 --- /dev/null +++ b/src/scripts/js/es6/common/vuecomponents/table/filter/RowFilter.js @@ -0,0 +1,45 @@ +const TEMPLATE =` +
+ +
+`; + +let RowFilter = Vue.component('pillar-table-row-filter', { + template: TEMPLATE, + props: { + rowObjects: Array + }, + data() { + return { + nameQuery: '', + } + }, + computed: { + nameQueryLoweCase() { + return this.nameQuery.toLowerCase(); + }, + visibleRowObjects() { + return this.rowObjects.filter((row) => { + return this.filterByName(row); + }); + } + }, + watch: { + visibleRowObjects(visibleRowObjects) { + this.$emit('visibleRowObjectsChanged', visibleRowObjects); + } + }, + created() { + this.$emit('visibleRowObjectsChanged', this.visibleRowObjects); + }, + methods: { + filterByName(rowObject) { + return rowObject.getName().toLowerCase().indexOf(this.nameQueryLoweCase) !== -1; + }, + }, +}); + +export { RowFilter } diff --git a/src/scripts/js/es6/common/vuecomponents/table/rows/RowObjectBase.js b/src/scripts/js/es6/common/vuecomponents/table/rows/RowObjectBase.js new file mode 100644 index 00000000..a8fde3ed --- /dev/null +++ b/src/scripts/js/es6/common/vuecomponents/table/rows/RowObjectBase.js @@ -0,0 +1,31 @@ +class RowBase { + constructor(underlyingObject) { + this.underlyingObject = underlyingObject; + this.isInitialized = false; + } + + thenInit() { + this.isInitialized = true + return Promise.resolve(); + } + + getName() { + return this.underlyingObject.name; + } + + getId() { + return this.underlyingObject._id; + } + + getProperties() { + return this.underlyingObject.properties; + } + + getRowClasses() { + return { + "is-busy": !this.isInitialized + } + } +} + +export { RowBase } diff --git a/src/scripts/js/es6/common/vuecomponents/table/rows/RowObjectsSourceBase.js b/src/scripts/js/es6/common/vuecomponents/table/rows/RowObjectsSourceBase.js new file mode 100644 index 00000000..6b88d22a --- /dev/null +++ b/src/scripts/js/es6/common/vuecomponents/table/rows/RowObjectsSourceBase.js @@ -0,0 +1,13 @@ +class RowObjectsSourceBase { + constructor(projectId) { + this.projectId = projectId; + this.rowObjects = []; + } + + // Override this + thenInit() { + throw Error('Not implemented'); + } +} + +export { RowObjectsSourceBase } diff --git a/src/scripts/js/es6/common/vuecomponents/table/rows/renderer/Head.js b/src/scripts/js/es6/common/vuecomponents/table/rows/renderer/Head.js new file mode 100644 index 00000000..d71a88b2 --- /dev/null +++ b/src/scripts/js/es6/common/vuecomponents/table/rows/renderer/Head.js @@ -0,0 +1,18 @@ +import '../../cells/renderer/HeadCell' +const TEMPLATE =` +
+ +
+`; + +Vue.component('pillar-table-head', { + template: TEMPLATE, + props: { + columns: Array + } +}); diff --git a/src/scripts/js/es6/common/vuecomponents/table/rows/renderer/Row.js b/src/scripts/js/es6/common/vuecomponents/table/rows/renderer/Row.js new file mode 100644 index 00000000..b5581311 --- /dev/null +++ b/src/scripts/js/es6/common/vuecomponents/table/rows/renderer/Row.js @@ -0,0 +1,27 @@ +import '../../cells/renderer/CellProxy' + +const TEMPLATE =` +
+ +
+`; + +Vue.component('pillar-table-row', { + template: TEMPLATE, + props: { + rowObject: Object, + columns: Array + }, + computed: { + rowClasses() { + return this.rowObject.getRowClasses(); + } + } +}); diff --git a/src/styles/components/_base.sass b/src/styles/components/_base.sass index e938f6e3..b0ddd7e3 100644 --- a/src/styles/components/_base.sass +++ b/src/styles/components/_base.sass @@ -11,6 +11,9 @@ body max-width: 100% min-width: auto +.page-body + height: 100% + body.has-overlay overflow: hidden padding-right: 5px @@ -24,6 +27,7 @@ body.has-overlay .page-content background-color: $white + height: 100% .container-box +container-box