1 dojo.require('dijit.Dialog');
2 dojo.require('dijit.form.Button');
3 dojo.require('dijit.form.FilteringSelect');
4 dojo.require('openils.PermaCrud');
5 dojo.require('openils.widget.AutoFieldWidget');
7 var recordAttrDefs = {};// full name => crad map
8 var codedValueMaps = {};// growing cache of id => ccvm
9 var compositeDef; // the thing what we're building / editing
10 var nodeTree; // internal composite attrs tree representation
11 var treeIndex = 0; // internal composit attrs node index
13 var localeStrings = {}; // TODO: move to nls file
14 localeStrings.OR = "OR";
15 localeStrings.AND = "AND";
16 localeStrings.NOT = "NOT";
19 console.log('fetching ccvm ' + ccvmId);
23 new openils.PermaCrud().retrieve('ccvm', ccvmId, {
25 flesh_fields : {ccvm : ['composite_def', 'ctype']},
26 oncomplete : function(r) {
27 map = openils.Util.readResponse(r);
30 dojo.byId('attr-def-name').innerHTML =
32 dojo.byId('coded-value-map-name').innerHTML =
33 map.code() + ' / ' + map.value();
35 dojo.byId('return-to-ccvm').onclick = function() {
36 location.href = oilsBasePath +
37 '/conify/global/config/coded_value_map/' +
41 // build a new def if needed
42 compositeDef = map.composite_def();
44 compositeDef = new fieldmapper.ccraed();
45 compositeDef.isnew(true);
46 compositeDef.coded_value(map.id());
48 if (!--asyncReqs) drawCompositDef();
52 new openils.PermaCrud().retrieveAll('crad', {
53 order_by : {crad : ['name']},
54 oncomplete : function(r) {
55 var defs = openils.Util.readResponse(r);
56 dojo.forEach(defs, function(def) {
57 recordAttrDefs[def.name()] = def;
59 if (!--asyncReqs) drawCompositDef();
65 function drawCompositDef() {
66 var defBlob = JSON2js(compositeDef.definition());
68 importNodeTree(null, defBlob);
70 if (fetchAttrs.length) {
71 new openils.PermaCrud().search('ccvm', {'-or' : fetchAttrs}, {
72 oncomplete : function(r) {
73 var maps = openils.Util.readResponse(r);
74 dojo.forEach(maps, function(map) {
75 codedValueMaps[map.id()] = map;
85 // translate the DB-stored tree into a local structure
86 function importNodeTree(pnode, node) {
96 pnode.children.push(newnode);
102 if (dojo.isArray(node)) {
104 dojo.forEach(node, function(n) { importNodeTree(newnode, n) });
106 } else if (node._not) {
108 importNodeTree(newnode, node._not);
110 } else if (node._attr) {
111 // list of attrs that we have to fetch for display
112 fetchAttrs.push({'-and' : {ctype : node._attr, code : node._val}});
114 newnode.attr = node._attr;
115 newnode.val = node._val;
119 dojo.forEach(Object.keys(node).sort(), function(key) {
120 importNodeTree(newnode, node[key]);
125 function byname(elm, name) {
126 return dojo.query('[name=' + name + ']', elm)[0];
128 function findccvm(ctype, code) {
129 for (var id in codedValueMaps) {
130 var m = codedValueMaps[id];
131 if (m.code() == code && m.ctype() == ctype) {
135 console.error('cannot find ccvm ' + ctype + ' : ' + code);
138 // render the local structure tree in the DOM
141 function drawNodeTree(node) {
144 nodeTbody = dojo.byId('tree-container');
145 nodeTemplate = nodeTbody.removeChild(dojo.byId('node-template'));
150 dojo.empty(nodeTbody);
152 newTreeBtn.attr('disabled', false);
153 delTreeBtn.attr('disabled', true);
161 newTreeBtn.attr('disabled', true);
162 delTreeBtn.attr('disabled', false);
165 function d(node) {if (node) {depth++; d(node.pnode);}};
168 node.element = nodeTemplate.cloneNode(true);
171 var addLink = byname(node.element, 'add-child');
172 var delLink = byname(node.element, 'del-child');
173 addLink.setAttribute('index', node.index);
174 delLink.setAttribute('index', node.index);
177 byname(node.element, 'attr').innerHTML = localeStrings.OR;
179 } else if (node.and) {
180 byname(node.element, 'attr').innerHTML = localeStrings.AND;
182 } else if (node.not) {
183 byname(node.element, 'attr').innerHTML = localeStrings.NOT;
186 dojo.addClass(addLink, 'hidden');
188 byname(node.element, 'attr').innerHTML =
189 recordAttrDefs[node.attr].label() + ' (' + node.attr + ')';
191 var map = findccvm(node.attr, node.val);
192 byname(node.element, 'val').innerHTML =
193 map.value() + ' (' + map.code() + ')';
196 dojo.query('.invisible', node.element)[0], 'invisible');
198 expression = map.value();
201 nodeTbody.appendChild(node.element);
203 var nc = dojo.query('.node-column', node.element)[0];
204 for (var i = 0; i < depth; i++) {
205 nc.insertBefore(dojo.byId('tree-pad').cloneNode(true), nc.firstChild);
208 if (node.attr) return expression;
211 if (node.children[0]) {
212 expression = localeStrings.NOT +
213 ' ' + drawNodeTree(node.children[0]);
218 if (!root) expression = '( ';
219 for (var i = 0; i < node.children.length; i++) {
220 expression += drawNodeTree(node.children[i]);
221 if (i == node.children.length - 1) break;
222 expression += ' ' + (node.or ? localeStrings.OR :
223 (node.and ? localeStrings.AND : localeStrings.NOT)) + ' ';
225 if (!root) expression += ' )';
229 dojo.byId('tree-expression').innerHTML = expression;
235 function findNode(index, node) {
236 if (!node) node = nodeTree;
237 if (node.index == index) return node;
238 for (var i = 0; i < node.children.length; i++) {
239 var n = findNode(index, node.children[i]);
245 function buildSelectors() {
246 if (cradSelector) return;
247 cradSelector = new openils.widget.AutoFieldWidget({
249 selfReference : true,
250 parentNode : 'new-data-crad-selector'
252 cradSelector.build(function(w, ww) {
253 dojo.connect(w, 'onChange', function(val) {
254 dojo.byId('new-data-attr').checked = true;
255 new openils.PermaCrud().search('ccvm', {ctype : val}, {
256 oncomplete : function(r) {
257 var maps = openils.Util.readResponse(r);
259 dojo.forEach(maps, function(map) {
260 codedValueMaps[map.id()] = map;
261 items.push({name : map.value(), value : map.id()});
263 ccvmSelector.store = new dojo.data.ItemFileReadStore({
265 identifier : 'value',
270 ccvmSelector.startup();
277 function addChild(link) {
279 var ctxNode = link ? findNode(link.getAttribute('index')) : null;
281 newDataSubmit.onClick = function(args) {
288 if (dojo.byId('new-data-and').checked) {
290 } else if (dojo.byId('new-data-or').checked) {
292 } else if (dojo.byId('new-data-not').checked) {
295 node.attr = cradSelector.widget.attr('value');
296 node.val = codedValueMaps[ccvmSelector.attr('value')].code();
297 if (!node.attr || !node.val) return;
300 newDataDialog.hide();
302 // for visual clarity, push the non-boolean children to the front
304 if (node.and || node.or || node.not) {
305 ctxNode.children.push(node);
307 ctxNode.children.unshift(node);
310 // starting a new tree from scratch
316 dojo.byId('new-data-attr').checked = true;
317 newDataDialog.show();
320 function delChild(link) {
321 var node = findNode(link.getAttribute('index'));
324 for (var i = 0; i < node.pnode.children.length; i++) {
325 var child = node.pnode.children[i];
326 if (child.index == node.index) {
327 node.pnode.children.splice(i, 1);
332 newTreeBtn.attr('disabled', false);
333 delTreeBtn.attr('disabled', true);
342 drawNodeTree(); // resets
343 new openils.PermaCrud().eliminate(compositeDef);
344 compositeDef.isnew(true);
345 compositeDef.definition(null);
348 function saveTree() {
349 var expression = exportTree();
351 compositeDef.definition(js2JSON(expression))
352 var pcrud = new openils.PermaCrud();
353 saveTreeBtn.attr('disabled', true);
355 var oncomplete = function(r) {
356 openils.Util.readResponse(r); // pickup any alerts
357 saveTreeBtn.attr('disabled', false);
358 compositeDef.isnew(false);
361 var pfunc = compositeDef.isnew() ? 'create' : 'update';
362 pcrud[pfunc](compositeDef, {oncomplete : oncomplete});
365 function exportTree(node) {
366 if (!node) node = nodeTree;
369 return {_attr : node.attr, _val : node.val};
372 // _not nodes may only have one child
373 return {_not : exportTree(node.children[0])};
376 for (var i = 0; i < node.children.length; i++) {
377 var child = node.children[i];
378 if (!compiled) compiled = node.or ? [] : {};
379 compiled[i] = exportTree(child);
385 openils.Util.addOnLoad(drawPage);