distrib formula streamlined drag-n-drop UI.
[working/Evergreen.git] / Open-ILS / web / js / ui / default / conify / global / acq / distribution_formula.js
1 dojo.require("dojo.dnd.Container");
2 dojo.require("dojo.dnd.Source");
3 dojo.require('openils.widget.AutoGrid');
4 dojo.require('dijit.form.FilteringSelect');
5 dojo.require('openils.PermaCrud');
6 dojo.require('openils.widget.AutoFieldWidget');
7
8 var formCache = [];
9 var formula, entryTbody, entryTemplate, dndSource;
10 var virtualId = -1;
11 var pcrud;
12
13
14 function draw() {
15
16     pcrud = new openils.PermaCrud();
17
18     if(formulaId) {
19         openils.Util.hide('formula-list-div');
20         drawFormulaSummary();
21     } else {
22
23         openils.Util.hide('formula-entry-div');
24         fListGrid.onPostCreate = function(fmObject) {
25             location.href = location.href + '/' + fmObject.id();
26         }
27
28         fieldmapper.standardRequest(
29             ['open-ils.acq', 'open-ils.acq.distribution_formula.ranged.retrieve'],
30             {   async: true,
31                 params: [openils.User.authtoken],
32                 onresponse: function (r) { 
33                     var form = openils.Util.readResponse(r);
34                     formCache[form.id()] = form;
35                     fListGrid.store.newItem(form.toStoreItem());
36                 },
37                 oncomplete: function() {
38                     fListGrid.hideLoadProgressIndicator();
39                 }
40             }
41         );
42
43     }
44 }
45 openils.Util.addOnLoad(draw);
46
47 function getItemCount(rowIndex, item) {
48     if(!item) return '';
49     var form = formCache[this.grid.store.getValue(item, "id")];
50     if(!form) return 0;
51     var count = 0;
52     dojo.forEach(form.entries(), function(e) { count = count + e.item_count(); });
53     return count;
54 }
55
56 function byName(node, name) {
57     return dojo.query('[name='+name+']', node)[0];
58 }
59
60 function drawFormulaSummary() {
61     openils.Util.show('formula-entry-div');
62
63     var entries = pcrud.search('acqdfe', {formula: formulaId}, {order_by:{acqdfe : 'position'}});
64     formula = pcrud.retrieve('acqdf', formulaId);
65     formula.entries(entries);
66
67     dojo.byId('formula_head').innerHTML = formula.name();
68     dojo.forEach(entries, function(entry) { addEntry(entry); } );
69 }
70
71 function addEntry(entry) {
72
73     if(!entryTbody) {
74         entryTbody = dojo.byId('formula-entry-tbody');
75         entryTemplate = entryTbody.removeChild(dojo.byId('formula-entry-tempate'));
76         dndSource = new dojo.dnd.Source(entryTbody);
77         dndSource.selectAll(); 
78         dndSource.deleteSelectedNodes();
79         dndSource.clearItems();
80     }
81
82     if(!entry) {
83         entry = new fieldmapper.acqdfe();
84         entry.formula(formulaId);
85         entry.item_count(1);
86         entry.owning_lib(openils.User.user.ws_ou());
87         entry.id(virtualId--);
88         entry.isnew(true);
89         formula.entries().push(entry);
90     }
91
92     var row = entryTbody.appendChild(entryTemplate.cloneNode(true));
93     row.setAttribute('entry', entry.id());
94     dndSource.insertNodes(false, [row]);
95     byName(row, 'delete').onclick = function() {
96         entry.isdeleted(true);
97         entryTbody.removeChild(row);
98         dndSource.sync();
99     };
100
101     dojo.forEach(
102         ['owning_lib', 'location', 'item_count'],
103         function(field) {
104             new openils.widget.AutoFieldWidget({
105                 forceSync : true,
106                 fmField : field, 
107                 fmObject : entry,
108                 fmClass : 'acqdfe',
109                 parentNode : byName(row, field),
110                 orgDefaultsToWs : true,
111                 orgLimitPerms : ['ADMIN_ACQ_DISTRIB_FORMULA'],
112                 widgetClass : (field == 'item_count') ? 'dijit.form.NumberSpinner' : null,
113                 dijitArgs : (field == 'item_count') ? {min:1, places:0} : null
114             }).build(
115                 function(w, ww) {
116                     dojo.connect(w, 'onChange', 
117                         function(newVal) {
118                             entry[field]( newVal );
119                             entry.ischanged(true);
120                         }
121                     )
122                 }
123             );
124         }
125     );
126 }
127
128 function saveFormula() {
129     var pos = 1;
130     var updatedEntries = [];
131     var deletedEntries = [];
132
133     // remove deleted entries from consideration for collision protection
134     for(var i = 0; i < formula.entries().length; i++) {
135         if(formula.entries()[i].isdeleted())
136             deletedEntries.push(formula.entries().splice(i--, 1)[0])
137     }
138
139     // update entry positions and create temporary collision avoidance entries
140     dojo.forEach(
141         dndSource.getAllNodes(),
142         function(node) {
143
144             var entryId = node.getAttribute('entry');
145             var entry = formula.entries().filter(function(e) {return (e.id() == entryId)})[0];
146
147             if(entry.position() != pos) {
148
149                 // update the position
150                 var changedEntry = entry.clone();
151                 changedEntry.position(pos);
152                 changedEntry.ischanged(true);
153                 updatedEntries.push(changedEntry);
154
155                 // clear the virtual ID
156                 if(changedEntry.isnew())
157                     changedEntry.id(null); 
158
159                 var oldEntry = formula.entries().filter(function(e) {return (e.position() == pos)})[0];
160
161                 if(oldEntry) {
162                     // move the entry currently in that spot temporarily into negative territory
163                     var moveMe = oldEntry.clone();
164                     moveMe.ischanged(true);
165                     moveMe.position(moveMe.position() * -1); 
166                     updatedEntries.unshift(moveMe);
167                 }
168             }
169             pos++;
170         }
171     );
172
173     // finally, for every entry that changed w/o changing position
174     // throw it on the list for update
175     dojo.forEach(
176         formula.entries(),
177         function(entry) {
178             if(entry.ischanged() && !entry.isdeleted() && !entry.isnew()) {
179                 if(updatedEntries.filter(function(e) { return (e.id() == entry.id()) }).length == 0)
180                     updatedEntries.push(entry);
181             }
182         }
183     );
184
185     updatedEntries = deletedEntries.concat(updatedEntries);
186     if(updatedEntries.length) {
187         pcrud = new openils.PermaCrud();
188         try { 
189             pcrud.apply(updatedEntries);
190         } catch(E) {
191             alert('error updating: ' + E);
192             return;
193         }
194         location.href = location.href;
195     }
196 }
197
198