| if(!dojo._hasResource["dojox.grid.compat.tests.databaseModel"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. |
| dojo._hasResource["dojox.grid.compat.tests.databaseModel"] = true; |
| dojo.provide("dojox.grid.compat.tests.databaseModel"); |
| dojo.require("dojox.grid.compat._data.model"); |
| |
| // Provides a sparse array that is also traversable inorder |
| // with basic Array: |
| // - iterating by index is slow for large sparse arrays |
| // - for...in iteration is in order of element creation |
| // maintains a secondary index for interating |
| // over sparse elements inorder |
| dojo.declare("dojox.grid.Sparse", null, { |
| constructor: function() { |
| this.clear(); |
| }, |
| clear: function() { |
| this.indices = []; |
| this.values = []; |
| }, |
| length: function() { |
| return this.indices.length; |
| }, |
| set: function(inIndex, inValue) { |
| for (var i=0,l=this.indices.length; i<l; i++) { |
| if (this.indices[i] >= inIndex) |
| break; |
| } |
| if (this.indices[i] != inIndex) |
| this.indices.splice(i, 0, inIndex); |
| this.values[inIndex] = inValue; |
| }, |
| get: function(inIndex) { |
| return this.values[inIndex]; |
| }, |
| remove: function(inIndex) { |
| for (var i=0,l=this.indices.length; i<l; i++) |
| if (this.indices[i] == inIndex) { |
| this.indices.splice(i, 1); |
| break; |
| } |
| delete this.values[inIndex]; |
| }, |
| inorder: function(inFor) { |
| for (var i=0,l=this.indices.length, ix; i<l; i++) { |
| ix = this.indices[i]; |
| if (inFor(this.values[ix], ix) === false) |
| break; |
| } |
| } |
| }); |
| |
| // sample custom model implementation that works with mysql server. |
| dojo.declare("dojox.grid.data.DbTable", dojox.grid.data.Dynamic, { |
| delayedInsertCommit: true, |
| constructor: function(inFields, inData, inServer, inDatabase, inTable) { |
| this.server = inServer; |
| this.database = inDatabase; |
| this.table = inTable; |
| this.stateNames = ['inflight', 'inserting', 'removing', 'error']; |
| this.clearStates(); |
| this.clearSort(); |
| }, |
| clearData: function() { |
| this.cache = [ ]; |
| this.clearStates(); |
| this.inherited(arguments); |
| }, |
| clearStates: function() { |
| this.states = {}; |
| for (var i=0, s; (s=this.stateNames[i]); i++) { |
| delete this.states[s]; |
| this.states[s] = new dojox.grid.Sparse(); |
| } |
| }, |
| // row state information |
| getState: function(inRowIndex) { |
| for (var i=0, r={}, s; (s=this.stateNames[i]); i++) |
| r[s] = this.states[s].get(inRowIndex); |
| return r; |
| }, |
| setState: function(inRowIndex, inState, inValue) { |
| this.states[inState].set(inRowIndex, inValue||true); |
| }, |
| clearState: function(inRowIndex, inState) { |
| if (arguments.length == 1) { |
| for (var i=0, s; (s=this.stateNames[i]); i++) |
| this.states[s].remove(inRowIndex); |
| } else { |
| for (var i=1, l=arguments.length, arg; (i<l) &&((arg=arguments[i])!=undefined); i++) |
| this.states[arg].remove(inRowIndex); |
| } |
| }, |
| setStateForIndexes: function(inRowIndexes, inState, inValue) { |
| for (var i=inRowIndexes.length-1, k; (i>=0) && ((k=inRowIndexes[i])!=undefined); i--) |
| this.setState(k, inState, inValue); |
| }, |
| clearStateForIndexes: function(inRowIndexes, inState) { |
| for (var i=inRowIndexes.length-1, k; (i>=0) && ((k=inRowIndexes[i])!=undefined); i--) |
| this.clearState(k, inState); |
| }, |
| //$ Return boolean stating whether or not an operation is in progress that may change row indexing. |
| isAddRemoving: function() { |
| return Boolean(this.states['inserting'].length() || this.states['removing'].length()); |
| }, |
| isInflight: function() { |
| return Boolean(this.states['inflight'].length()); |
| }, |
| //$ Return boolean stating if the model is currently undergoing any type of edit. |
| isEditing: function() { |
| for (var i=0, r={}, s; (s=this.stateNames[i]); i++) |
| if (this.states[s].length()) |
| return true; |
| }, |
| //$ Return true if ok to modify the given row. Override as needed, using model editing state information. |
| canModify: function(inRowIndex) { |
| return !this.getState(inRowIndex).inflight && !(this.isInflight() && this.isAddRemoving()); |
| }, |
| // server send / receive |
| getSendParams: function(inParams) { |
| var p = { |
| database: this.database || '', |
| table: this.table || '' |
| } |
| return dojo.mixin(p, inParams || {}); |
| }, |
| send: function(inAsync, inParams, inCallbacks) { |
| //console.log('send', inParams.command); |
| var p = this.getSendParams(inParams); |
| var d = dojo.xhrPost({ |
| url: this.server, |
| content: p, |
| handleAs: 'json-comment-filtered', |
| contentType: "application/x-www-form-urlencoded; charset=utf-8", |
| sync: !inAsync |
| }); |
| d.addCallbacks(dojo.hitch(this, "receive", inCallbacks), dojo.hitch(this, "receiveError", inCallbacks)); |
| return d; |
| }, |
| _callback: function(cb, eb, data) { |
| try{ cb && cb(data); } |
| catch(e){ eb && eb(data, e); } |
| }, |
| receive: function(inCallbacks, inData) { |
| inCallbacks && this._callback(inCallbacks.callback, inCallbacks.errback, inData); |
| }, |
| receiveError: function(inCallbacks, inErr) { |
| this._callback(inCallbacks.errback, null, inErr) |
| }, |
| encodeRow: function(inParams, inRow, inPrefix) { |
| for (var i=0, l=inRow.length; i < l; i++) |
| inParams['_' + (inPrefix ? inPrefix : '') + i] = (inRow[i] ? inRow[i] : ''); |
| }, |
| measure: function() { |
| this.send(true, { command: 'info' }, { callback: dojo.hitch(this, this.callbacks.info) }); |
| }, |
| fetchRowCount: function(inCallbacks) { |
| this.send(true, { command: 'count' }, inCallbacks); |
| }, |
| // server commits |
| commitEdit: function(inOldData, inNewData, inRowIndex, inCallbacks) { |
| this.setState(inRowIndex, "inflight", true); |
| var params = {command: 'update'}; |
| this.encodeRow(params, inOldData, 'o'); |
| this.encodeRow(params, inNewData); |
| this.send(true, params, inCallbacks); |
| }, |
| commitInsert: function(inRowIndex, inNewData, inCallbacks) { |
| this.setState(inRowIndex, "inflight", true); |
| var params = {command: 'insert'}; |
| this.encodeRow(params, inNewData); |
| this.send(true, params, inCallbacks); |
| }, |
| // NOTE: supported only in tables with pk |
| commitDelete: function(inRows, inCallbacks) { |
| var params = { |
| command: 'delete', |
| count: inRows.length |
| } |
| var pk = this.getPkIndex(); |
| if (pk < 0) |
| return; |
| for (var i=0; i < inRows.length; i++) { |
| params['_' + i] = inRows[i][pk]; |
| } |
| this.send(true, params, inCallbacks); |
| }, |
| getUpdateCallbacks: function(inRowIndex) { |
| return { |
| callback: dojo.hitch(this, this.callbacks.update, inRowIndex), |
| errback: dojo.hitch(this, this.callbacks.updateError, inRowIndex) |
| }; |
| }, |
| // primary key from fields |
| getPkIndex: function() { |
| for (var i=0, l=this.fields.count(), f; (i<l) && (f=this.fields.get(i)); i++) |
| if (f.Key = 'PRI') |
| return i; |
| return -1; |
| }, |
| // model implementations |
| update: function(inOldData, inNewData, inRowIndex) { |
| var cbs = this.getUpdateCallbacks(inRowIndex); |
| if (this.getState(inRowIndex).inserting) |
| this.commitInsert(inRowIndex, inNewData, cbs); |
| else |
| this.commitEdit(this.cache[inRowIndex] || inOldData, inNewData, inRowIndex, cbs); |
| // set push data immediately to model so reflectd while committing |
| this.setRow(inNewData, inRowIndex); |
| }, |
| insert: function(inData, inRowIndex) { |
| this.setState(inRowIndex, 'inserting', true); |
| if (!this.delayedInsertCommit) |
| this.commitInsert(inRowIndex, inData, this.getUpdateCallbacks(inRowIndex)); |
| return this.inherited(arguments); |
| }, |
| remove: function(inRowIndexes) { |
| var rows = []; |
| for (var i=0, r=0, indexes=[]; (r=inRowIndexes[i]) !== undefined; i++) |
| if (!this.getState(r).inserting) { |
| rows.push(this.getRow(r)); |
| indexes.push(r); |
| this.setState(r, 'removing'); |
| } |
| var cbs = { |
| callback: dojo.hitch(this, this.callbacks.remove, indexes), |
| errback: dojo.hitch(this, this.callbacks.removeError, indexes) |
| }; |
| this.commitDelete(rows, cbs); |
| dojox.grid.data.Dynamic.prototype.remove.apply(this, arguments); |
| }, |
| cancelModifyRow: function(inRowIndex) { |
| if (this.isDelayedInsert(inRowIndex)) { |
| this.removeInsert(inRowIndex); |
| } else |
| this.finishUpdate(inRowIndex); |
| }, |
| finishUpdate: function(inRowIndex, inData) { |
| this.clearState(inRowIndex); |
| var d = (inData&&inData[0]) || this.cache[inRowIndex]; |
| if (d) |
| this.setRow(d, inRowIndex); |
| delete this.cache[inRowIndex]; |
| }, |
| isDelayedInsert: function(inRowIndex) { |
| return (this.delayedInsertCommit && this.getState(inRowIndex).inserting); |
| }, |
| removeInsert: function(inRowIndex) { |
| this.clearState(inRowIndex); |
| dojox.grid.data.Dynamic.prototype.remove.call(this, [inRowIndex]); |
| }, |
| // request data |
| requestRows: function(inRowIndex, inCount) { |
| var params = { |
| command: 'select', |
| orderby: this.sortField, |
| desc: (this.sortDesc ? "true" : ''), |
| offset: inRowIndex, |
| limit: inCount |
| } |
| this.send(true, params, {callback: dojo.hitch(this, this.callbacks.rows, inRowIndex)}); |
| }, |
| // sorting |
| canSort: function () { |
| return true; |
| }, |
| setSort: function(inSortIndex) { |
| this.sortField = this.fields.get(Math.abs(inSortIndex) - 1).name || inSortIndex; |
| this.sortDesc = (inSortIndex < 0); |
| }, |
| sort: function(inSortIndex) { |
| this.setSort(inSortIndex); |
| this.clearData(); |
| }, |
| clearSort: function(){ |
| this.sortField = ''; |
| this.sortDesc = false; |
| }, |
| endModifyRow: function(inRowIndex){ |
| var cache = this.cache[inRowIndex]; |
| var m = false; |
| if(cache){ |
| var data = this.getRow(inRowIndex); |
| if(!dojox.grid.arrayCompare(cache, data)){ |
| m = true; |
| this.update(cache, data, inRowIndex); |
| } |
| } |
| if (!m) |
| this.cancelModifyRow(inRowIndex); |
| }, |
| // server callbacks (called with this == model) |
| callbacks: { |
| update: function(inRowIndex, inData) { |
| console.log('received update', arguments); |
| if (inData.error) |
| this.updateError(inData) |
| else |
| this.finishUpdate(inRowIndex, inData); |
| }, |
| updateError: function(inRowIndex) { |
| this.clearState(inRowIndex, 'inflight'); |
| this.setState(inRowIndex, "error", "update failed: " + inRowIndex); |
| this.rowChange(this.getRow(inRowIndex), inRowIndex); |
| }, |
| remove: function(inRowIndexes) { |
| this.clearStateForIndexes(inRowIndexes); |
| }, |
| removeError: function(inRowIndexes) { |
| this.clearStateForIndexes(inRowIndexes); |
| alert('Removal error. Please refresh.'); |
| }, |
| rows: function(inRowIndex, inData) { |
| //this.beginUpdate(); |
| for (var i=0, l=inData.length; i<l; i++) |
| this.setRow(inData[i], inRowIndex + i); |
| //this.endUpdate(); |
| //this.allChange(); |
| }, |
| count: function(inRowCount) { |
| this.count = Number(inRowCount); |
| this.clearData(); |
| }, |
| info: function(inInfo) { |
| this.fields.clear(); |
| for (var i=0, c; (c=inInfo.columns[i]); i++) { |
| c.name = c.Field; |
| this.fields.set(i, c); |
| } |
| this.table = inInfo.table; |
| this.database = inInfo.database; |
| this.notify("MetaData", arguments); |
| this.callbacks.count.call(this, inInfo.count); |
| } |
| } |
| }); |
| |
| } |