[IMP]some changes.
[odoo/odoo.git] / addons / web / static / src / js / view_editor.js
1 openerp.web.view_editor = function(openerp) {
2 var QWeb = openerp.web.qweb;
3 openerp.web.ViewEditor =   openerp.web.Widget.extend({
4     init: function(parent, element_id, dataset, view, options) {
5         this._super(parent);
6         this.element_id = element_id
7         this.parent = parent
8         this.dataset = new openerp.web.DataSetSearch(this, 'ir.ui.view', null, null);
9         this.model = dataset.model;
10         this.xml_element_id = 0;
11     },
12     start: function() {
13         this.init_view_editor();
14     },
15     init_view_editor: function() {
16         var self = this;
17         var action = {
18             name: _.sprintf("Manage Views (%s)", this.model),
19             context: this.session.user_context,
20             domain: [["model", "=", this.model]],
21             res_model: 'ir.ui.view',
22             views: [[false, 'list']],
23             type: 'ir.actions.act_window',
24             target: "current",
25             limit: this.dataset.limit || 80,
26             auto_search: true,
27             flags: {
28                 sidebar: false,
29                 deletable: false,
30                 views_switcher: false,
31                 action_buttons: false,
32                 search_view: false,
33                 pager: false,
34                 radio: true
35             },
36         };
37         this.view_edit_dialog = new openerp.web.Dialog(this, {
38             modal: true,
39             title: 'ViewEditor',
40             width: 750,
41             height: 500,
42             buttons: {
43                 "Create": function(){
44                     //to do
45                 },
46                 "Edit": function(){
47                     self.xml_element_id = 0;
48                     self.get_arch();
49                 },
50                 "Close": function(){
51                     self.view_edit_dialog.close();
52                 }
53             },
54         }).start().open();
55         var action_manager = new openerp.web.ActionManager(this);
56         action_manager.appendTo(this.view_edit_dialog);
57         $.when(action_manager.do_action(action)).then(function() {
58             var viewmanager = action_manager.inner_viewmanager,
59                 controller = viewmanager.views[viewmanager.active_view].controller;
60             controller.on_loaded.add_last(function(){
61                 $(controller.groups).bind({
62                     'selected': function(e, ids, records) {
63                         self.main_view_id = ids[0];
64                     }
65                 })
66             });
67         });
68     },
69     add_node_name : function(node) {
70         if(node.tagName.toLowerCase() == "button" || node.tagName.toLowerCase() == "field"){
71             return (node.getAttribute('name'))?
72                 _.sprintf( "<%s name='%s'>",node.tagName.toLowerCase(), node.getAttribute('name')):
73                 _.sprintf( "<%s>",node.tagName.toLowerCase());
74         }else if(node.tagName.toLowerCase() == "group"){
75             return (node.getAttribute('string'))?
76                 _.sprintf( "<%s>",node.getAttribute('string')):
77                 _.sprintf( "<%s>",node.tagName.toLowerCase());
78         }else{
79             return (node.getAttribute('string'))?
80                 _.sprintf( "<%s string='%s'>",node.tagName.toLowerCase(), node.getAttribute('string')):
81                 _.sprintf( "<%s>",node.tagName.toLowerCase());
82         }
83     },
84
85     create_View_Node: function(node){
86         var self = this;
87         ViewNode = {
88             'level': ($(node).parents()).length + 1,
89             'id': self.xml_element_id += 1,
90             'att_list': [],
91             'name': self.add_node_name(node),
92             'child_id': []
93         }
94         ViewNode.att_list.push(node.tagName.toLowerCase());
95         _.each(node.attributes ,function(att){
96            ViewNode.att_list.push([att.nodeName,att.nodeValue]);
97        });
98         return ViewNode;
99     },
100
101     append_child_object: function(main_object, parent_id, child_obj_list) {
102         var self = this;
103             if(main_object.id == parent_id){
104                 var pare
105                 main_object.child_id = child_obj_list;
106                 return main_object;
107             }else{
108                 _.each(main_object.child_id ,function(child_object){
109                     self.append_child_object(child_object, parent_id, child_obj_list);
110                 });
111             }
112     },
113
114     convert_arch_to_obj: function(xml_Node, main_object, parent_id){
115         var self = this;
116         var child_obj_list = [];
117         _.each(xml_Node,function(element){
118            child_obj_list.push(self.create_View_Node(element)) ;
119         });
120         this.append_child_object(main_object, parent_id, child_obj_list);
121         var obj_xml_list = _.zip(xml_Node,child_obj_list);
122         _.each(obj_xml_list, function(node){
123             if(node[0].children.length != 0){
124             self.convert_arch_to_obj(node[0].children, main_object, node[1].id);}
125         });
126         return main_object;
127     },
128
129     parse_xml: function(arch, view_id) {
130         main_object = {
131             'level': 0,
132             'id': this.xml_element_id +=1,
133             'att_list': [],
134             'name': _.sprintf("<view view_id = %s>", view_id),
135             'child_id': []
136         };
137         var xml_arch = QWeb.load_xml(arch);
138         return [this.convert_arch_to_obj(xml_arch.childNodes, main_object, this.xml_element_id)];
139     },
140
141     get_arch: function() {
142         var self = this;
143         var view_arch_list = [];
144         this.dataset.read_ids([parseInt(self.main_view_id)], ['arch', 'type'], function(arch) {
145             var arch_object = self.parse_xml(arch[0].arch, self.main_view_id);
146             self.main_view_type = arch[0].type
147             view_arch_list.push({"view_id": self.main_view_id, "arch": arch[0].arch});
148             self.dataset.read_slice([], {domain: [['inherit_id','=', parseInt(self.main_view_id)]]}, function(result) {
149                 _.each(result, function(res) {
150                     view_arch_list.push({"view_id": res.id, "arch": res.arch});
151                     self.inherit_view(arch_object, res);
152                 });
153                 return self.edit_view({"main_object": arch_object,
154                     "parent_child_id": self.parent_child_list(arch_object, []),
155                     "arch": view_arch_list});
156             });
157         });
158     },
159     parent_child_list : function(one_object, parent_list) {
160         var self = this;
161         _.each(one_object , function(element) {
162             if (element.child_id.length != 0) {
163                 parent_list.push({"key": element.id, "value": _.pluck(element.child_id, 'id')});
164                 self.parent_child_list(element.child_id, parent_list);
165             }
166         });
167         return parent_list;
168     },
169
170     inherit_view : function(arch_object, result) {
171         var self = this;
172         var xml_list = [];
173         var xml_arch = QWeb.load_xml(result.arch);
174         (xml_arch.childNodes[0].tagName == "data")
175             ? xml_list = xml_arch.childNodes[0].children 
176                 : xml_list.push(xml_arch.childNodes[0]);
177         _.each(xml_list, function(xml) {
178             var expr_to_list = [];
179             var xpath_arch_object = self.parse_xml(QWeb.tools.xml_node_to_string(xml), result.id);
180             if(xml.tagName == "xpath"){
181                 var part_expr = _.without(xml.getAttribute('expr').split("/"), "");
182                 _.each(part_expr, function(part) {
183                     expr_to_list.push(_.without($.trim(part.replace(/[^a-zA-Z 0-9 _]+/g,'!')).split("!"), ""));
184                 });
185             }else{
186                 var temp = _.reject(xpath_arch_object[0].child_id[0].att_list, function(list) {
187                     return _.include(list, "position")
188                 });
189                 expr_to_list = [_.flatten(temp)];
190             }
191             self.inherit_apply(expr_to_list, arch_object ,xpath_arch_object);
192         });
193     },
194     inherit_apply: function(expr_list ,arch_object ,xpath_arch_object) {
195         var self = this;
196         if (xpath_arch_object.length) {
197             var check = expr_list[0];
198             var obj;
199             switch (check.length) {
200                 case 2:
201                     if (parseInt(check[1])) {
202                         //for field[3]
203                         var temp_list = _.select(arch_object, function(element) {
204                             return _.include(_.flatten(element.att_list), check[0]);
205                         });
206                         obj = arch_object[_.indexOf(arch_object, temp_list[parseInt(check[1]) - 1])];
207                     } else {
208                         //for notebook[last()]
209                         obj = _.detect(arch_object, function(element) {
210                             return _.include(_.flatten(element.att_list), check[0]);
211                         });
212                     }
213                     break;
214                 case 3:
215                     //for field[@name='type']
216                     obj = _.detect(arch_object, function(element){
217                         if ((_.intersection(_.flatten(element.att_list), _.uniq(check))).length == check.length) {
218                             return element;
219                         }
220                     });
221                     break;
222                 case 1:
223                     //for /form/notebook
224                     var temp_list = _.select(arch_object, function(element) {
225                         return _.include(_.flatten(element.att_list), check[0]);
226                     });
227                     if (temp_list.length != 0) {
228                         expr_list.length == 1 ? obj = temp_list[0] : expr_list.shift();
229                     }
230                     break;
231             }
232             if (obj) {
233                 expr_list.shift();
234                 if (expr_list.length) {
235                     self.inherit_apply(expr_list, obj.child_id, xpath_arch_object);
236                 } else {
237                     self.increase_level(xpath_arch_object[0], obj.level + 1);
238                     obj.child_id.push(xpath_arch_object[0]);
239                     xpath_arch_object.pop();
240                 }
241             }
242             else {
243                 _.each(arch_object, function(element) {
244                     self.inherit_apply(expr_list, element.child_id, xpath_arch_object);
245                 });
246             }
247         }
248     },
249     increase_level: function(val, level) {
250         var self = this;
251         val.level = level;
252         _.each(val.child_id, function(val, key) {
253             self.increase_level(val, level + 1);
254         });
255     },
256     edit_view: function(one_object) {
257         var self = this;
258         this.edit_xml_dialog = new openerp.web.Dialog(this, {
259             modal: true,
260             title: _.sprintf("View Editor %d - %s", self.main_view_id, self.model),
261             width: 750,
262             height: 500,
263             buttons: {
264                 "Inherited View": function() {
265                     //todo
266                 },
267                 "Preview": function() {
268                     var action = {
269                         context: self.session.user_context,
270                         res_model: self.model,
271                         views: [[self.main_view_id, self.main_view_type]],
272                         type: 'ir.actions.act_window',
273                         target: "new",
274                         flags: {
275                             sidebar: false,
276                             views_switcher: false,
277                             action_buttons: false,
278                             search_view: false,
279                             pager: false,
280                         },
281                     };
282                     var action_manager = new openerp.web.ActionManager(self);
283                     action_manager.do_action(action);
284                 },
285                 "Close": function(){
286                     self.edit_xml_dialog.close();
287                 }
288             }
289         }).start().open();
290         this.edit_xml_dialog.$element.html(QWeb.render('view_editor', {'data': one_object['main_object']}));
291         this.edit_xml_dialog.$element.find("tr[id^='viewedit-']").click(function() {
292             self.edit_xml_dialog.$element.find("tr[id^='viewedit-']").removeClass('ui-selected');
293             $(this).addClass('ui-selected');
294         });
295         this.edit_xml_dialog.$element.find("img[id^='parentimg-']").click(function() {
296             if ($(this).attr('src') == '/web/static/src/img/collapse.gif') {
297                 $(this).attr('src', '/web/static/src/img/expand.gif');
298                 self.on_expand(this);
299             } else {
300                 $(this).attr('src', '/web/static/src/img/collapse.gif');
301                 var id = this.id.split('-')[1];
302                 self.on_collapse(this,one_object['parent_child_id'], one_object['main_object']);
303             }
304         });
305         this.edit_xml_dialog.$element.find("img[id^='side-']").click(function() {
306             var side = $(this).closest("tr[id^='viewedit-']");
307             var clicked_tr_id = (side.attr('id')).split('-')[1];
308             var img = side.find("img[id='parentimg-" + clicked_tr_id + "']").attr('src');
309             var clicked_tr_level = parseInt(side.attr('level'));
310             var cur_tr = side;
311             var last_tr;
312             var next_tr;
313             var tr_to_move = [];
314             tr_to_move.push(side);
315             var view_id;
316             var view_xml_id;
317             var view_find = side;
318             while (1) {
319                 view_find = view_find.prev();
320                 if((self.edit_xml_dialog.$element.find(view_find).find('a').text()).search("view_id") != -1
321                         && parseInt(view_find.attr('level')) < clicked_tr_level) {
322                     view_id = parseInt(($(view_find).find('a').text()).replace(/[^0-9]+/g, ''));
323                     view_xml_id = (view_find.attr('id')).split('-')[1];
324                     break;
325                 }
326             }
327             switch (this.id) {
328                 case "side-add":
329                     break;
330                 case "side-remove":
331                     break;
332                 case "side-edit":
333                     break;
334                 case "side-up":
335                     while (1) {
336                         var prev_tr = cur_tr.prev();
337                         if (clicked_tr_level >= parseInt(prev_tr.attr('level')) || prev_tr.length == 0) {
338                            last_tr = prev_tr;
339                            break;
340                         }
341                         cur_tr = prev_tr;
342                     }
343                     if (img) {
344                     self.edit_xml_dialog.$element.find("img[id='parentimg-" + clicked_tr_id + "']").
345                             attr('src', '/web/static/src/img/expand.gif');
346                         while (1) {
347                             next_tr = side.next();
348                             if (parseInt(next_tr.attr('level')) <= clicked_tr_level || next_tr.length == 0) {
349                                 break;
350                             } else {
351                                 next_tr.hide();
352                                 tr_to_move.push(next_tr);
353                                 side = next_tr;
354                             }
355                         }
356                     }
357                     if (last_tr.length != 0 && parseInt(last_tr.attr('level')) == clicked_tr_level &&
358                             (self.edit_xml_dialog.$element.find(last_tr).find('a').text()).search("view_id") == -1) {
359                         _.each(tr_to_move, function(rec) {
360                              $(last_tr).before(rec);
361                         });
362                         self.save_move_arch(one_object, view_id, view_xml_id, clicked_tr_id, clicked_tr_level, "up");
363                     }
364                 break;
365             case "side-down":
366                 if (img) {
367                     while (1) {
368                         next_tr = cur_tr.next();
369                         if ( parseInt(next_tr.attr('level')) <= clicked_tr_level || next_tr.length == 0) {
370                             last_tr = next_tr;
371                             break;
372                         } else {
373                             tr_to_move.push(next_tr);
374                             cur_tr = next_tr;
375                         }
376                    }
377                 }
378                 else {
379                     last_tr = cur_tr.next();
380                 }
381                 if ((self.edit_xml_dialog.$element.find(last_tr).find('a').text()).search("view_id") != -1) {
382                     return;
383                 }
384                 if (last_tr.length != 0 &&  parseInt(last_tr.attr('level')) == clicked_tr_level) {
385                     var last_tr_id = (last_tr.attr('id')).split('-')[1];
386                     img = last_tr.find("img[id='parentimg-" + last_tr_id + "']").attr('src');
387                     if (img) {
388                         self.edit_xml_dialog.$element.find("img[id='parentimg-" + last_tr_id + "']").
389                                                         attr('src', '/web/static/src/img/expand.gif');
390                         while (1) {
391                             var next_tr = last_tr.next();
392                             if (next_tr.attr('level') <= clicked_tr_level || next_tr.length == 0) break;
393                             next_tr.hide();
394                             last_tr = next_tr;
395                         }
396                     }
397                     tr_to_move.reverse();
398                     _.each(tr_to_move, function(rec) {
399                        $(last_tr).after(rec);
400                     });
401                     self.save_move_arch(one_object, view_id, view_xml_id, clicked_tr_id, clicked_tr_level, "down");
402                 }
403                 break;
404             }
405         });
406     },
407     save_move_arch: function(one_object, view_id, view_xml_id, clicked_tr_id, level, move_direct) {
408         var self = this;
409         var arch = _.detect(one_object['arch'], function(element) {return element.view_id == view_id;});
410         var obj = self.get_object_by_id(view_xml_id, one_object['main_object'], []);
411          //for finding xpath tag from inherit view
412         var xml_arch = QWeb.load_xml(arch.arch);
413         if (xml_arch.childNodes[0].tagName == "data") {
414             var check_list = _.flatten(obj[0].child_id[0].att_list);
415             arch.arch = _.detect(xml_arch.childNodes[0].children, function(xml_child){
416                 var temp_obj = self.create_View_Node(xml_child);
417                 var insert = _.intersection(_.flatten(temp_obj.att_list),_.uniq(check_list));
418                 if (insert.length == check_list.length ) {return xml_child;}
419             });
420         }
421         return self.save_arch(arch.arch, obj[0].child_id[0], parseInt(clicked_tr_id), [], parseInt(level),
422                         parseInt(view_id), arch, move_direct);
423     },
424
425     get_object_by_id: function(view_xml_id, one_object, result) {
426         var self = this;
427         if (result.length == 0 ) {
428             var check = _.detect(one_object , function(obj) {
429                 return view_xml_id == obj.id;
430             });
431             if (check) {result.push(check);};
432             _.each(one_object, function(obj) {
433                self.get_object_by_id(view_xml_id, obj.child_id, result);
434             });
435         }
436         return result;
437     },
438
439     save_arch: function(arch1, obj, id, child_list, level, view_id, arch, move_direct){
440         var self = this;
441         var children_list =  $(arch1).children();
442         var list_obj_xml = _.zip(children_list,obj.child_id);
443         if (id) {
444             if (obj.id == id) {
445                 var id;
446                 var parent = $(arch1).parents();
447                 var index = _.indexOf(child_list, obj);
448                 var re_insert_obj = child_list.splice(index, 1);
449                 if (move_direct == "down") {
450                     var next = $(arch1).next();
451                     $(next).after(arch1);
452                     child_list.splice(index+1, 0, re_insert_obj[0]);
453                 } else {
454                     var prev = $(arch1).prev();
455                     $(prev).before(arch1);
456                     child_list.splice(index-1, 0, re_insert_obj[0]);
457                 }
458                 var convert_to_utf = QWeb.tools.xml_node_to_string(parent[parent.length-1]);
459                 convert_to_utf = convert_to_utf.replace('xmlns="http://www.w3.org/1999/xhtml"', "");
460                 convert_to_utf = '<?xml version="1.0"?>' + convert_to_utf;
461                 arch.arch = convert_to_utf;
462                 this.dataset.write(parseInt(view_id),{"arch":convert_to_utf}, function(r) {
463                 });
464             }
465             if (obj.level <= level) {
466                 _.each(list_obj_xml, function(child_node) {
467                     self.save_arch(child_node[0], child_node[1], id, obj.child_id, level, view_id, arch, move_direct);
468                 });
469             }
470         }
471     }, 
472     on_expand: function(expand_img){
473         var level = parseInt($(expand_img).closest("tr[id^='viewedit-']").attr('level'));
474         var cur_tr = $(expand_img).closest("tr[id^='viewedit-']");
475         while (1) {
476             var nxt_tr = cur_tr.next();
477             if (parseInt(nxt_tr.attr('level')) > level) {
478                 cur_tr = nxt_tr;
479                 nxt_tr.hide();
480             } else return nxt_tr;
481         }
482     },
483     on_collapse: function(collapse_img, parent_child_id, id, main_object) {
484         var self = this;
485         var id = collapse_img.id.split('-')[1];
486         var datas = _.detect(parent_child_id, function(res) {
487             return res.key == id;
488         });
489         _.each(datas.value, function (rec) {
490             var tr = self.edit_xml_dialog.$element.find("tr[id='viewedit-" + rec + "']");
491             tr.find("img[id='parentimg-" + rec + "']").attr('src', '/web/static/src/img/expand.gif');
492             tr.show();
493         });
494     }
495 });
496 };