diff --git a/modules/backend/widgets/Table.php b/modules/backend/widgets/Table.php index 6dc00cf50..6c7995cdf 100644 --- a/modules/backend/widgets/Table.php +++ b/modules/backend/widgets/Table.php @@ -104,11 +104,19 @@ class Table extends WidgetBase traceLog($columnName); traceLog($rowData); - $options = [ - 'string'=>'String', - 'checkbox'=>'Checkbox', - 'dropdown'=>'Dropdown' - ]; + if ($rowData['billable'] == 'yes' || $rowData['billable'] == 'no') { + $options = [ + 'string'=>'String - '.$rowData['billable'], + 'checkbox'=>'Checkbox - '.$rowData['billable'], + 'dropdown'=>'Dropdown - '.$rowData['billable'] + ]; + } else { + $options = [ + 'who-knows'=>'Who knows?', + 'whatever'=>'Whatever', + 'sometimes'=>'Sometimes' + ]; + } return [ 'options' => $options diff --git a/modules/backend/widgets/table/assets/css/table.css b/modules/backend/widgets/table/assets/css/table.css index 35fe8de0e..c3a17057a 100644 --- a/modules/backend/widgets/table/assets/css/table.css +++ b/modules/backend/widgets/table/assets/css/table.css @@ -196,6 +196,19 @@ .table-control td[data-column-type=dropdown] .content-container { outline: none; } +html.cssanimations .table-control td[data-column-type=dropdown] [data-view-container].loading:after { + background-image: url(../../../../assets/images/loading-indicator-transparent.svg); + background-size: 15px 15px; + background-position: 50% 50%; + position: absolute; + width: 15px; + height: 15px; + top: 6px; + right: 5px; + content: ' '; + -webkit-animation: spin 1s linear infinite; + animation: spin 1s linear infinite; +} .table-control-dropdown-list { -webkit-user-select: none; -moz-user-select: none; diff --git a/modules/backend/widgets/table/assets/js/table.js b/modules/backend/widgets/table/assets/js/table.js index c0ee919d8..f78cc8ddf 100644 --- a/modules/backend/widgets/table/assets/js/table.js +++ b/modules/backend/widgets/table/assets/js/table.js @@ -519,6 +519,17 @@ return } + Table.prototype.notifyRowProcessorsOnChange = function(cellElement) { + var columnName = cellElement.getAttribute('data-column'), + row = cellElement.parentNode + + for (var i = 0, len = row.children.length; i < len; i++) { + var column = this.options.columns[i].key + + this.cellProcessors[column].onRowValueChanged(columnName, row.children[i]) + } + } + // PUBLIC METHODS // ============================ @@ -558,7 +569,6 @@ this.activeCell = null } - // HELPER METHODS // ============================ @@ -661,6 +671,8 @@ dataContainer.value = value this.markCellRowDirty(cellElement) + + this.notifyRowProcessorsOnChange(cellElement) } } diff --git a/modules/backend/widgets/table/assets/js/table.processor.base.js b/modules/backend/widgets/table/assets/js/table.processor.base.js index b3baa588b..0eb04a4b5 100644 --- a/modules/backend/widgets/table/assets/js/table.processor.base.js +++ b/modules/backend/widgets/table/assets/js/table.processor.base.js @@ -93,6 +93,12 @@ Base.prototype.onClick = function(ev) { } + /* + * This method is called when a cell value in the row changes. + */ + Base.prototype.onRowValueChanged = function(columnName, cellElement) { + } + /* * Determines if the keyboard navigation in the specified direction is allowed * by the cell processor. Some processors could reject the navigation, for example @@ -129,6 +135,8 @@ viewContainer.textContent = value cellContentContainer.appendChild(viewContainer) + + return viewContainer } /* diff --git a/modules/backend/widgets/table/assets/js/table.processor.dropdown.js b/modules/backend/widgets/table/assets/js/table.processor.dropdown.js index 0fc6670ba..6287f453c 100644 --- a/modules/backend/widgets/table/assets/js/table.processor.dropdown.js +++ b/modules/backend/widgets/table/assets/js/table.processor.dropdown.js @@ -30,8 +30,6 @@ this.itemListElement = null - this.optionsCache = {} - this.cachedOptionPromises = {} // Event handlers @@ -51,10 +49,9 @@ DropdownProcessor.prototype.dispose = function() { this.unregisterListHandlers() this.itemClickHandler = null + this.itemKeyDownHandler = null this.itemListElement = null - this.optionsCache = null this.cachedOptionPromises = null - BaseProto.dispose.call(this) } @@ -74,15 +71,14 @@ * Renders the cell in the normal (no edit) mode */ DropdownProcessor.prototype.renderCell = function(value, cellContentContainer) { - var self = this + var viewContainer = this.createViewContainer(cellContentContainer, '...') this.fetchOptions(cellContentContainer.parentNode, function renderCellFetchOptions(options) { - if ( options[value] !== undefined ) + if (options[value] !== undefined) value = options[value] - self.createViewContainer(cellContentContainer, value) + viewContainer.textContent = value cellContentContainer.setAttribute('tabindex', 0) - self = null }) } @@ -199,19 +195,15 @@ // the caching key contains the master column values. var row = cellElement.parentNode, - cachingKey = this.createOptionsCachingKey(row) - - if (this.optionsCache[cachingKey] !== undefined) { - onSuccess(this.optionsCache[cachingKey]) - return - } + cachingKey = this.createOptionsCachingKey(row), + viewContainer = this.getViewContainer(cellElement) // Request options from the server. When the table widget builds, // multiple cells in the column could require loading the options. // The AJAX promises are cached here so that we have a single // request per caching key. - // TODO: Loading indicator + viewContainer.setAttribute('class', 'loading') if (!this.cachedOptionPromises[cachingKey]) { var requestData = { @@ -225,8 +217,8 @@ this.cachedOptionPromises[cachingKey].done(function onDropDownLoadOptionsSuccess(data){ onSuccess(data.options) - - row = null + }).always(function onDropDownLoadOptionsAlways(){ + viewContainer.setAttribute('class', '') }) } } @@ -236,7 +228,7 @@ dependsOn = this.columnConfiguration.depends_on if (dependsOn) { - if (typeof this.columnConfiguration.depends_on == 'object') { + if (typeof dependsOn == 'object') { for (var i = 0, len = dependsOn.length; i < len; i++ ) cachingKey += dependsOn[i] + this.tableObj.getRowCellValueByColumnName(row, dependsOn[i]) } else @@ -344,5 +336,44 @@ this.showDropdown() } + /* + * This method is called when a cell value in the row changes. + */ + Base.prototype.onRowValueChanged = function(columnName, cellElement) { + // Determine if this drop-down depends on the changed column + // and update the option list if necessary + + if (!this.columnConfiguration.depends_on) + return + + var dependsOnColumn = false, + dependsOn = this.columnConfiguration.depends_on + + if (typeof dependsOn == 'object') { + for (var i = 0, len = dependsOn.length; i < len; i++ ) { + if (dependsOn[i] == columnName) { + dependsOnColumn = true + break + } + } + } else + dependsOnColumn = dependsOn == columnName + + if (!dependsOnColumn) + return + + var currentValue = this.tableObj.getCellValue(cellElement), + viewContainer = this.getViewContainer(cellElement) + + this.fetchOptions(cellElement, function rowValueChangedFetchOptions(options) { + var value = options[currentValue] !== undefined ? + options[currentValue] : + '...' + + viewContainer.textContent = value + viewContainer = null + }) + } + $.oc.table.processor.dropdown = DropdownProcessor; }(window.jQuery); \ No newline at end of file diff --git a/modules/backend/widgets/table/assets/less/table.less b/modules/backend/widgets/table/assets/less/table.less index 3c6a55569..098883b0a 100644 --- a/modules/backend/widgets/table/assets/less/table.less +++ b/modules/backend/widgets/table/assets/less/table.less @@ -230,6 +230,23 @@ } } +html.cssanimations { + .table-control td[data-column-type=dropdown] { + [data-view-container].loading:after { + background-image:url(../../../../assets/images/loading-indicator-transparent.svg); + background-size: 15px 15px; + background-position: 50% 50%; + position: absolute; + width: 15px; + height: 15px; + top: 6px; + right: 5px; + content: ' '; + .animation(spin 1s linear infinite); + } + } +} + .table-control-dropdown-list { .user-select(none); position: absolute;