@vaadin/vaadin-crud
Advanced tools
Comparing version 1.0.0-alpha3 to 1.0.0-alpha4
@@ -13,3 +13,3 @@ { | ||
"name": "@vaadin/vaadin-crud", | ||
"version": "1.0.0-alpha3", | ||
"version": "1.0.0-alpha4", | ||
"main": "vaadin-crud.js", | ||
@@ -42,3 +42,3 @@ "author": "Vaadin Ltd", | ||
"@vaadin/vaadin-dialog": "^2.2.0-alpha1", | ||
"@vaadin/vaadin-grid": "5.2.0-alpha2", | ||
"@vaadin/vaadin-grid": "^5.2.0-alpha1", | ||
"@vaadin/vaadin-form-layout": "^2.1.0", | ||
@@ -45,0 +45,0 @@ "@vaadin/vaadin-text-field": "^2.1.1", |
@@ -28,12 +28,25 @@ /** | ||
/** | ||
* A RegExp used to exclude properties in the item that do not need | ||
* to be mapped to form fields. | ||
* A list of item fields that should not be mapped to form fields. | ||
* | ||
* Default is not to exclude any property. | ||
* When [`include`](#/elements/vaadin-crud-form#property-include) is defined, this property is ignored. | ||
* | ||
* Default is to exclude any private property. | ||
* | ||
* @type{String|RegExp} | ||
*/ | ||
exclude: { | ||
type: RegExp, | ||
value: '^_', | ||
observer: '__onExcludeChange' | ||
}, | ||
/** | ||
* A list of item properties that should be mapped to form fields. | ||
* | ||
* When it is defined [`exclude`](#/elements/vaadin-crud-form#property-exclude) is ignored. | ||
* | ||
* @type{String|Array} | ||
*/ | ||
include: { | ||
observer: '__onIncludeChange' | ||
}, | ||
/** | ||
* The item being edited. | ||
@@ -63,6 +76,16 @@ */ | ||
if (typeof exclude == 'string') { | ||
this.exclude = RegExp(exclude, 'i'); | ||
this.exclude = exclude ? RegExp(exclude.replace(/, */g, '|'), 'i') : undefined; | ||
} | ||
} | ||
__onIncludeChange(include) { | ||
if (typeof include == 'string') { | ||
this.include = include ? include.split(/, */) : undefined; | ||
} else if (!this._fields && Array.isArray(include)) { | ||
const item = {}; | ||
this.include.forEach(path => this.__set(path, null, item)); | ||
this.configure(item); | ||
} | ||
} | ||
__onItemChange(item) { | ||
@@ -85,17 +108,15 @@ if (!this._fields) { | ||
__createFields(parent, object, path) { | ||
if (typeof object === 'object') { | ||
Object.keys(object).forEach(prop => { | ||
if (this.exclude && this.exclude.test(prop)) { | ||
return; | ||
} | ||
const newPath = (path ? `${path}.` : '') + prop; | ||
if (typeof object[prop] === 'object') { | ||
this.__createFields(parent, object[prop], newPath); | ||
} else { | ||
this.__createField(parent, newPath); | ||
} | ||
}); | ||
if (!this._fields.length) { | ||
this._fields = undefined; | ||
Object.keys(object).forEach(prop => { | ||
if (!this.include && this.exclude && this.exclude.test(prop)) { | ||
return; | ||
} | ||
const newPath = (path ? `${path}.` : '') + prop; | ||
if (object[prop] && typeof object[prop] === 'object') { | ||
this.__createFields(parent, object[prop], newPath); | ||
} else { | ||
this.__createField(parent, newPath); | ||
} | ||
}); | ||
if (!this._fields.length) { | ||
this._fields = undefined; | ||
} | ||
@@ -107,2 +128,9 @@ } | ||
} | ||
__set(path, val, obj) { | ||
if (obj && path) { | ||
path.split('.').slice(0, -1).reduce((o, p) => (o[p] = o[p] || {}), obj); | ||
this.set(path, val, obj); | ||
} | ||
} | ||
} | ||
@@ -109,0 +137,0 @@ |
@@ -13,3 +13,3 @@ /** | ||
import '@vaadin/vaadin-grid/src/vaadin-grid-filter.js'; | ||
import './vaadin-crud-grid-edit-column.js'; | ||
import './vaadin-crud-edit-column.js'; | ||
@@ -45,11 +45,25 @@ /** | ||
/** | ||
* A RegExp used to exclude properties in the item that do not need | ||
* to be mapped to columns. | ||
* A list of item fields that should not be mapped to columns. | ||
* | ||
* Default is not to exclude any property. | ||
* When [`include`](#/elements/vaadin-crud-grid#property-include) is defined, this property is ignored. | ||
* | ||
* Default is to exclude any private property. | ||
* | ||
* @type{String|RegExp} | ||
*/ | ||
exclude: { | ||
type: RegExp, | ||
type: String, | ||
value: '^_', | ||
observer: '__onExcludeChange' | ||
}, | ||
/** | ||
* A list of item properties that should be mapped to columns. | ||
* | ||
* When it is defined [`exclude`](#/elements/vaadin-crud-grid#property-exclude) is ignored. | ||
* | ||
* @type{String|Array} | ||
*/ | ||
include: { | ||
observer: '__onIncludeChange' | ||
} | ||
}; | ||
@@ -64,9 +78,18 @@ } | ||
if (typeof exclude == 'string') { | ||
this.exclude = RegExp(exclude, 'i'); | ||
this.exclude = exclude ? RegExp(exclude.replace(/, */g, '|'), 'i') : undefined; | ||
} | ||
} | ||
__onIncludeChange(include) { | ||
if (typeof include == 'string') { | ||
this.include = include ? include.split(/, */) : undefined; | ||
} else if (!this._fields && Array.isArray(include)) { | ||
const item = {}; | ||
this.include.forEach(path => this.__set(path, null, item)); | ||
this.__configure(item); | ||
} | ||
} | ||
__onItemsChange(items) { | ||
if ((!this.dataProvider || this.dataProvider == this._arrayDataProvider) && items && items[0]) { | ||
this.innerHTML = ''; | ||
if ((!this.dataProvider || this.dataProvider == this._arrayDataProvider) && !this.include && items && items[0]) { | ||
this.__configure(items[0]); | ||
@@ -78,3 +101,3 @@ } | ||
this.__dataProvider(params, (items, size) => { | ||
if (this.innerHTML == '' && items[0]) { | ||
if (this.innerHTML == '' && !this.include && items[0]) { | ||
this.__configure(items[0]); | ||
@@ -102,4 +125,5 @@ } | ||
__configure(item) { | ||
this.innerHTML = ''; | ||
this.__createColumns(this, item); | ||
this.appendChild(document.createElement('vaadin-crud-grid-edit-column')); | ||
this.appendChild(document.createElement('vaadin-crud-edit-column')); | ||
} | ||
@@ -157,7 +181,7 @@ | ||
Object.keys(object).forEach(prop => { | ||
if (this.exclude && this.exclude.test(prop)) { | ||
if (!this.include && this.exclude && this.exclude.test(prop)) { | ||
return; | ||
} | ||
const newPath = (path ? `${path}.` : '') + prop; | ||
if (typeof object[prop] === 'object') { | ||
if (object[prop] && typeof object[prop] === 'object') { | ||
const group = this.noHead ? parent : this.__createGroup(parent, newPath, object[prop]); | ||
@@ -184,2 +208,9 @@ this.__createColumns(group, object[prop], newPath); | ||
} | ||
__set(path, val, obj) { | ||
if (obj && path) { | ||
path.split('.').slice(0, -1).reduce((o, p) => (o[p] = o[p] || {}), obj); | ||
this.set(path, val, obj); | ||
} | ||
} | ||
} | ||
@@ -186,0 +217,0 @@ |
@@ -19,3 +19,2 @@ /** | ||
import { FlattenedNodesObserver } from '@polymer/polymer/lib/utils/flattened-nodes-observer.js'; | ||
import { GridElement } from '@vaadin/vaadin-grid/src/vaadin-grid.js'; | ||
/** | ||
@@ -33,4 +32,3 @@ * `<vaadin-crud>` is a Web Component for [CRUD](https://en.wikipedia.org/wiki/Create,_read,_update_and_delete) operations. | ||
* <vaadin-crud items='[{"name": "John", "surname": "Lennon", "role": "singer"}, | ||
* {"name": "Ringo", "surname": "Starr", "role": "drums"}]'> | ||
* </vaadin-crud> | ||
* {"name": "Ringo", "surname": "Starr", "role": "drums"}]'></vaadin-crud> | ||
* ``` | ||
@@ -54,7 +52,15 @@ * | ||
* | ||
* NOTE: The autogenerated editor only supports string types. If you need to handle special cases | ||
* customizing the editor is discussed below. | ||
* | ||
* ### Customization | ||
* | ||
* Alternatively you can fully configure the component by providing your own Grid and Editor and Footer content. | ||
* Alternatively you can fully configure the component by using `slot` names. | ||
* | ||
* NOTE: that you need to provide a `vaadin-crud-grid-edit-column`. | ||
* Slot name | Description | ||
* ----------------|---------------- | ||
* `slot=grid` | To replace the autogenerated grid with a custom one. | ||
* `slot=form` | To replace the autogenerated form. | ||
* `slot=footer` | To add some content to the toolbar. | ||
* `slot=new` | For customizing the 'new item' button. | ||
* | ||
@@ -65,4 +71,5 @@ * #### Example: | ||
* {"name": "Ringo", "surname": "Starr", "role": "drums"}]'> | ||
* | ||
* <vaadin-grid slot="grid"> | ||
* <vaadin-crud-grid-edit-column></vaadin-crud-grid-edit-column> | ||
* <vaadin-crud-edit-column></vaadin-crud-edit-column> | ||
* <vaadin-grid-column> | ||
@@ -75,2 +82,3 @@ * <template class="header">Name</template><template>[[item.name]]</template> | ||
* </vaadin-grid> | ||
* | ||
* <vaadin-form-layout slot="form"> | ||
@@ -80,16 +88,14 @@ * <vaadin-text-field label="First" path="name"></vaadin-text-field> | ||
* </vaadin-form-layout> | ||
* <div slot="footer">Total Users: [[size]]</div> | ||
* | ||
* <div slot="footer">Total singers: [[size]]</div> | ||
* | ||
* <button slot="new">New singer</button> | ||
* </vaadin-crud> | ||
* ``` | ||
* ```js | ||
* const crud = document.querySelector('vaadin-crud'); | ||
* const users = [{'name': 'John', 'surname': 'Lennon', 'role': 'singer'}, ...]; | ||
* crud.dataProvider = function(params, callback) { | ||
* const chunk = users.slice(params.page * params.pageSize, params.page * params.pageSize + params.pageSize); | ||
* callback(chunk, people.length); | ||
* }; | ||
* ``` | ||
* | ||
* The following helper elements are used to autofonfigure CRUD grid and editor | ||
* ### Helpers | ||
* | ||
* The following elements are used to autoconfigure the grid and the editor | ||
* - [`<vaadin-crud-grid>`](#/elements/vaadin-crud-grid) | ||
* - [`<vaadin-crud-edit-column>`](#/elements/vaadin-crud-edit-column) | ||
* - [`<vaadin-crud-form>`](#/elements/vaadin-crud-form) | ||
@@ -103,3 +109,3 @@ * | ||
* ----------------|---------------- | ||
* `toolbar` | Toolbar container. | ||
* `toolbar` | Toolbar container at the bottom. It contains the `footer` and the `new` button | ||
* `footer` | The footer container in the toolbar. | ||
@@ -143,3 +149,3 @@ * | ||
<slot name="grid"> | ||
<vaadin-crud-grid id="grid" exclude="[[exclude]]" no-sort="[[noSort]]" no-filter="[[noFilter]]" no-head="[[noHead]]"></vaadin-crud-grid> | ||
<vaadin-crud-grid theme\$="[[theme]]" id="grid" include="[[include]]" exclude="[[exclude]]" no-sort="[[noSort]]" no-filter="[[noFilter]]" no-head="[[noHead]]"></vaadin-crud-grid> | ||
</slot> | ||
@@ -150,11 +156,11 @@ | ||
<slot name="new"> | ||
<vaadin-button id="new">[[i18n.new]]</vaadin-button> | ||
<vaadin-button id="new">[[i18n.newItem]]</vaadin-button> | ||
</slot> | ||
</div> | ||
<vaadin-dialog-layout id="dialog" no-close-on-outside-click="[[__isDirty]]" no-close-on-esc="[[__isDirty]]" opened="{{opened}}" theme="crud"> | ||
<vaadin-dialog-layout theme\$="[[theme]]" id="dialog" no-close-on-outside-click="[[__isDirty]]" no-close-on-esc="[[__isDirty]]" opened="{{editorOpened}}" theme="crud"> | ||
<h3 slot="header">[[__editorHeader]]</h3> | ||
<div id="editor"> | ||
<slot name="form"> | ||
<vaadin-crud-form id="form" exclude="[[exclude]]"></vaadin-crud-form> | ||
<vaadin-crud-form theme\$="[[theme]]" id="form" include="[[include]]"></vaadin-crud-form> | ||
</slot> | ||
@@ -169,6 +175,6 @@ </div> | ||
<vaadin-confirm-dialog id="confirmCancel" on-reject="__confirmCancel" reject="" reject-text="[[i18n.confirm.cancel.button.continue]]" confirm-text="[[i18n.confirm.cancel.button.cancel]]" header="[[i18n.confirm.cancel.header]]"> | ||
<vaadin-confirm-dialog theme\$="[[theme]]" id="confirmCancel" on-confirm="__confirmCancel" cancel="" confirm-text="[[i18n.confirm.cancel.button.ok]]" cancel-text="[[i18n.confirm.cancel.button.cancel]]" header="[[i18n.confirm.cancel.header]]" confirm-theme="primary error"> | ||
[[i18n.confirm.cancel.message]] | ||
</vaadin-confirm-dialog> | ||
<vaadin-confirm-dialog id="confirmDelete" on-confirm="__confirmDelete" cancel="" confirm-text="[[i18n.confirm.delete.button.continue]]" reject-text="[[i18n.confirm.delete.button.cancel]]" header="[[i18n.confirm.delete.header]]" confirm-theme="error"> | ||
<vaadin-confirm-dialog theme\$="[[theme]]" id="confirmDelete" on-confirm="__confirmDelete" cancel="" confirm-text="[[i18n.confirm.delete.button.ok]]" cancel-text="[[i18n.confirm.delete.button.cancel]]" header="[[i18n.confirm.delete.header]]" confirm-theme="primary error"> | ||
[[i18n.confirm.delete.message]] | ||
@@ -184,3 +190,3 @@ </vaadin-confirm-dialog> | ||
static get version() { | ||
return '1.0.0-alpha3'; | ||
return '1.0.0-alpha4'; | ||
} | ||
@@ -200,2 +206,7 @@ | ||
}, | ||
/** The theme to use and to apply to the generated elements */ | ||
theme: { | ||
type: String, | ||
reflectToAttribute: true | ||
}, | ||
/** | ||
@@ -206,2 +217,3 @@ * An array containing the items which will be stamped to the column template instances. | ||
type: Array, | ||
notify: true, | ||
observer: '__onItemsChange' | ||
@@ -212,3 +224,3 @@ }, | ||
*/ | ||
item: { | ||
editedItem: { | ||
type: Object, | ||
@@ -246,15 +258,23 @@ observer: '__onItemChange' | ||
/** | ||
* A regular expression string to applied to fields that will be exclude | ||
* when using autoconfigured elements. | ||
* A comma-separated list of fields to include in the generated grid and the generated editor. | ||
* | ||
* Default is `/^_` meaning that all protected properties are excluded | ||
* It can be used to explicitly define the field order. | ||
* | ||
* When it is defined [`exclude`](#/elements/vaadin-crud#property-exclude) is ignored. | ||
* | ||
* Default is undefined meaning that all properties in the object should be mapped to fields. | ||
*/ | ||
exclude: { | ||
type: String, | ||
value: '^_' | ||
}, | ||
include: String, | ||
/** | ||
* A comma-separated list of fields to be excluded from the generated grid and the generated editor. | ||
* | ||
* When [`include`](#/elements/vaadin-crud#property-include) is defined, this parameter is ignored. | ||
* | ||
* Default is to exclude all private fields (those properties starting with underscore) | ||
*/ | ||
exclude: String, | ||
/** | ||
* Reflects the opened status of the editor. | ||
*/ | ||
opened: { | ||
editorOpened: { | ||
type: Boolean, | ||
@@ -266,2 +286,3 @@ notify: true, | ||
* Number of items in the data set which is reported by the grid. | ||
* Typically it refects the number of filtered items displayed in the grid. | ||
*/ | ||
@@ -281,4 +302,4 @@ size: { | ||
{ | ||
new: 'New item', | ||
edit: 'Edit item', | ||
newItem: 'New item', | ||
editItem: 'Edit item', | ||
save: 'Save', | ||
@@ -292,3 +313,3 @@ cancel: 'Cancel', | ||
button: { | ||
continue: 'Delete', | ||
ok: 'Delete', | ||
cancel: 'Cancel' | ||
@@ -299,5 +320,5 @@ } | ||
header: 'Unsaved changes', | ||
prefix: 'There are unsaved modifications to the item.', | ||
message: 'There are unsaved modifications to the item.', | ||
button: { | ||
continue: 'Discard changes', | ||
ok: 'Discard', | ||
cancel: 'Continue editing' | ||
@@ -316,4 +337,4 @@ } | ||
return { | ||
new: 'New item', | ||
edit: 'Edit item', | ||
newItem: 'New item', | ||
editItem: 'Edit item', | ||
save: 'Save', | ||
@@ -327,3 +348,3 @@ cancel: 'Cancel', | ||
button: { | ||
continue: 'Delete', | ||
ok: 'Delete', | ||
cancel: 'Cancel' | ||
@@ -334,5 +355,5 @@ } | ||
header: 'Unsaved changes', | ||
prefix: 'There are unsaved modifications to the item.', | ||
message: 'There are unsaved modifications to the item.', | ||
button: { | ||
continue: 'Discard changes', | ||
ok: 'Discard', | ||
cancel: 'Continue editing' | ||
@@ -371,3 +392,3 @@ } | ||
} else { | ||
this.__editorHeader = this.__isNew ? this.i18n.new : this.i18n.edit; | ||
this.__editorHeader = this.__isNew ? this.i18n.newItem : this.i18n.editItem; | ||
this.__onFormChange(this._form); | ||
@@ -379,8 +400,9 @@ } | ||
nodes.forEach(node => { | ||
if (node instanceof GridElement) { | ||
this._grid = node; | ||
if (node.getAttribute) { | ||
if (node.getAttribute('slot') == 'grid') { | ||
this._grid = node; | ||
} else if (node.getAttribute('slot') == 'form') { | ||
this._form = node; | ||
} | ||
} | ||
if (node.getAttribute && node.getAttribute('slot') === 'form') { | ||
this._form = node; | ||
} | ||
}); | ||
@@ -407,10 +429,7 @@ } | ||
} | ||
if (grid != this.$.grid) { | ||
grid.setAttribute('slot', 'grid'); | ||
} | ||
if (this.items) { | ||
this.__onItemsChange(this.items); | ||
} | ||
if (this.item) { | ||
this.__onItemChange(this.item); | ||
if (this.editedItem) { | ||
this.__onItemChange(this.editedItem); | ||
} | ||
@@ -426,2 +445,3 @@ grid.addEventListener('edit', this.__editListener); | ||
old.removeEventListener('change', this.__changeListener); | ||
old.removeEventListener('input', this.__changeListener); | ||
} | ||
@@ -434,4 +454,4 @@ if (!form) { | ||
} | ||
if (this.item) { | ||
this.__onItemChange(this.item); | ||
if (this.editedItem) { | ||
this.__onItemChange(this.editedItem); | ||
} | ||
@@ -443,2 +463,3 @@ if (this.$.form != form) { | ||
form.addEventListener('change', this.__changeListener); | ||
form.addEventListener('input', this.__changeListener); | ||
} | ||
@@ -474,3 +495,3 @@ | ||
this.__isNew = this.__isNew || this.items && this.items.indexOf(item) < 0; | ||
this.opened = !!item; | ||
this.editorOpened = !!item; | ||
} | ||
@@ -491,3 +512,3 @@ | ||
__closeEditor() { | ||
this.opened = false; | ||
this.editorOpened = false; | ||
// Delay changing the item in order not to modify editor while closing | ||
@@ -513,5 +534,5 @@ setTimeout(() => this.item = undefined); | ||
if (evt) { | ||
this.item = item || {}; | ||
this.editedItem = item || {}; | ||
} else { | ||
this.opened = true; | ||
this.editorOpened = true; | ||
} | ||
@@ -525,11 +546,15 @@ } | ||
const item = this.item || {}; | ||
const item = this.editedItem || {}; | ||
this._fields.forEach(e => { | ||
const path = e.path || e.getAttribute('path'); | ||
path && this.__set(path, e.value, this.item); | ||
path && this.__set(path, e.value, this.editedItem); | ||
}); | ||
const evt = this.dispatchEvent(new CustomEvent('save', {detail: {item: item}, cancelable: true})); | ||
if (evt) { | ||
if (this.__isNew && this.items) { | ||
this.items.push(item); | ||
if (this.__isNew && !this.dataProvider) { | ||
if (!this.items) { | ||
this.items = [item]; | ||
} else { | ||
this.items.push(item); | ||
} | ||
} | ||
@@ -556,3 +581,3 @@ this._grid.clearCache(); | ||
__confirmCancel() { | ||
const evt = this.dispatchEvent(new CustomEvent('cancel', {detail: {item: this.item}, cancelable: true})); | ||
const evt = this.dispatchEvent(new CustomEvent('cancel', {detail: {item: this.editedItem}, cancelable: true})); | ||
if (evt) { | ||
@@ -569,6 +594,6 @@ this.__closeEditor(); | ||
__confirmDelete() { | ||
const evt = this.dispatchEvent(new CustomEvent('delete', {detail: {item: this.item}, cancelable: true})); | ||
const evt = this.dispatchEvent(new CustomEvent('delete', {detail: {item: this.editedItem}, cancelable: true})); | ||
if (evt) { | ||
if (this.items && this.items.indexOf(this.item) >= 0) { | ||
this.items.splice(this.items.indexOf(this.item), 1); | ||
if (this.items && this.items.indexOf(this.editedItem) >= 0) { | ||
this.items.splice(this.items.indexOf(this.editedItem), 1); | ||
} | ||
@@ -575,0 +600,0 @@ this._grid.clearCache(); |
@@ -14,3 +14,2 @@ /** | ||
import { html } from '@polymer/polymer/lib/utils/html-tag.js'; | ||
/** | ||
@@ -17,0 +16,0 @@ * `<vaadin-dialog-layout>` configures a `vaadin-dialog` with a layout |
import '@vaadin/vaadin-lumo-styles/typography.js'; | ||
import '@vaadin/vaadin-lumo-styles/color.js'; | ||
import '@vaadin/vaadin-lumo-styles/font-icons.js'; | ||
@@ -6,3 +7,3 @@ import '../vaadin-dialog-layout-overlay-styles.js'; | ||
$_documentContainer.innerHTML = `<dom-module id="lumo-crud-grid-edit" theme-for="vaadin-crud-grid-edit"> | ||
$_documentContainer.innerHTML = `<dom-module id="lumo-crud-grid-edit" theme-for="vaadin-crud-edit"> | ||
<template> | ||
@@ -9,0 +10,0 @@ <style> |
64043
1274
+ Added@vaadin/vaadin-grid@5.10.1(transitive)
- Removed@vaadin/vaadin-grid@5.2.0-alpha2(transitive)