41bac335de7511151aa43be9f84a0a4a4f57299b
[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 dojo.requireLocalization('openils.conify', 'conify');
8 var localeStrings = dojo.i18n.getLocalization('openils.conify', 'conify');
9
10
11 var formCache = {};
12 var formula, entryTbody, entryTemplate, dndSource;
13 var virtualId = -1;
14 var pcrud;
15 var _collection_code_textboxes = [];
16 var _collection_code_kludge_active = false;
17 var fundSearchFilter = {active : 't'};
18
19 function gridDataLoader() {
20     fListGrid.resetStore();
21     fListGrid.showLoadProgressIndicator();
22     fieldmapper.standardRequest(
23         ["open-ils.acq", "open-ils.acq.distribution_formula.ranged.retrieve"], {
24             "async": true,
25             "params": [
26                 openils.User.authtoken,
27                 fListGrid.displayOffset,
28                 fListGrid.displayLimit
29             ],
30             "onresponse": function(r) {
31                 var form = openils.Util.readResponse(r);
32                 formCache[form.id()] = form;
33                 fListGrid.store.newItem(form.toStoreItem());
34             },
35             "oncomplete": function() {
36                 fListGrid.hideLoadProgressIndicator();
37             }
38         }
39     );
40 }
41
42 function setFundSearchFilter(callback) {
43     new openils.User().getPermOrgList(
44         ['ADMIN_ACQ_DISTRIB_FORMULA'],
45         function(orgs) { 
46             fundSearchFilter.org = orgs;
47             if (callback) callback();
48         },
49         true, true // descendants, id_list
50     );
51 }
52
53 function draw() {
54
55     pcrud = new openils.PermaCrud();
56
57     if(formulaId) {
58         openils.Util.hide('formula-list-div');
59         setFundSearchFilter(drawFormulaSummary);
60     } else {
61
62         openils.Util.hide('formula-entry-div');
63         fListGrid.onPostCreate = function(fmObject) {
64             location.href = location.href + '/' + fmObject.id();
65         }
66
67         fListGrid.dataLoader = gridDataLoader;
68         gridDataLoader();
69     }
70 }
71
72 function cloneSelectedFormula() {
73     var item = fListGrid.getSelectedItems()[0];
74     if(!item) return;
75     var formula = new fieldmapper.acqf().fromStoreItem(item);
76     fieldmapper.standardRequest(
77         ['open-ils.acq', 'open-ils.acq.distribution_formula.clone'],
78         {
79             asnyc : true,
80             params : [
81                 openils.User.authtoken, 
82                 formula.id(), 
83                 dojo.string.substitute(localeStrings.ACQ_DISTRIB_FORMULA_NAME_CLONE, [formula.name()])
84             ],
85             oncomplete : function(r) {
86                 if(r = openils.Util.readResponse(r)) {
87                     location.href = oilsBasePath + '/conify/global/acq/distribution_formula/' + r;
88                 }
89             }
90         }
91     );
92 }
93
94 openils.Util.addOnLoad(draw);
95
96 function getItemCount(rowIndex, item) {
97     if(!item) return '';
98     var form = formCache[this.grid.store.getValue(item, "id")];
99     if(!form) return 0;
100     var count = 0;
101     dojo.forEach(form.entries(), function(e) { count = count + e.item_count(); });
102     return count;
103 }
104
105 function byName(node, name) {
106     return dojo.query('[name='+name+']', node)[0];
107 }
108
109 function drawFormulaSummary() {
110     openils.Util.show('formula-entry-div');
111
112     var entries = pcrud.search('acqdfe', {formula: formulaId}, {order_by:{acqdfe : 'position'}});
113     formula = pcrud.retrieve('acqdf', formulaId);
114     formula.entries(entries);
115
116     dojo.byId('formula_head').innerHTML = formula.name();
117     dojo.byId('formula_head').onclick = function() {
118         var name = prompt(localeStrings.ACQ_DISTRIB_FORMULA_NAME_PROMPT, formula.name());
119         if(name && name != formula.name()) {
120             formula.name(name);
121             pcrud = new openils.PermaCrud();
122             pcrud.update(formula);
123             dojo.byId('formula_head').innerHTML = name;
124         }
125     }
126
127     dojo.forEach(entries, function(entry) { addEntry(entry); } );
128 }
129
130 function addEntry(entry) {
131
132     if(!entryTbody) {
133         entryTbody = dojo.byId('formula-entry-tbody');
134         entryTemplate = entryTbody.removeChild(dojo.byId('formula-entry-tempate'));
135         dndSource = new dojo.dnd.Source(entryTbody);
136         dndSource.selectAll(); 
137         dndSource.deleteSelectedNodes();
138         dndSource.clearItems();
139     }
140
141     if(!entry) {
142         entry = new fieldmapper.acqdfe();
143         entry.formula(formulaId);
144         entry.item_count(1);
145         entry.owning_lib(openils.User.user.ws_ou());
146         entry.id(virtualId--);
147         entry.isnew(true);
148         formula.entries().push(entry);
149     }
150
151     var row = entryTbody.appendChild(entryTemplate.cloneNode(true));
152     row.setAttribute('entry', entry.id());
153     dndSource.insertNodes(false, [row]);
154     byName(row, 'delete').onclick = function() {
155         entry.isdeleted(true);
156         entryTbody.removeChild(row);
157         dndSource.sync();
158     };
159
160     dojo.forEach(
161         ['owning_lib', 'location', 'fund', 'circ_modifier', 'collection_code', 'item_count'],
162         function(field) {
163             new openils.widget.AutoFieldWidget({
164                 forceSync : true,
165                 fmField : field, 
166                 fmObject : entry,
167                 fmClass : 'acqdfe',
168                 searchFilter : (field == 'fund') ? fundSearchFilter : null,
169                 parentNode : byName(row, field),
170                 orgDefaultsToWs : true,
171                 orgLimitPerms : ['ADMIN_ACQ_DISTRIB_FORMULA'],
172                 widgetClass : (field == 'item_count') ? 'dijit.form.NumberSpinner' : null,
173                 dijitArgs : (field == 'item_count') ? {min:1, places:0} : null
174             }).build(
175                 function(w, ww) {
176                     if (field == "collection_code") {
177                         /* kludge for glitchy textbox */
178                         _collection_code_textboxes.push(w);
179                     }
180                     dojo.connect(w, 'onChange', 
181                         function(newVal) {
182                             entry[field]( newVal );
183                             entry.ischanged(true);
184                         }
185                     )
186                 }
187             );
188         }
189     );
190
191     /* For some reason (bug) the dndSource intercepts onMouseDown events
192      * that should hit dijit textboxes in our table thingy. Other dijits
193      * (buttons, filteringselects, etc) seem not to be affected.  This
194      * workaround deals with the only textboxes we have for now: the ones
195      * for the collection_code field. */
196     if (!_collection_code_kludge_active) {
197         _collection_code_kludge_active = true;
198         var original = dojo.hitch(dndSource, dndSource.onMouseDown);
199         dndSource.onMouseDown = function(e) {
200             var hits = _collection_code_textboxes.filter(
201                 function(w) {
202                     var c = dojo.coords(w.domNode);
203                     if (e.clientX >= c.x && e.clientX < c.x + c.w) {
204                         if (e.clientY >= c.y && e.clientY < c.y + c.h) {
205                             return true;
206                         }
207                     }
208                     return false;
209                 }
210             );
211
212             if (hits.length) {
213                 hits[0].focus();
214             } else {
215                 original(e);
216             }
217         };
218     }
219 }
220
221 function saveFormula() {
222     var pos = 1;
223     var updatedEntries = [];
224     var deletedEntries = [];
225
226     // remove deleted entries from consideration for collision protection
227     for(var i = 0; i < formula.entries().length; i++) {
228         if(formula.entries()[i].isdeleted())
229             deletedEntries.push(formula.entries().splice(i--, 1)[0])
230     }
231
232     // update entry positions and create temporary collision avoidance entries
233     dojo.forEach(
234         dndSource.getAllNodes(),
235         function(node) {
236
237             var entryId = node.getAttribute('entry');
238             var entry = formula.entries().filter(function(e) {return (e.id() == entryId)})[0];
239
240             if(entry.position() != pos) {
241
242                 // update the position
243                 var changedEntry = entry.clone();
244                 changedEntry.position(pos);
245                 changedEntry.ischanged(true);
246                 updatedEntries.push(changedEntry);
247
248                 // clear the virtual ID
249                 if(changedEntry.isnew())
250                     changedEntry.id(null); 
251
252                 var oldEntry = formula.entries().filter(function(e) {return (e.position() == pos)})[0];
253
254                 if(oldEntry) {
255                     // move the entry currently in that spot temporarily into negative territory
256                     var moveMe = oldEntry.clone();
257                     moveMe.ischanged(true);
258                     moveMe.position(moveMe.position() * -1); 
259                     updatedEntries.unshift(moveMe);
260                 }
261             }
262             pos++;
263         }
264     );
265
266     // finally, for every entry that changed w/o changing position
267     // throw it on the list for update
268     dojo.forEach(
269         formula.entries(),
270         function(entry) {
271             if(entry.ischanged() && !entry.isdeleted() && !entry.isnew()) {
272                 if(updatedEntries.filter(function(e) { return (e.id() == entry.id()) }).length == 0)
273                     updatedEntries.push(entry);
274             }
275         }
276     );
277
278     updatedEntries = deletedEntries.concat(updatedEntries);
279     if(updatedEntries.length) {
280         pcrud = new openils.PermaCrud();
281         try { 
282             pcrud.apply(updatedEntries);
283         } catch(E) {
284             alert('error updating: ' + E);
285             return;
286         }
287         location.href = location.href;
288     }
289 }
290
291