distrib formula streamlined drag-n-drop UI.
authorerickson <erickson@dcc99617-32d9-48b4-a31d-7c20da2025e4>
Tue, 31 Aug 2010 03:52:53 +0000 (03:52 +0000)
committererickson <erickson@dcc99617-32d9-48b4-a31d-7c20da2025e4>
Tue, 31 Aug 2010 03:52:53 +0000 (03:52 +0000)
Goal is to make distrib formulas faster/easier to create and manage
TODO: add a clone option for formulas; style tweaks

git-svn-id: svn://svn.open-ils.org/ILS/trunk@17399 dcc99617-32d9-48b4-a31d-7c20da2025e4

Open-ILS/web/js/ui/default/conify/global/acq/distribution_formula.js
Open-ILS/web/templates/default/conify/global/acq/distribution_formula.tt2

index 10d1990..130bcc9 100644 (file)
@@ -1,11 +1,20 @@
+dojo.require("dojo.dnd.Container");
+dojo.require("dojo.dnd.Source");
 dojo.require('openils.widget.AutoGrid');
 dojo.require('dijit.form.FilteringSelect');
 dojo.require('openils.PermaCrud');
-var formula;
+dojo.require('openils.widget.AutoFieldWidget');
+
 var formCache = [];
+var formula, entryTbody, entryTemplate, dndSource;
+var virtualId = -1;
+var pcrud;
+
 
 function draw() {
 
+    pcrud = new openils.PermaCrud();
+
     if(formulaId) {
         openils.Util.hide('formula-list-div');
         drawFormulaSummary();
@@ -35,16 +44,6 @@ function draw() {
 }
 openils.Util.addOnLoad(draw);
 
-function drawFormulaSummary() {
-    openils.Util.show('formula-entry-div');
-    dfeListGrid.overrideEditWidgets.formula = new
-        dijit.form.TextBox({style:'display:none', value: formulaId});
-    dfeListGrid.loadAll({order_by:{acqdfe : 'formula'}}, {formula : formulaId});
-    var pcrud = new openils.PermaCrud();
-    var formulaName = pcrud.retrieve('acqdf', formulaId);
-    dojo.byId('formula_head').innerHTML = formulaName.name();
-}
-
 function getItemCount(rowIndex, item) {
     if(!item) return '';
     var form = formCache[this.grid.store.getValue(item, "id")];
@@ -54,3 +53,146 @@ function getItemCount(rowIndex, item) {
     return count;
 }
 
+function byName(node, name) {
+    return dojo.query('[name='+name+']', node)[0];
+}
+
+function drawFormulaSummary() {
+    openils.Util.show('formula-entry-div');
+
+    var entries = pcrud.search('acqdfe', {formula: formulaId}, {order_by:{acqdfe : 'position'}});
+    formula = pcrud.retrieve('acqdf', formulaId);
+    formula.entries(entries);
+
+    dojo.byId('formula_head').innerHTML = formula.name();
+    dojo.forEach(entries, function(entry) { addEntry(entry); } );
+}
+
+function addEntry(entry) {
+
+    if(!entryTbody) {
+        entryTbody = dojo.byId('formula-entry-tbody');
+        entryTemplate = entryTbody.removeChild(dojo.byId('formula-entry-tempate'));
+        dndSource = new dojo.dnd.Source(entryTbody);
+        dndSource.selectAll(); 
+        dndSource.deleteSelectedNodes();
+        dndSource.clearItems();
+    }
+
+    if(!entry) {
+        entry = new fieldmapper.acqdfe();
+        entry.formula(formulaId);
+        entry.item_count(1);
+        entry.owning_lib(openils.User.user.ws_ou());
+        entry.id(virtualId--);
+        entry.isnew(true);
+        formula.entries().push(entry);
+    }
+
+    var row = entryTbody.appendChild(entryTemplate.cloneNode(true));
+    row.setAttribute('entry', entry.id());
+    dndSource.insertNodes(false, [row]);
+    byName(row, 'delete').onclick = function() {
+        entry.isdeleted(true);
+        entryTbody.removeChild(row);
+        dndSource.sync();
+    };
+
+    dojo.forEach(
+        ['owning_lib', 'location', 'item_count'],
+        function(field) {
+            new openils.widget.AutoFieldWidget({
+                forceSync : true,
+                fmField : field, 
+                fmObject : entry,
+                fmClass : 'acqdfe',
+                parentNode : byName(row, field),
+                orgDefaultsToWs : true,
+                orgLimitPerms : ['ADMIN_ACQ_DISTRIB_FORMULA'],
+                widgetClass : (field == 'item_count') ? 'dijit.form.NumberSpinner' : null,
+                dijitArgs : (field == 'item_count') ? {min:1, places:0} : null
+            }).build(
+                function(w, ww) {
+                    dojo.connect(w, 'onChange', 
+                        function(newVal) {
+                            entry[field]( newVal );
+                            entry.ischanged(true);
+                        }
+                    )
+                }
+            );
+        }
+    );
+}
+
+function saveFormula() {
+    var pos = 1;
+    var updatedEntries = [];
+    var deletedEntries = [];
+
+    // remove deleted entries from consideration for collision protection
+    for(var i = 0; i < formula.entries().length; i++) {
+        if(formula.entries()[i].isdeleted())
+            deletedEntries.push(formula.entries().splice(i--, 1)[0])
+    }
+
+    // update entry positions and create temporary collision avoidance entries
+    dojo.forEach(
+        dndSource.getAllNodes(),
+        function(node) {
+
+            var entryId = node.getAttribute('entry');
+            var entry = formula.entries().filter(function(e) {return (e.id() == entryId)})[0];
+
+            if(entry.position() != pos) {
+
+                // update the position
+                var changedEntry = entry.clone();
+                changedEntry.position(pos);
+                changedEntry.ischanged(true);
+                updatedEntries.push(changedEntry);
+
+                // clear the virtual ID
+                if(changedEntry.isnew())
+                    changedEntry.id(null); 
+
+                var oldEntry = formula.entries().filter(function(e) {return (e.position() == pos)})[0];
+
+                if(oldEntry) {
+                    // move the entry currently in that spot temporarily into negative territory
+                    var moveMe = oldEntry.clone();
+                    moveMe.ischanged(true);
+                    moveMe.position(moveMe.position() * -1); 
+                    updatedEntries.unshift(moveMe);
+                }
+            }
+            pos++;
+        }
+    );
+
+    // finally, for every entry that changed w/o changing position
+    // throw it on the list for update
+    dojo.forEach(
+        formula.entries(),
+        function(entry) {
+            if(entry.ischanged() && !entry.isdeleted() && !entry.isnew()) {
+                if(updatedEntries.filter(function(e) { return (e.id() == entry.id()) }).length == 0)
+                    updatedEntries.push(entry);
+            }
+        }
+    );
+
+    updatedEntries = deletedEntries.concat(updatedEntries);
+    if(updatedEntries.length) {
+        pcrud = new openils.PermaCrud();
+        try { 
+            pcrud.apply(updatedEntries);
+        } catch(E) {
+            alert('error updating: ' + E);
+            return;
+        }
+        location.href = location.href;
+    }
+}
+
+
index bb932ca..2f900f2 100644 (file)
@@ -49,34 +49,50 @@ function formatName(value) {
 
 
 <div id='formula-entry-div'>
-    <div dojoType="dijit.layout.ContentPane" layoutAlign="client">
-        <div id='formula-summary-pane'/>
-    </div>
-        <div dojoType="dijit.layout.ContentPane" layoutAlign="client" class='oils-header-panel'>
-            <div id="formula_head"></div>
-            <div>
-                <button dojoType='dijit.form.Button' onClick='dfeListGrid.showCreateDialog()'>New Formula Entry</button>
-                <button dojoType='dijit.form.Button' onClick='dfeListGrid.deleteSelected()'>Delete Selected</button>
-            </div>
-        </div>
-        <div dojoType="dijit.layout.ContentPane" layoutAlign="client">
-            <table  jsId="dfeListGrid"
-                    autoHeight='true'
-                    dojoType="openils.widget.AutoGrid"
-                    fieldOrder="['id','formula', 'owning_lib', 'location', 'item_count', 'position']"
-                    suppressFields="['formula']"
-                    query="{id: '*'}"
-                    defaultCellWidth='12'
-                    fmClass='acqdfe'
-                    editOnEnter='true'>
-                <thead>
-                    <tr>
-                        <th field='formula' get='getFormulaId' formatter='formatName'/>
-                    </tr>
-                </thead>
-            </table>
+    <div dojoType="dijit.layout.ContentPane" layoutAlign="client" class='oils-header-panel'>
+        <div id="formula_head"></div>
+        <div>
         </div>
     </div>
+    <br/>
+    <div>
+        <button dojoType='dijit.form.Button' onClick='addEntry()'>New Entry</button>
+        <span style='padding-right:20px;'></span>
+        <button dojoType='dijit.form.Button' onClick='saveFormula()'>Apply Changes</button>
+    </div>
+    <br/>
+    <table class='oils-generic-table'>
+        <thead>
+            <tr>
+                <th></th>
+                <th>Owning Library</th>
+                <th>Shelving Location</th>
+                <th>Item Count</th>
+                <th></th>
+            </tr>
+        </thead>
+        <tbody id='formula-entry-tbody'>
+            <tr id='formula-entry-tempate'>
+                <td><div name='delete' dojoType='dijit.form.Button' style='color:red;' scrollOnFocus='false'>X</div></td>
+                <td><div name='owning_lib'></td>
+                <td><div name='location'></td>
+                <td><div name='item_count'></td>
+                <td>
+                    <!-- TODO: add to repo / use local images -->
+                    <img src='http://mxr.mozilla.org/mozilla-central/source/toolkit/themes/pinstripe/global/splitter/dimple.png?raw=1'/>
+                    <img src='http://mxr.mozilla.org/mozilla-central/source/toolkit/themes/pinstripe/global/splitter/dimple.png?raw=1'/>
+                    <img src='http://mxr.mozilla.org/mozilla-central/source/toolkit/themes/pinstripe/global/splitter/dimple.png?raw=1'/>
+                <td>
+            </tr>
+        </tbody>
+    </table>
 </div>
+<br/>
+<div>
+    <button dojoType='dijit.form.Button' onClick='addEntry()'>New Entry</button>
+    <span style='padding-right:20px;'></span>
+    <button dojoType='dijit.form.Button' onClick='saveFormula()'>Apply Changes</button>
+</div>
+
 [% END %]