summaryrefslogtreecommitdiff
path: root/includes/js/dojox/grid/Grid.js
diff options
context:
space:
mode:
Diffstat (limited to 'includes/js/dojox/grid/Grid.js')
-rw-r--r--includes/js/dojox/grid/Grid.js363
1 files changed, 363 insertions, 0 deletions
diff --git a/includes/js/dojox/grid/Grid.js b/includes/js/dojox/grid/Grid.js
new file mode 100644
index 0000000..309bb25
--- /dev/null
+++ b/includes/js/dojox/grid/Grid.js
@@ -0,0 +1,363 @@
+if(!dojo._hasResource["dojox.grid.Grid"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojox.grid.Grid"] = true;
+dojo.provide("dojox.grid.Grid");
+dojo.require("dojox.grid.VirtualGrid");
+dojo.require("dojox.grid._data.model");
+dojo.require("dojox.grid._data.editors");
+dojo.require("dojox.grid._data.dijitEditors");
+
+// FIXME:
+// we are at the wrong location!
+
+dojo.declare('dojox.Grid', dojox.VirtualGrid, {
+ // summary:
+ // A grid widget with virtual scrolling, cell editing, complex rows,
+ // sorting, fixed columns, sizeable columns, etc.
+ // description:
+ // Grid is a subclass of VirtualGrid, providing binding to a data
+ // store.
+ // example:
+ // define the grid structure:
+ // | var structure = [ // array of view objects
+ // | { cells: [// array of rows, a row is an array of cells
+ // | [ { name: "Alpha", width: 6 },
+ // | { name: "Beta" },
+ // | { name: "Gamma", get: formatFunction }
+ // | ]
+ // | ]}
+ // | ];
+ //
+ // define a grid data model
+ // | var model = new dojox.grid.data.table(null, data);
+ // |
+ // | <div id="grid" model="model" structure="structure"
+ // | dojoType="dojox.VirtualGrid"></div>
+ //
+
+ // model:
+ // string or object grid data model
+ model: 'dojox.grid.data.Table',
+
+ // life cycle
+ postCreate: function(){
+ if(this.model){
+ var m = this.model;
+ if(dojo.isString(m)){
+ m = dojo.getObject(m);
+ }
+ this.model = (dojo.isFunction(m)) ? new m() : m;
+ this._setModel(this.model);
+ }
+ this.inherited(arguments);
+ },
+
+ destroy: function(){
+ this.setModel(null);
+ this.inherited(arguments);
+ },
+
+ // structure
+ _structureChanged: function() {
+ this.indexCellFields();
+ this.inherited(arguments);
+ },
+
+ // model
+ _setModel: function(inModel){
+ // if(!inModel){ return; }
+ this.model = inModel;
+ if(this.model){
+ this.model.observer(this);
+ this.model.measure();
+ this.indexCellFields();
+ }
+ },
+
+ setModel: function(inModel){
+ // summary:
+ // Set the grid's data model
+ // inModel: Object
+ // Model object, usually an instance of a dojox.grid.data.Model
+ // subclass
+ if(this.model){
+ this.model.notObserver(this);
+ }
+ this._setModel(inModel);
+ },
+
+
+ get: function(inRowIndex){
+ // summary: data socket (called in cell's context)
+ return this.grid.model.getDatum(inRowIndex, this.fieldIndex);
+ },
+
+ // model modifications
+ modelAllChange: function(){
+ this.rowCount = (this.model ? this.model.getRowCount() : 0);
+ this.updateRowCount(this.rowCount);
+ },
+
+ modelRowChange: function(inData, inRowIndex){
+ this.updateRow(inRowIndex);
+ },
+
+ modelDatumChange: function(inDatum, inRowIndex, inFieldIndex){
+ this.updateRow(inRowIndex);
+ },
+
+ modelFieldsChange: function() {
+ this.indexCellFields();
+ this.render();
+ },
+
+ // model insertion
+ modelInsertion: function(inRowIndex){
+ this.updateRowCount(this.model.getRowCount());
+ },
+
+ // model removal
+ modelRemoval: function(inKeys){
+ this.updateRowCount(this.model.getRowCount());
+ },
+
+ // cells
+ getCellName: function(inCell){
+ var v = this.model.fields.values, i = inCell.fieldIndex;
+ return i>=0 && i<v.length && v[i].name || this.inherited(arguments);
+ },
+
+ indexCellFields: function(){
+ var cells = this.layout.cells;
+ for(var i=0, c; cells && (c=cells[i]); i++){
+ if(dojo.isString(c.field)){
+ c.fieldIndex = this.model.fields.indexOf(c.field);
+ }
+ }
+ },
+
+ // utility
+ refresh: function(){
+ // summary:
+ // Re-render the grid, getting new data from the model
+ this.edit.cancel();
+ this.model.measure();
+ },
+
+ // sorting
+ canSort: function(inSortInfo){
+ var f = this.getSortField(inSortInfo);
+ // 0 is not a valid sort field
+ return f && this.model.canSort(f);
+ },
+
+ getSortField: function(inSortInfo){
+ // summary:
+ // Retrieves the model field on which to sort data.
+ // inSortInfo: Integer
+ // 1-based grid column index; positive if sort is ascending, otherwise negative
+ var c = this.getCell(this.getSortIndex(inSortInfo));
+ // we expect c.fieldIndex == -1 for non model fields
+ // that yields a getSortField value of 0, which can be detected as invalid
+ return (c.fieldIndex+1) * (this.sortInfo > 0 ? 1 : -1);
+ },
+
+ sort: function(){
+ this.edit.apply();
+ this.model.sort(this.getSortField());
+ },
+
+ // row editing
+ addRow: function(inRowData, inIndex){
+ this.edit.apply();
+ var i = inIndex || -1;
+ if(i<0){
+ i = this.selection.getFirstSelected() || 0;
+ }
+ if(i<0){
+ i = 0;
+ }
+ this.model.insert(inRowData, i);
+ this.model.beginModifyRow(i);
+ // begin editing row
+ // FIXME: add to edit
+ for(var j=0, c; ((c=this.getCell(j)) && !c.editor); j++){}
+ if(c&&c.editor){
+ this.edit.setEditCell(c, i);
+ this.focus.setFocusCell(c, i);
+ }else{
+ this.focus.setFocusCell(this.getCell(0), i);
+ }
+ },
+
+ removeSelectedRows: function(){
+ this.edit.apply();
+ var s = this.selection.getSelected();
+ if(s.length){
+ this.model.remove(s);
+ this.selection.clear();
+ }
+ },
+
+ //: protected
+ // editing
+ canEdit: function(inCell, inRowIndex){
+ // summary:
+ // Determines if a given cell may be edited
+ // inCell: Object
+ // A grid cell
+ // inRowIndex: Integer
+ // Grid row index
+ // returns: Boolean
+ // True if given cell may be edited
+ return (this.model.canModify ? this.model.canModify(inRowIndex) : true);
+ },
+
+ doStartEdit: function(inCell, inRowIndex){
+ this.model.beginModifyRow(inRowIndex);
+ this.onStartEdit(inCell, inRowIndex);
+ },
+
+ doApplyCellEdit: function(inValue, inRowIndex, inFieldIndex){
+ this.model.setDatum(inValue, inRowIndex, inFieldIndex);
+ this.onApplyCellEdit(inValue, inRowIndex, inFieldIndex);
+ },
+
+ doCancelEdit: function(inRowIndex){
+ this.model.cancelModifyRow(inRowIndex);
+ this.onCancelEdit.apply(this, arguments);
+ },
+
+ doApplyEdit: function(inRowIndex){
+ this.model.endModifyRow(inRowIndex);
+ this.onApplyEdit(inRowIndex);
+ },
+
+ styleRowState: function(inRow){
+ // summary: Perform row styling
+ if(this.model.getState){
+ var states=this.model.getState(inRow.index), c='';
+ for(var i=0, ss=["inflight", "error", "inserting"], s; s=ss[i]; i++){
+ if(states[s]){
+ c = ' dojoxGrid-row-' + s;
+ break;
+ }
+ }
+ inRow.customClasses += c;
+ }
+ },
+
+ onStyleRow: function(inRow){
+ this.styleRowState(inRow);
+ this.inherited(arguments);
+ }
+
+});
+
+dojox.Grid.markupFactory = function(props, node, ctor){
+ // handle setting up a data model for a store if one
+ // isn't provided. There are some caveats:
+ // * we only really handle dojo.data sources well. They're the future
+ // so it's no big deal, but it's something to be aware of.
+ // * I'm pretty sure that colgroup introspection is missing some of
+ // the available settable properties.
+ // * No handling of cell formatting and content getting is done
+ var d = dojo;
+ var widthFromAttr = function(n){
+ var w = d.attr(n, "width")||"auto";
+ if((w != "auto")&&(w.substr(-2) != "em")){
+ w = parseInt(w)+"px";
+ }
+ return w;
+ }
+ if(!props.model && d.hasAttr(node, "store")){
+ // if a model isn't specified and we point to a store, assume
+ // we're also folding the definition for a model up into the
+ // inline ctor for the Grid. This will then take properties
+ // like "query", "rowsPerPage", and "clientSort" from the grid
+ // definition.
+ var mNode = node.cloneNode(false);
+ d.attr(mNode, {
+ "jsId": null,
+ "dojoType": d.attr(node, "dataModelClass") || "dojox.grid.data.DojoData"
+ });
+ props.model = d.parser.instantiate([mNode])[0];
+ }
+ // if(!props.model){ console.debug("no model!"); }
+ // if a structure isn't referenced, do we have enough
+ // data to try to build one automatically?
+ if( !props.structure &&
+ node.nodeName.toLowerCase() == "table"){
+
+ // try to discover a structure
+ props.structure = d.query("> colgroup", node).map(function(cg){
+ var sv = d.attr(cg, "span");
+ var v = {
+ noscroll: (d.attr(cg, "noscroll") == "true") ? true : false,
+ __span: (!!sv ? parseInt(sv) : 1),
+ cells: []
+ };
+ if(d.hasAttr(cg, "width")){
+ v.width = widthFromAttr(cg);
+ }
+ return v; // for vendetta
+ });
+ if(!props.structure.length){
+ props.structure.push({
+ __span: Infinity,
+ cells: [] // catch-all view
+ });
+ }
+ // check to see if we're gonna have more than one view
+
+ // for each tr in our th, create a row of cells
+ d.query("thead > tr", node).forEach(function(tr, tr_idx){
+ var cellCount = 0;
+ var viewIdx = 0;
+ var lastViewIdx;
+ var cView = null;
+ d.query("> th", tr).map(function(th){
+ // what view will this cell go into?
+
+ // NOTE:
+ // to prevent extraneous iteration, we start counters over
+ // for each row, incrementing over the surface area of the
+ // structure that colgroup processing generates and
+ // creating cell objects for each <th> to place into those
+ // cell groups. There's a lot of state-keepking logic
+ // here, but it is what it has to be.
+ if(!cView){ // current view book keeping
+ lastViewIdx = 0;
+ cView = props.structure[0];
+ }else if(cellCount >= (lastViewIdx+cView.__span)){
+ viewIdx++;
+ // move to allocating things into the next view
+ lastViewIdx += cView.__span;
+ lastView = cView;
+ cView = props.structure[viewIdx];
+ }
+
+ // actually define the cell from what markup hands us
+ var cell = {
+ name: d.trim(d.attr(th, "name")||th.innerHTML),
+ field: d.trim(d.attr(th, "field")||""),
+ colSpan: parseInt(d.attr(th, "colspan")||1)
+ };
+ cellCount += cell.colSpan;
+ cell.field = cell.field||cell.name;
+ cell.width = widthFromAttr(th);
+ if(!cView.cells[tr_idx]){
+ cView.cells[tr_idx] = [];
+ }
+ cView.cells[tr_idx].push(cell);
+ });
+ });
+ // console.debug(dojo.toJson(props.structure, true));
+ }
+ return new dojox.Grid(props, node);
+}
+
+
+// alias us to the right location
+dojox.grid.Grid = dojox.Grid;
+
+}