Table widget dropdowns - dependent drop-downs and loading indicators

This commit is contained in:
alekseybobkov 2014-12-09 22:37:52 -08:00
parent d880f1ffbd
commit 9377bcf7c1
6 changed files with 113 additions and 24 deletions

View File

@ -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

View File

@ -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;

View File

@ -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)
}
}

View File

@ -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
}
/*

View File

@ -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);

View File

@ -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;