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;
262 name : map.value() + ' (' + map.code() + ')',
266 ccvmSelector.store = new dojo.data.ItemFileReadStore({
268 identifier : 'value',
273 ccvmSelector.startup();
280 function addChild(link) {
282 var ctxNode = link ? findNode(link.getAttribute('index')) : null;
284 newDataSubmit.onClick = function(args) {
291 if (dojo.byId('new-data-and').checked) {
293 } else if (dojo.byId('new-data-or').checked) {
295 } else if (dojo.byId('new-data-not').checked) {
298 node.attr = cradSelector.widget.attr('value');
299 node.val = codedValueMaps[ccvmSelector.attr('value')].code();
300 if (!node.attr || !node.val) return;
303 newDataDialog.hide();
305 // for visual clarity, push the non-boolean children to the front
307 if (node.and || node.or || node.not) {
308 ctxNode.children.push(node);
310 ctxNode.children.unshift(node);
313 // starting a new tree from scratch
319 dojo.byId('new-data-attr').checked = true;
320 newDataDialog.show();
323 function delChild(link) {
324 var node = findNode(link.getAttribute('index'));
327 for (var i = 0; i < node.pnode.children.length; i++) {
328 var child = node.pnode.children[i];
329 if (child.index == node.index) {
330 node.pnode.children.splice(i, 1);
335 newTreeBtn.attr('disabled', false);
336 delTreeBtn.attr('disabled', true);
345 drawNodeTree(); // resets
346 new openils.PermaCrud().eliminate(compositeDef);
347 compositeDef.isnew(true);
348 compositeDef.definition(null);
351 function saveTree() {
352 var expression = exportTree();
354 compositeDef.definition(js2JSON(expression))
355 var pcrud = new openils.PermaCrud();
356 saveTreeBtn.attr('disabled', true);
358 var oncomplete = function(r) {
359 openils.Util.readResponse(r); // pickup any alerts
360 saveTreeBtn.attr('disabled', false);
361 compositeDef.isnew(false);
364 var pfunc = compositeDef.isnew() ? 'create' : 'update';
365 pcrud[pfunc](compositeDef, {oncomplete : oncomplete});
368 function exportTree(node) {
369 if (!node) node = nodeTree;
372 return {_attr : node.attr, _val : node.val};
375 // _not nodes may only have one child
376 return {_not : exportTree(node.children[0])};
379 for (var i = 0; i < node.children.length; i++) {
380 var child = node.children[i];
381 if (!compiled) compiled = node.or ? [] : {};
382 compiled[i] = exportTree(child);
388 openils.Util.addOnLoad(drawPage);