Implementing AJAX loading for drop-down options, in progress.

This commit is contained in:
alekseybobkov 2014-12-08 22:50:25 -08:00
parent 4b28ee8bcb
commit f56bfe12d0
7 changed files with 160 additions and 44 deletions

View File

@ -36,9 +36,9 @@
<script src="<?= Backend::skinAsset('assets/vendor/flot/jquery.flot.resize.js') ?>"></script>
<script src="<?= Backend::skinAsset('assets/vendor/flot/jquery.flot.time.js') ?>"></script>
<script src="<?= Backend::skinAsset('assets/js/october.controls.js') ?>"></script>
<script src="<?= Backend::skinAsset('assets/js/october.controls.js') ?>"></script> -->
<script src="<?= Backend::skinAsset('assets/js/october.utils.js') ?>"></script>
<script src="<?= Backend::skinAsset('assets/js/october.triggerapi.js') ?>"></script>
<!--<script src="<?= Backend::skinAsset('assets/js/october.triggerapi.js') ?>"></script>
<script src="<?= Backend::skinAsset('assets/js/october.dragscroll.js') ?>"></script>
<script src="<?= Backend::skinAsset('assets/js/october.toolbar.js') ?>"></script>
<script src="<?= Backend::skinAsset('assets/js/october.verticalmenu.js') ?>"></script>

View File

@ -1,5 +1,6 @@
<?php namespace Backend\Widgets;
use Input;
use Backend\Classes\WidgetBase;
/**
@ -90,4 +91,27 @@ class Table extends WidgetBase
return $result;
}
/*
* Event handlers
*/
public function onGetDropdownOptions()
{
$columnName = Input::get('column');
$rowData = Input::get('rowData');
traceLog($columnName);
traceLog($rowData);
$options = [
'string'=>'String',
'checkbox'=>'Checkbox',
'dropdown'=>'Dropdown'
];
return [
'options' => $options
];
}
}

View File

