diff options
Diffstat (limited to 'vaadin-grid/vaadin-grid.html')
-rw-r--r-- | vaadin-grid/vaadin-grid.html | 983 |
1 files changed, 983 insertions, 0 deletions
diff --git a/vaadin-grid/vaadin-grid.html b/vaadin-grid/vaadin-grid.html new file mode 100644 index 0000000..5a545bf --- /dev/null +++ b/vaadin-grid/vaadin-grid.html @@ -0,0 +1,983 @@ +<!-- +@element v-grid +--> + +<link rel='import' href='vaadin-grid-import.html'> +<link rel='import' href='../../polymer/polymer.html'> + +<style> + v-grid > table { + display: none; + } +</style> + +<!-- +Vaadin v-grid is a grid component fully configurable and customizable, plenty of features and with the mind set on performance. +--> +<dom-module id="v-grid"> +<style> + /* Functional properties */ + + :host { + white-space: nowrap; + -webkit-tap-highlight-color: transparent; + -webkit-touch-callout: none; + transition: opacity 200ms; + cursor: default; + } + + :host(.loading) { + opacity: 0; + height: 0; + transition: none; + } + + :host, + .v-grid-tablewrapper > table, + .v-grid-body, + .v-grid-header, + .v-grid-footer, + .v-grid-row { + display: block; + box-sizing: border-box; + } + + .v-grid-cell { + display: -webkit-inline-flex; + display: inline-flex; + -webkit-align-items: center; + align-items: center; + box-sizing: border-box; + overflow: hidden; + text-overflow: ellipsis; + background: #fff; + } + + :host > div { + position: relative; + outline: none; + } + + .v-grid-scroller { + position: absolute; + z-index: 1; + outline: none; + box-sizing: border-box; + } + + .v-grid-scroller-horizontal { + left: 0; + right: 0; + bottom: 0; + overflow-y: hidden; + -ms-overflow-y: hidden; + } + + .v-grid-scroller-vertical { + right: 0; + top: 0; + bottom: 0; + overflow-x: hidden; + -ms-overflow-x: hidden; + } + + .v-grid-tablewrapper { + position: absolute; + overflow: hidden; + box-sizing: border-box; + z-index: 5; + outline: none; + } + + .v-grid-header-deco, + .v-grid-footer-deco, + .v-grid-horizontal-scrollbar-deco { + position: absolute; + right: 0; + box-sizing: border-box; + } + + .v-grid-header, + .v-grid-body, + .v-grid-footer { + position: absolute; + left: 0; + z-index: 10; + } + + .v-grid-header, + .v-grid-header-deco { + top: 0; + } + + .v-grid-footer, + .v-grid-footer-deco { + bottom: 0; + } + + .v-grid-horizontal-scrollbar-deco { + left: 0; + bottom: 0; + } + + .v-grid-body { + z-index: 0; + top: 0; + } + + .v-grid-body .v-grid-row { + position: absolute; + top: 0; + left: 0; + } + + :host(:not([selection-mode])) .v-grid-body, + :host([selection-mode="single"]) .v-grid-body { + cursor: pointer; + } + + .v-grid-editor { + position: absolute; + z-index: 20; + overflow: hidden; + left: 0; + right: 0; + margin-top: -1px; + } + + .v-grid-editor-cells { + position: relative; + } + + .v-grid-editor-cells > div { + display: inline-block; + } + + .v-grid-editor-footer { + display: -webkit-flex; + display: flex; + -webkit-align-items: center; + align-items: center; + box-sizing: border-box; + } + + .v-grid-editor-message { + -webkit-flex: 1; + flex: 1; + } + + /* Theming properties */ + + :host { + font: 400 100%/1.1 Roboto, sans-serif; + color: rgba(0, 0, 0, 0.83); + } + + .v-grid-cell { + padding: 0 16px; + height: 32px; + } + + .v-grid-header, + .v-grid-header-deco { + box-shadow: 0px 3px 2px 0px rgba(0, 0, 0, 0.20); + } + + .v-grid-header th { + background: #03A9F4; + color: #fff; + text-transform: uppercase; + font-weight: 600; + font-size: 0.8125em; + height: 32px; + border-right: 1px solid rgba(255, 255, 255, 0.3); + border-bottom: 1px solid rgba(255, 255, 255, 0.3); + } + + .v-grid-header-deco { + background: #03A9F4; + border-left: 1px solid rgba(255, 255, 255, 0.3); + z-index: 1; + } + + .v-grid-header [class*="sort-"] { + position: relative; + padding-right: 32px; + } + + .v-grid-header [class*="sort-"]:after { + position: absolute; + font-family: sans-serif; + content: url(sort-asc.svg) " " attr(sort-order); + right: 12px; + font-size: 12px; + width: 11px; + height: 5px; + } + + .v-grid-header .sort-desc:after { + content: url(sort-desc.svg) " " attr(sort-order); + } + + .v-grid-header [class*="sort-"][sort-order]:after { + right: 20px; + } + + .v-grid-footer td, + .v-grid-footer-deco, + .v-grid-horizontal-scrollbar-deco { + background: #E6E6E6; + font-size: 0.8125em; + font-weight: 500; + color: rgba(0, 0, 0, 0.56); + } + + .v-grid-footer td { + border-right: 1px solid rgba(255, 255, 255, 0.5); + border-bottom: 1px solid rgba(255, 255, 255, 0.5); + } + + .v-grid-footer-deco { + border-left: 1px solid rgba(255, 255, 255, 0.5); + } + + .v-grid-horizontal-scrollbar-deco { + border-top: 1px solid rgba(255, 255, 255, 0.5); + } + + .v-grid-header th:last-child, + .v-grid-footer td:last-child { + border-right: 0; + } + + .v-grid-header tr:last-child th, + .v-grid-footer tr:last-child td { + border-bottom: 0; + } + + /* TODO We need some other way of defining the frozen column divider than + using the cell, since this will affect all frozen columns, when we only + want to apply it to the last frozen column .*/ + /* Double selector to increase specificity. Otherwise Polymer increases the + specificity of the ".v-grid-header th" more than this, and we can't + override the border */ + .v-grid-cell.frozen.frozen { + position: relative; + z-index: 1; + border-right: 0; + box-shadow: 1px 0 0 0 rgba(0,0,0,0.04), + 2px 0 0 0 rgba(0,0,0,0.04), + 3px 0 0 0 rgba(0,0,0,0.04), + 4px 0 0 0 rgba(0,0,0,0.04); + } + + .v-grid-row-selected > td { + background-color: #f2f2f2; + } + + .v-grid-editor { + background: #fff; + box-shadow: 0 0 0 1px rgba(0,0,0,0.15), + 0 8px 17px 0 rgba(0,0,0,0.2), + 0 6px 20px 0 rgba(0,0,0,0.188235); + margin-top: -5px; + } + + .v-grid-editor[style*="bottom"] { + margin-top: 0; + margin-bottom: -5px; + } + + .v-grid-editor input[type="text"], + .v-grid-editor input:not([type]) { + box-sizing: border-box; + width: 100%; + height: 100%; + padding: 0 0 1px; + font: inherit; + color: inherit; + border: 0; + border-bottom: 1px solid rgba(0,0,0,0.2); + background: transparent; + outline: none; + transition: all 200ms; + } + + .v-grid-editor input[type="text"]:focus { + border-bottom: 2px solid #03A9F4; + padding-bottom: 0; + } + + .v-grid-editor-cells > div { + box-sizing: border-box; + margin: 5px 0; + padding: 5px 16px; + height: 42px; + } + + .v-grid-editor-buttons button { + height: 32px; + padding: 0 11px; + margin: 5px; + font: inherit; + font-size: 14px; + color: #03A9F4; + text-transform: uppercase; + background: transparent; + border: 0; + border-radius: 3px; + outline: none; + cursor: pointer; + transition: all 200ms; + } + + .v-grid-editor-buttons button:focus { + box-shadow: 0 2px 6px 0 rgba(0,0,0,0.5); + } + + .v-grid-editor-buttons button:active:focus { + box-shadow: none; + } + + input[type="checkbox"] { + position: absolute; + opacity: 0; + } + + input[type="checkbox"] + label { + position: relative; + left: 0; + box-sizing: border-box; + display: block; + width: 16px; + height: 16px; + border: 2px solid rgba(0,0,0,0.3); + border-radius: 2px; + cursor: pointer; + transition: background-color 120ms, border-color 120ms; + } + + input[type="checkbox"]:focus { + outline: none; + } + + input[type="checkbox"]:focus + label { + border-color: rgba(0,0,0,0.6); + } + + input[type="checkbox"] + label:after { + content: url("tick.svg"); + position: absolute; + top: -2px; + left: -2px; + display: block; + width: 16px; + height: 16px; + transition: all 200ms; + -webkit-transform: scale(0); + transform: scale(0); + -webkit-transform-origin: 40% 80%; + transform-origin: 40% 80%; + } + + input[type="checkbox"]:checked + label { + background-color: #03A9F4; + border-color: transparent; + } + + input[type="checkbox"]:checked + label:after { + -webkit-transform: scale(1); + transform: scale(1); + } + + input[type="checkbox"]:indeterminate + label:after { + content: "–"; + font-size: 14px; + text-align: center; + -webkit-transform: none; + transform: none; + } + + /* Activation "splash" */ + input[type="checkbox"] + label:before { + content: ""; + position: absolute; + top: -14px; + left: -14px; + width: 40px; + height: 40px; + border-radius: 50%; + background: #666; + opacity: 0; + -webkit-transform: scale(0.8); + transform: scale(0.8); + transition: all 180ms cubic-bezier(0.75,.0,0.25,1); + } + + input[type="checkbox"] + label:active:before { + transform: scale(1.1); + opacity: 0.15; + transition-duration: 80ms; + transition-property: all; + } + + input[type="checkbox"]:checked + label:before { + background: #03A9F4; + } + + /* Small adjustments for the checkbox in the header */ + + .v-grid-header input[type="checkbox"] + label { + border-color: rgba(255,255,255,0.5); + } + + .v-grid-header input[type="checkbox"] + label:before { + background: #fff; + } + + .v-grid-header input[type="checkbox"] + label:after { + transition: none; + } + + /* Focus styles */ + + .v-grid-row-focused:after { + content: ""; + position: absolute; + z-index: 1; + top: 0; + right: 0; + bottom: 0; + left: 0; + border: 1px solid rgba(0,0,0,0.2); + pointer-events: none; + opacity: 0; + transition: opacity 300ms; + } + + :focus .v-grid-row-focused:after { + opacity: 1; + } + + #measure { + width: 100% !important; + height: 100% !important; + z-index: -1 !important; + pointer-events: none !important; + position: relative !important; + float: left !important; + margin-left: -100% !important; + opacity: 0 !important; + } + + #measureobject { + position: absolute !important; + width: 100% !important; + height: 100% !important; + } +</style> + <template> + <div id="measure" class="v-grid"> + <object id="measureobject" class="v-grid" type="text/html"></object> + </div> + <content></content> + </template> +</dom-module> + +<script> + function loadComponent() { + VGrid = Polymer({ + is: "v-grid", + + _grid: undefined, + + properties: { + /** + * The row editor specific fields + * + * @property editor + * @type {Editor} + */ + editor: { + type: Object, + readOnly: true, + value: function() { + var _this = this; + return { + get enabled() { + return _this._grid.getEditor().isEnabled(); + }, + set enabled(enabled) { + _this._grid.getEditor().setEnabled(enabled); + if (_this.editable !== enabled) { + _this.editable = enabled; + } + }, + get handler() { + return _this._grid.getEditor().getHandler(); + }, + set handler(handler) { + _this._grid.getEditor().setHandler(handler); + }, + get saveButtonText() { + return _this._grid.getEditor().getSaveButtonText(); + }, + set saveButtonText(saveButtonText) { + _this._grid.getEditor().setSaveButtonText(saveButtonText); + }, + get cancelButtonText() { + return _this._grid.getEditor().getSaveButtonText(); + }, + set cancelButtonText(cancelButtonText) { + _this._grid.getEditor().setCancelButtonText(cancelButtonText); + }, + editRow: function(row) { + _this._grid.getEditor().editRow(row); + }, + save: function() { + _this._grid.getEditor().save(); + }, + cancel: function() { + _this._grid.getEditor().cancel(); + } + }; + }, + }, + /** + * The data source object for the grid. + * + * @property data + * @type {Data} + */ + data: { + type: Object, + readOnly: true, + value: function() { + var _this = this; + return { + + get source() { + return this._source; + }, + set source(source) { + var sourceFunction = source; + if (Array.isArray(source)) { + sourceFunction = function(req) { + var array = source.slice(req.index, req.index + req.count); + req.success(array, source.length); + }; + } + _this._grid.setDataSource(sourceFunction); + + this._source = source; + }, + get sortOrder() { + return _this._grid.getSortOrder(); + }, + set sortOrder(sortOrder) { + _this._grid.setSortOrder(sortOrder); + }, + + clearCache: function(estimatedNewSize) { + _this._grid.getDataSource().clearCache(estimatedNewSize); + }, + + }; + } + }, + + /** + * Object for manipulating header rows + * + * @property header + * @type {Header} + */ + header: { + type: Object, + readOnly: true, + value: function() { + var _this = this; + return { + getCell: function(rowIndex, columnId) { + return _this._grid.getStaticSection().getHeaderCell(rowIndex, columnId); + }, + addRow: function(rowIndex, cellContent) { + _this._grid.getStaticSection().addHeader(rowIndex, cellContent); + }, + removeRow: function(rowIndex) { + _this._grid.getStaticSection().removeHeader(rowIndex); + }, + setRowClassName: function(rowIndex, className) { + _this._grid.getStaticSection().setHeaderRowClassName(rowIndex, className); + }, + get defaultRow() { + return _this._grid.getStaticSection().getDefaultHeader(); + }, + set defaultRow(rowIndex) { + _this._grid.getStaticSection().setDefaultHeader(rowIndex); + }, + get hidden() { + return _this._grid.getStaticSection().isHeaderHidden(); + }, + set hidden(hidden) { + _this._grid.getStaticSection().setHeaderHidden(hidden); + }, + get rowCount() { + return _this._grid.getStaticSection().getHeaderRowCount(); + } + }; + } + }, + + /** + * Object for manipulating footer rows + * + * @property footer + * @type {Footer} + */ + footer: { + type: Object, + readOnly: true, + value: function() { + var _this = this; + return { + getCell: function(rowIndex, columnId) { + return _this._grid.getStaticSection().getFooterCell(rowIndex, columnId); + }, + addRow: function(rowIndex, cellContent) { + _this._grid.getStaticSection().addFooter(rowIndex, cellContent); + }, + removeRow: function(rowIndex) { + _this._grid.getStaticSection().removeFooter(rowIndex); + }, + setRowClassName: function(rowIndex, className) { + _this._grid.getStaticSection().setFooterRowClassName(rowIndex, className); + }, + get hidden() { + return _this._grid.getStaticSection().isFooterHidden(); + }, + set hidden(hidden) { + _this._grid.getStaticSection().setFooterHidden(hidden); + }, + get rowCount() { + return _this._grid.getStaticSection().getFooterRowCount(); + } + }; + } + }, + + /** + * Selection model + * + * @property selection + * @type {Selection} + */ + selection: { + type: Object, + readOnly: true, + value: function() { + var _this = this; + return { + select: function(index) { + _this._grid.getSelectionModel().select(index); + + return _this; + }, + deselect: function(index) { + _this._grid.getSelectionModel().deselect(index); + + return _this; + }, + clear: function() { + _this._grid.getSelectionModel().clear(); + + return _this; + }, + selectAll: function() { + _this._grid.getSelectionModel().selectAll(); + + return _this; + }, + selected: function(mapper, from, to) { + return _this._grid.getSelectionModel().selected(mapper, from, to); + }, + deselected: function(mapper, from, to) { + return _this._grid.getSelectionModel().deselected(mapper, from, to); + }, + get size() { + return _this._grid.getSelectionModel().size(); + }, + get mode() { + return _this._grid.getSelectionMode(); + }, + set mode(mode) { + _this._grid.setSelectionMode(mode); + _this.serializeValueToAttribute(_this.selection.mode, "selection-mode"); + } + }; + } + }, + }, + + attributeChanged: function(name, type, value) { + switch (name) { + case 'disabled': + this.disabled = typeof value == "string"; + break; + case 'editable': + this.editable = typeof value == "string"; + break; + case 'style': + this._grid.redraw(); + break; + case 'selection-mode': + this.selection.mode = value; + break; + default: + this[Polymer.CaseMap.dashToCamelCase(name)] = value; + } + }, + + listeners: { + /** + * @event sort + */ + /** + * @event select + */ + /** + * @event selectionmodechange + */ + 'selectionmodechange': 'onSelectionModeChange' + }, + + onSelectionModeChange: function() { + this.serializeValueToAttribute(this.selection.mode, "selection-mode"); + }, + + created: function() { + this._grid = new vaadin.GridComponent(); + }, + + ready: function() { + var _this = this; + setTimeout(function() { + for (var i = 0; i < _this.attributes.length; i++) { + _this.attributeChanged(_this.attributes[i].nodeName, null, _this.attributes[i].nodeValue); + } + }, 1); + + }, + + _bindResizeListener: function() { + var _this = this; + this.$.measureobject.addEventListener("load", function() { + this.contentDocument.defaultView.addEventListener('resize', function(e) { + _this._grid.redraw(); + }); + + _this.then(function() { + // ...because one then just isn't enough. + _this.then(function() { + _this._grid.redraw(); + }); + }); + }); + this.$.measureobject.data = "about:blank"; + }, + + attached: function() { + var _this = this; + this._grid.attached(this, Polymer.dom(this).querySelector("table"), Polymer.dom(this.root)); + this._bindResizeListener(); + + // hide until fully loaded + this.toggleClass('loading', true); + this.then(function() { + _this.toggleClass('loading', false); + }); + }, + + /** + * Scrolls to a certain row, using user-specified scroll destination. + * Since its asynchronous nature, this method returns a 'thenable' + * so as you can use the 'then()' method to be notified when the data + * request finished and the scroll is actually moved. + * + * @method scrollToRow + * @param {number} index - zero-based index of the row to scroll to. + * @param {string} scrollDestination - desired destination placement of scrolled-to-row. + */ + scrollToRow: function(index, scrollDestination) { + this._grid.scrollToRow(index, scrollDestination); + return this; + }, + + /** + * Scrolls to the beginning of the very first row. + * Since its asynchronous nature, this method returns a 'thenable' + * so as you can use the 'then()' method to be notified when the data + * request finished and the scroll is actually moved. + * + * @method scrollToStart + */ + scrollToStart: function() { + this._grid.scrollToStart(); + return this; + }, + + /** + * Scrolls to the end of the very last row. + * Since its asynchronous nature, this method returns a 'thenable' + * so as you can use the 'then()' method to be notified when the data + * request finished and the scroll is actually moved. + * + * @method scrollToEnd + */ + scrollToEnd: function() { + this._grid.scrollToEnd(); + return this; + }, + + /** + * Adds new column + * + * @method addColumn + * @param {Column} column + * @param {string} beforeColumn + */ + addColumn: function(column, beforeColumn) { + this._grid.addColumn(column, beforeColumn); + }, + + /** + * Removes column with certain id + * + * @method removeColumn + * @param {string} id + */ + removeColumn: function(id) { + this._grid.removeColumn(id); + }, + + /** + * Sets the style generator that is used for generating styles for rows. + * + * @attribute rowClassGenerator + * @type object + */ + get rowClassGenerator() { + return this._grid.getRowClassGenerator(); + }, + set rowClassGenerator(rowClassGenerator) { + this._grid.setRowClassGenerator(rowClassGenerator); + }, + /** + * Sets the style generator that is used for generating styles for cells. + * + * @attribute cellClassGenerator + * @type object + */ + get cellClassGenerator() { + return this._grid.getCellClassGenerator(); + }, + set cellClassGenerator(cellClassGenerator) { + this._grid.setCellClassGenerator(cellClassGenerator); + }, + /** + * Disables the grid functionality. + * + * @attribute disabled + * @type boolean + */ + get disabled() { + return this._grid.isDisabled(); + }, + set disabled(disabled) { + this._grid.setDisabled(disabled); + this.reflectPropertyToAttribute("disabled"); + }, + /** + * Enables the row editor feature (double click/tap or or Enter key in a content row activates the editing mode) + * + * @attribute editable + * @type boolean + */ + get editable() { + return this.editor.enabled; + }, + set editable(editable) { + this.editor.enabled = editable; + this.reflectPropertyToAttribute("editable"); + }, + /** + * Sets the number of frozen columns in this grid. Setting the count to 0 + * means that no data columns will be frozen, but the built-in selection + * checkbox column will still be frozen if it's in use. Setting the count to + * -1 will also disable the selection column. + * + * @attribute frozen-columns + * @type Number + */ + get frozenColumns() { + return this._grid.getFrozenColumns(); + }, + set frozenColumns(frozenColumns) { + this._grid.setFrozenColumns(frozenColumns); + this.reflectPropertyToAttribute("frozenColumns"); + }, + /** + * Declares the number of visible rows in the grid. Implicitly sets the height + * in the inline style, overriding any previous height. Setting style.height + * in this case should be ignored if possible. + * + * @attribute rows + * @type Number + */ + get rows() { + return this._grid.getRows(); + }, + set rows(rows) { + this._grid.setRows(rows); + this.reflectPropertyToAttribute("rows"); + }, + /** + * The columns array + * + * @property columns + * @type {Array<Column>} + */ + get columns() { + return this._grid.getColumns(); + }, + set columns(cols) { + this._grid.setColumns(cols); + }, + /** + * Executes a callback when the grid has finished any pending work. + * + * @method them + * @param {Function} callback + * @return a chainable promise + */ + then: function(cb) { + return this._grid.then(cb); + } + }); // End Polymer prototype + + // Give some time to gwt async processes to run (we need this in FF) + setTimeout(function() { + vaadin._v_grid_ready = true; + document.dispatchEvent(new CustomEvent('v-grid-ready')); + }, 5); + + } // End loadComponent function + + if (window.vaadin && window.vaadin.GridComponent) { + loadComponent(); + } else { + document.addEventListener("v-grid-loaded", function() { + loadComponent(); + }); + } +</script> |