<script type="text/javascript">
dojo.require("dijit.form.Button");
dojo.require("openils.widget.FlattenerGrid");
- //dojo.require("dojo.data.ItemFileReadStore");
- //dojo.require("openils.DebuggingIFRS");
-
- /*
- var gridData = <esc>:r ~/grid-data
- var gridStore = new openils.DebuggingIFRS(gridData);
- console.log("gridStore built");
- */
-
- /* mapClause="{ 'barcode': 'barcode', 'circ_lib_name': 'circ_lib.name', 'circ_lib': 'circ_lib.shortname', 'call_number': { 'path': 'call_number.label', 'sort': true, 'display': true }, 'id': 'id', 'tcn': { 'path': 'call_number.record.tcn_value', 'filter': true, 'sort': true } }" */
-
- /* query="{tcn: {'>': 100, circ_lib: 'BR1'}}" */
</script>
-<table
- id="gridNode"
- jsid="grid"
- dojoType="openils.widget.FlattenerGrid"
- columnPickerPrefix='"conify.flattener_test"'
- fmClass="'acp'"
- autoHeight="10"
- mapExtras="{copy_status: {path: 'status.name', filter: true}}"
- query="{'copy_status': ['Available','Reshelving','In process'],'circ_lib': 'BR1'}">
- <thead>
- <tr>
- <th field="barcode" fpath="barcode">Barcode</th>
- <th field="circ_lib_name" fpath="circ_lib.name">Circulation Library Name</th>
- <th field="circ_lib" fpath="circ_lib.shortname" ffilter="true">Circulation Library</th>
- <th field="call_number" fpath="call_number.label">Call Number</th>
- <th field="shelving_loc" fpath="location.name" ffilter="true">Shelving Location</th>
- </tr>
- </thead>
-</table>
+<div dojoType="dijit.layout.ContentPane" layoutAlign="client">
+ <div dojoType="dijit.layout.ContentPane"
+ layoutAlign="top" class="oils-header-panel">
+ <div>Flattener Test</div>
+ <div>
+ <button dojoType="dijit.form.Button"
+ onClick="grid.showCreateDialog()">New Thing</button>
+ <button dojoType="dijit.form.Button"
+ onClick="grid.deleteSelected()">Delete Selected Thing</button>
+ </div>
+ </div>
+ <!-- <div class="oils-acq-basic-roomy">
+ blah, a dropdown or something here (optional; typical interfaces might
+ have a filtering org select here.
+ </div> -->
+ <table
+ id="gridNode"
+ jsid="grid"
+ dojoType="openils.widget.FlattenerGrid"
+ columnPickerPrefix='"conify.flattener_test"'
+ fmClass="'acp'"
+ autoHeight="10"
+ editOnEnter="true"
+ editStyle="pane"
+ defaultSort="['call_number']"
+ mapExtras="{copy_status: {path: 'status.name', filter: true}}"
+ query="{'copy_status': ['Available','Reshelving','In process'],'circ_lib': 'BR1'}">
+ <thead>
+ <tr>
+ <th field="barcode" fpath="barcode">Barcode</th>
+ <th field="circ_lib_name" fpath="circ_lib.name">Circulation Library Name</th>
+ <th field="circ_lib" fpath="circ_lib.shortname" ffilter="true">Circulation Library</th>
+ <th field="call_number" fpath="call_number.label">Call Number</th>
+ <th field="shelving_loc" fpath="location.name" ffilter="true">Shelving Location</th>
+ </tr>
+ </thead>
+ </table>
+</div>
[% END %]
}
}
-
dojo.declare(
"openils.FlattenerStore", null, {
"sloClause": null,
"limit": 25,
"offset": 0,
-
+ "baseSort": null,
+ "defaultSort": null,
"constructor": function(/* object */ args) {
- dojo.mixin(this, args); /* XXX do we actually need this? */
+ dojo.mixin(this, args);
this._current_items = {};
},
/* turn dojo-style sort into flattener-style sort */
"_prepare_sort": function(dsort) {
- if (!dsort)
- return [];
- return dsort.map(
- function(d) {
- var o = {};
- o[d.attribute] = d.descending ? "desc" : "asc";
- return o;
- }
+ if (!dsort || !dsort.length)
+ return this.baseSort || this.defaultSort || [];
+
+ return (this.baseSort || []).concat(
+ dsort.map(
+ function(d) {
+ var o = {};
+ o[d.attribute] = d.descending ? "desc" : "asc";
+ return o;
+ }
+ )
);
},
},
"isItemLoaded": function(/* anything */ something) {
- console.warning("[unfinished] isItemLoaded(" + something + ")");
+ console.warn("[unfinished] isItemLoaded(" + something + ")");
/* This is assuming items are always loaded, which is probably not right for this particular store.*/
return this.isItem(something);
if (when < self._last_fetch) /* Stale response. Discard. */
return;
+ /* The following is apparently the "right" way to call onBegin,
+ * and is very necessary (at least in Dojo 1.3.3) to get
+ * the Grid's fetch-more-when-I-need-it logic to work
+ * correctly. *grumble* crummy documentation *snarl!*
+ */
if (typeof req.onBegin == "function") {
/* We lie to onBegin like this because we don't know how
* many more rows we might be able to fetch if the
* user keeps scrolling. Once we get a number of
* results that is less than the limit we asked for,
- * the grid is smart enough to know we're at the end and
- * it does the right thing. */
- var might_be_a_lie = obj.length;
+ * we stop exaggerating, and the grid is smart enough to
+ * know we're at the end and it does the right thing. */
+ var might_be_a_lie = req.start;
if (obj.length >= req.count)
- might_be_a_lie += req.count;
+ might_be_a_lie += obj.length + req.count;
+ else
+ might_be_a_lie += obj.length;
req.onBegin.call(callback_scope, might_be_a_lie, req);
}
* doesn't use it (or loadItem)?), and needs to be able to call
* fetch() or to talk to the web service directly. */
- console.warning(
+ console.warn(
"[unfinished] fetchItemByIdentity(" +
dojo.toJson(keywordArgs) + ")"
);
dojo.require("DojoSRF");
dojo.require("dojox.grid.DataGrid");
dojo.require("openils.FlattenerStore");
+ dojo.require("openils.PermaCrud");
dojo.require("openils.widget.GridColumnPicker");
+ dojo.require("openils.widget.EditDialog"); /* includes EditPane */
dojo.declare(
"openils.widget.FlattenerGrid",
[dojox.grid.DataGrid], {
+ /* These potential constructor arguments are useful to
+ * lattenerGrid in their own right */
"columnReordering": true,
+ "columnPickerPrefix": null,
+
+ /* These potential constructor arguments maybe useful to
+ * FlattenerGrid in their own right, and are passed to
+ * FlattenerStore. */
"fmClass": null,
"fmIdentifier": null,
"mapExtras": null,
- "columnPickerPrefix": null,
+ "defaultSort": null, /* whatever the UI says /replaces/ this */
+ "baseSort": null, /* whatever the UI says /follows/ this */
+
+ /* These potential constructor arguments are for functionality
+ * copied from AutoGrid */
+ "editOnEnter": false, /* also implies edit-on-dblclick */
+ "editStyle": "dialog", /* "dialog" or "pane" */
+ "requiredFields": null, /* affects create/edit dialogs */
+ "suppressEditFields": null, /* affects create/edit dialogs */
/* _generate_map() lives to interpret the attributes of the
* FlattenerGrid dijit itself plus those definined in
"constructor": function(args) {
dojo.mixin(this, args);
+
this.fmIdentifier = this.fmIdentifier ||
fieldmapper.IDL.fmclasses[this.fmClass].pkey;
},
this.store = new openils.FlattenerStore({
"fmClass": this.fmClass,
"fmIdentifier": this.fmIdentifier,
- "mapClause": (this.mapClause || this._generate_map())
+ "mapClause": (this.mapClause || this._generate_map()),
+ "baseSort": this.baseSort,
+ "defaultSort": this.defaultSort
});
}
}
this.inherited(arguments);
+
+ this._showing_create_pane = false;
+
+ this.overrideEditWidgets = {};
+ this.overrideEditWidgetClass = {};
+ this.overrideWidgetArgs = {};
+
+ if (this.editOnEnter)
+ this._applyEditOnEnter();
+ else if (this.singleEditStyle)
+ this._applySingleEditStyle();
+ },
+
+ /* ******** below are methods mostly copied but
+ * slightly changed from AutoGrid ******** */
+
+ "_applySingleEditStyle": function() {
+ this.onMouseOverRow = function(e) {};
+ this.onMouseOutRow = function(e) {};
+ this.onCellFocus = function(cell, rowIndex) {
+ this.selection.deselectAll();
+ this.selection.select(this.focus.rowIndex);
+ };
+ },
+
+ /* capture keydown and launch edit dialog on enter */
+ "_applyEditOnEnter": function() {
+ this._applySingleEditStyle();
+
+ dojo.connect(
+ this, "onRowDblClick", function(e) {
+ if (this.editStyle == "pane")
+ this._drawEditPane(
+ this.selection.getFirstSelected(),
+ this.focus.rowIndex
+ );
+ else
+ this._drawEditDialog(
+ this.selection.getFirstSelected(),
+ this.focus.rowIndex
+ );
+ }
+ );
+
+ dojo.connect(
+ this, "onKeyDown", function(e) {
+ if (e.keyCode == dojo.keys.ENTER) {
+ this.selection.deselectAll();
+ this.selection.select(this.focus.rowIndex);
+ if (this.editStyle == "pane")
+ this._drawEditPane(
+ this.selection.getFirstSelected(),
+ this.focus.rowIndex
+ );
+ else
+ this._drawEditDialog(
+ this.selection.getFirstSelected(),
+ this.focus.rowIndex
+ );
+ }
+ }
+ );
+ },
+
+ "_makeEditPane": function(storeItem, rowIndex, onPostSubmit, onCancel) {
+ var grid = this;
+ var fmObject = (new openils.PermaCrud()).retrieve(
+ this.fmClass,
+ this.store.getIdentity(storeItem)
+ );
+
+ var pane = new openils.widget.EditPane({
+ "fmObject": fmObject,
+ "hideSaveButton": this.editReadOnly,
+ "readOnly": this.editReadOnly,
+ "overrideWidgets": this.overrideEditWidgets,
+ "overrideWidgetClass": this.overrideEditWidgetClass,
+ "overrideWidgetArgs": this.overrideWidgetArgs,
+ "disableWidgetTest": this.disableWidgetTest,
+ "requiredFields": this.requiredFields,
+ "suppressFields": this.suppressEditFields,
+ "onPostSubmit": function() {
+ console.info("onPostSubmit");
+ console.warn("[unfinished] would update store with fmObject values here");
+ // for(var i in fmObject._fields) {
+ // var field = fmObject._fields[i];
+ // if(idents.filter(function(j){return (j == field)})[0])
+ // continue; // don't try to edit an identifier field
+ // grid.store.setValue(storeItem, field, fmObject[field]());
+ // }
+ if (grid.onPostUpdate)
+ grid.onPostUpdate(storeItem, rowIndex);
+ setTimeout(
+ function() {
+ try {
+ grid.views.views[0].getCellNode(
+ rowIndex, 0
+ ).focus();
+ } catch (E) { }
+ }, 200
+ );
+ if (onPostSubmit)
+ onPostSubmit();
+ },
+ "onCancel": function() {
+ console.info("onCancel");
+ setTimeout(
+ function() {
+ grid.views.views[0].getCellNode(
+ rowIndex, 0
+ ).focus();
+ }, 200
+ );
+ if (onCancel)
+ onCancel();
+ }
+ });
+
+ if (typeof this.editPaneOnSubmit == "function")
+ pane.onSubmit = this.editPaneOnSubmit;
+
+ pane.fieldOrder = this.fieldOrder;
+ pane.mode = "update";
+ return pane;
+ },
+
+ "_makeCreatePane": function(onPostSubmit, onCancel) {
+ var grid = this;
+ var pane = new openils.widget.EditPane({
+ "fmClass": this.fmClass,
+ "overrideWidgets": this.overrideEditWidgets,
+ "overrideWidgetClass": this.overrideEditWidgetClass,
+ "overrideWidgetArgs": this.overrideWidgetArgs,
+ "disableWidgetTest": this.disableWidgetTest,
+ "requiredFields": this.requiredFields,
+ "suppressFields": this.suppressEditFields,
+ "onPostSubmit": function(req, cudResults) {
+ var fmObject = cudResults[0];
+ if (grid.onPostCreate)
+ grid.onPostCreate(fmObject);
+ if (fmObject) {
+ //grid.store.newItem(fmObject.toStoreItem());
+ console.warn("[unfinished] here we have fmObject and must update the grid somehow");
+ }
+
+ setTimeout(
+ function() {
+ try {
+ grid.selection.select(grid.rowCount - 1);
+ grid.views.views[0].getCellNode(
+ grid.rowCount - 1, 1
+ ).focus();
+ } catch (E) { }
+ }, 200
+ );
+
+ if (onPostSubmit)
+ onPostSubmit(fmObject);
+ },
+ "onCancel": function() { if (onCancel) onCancel(); }
+ });
+
+ if (typeof this.createPaneOnSubmit == "function")
+ pane.onSubmit = this.createPaneOnSubmit;
+ pane.fieldOrder = this.fieldOrder;
+ pane.mode = "create";
+ return pane;
+ },
+
+ /**
+ * Creates an EditPane with a copy of the data from the provided store
+ * item for cloning said item
+ * @param {Object} storeItem Dojo data item
+ * @param {Number} rowIndex The Grid row index of the item to be cloned
+ * @param {Function} onPostSubmit Optional callback for post-submit behavior
+ * @param {Function} onCancel Optional callback for clone cancelation
+ * @return {Object} The clone EditPane
+ */
+ "_makeClonePane": function(storeItem,rowIndex,onPostSubmit,onCancel) {
+ var clonePane = this._makeCreatePane(onPostSubmit, onCancel);
+ var origPane = this._makeEditPane(storeItem, rowIndex);
+ clonePane.startup();
+ origPane.startup();
+ dojo.forEach(
+ origPane.fieldList, function(field) {
+ if (field.widget.widget.attr('disabled'))
+ return;
+
+ var w = clonePane.fieldList.filter(
+ function(i) { return (i.name == field.name) }
+ )[0];
+
+ // sync widgets
+ w.widget.baseWidgetValue(field.widget.widget.attr('value'));
+
+ // async widgets
+ w.widget.onload = function() {
+ w.widget.baseWidgetValue(
+ field.widget.widget.attr('value')
+ )
+ };
+ }
+ );
+ origPane.destroy();
+ return clonePane;
+ },
+
+
+ "_drawEditDialog": function(storeItem, rowIndex) {
+ var done = dojo.hitch(this, function() { this.hideDialog(); });
+ var pane = this._makeEditPane(storeItem, rowIndex, done, done);
+ this.editDialog = new openils.widget.EditDialog({editPane:pane});
+ this.editDialog.startup();
+ this.editDialog.show();
+ },
+
+ /**
+ * Generates an EditDialog for object creation and displays it to the user
+ */
+ "showCreateDialog": function() {
+ var done = dojo.hitch(this, function() { this.hideDialog(); });
+ var pane = this._makeCreatePane(done, done);
+ this.editDialog = new openils.widget.EditDialog({editPane:pane});
+ this.editDialog.startup();
+ this.editDialog.show();
+ },
+
+ "_drawEditPane": function(storeItem, rowIndex) {
+ var done = dojo.hitch(this, function() { this.hidePane(); });
+
+ dojo.style(this.domNode, "display", "none");
+
+ this.editPane = this._makeEditPane(storeItem, rowIndex, done, done);
+ this.editPane.startup();
+ dojo.place(this.editPane.domNode, this.domNode, "before");
+
+ if (this.onEditPane)
+ this.onEditPane(this.editPane);
+ },
+
+ "showClonePane": function(onPostSubmit) {
+ var done = dojo.hitch(this, function() { this.hidePane(); });
+ var row = this.getFirstSelectedRow();
+
+ if (!row)
+ return;
+
+ if (onPostSubmit) {
+ postSubmit = dojo.hitch(
+ this, function(result) {
+ onPostSubmit(this.getItem(row), result);
+ this.hidePane();
+ }
+ );
+ } else {
+ postSubmit = done;
+ }
+
+ dojo.style(this.domNode, "display", "none");
+ this.editPane = this._makeClonePane(
+ this.getItem(row), row, postSubmit, done
+ );
+ dojo.place(this.editPane.domNode, this.domNode, "before");
+ if (this.onEditPane)
+ this.onEditPane(this.editPane);
+ },
+
+ "showCreatePane": function() {
+ if (this._showing_create_pane)
+ return;
+ this._showing_create_pane = true;
+
+ var done = dojo.hitch(
+ this, function() {
+ this._showing_create_pane = false;
+ this.hidePane();
+ }
+ );
+
+ dojo.style(this.domNode, "display", "none");
+
+ this.editPane = this._makeCreatePane(done, done);
+ this.editPane.startup();
+
+ dojo.place(this.editPane.domNode, this.domNode, "before");
+
+ if (this.onEditPane)
+ this.onEditPane(this.editPane);
+ },
+
+ "hideDialog": function() {
+ this.editDialog.hide();
+ this.editDialog.destroy();
+ delete this.editDialog;
+ this.update();
+ },
+
+ "hidePane": function() {
+ this.domNode.parentNode.removeChild(this.editPane.domNode);
+ this.editPane.destroy();
+ delete this.editPane;
+ dojo.style(this.domNode, "display", "block");
+ this.update();
}
}
);