@ -217,6 +217,8 @@
border-top: 1px solid #ecf0f1;
padding: 0;
margin: 0;
max-height: 200px;
overflow: auto;
}
.table-control-dropdown-list li {
list-style: none;

View File

@ -17,6 +17,8 @@
var Table = function(element, options) {
this.el = element
this.$el = $(element)
this.options = options
//
@ -250,12 +252,11 @@
cellContentContainer.setAttribute('class', 'content-container')
cellProcessor.renderCell(records[i][columnName], cellContentContainer)
cell.appendChild(cellContentContainer)
cell.appendChild(dataContainer)
row.appendChild(cell)
cell.appendChild(dataContainer)
cellProcessor.renderCell(records[i][columnName], cellContentContainer)
}
tbody.appendChild(row)
@ -551,6 +552,7 @@
// collector can delete the elements if needed.
this.el = null
this.tableContainer = null
this.$el = null
// Delete references to other DOM elements
this.activeCell = null
@ -564,6 +566,10 @@
return this.el
}
Table.prototype.getAlias = function() {
return this.options.alias
}
Table.prototype.getTableContainer = function() {
return this.tableContainer
}
@ -628,6 +634,26 @@
return parseInt(cellElement.parentNode.rowIndex)
}
Table.prototype.getRowCellValueByColumnName = function(row, columnName) {
var cell = row.querySelector('td[data-column="'+columnName+'"]')
if (!cell)
return cell
return this.getCellValue(cell)
}
Table.prototype.getRowData = function(row) {
var result = {}
for (var i = 0, len = row.children.length; i < len; i++) {
var cell = row.children[i]
result[cell.getAttribute('data-column')] = this.getCellValue(cell)
}
return result
}
Table.prototype.setCellValue = function(cellElement, value) {
var dataContainer = cellElement.querySelector('[data-container]')

View File

@ -1,6 +1,11 @@
/*
* Drop-down cell processor for the table control.
*/
/*
* TODO: implement the search
*/
+function ($) { "use strict";
// NAMESPACE CHECK
@ -25,6 +30,10 @@
this.itemListElement = null
this.optionsCache = {}
this.cachedOptionPromises = {}
// Event handlers
this.itemClickHandler = this.onItemClick.bind(this)
this.itemKeyDownHandler = this.onItemKeyDown.bind(this)
@ -42,8 +51,9 @@
DropdownProcessor.prototype.dispose = function() {
this.unregisterListHandlers()
this.itemClickHandler = null
this.itemListElement = null
this.optionsCache = null
this.cachedOptionPromises = null
BaseProto.dispose.call(this)
}
@ -66,7 +76,7 @@
DropdownProcessor.prototype.renderCell = function(value, cellContentContainer) {
var self = this
this.fetchOptions(function renderCellFetchOptions(options) {
this.fetchOptions(cellContentContainer.parentNode, function renderCellFetchOptions(options) {
if ( options[value] !== undefined )
value = options[value]
@ -127,7 +137,7 @@
this.itemListElement.style.left = containerPosition.left + 'px'
this.itemListElement.style.top = containerPosition.top - 1 + cellContentContainer.offsetHeight + 'px'
this.fetchOptions(function renderCellFetchOptions(options) {
this.fetchOptions(cellElement, function renderCellFetchOptions(options) {
var listElement = document.createElement('ul')
for (var value in options) {
@ -173,17 +183,65 @@
var activeItemElement = this.itemListElement.querySelector('ul li.selected')
if (activeItemElement) {
activeItemElement.focus()
window.setTimeout(function(){
activeItemElement.focus()
}, 0)
}
}
}
DropdownProcessor.prototype.fetchOptions = function(onSuccess) {
// TODO: implement caching and AJAX support,
// loading indicator is required here for AJAX-based options.
//
if ( this.columnConfiguration.options )
DropdownProcessor.prototype.fetchOptions = function(cellElement, onSuccess) {
if (this.columnConfiguration.options)
onSuccess(this.columnConfiguration.options)
else {
// If options are not provided and not found in the cache,
// request them from the server. For dependent drop-downs
// 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
}
// 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
if (!this.cachedOptionPromises[cachingKey]) {
var requestData = {
column: this.columnName,
rowData: this.tableObj.getRowData(row)
},
handlerName = this.tableObj.getAlias()+'::onGetDropdownOptions'
this.cachedOptionPromises[cachingKey] = this.tableObj.$el.request(handlerName, {data: requestData})
}
this.cachedOptionPromises[cachingKey].done(function(data){
onSuccess(data.options)
})
}
}
DropdownProcessor.prototype.createOptionsCachingKey = function(row) {
var cachingKey = 'non-dependent',
dependsOn = this.columnConfiguration.depends_on
if (dependsOn) {
if (typeof this.columnConfiguration.depends_on == 'object') {
for (var i = 0, len = dependsOn.length; i < len; i++ )
cachingKey += dependsOn[i] + this.tableObj.getRowCellValueByColumnName(row, dependsOn[i])
} else
cachingKey = dependsOn + this.tableObj.getRowCellValueByColumnName(row, dependsOn)
}
return cachingKey
}
DropdownProcessor.prototype.getAbsolutePosition = function(element) {
@ -259,7 +317,6 @@
this.updateCellFromSelectedItem(this.findSelectedItem())
this.hideDropdown()
return
}
@ -269,6 +326,11 @@
this.tableObj.navigation.navigateNext(ev)
this.tableObj.stopEvent(ev)
}
if (ev.keyCode == 27) {
// Esc - hide the drop-down
this.hideDropdown()
}
}
/*

View File

@ -245,6 +245,8 @@
border-top: 1px solid #ecf0f1;
padding: 0;
margin: 0;
max-height: 200px;
overflow: auto;
}
li {

View File

@ -3,7 +3,7 @@
$data = [
[
'name' => 'City',
'billabe' => true,
'billable' => 'yes',
'type' => 'string',
'description' => 'City name',
'details' => 'Details string',
@ -15,7 +15,7 @@
],
[
'name' => 'Country',
'billabe' => false,
'billable' => 'no',
'type' => 'checkbox',
'description' => 'Country name',
'details' => 'Details string',
@ -27,7 +27,7 @@
],
[
'name' => 'State',
'billabe' => true,
'billable' => 'no',
'type' => 'dropdown',
'description' => 'British columbia',
'details' => 'Details string',
@ -39,7 +39,7 @@
],
[
'name' => 'Country',
'billabe' => true,
'billable' => 'yes',
'type' => 'checkbox',
'description' => 'Country name',
'details' => 'Details string',
@ -51,7 +51,7 @@
],
[
'name' => 'State',
'billabe' => false,
'billable' => 'no',
'type' => 'dropdown',
'description' => 'British columbia',
'details' => 'Details string',
@ -63,7 +63,7 @@
],
[
'name' => 'Country',
'billabe' => false,
'billable' => 'no',
'type' => 'checkbox',
'description' => 'Country name',
'details' => 'Details string',
@ -75,7 +75,7 @@
],
[
'name' => 'State',
'billabe' => false,
'billable' => 'no',
'type' => 'dropdown',
'description' => 'British columbia',
'details' => 'Details string',
@ -87,7 +87,7 @@
],
[
'name' => 'Country',
'billabe' => true,
'billable' => 'yes',
'type' => 'checkbox',
'description' => 'Country name',
'details' => 'Details string',
@ -99,7 +99,7 @@
],
[
'name' => 'State',
'billabe' => true,
'billable' => 'yes',
'type' => 'dropdown',
'description' => 'British columbia',
'details' => 'Details string',
@ -111,7 +111,7 @@
],
[
'name' => 'Country',
'billabe' => false,
'billable' => 'no',
'type' => 'checkbox',
'description' => 'Country name',
'details' => 'Details string',
@ -123,7 +123,7 @@
],
[
'name' => 'State',
'billabe' => true,
'billable' => 'yes',
'type' => 'dropdown',
'description' => 'British columbia',
'details' => 'Details string',
@ -135,7 +135,7 @@
],
[
'name' => 'Country',
'billabe' => false,
'billable' => 'no',
'type' => 'checkbox',
'description' => 'Country name',
'details' => 'Details string',
@ -147,7 +147,7 @@
],
[
'name' => 'State',
'billabe' => true,
'billable' => 'yes',
'type' => 'dropdown',
'description' => 'British columbia',
'details' => 'Details string',
@ -159,7 +159,7 @@
],
[
'name' => 'State',
'billabe' => false,
'billable' => 'no',
'type' => 'dropdown',
'description' => 'British columbia',
'details' => 'Details string',
@ -171,7 +171,7 @@
],
[
'name' => 'Country',
'billabe' => false,
'billable' => 'no',
'type' => 'checkbox',
'description' => 'Country name',
'details' => 'Details string',
@ -183,7 +183,7 @@
],
[
'name' => 'State',
'billabe' => true,
'billable' => 'yes',
'type' => 'dropdown',
'description' => 'British columbia',
'details' => 'Details string',
@ -195,7 +195,7 @@
],
[
'name' => 'Country',
'billabe' => true,
'billable' => 'yes',
'type' => 'checkbox',
'description' => 'Country name',
'details' => 'Details string',
@ -207,7 +207,7 @@
],
[
'name' => 'State',
'billabe' => true,
'billable' => 'yes',
'type' => 'dropdown',
'description' => 'British columbia',
'details' => 'Details string',
@ -219,7 +219,7 @@
],
[
'name' => 'Country',
'billabe' => true,
'billable' => 'yes',
'type' => 'checkbox',
'description' => 'Country name',
'details' => 'Details string',
@ -231,7 +231,7 @@
],
[
'name' => 'State',
'billabe' => true,
'billable' => 'yes',
'type' => 'dropdown',
'description' => 'British columbia',
'details' => 'Details string',
@ -243,7 +243,7 @@
],
[
'name' => 'State',
'billabe' => true,
'billable' => 'yes',
'type' => 'dropdown',
'description' => 'British columbia',
'details' => 'Details string',
@ -255,7 +255,7 @@
],
[
'name' => 'Country',
'billabe' => true,
'billable' => 'yes',
'type' => 'checkbox',
'description' => 'Country name',
'details' => 'Details string',
@ -267,7 +267,7 @@
],
[
'name' => 'State',
'billabe' => true,
'billable' => 'yes',
'type' => 'dropdown',
'description' => 'British columbia',
'details' => 'Details string',
@ -279,7 +279,7 @@
],
[
'name' => 'Country',
'billabe' => true,
'billable' => 'yes',
'type' => 'checkbox',
'description' => 'Country name',
'details' => 'Details string',
@ -291,7 +291,7 @@
],
[
'name' => 'State',
'billabe' => true,
'billable' => 'yes',
'type' => 'dropdown',
'description' => 'British columbia',
'details' => 'Details string',
@ -303,7 +303,7 @@
],
[
'name' => 'Country',
'billabe' => true,
'billable' => 'yes',
'type' => 'checkbox',
'description' => 'Country name',
'details' => 'Details string',
@ -315,7 +315,7 @@
],
[
'name' => 'State',
'billabe' => true,
'billable' => 'yes',
'type' => 'dropdown',
'description' => 'British columbia',
'details' => 'Details string',
@ -331,4 +331,4 @@
<!-- <div data-control="table" data-row-sorting="1" data-columns="<?= e(json_encode($columns)) ?>" data-data="<?= e(json_encode($data)) ?>"></div> -->
<div data-control="table" class="table-control" data-columns="<?= e(json_encode($columns)) ?>" data-data="<?= e(json_encode($data)) ?>" data-records-per-page="10"></div>
<div data-control="table" class="table-control" data-columns="<?= e(json_encode($columns)) ?>" data-data="<?= e(json_encode($data)) ?>" data-records-per-page="10" data-alias="<?= e($this->alias) ?>"></div>