[FIX] editable listview @on_write handling in case of @colors
[odoo/odoo.git] / addons / web / static / test / Widget.js
1 $(document).ready(function () {
2     var $fix = $('#qunit-fixture');
3     var mod = {
4         setup: function () {
5             instance = window.openerp.init([]);
6             window.openerp.web.corelib(instance);
7
8             instance.web.qweb = new QWeb2.Engine();
9             instance.web.qweb.add_template(
10             '<no>' +
11                 '<t t-name="test.widget.template">' +
12                     '<ol>' +
13                         '<li t-foreach="5" t-as="counter" ' +
14                             't-attf-class="class-#{counter}">' +
15                             '<input/>' +
16                             '<t t-esc="counter"/>' +
17                         '</li>' +
18                     '</ol>' +
19                 '</t>' +
20                 '<t t-name="test.widget.template-value">' +
21                     '<p><t t-esc="widget.value"/></p>' +
22                 '</t>' +
23             '</no>');
24         }
25     };
26     var instance;
27
28     module('Widget.proxy', mod);
29     test('(String)', function () {
30         var W = instance.web.Widget.extend({
31             exec: function () {
32                 this.executed = true;
33             }
34         });
35         var w = new W;
36         var fn = w.proxy('exec');
37         fn();
38         ok(w.executed, 'should execute the named method in the right context');
39     });
40     test('(String)(*args)', function () {
41         var W = instance.web.Widget.extend({
42             exec: function (arg) {
43                 this.executed = arg;
44             }
45         });
46         var w = new W;
47         var fn = w.proxy('exec');
48         fn(42);
49         ok(w.executed, "should execute the named method in the right context");
50         equal(w.executed, 42, "should be passed the proxy's arguments");
51     });
52     test('(String), include', function () {
53         // the proxy function should handle methods being changed on the class
54         // and should always proxy "by name", to the most recent one
55         var W = instance.web.Widget.extend({
56             exec: function () {
57                 this.executed = 1;
58             }
59         });
60         var w = new W;
61         var fn = w.proxy('exec');
62         W.include({
63             exec: function () { this.executed = 2; }
64         });
65
66         fn();
67         equal(w.executed, 2, "should be lazily resolved");
68     });
69
70     test('(Function)', function () {
71         var w = new (instance.web.Widget.extend({ }));
72
73         var fn = w.proxy(function () { this.executed = true; });
74         fn();
75         ok(w.executed, "should set the function's context (like Function#bind)");
76     });
77     test('(Function)(*args)', function () {
78         var w = new (instance.web.Widget.extend({ }));
79
80         var fn = w.proxy(function (arg) { this.executed = arg; });
81         fn(42);
82         equal(w.executed, 42, "should be passed the proxy's arguments");
83     });
84
85     module('Widget.renderElement', mod);
86     test('no template, default', function () {
87         var w = new (instance.web.Widget.extend({ }));
88
89         var $original = w.$el;
90         ok($original, "should initially have a root element");
91         w.renderElement();
92         ok(w.$el, "should have generated a root element");
93         ok($original !== w.$el, "should have generated a new root element");
94         strictEqual(w.$el, w.$el, "should provide $el alias");
95         ok(w.$el.is(w.el), "should provide raw DOM alias");
96
97         equal(w.el.nodeName, 'DIV', "should have generated the default element");
98         equal(w.el.attributes.length, 0, "should not have generated any attribute");
99         ok(_.isEmpty(w.$el.html(), "should not have generated any content"));
100     });
101     test('no template, custom tag', function () {
102         var w = new (instance.web.Widget.extend({
103             tagName: 'ul'
104         }));
105         w.renderElement();
106
107         equal(w.el.nodeName, 'UL', "should have generated the custom element tag");
108     });
109     test('no template, @id', function () {
110         var w = new (instance.web.Widget.extend({
111             id: 'foo'
112         }));
113         w.renderElement();
114
115         equal(w.el.attributes.length, 1, "should have one attribute");
116         equal(w.$el.attr('id'), 'foo', "should have generated the id attribute");
117         equal(w.el.id, 'foo', "should also be available via property");
118     });
119     test('no template, @className', function () {
120         var w = new (instance.web.Widget.extend({
121             className: 'oe_some_class'
122         }));
123         w.renderElement();
124
125         equal(w.el.className, 'oe_some_class', "should have the right property");
126         equal(w.$el.attr('class'), 'oe_some_class', "should have the right attribute");
127     });
128     test('no template, bunch of attributes', function () {
129         var w = new (instance.web.Widget.extend({
130             attributes: {
131                 'id': 'some_id',
132                 'class': 'some_class',
133                 'data-foo': 'data attribute',
134                 'clark': 'gable',
135                 'spoiler': 'snape kills dumbledore'
136             }
137         }));
138         w.renderElement();
139
140         equal(w.el.attributes.length, 5, "should have all the specified attributes");
141
142         equal(w.el.id, 'some_id');
143         equal(w.$el.attr('id'), 'some_id');
144
145         equal(w.el.className, 'some_class');
146         equal(w.$el.attr('class'), 'some_class');
147
148         equal(w.$el.attr('data-foo'), 'data attribute');
149         equal(w.$el.data('foo'), 'data attribute');
150
151         equal(w.$el.attr('clark'), 'gable');
152         equal(w.$el.attr('spoiler'), 'snape kills dumbledore');
153     });
154
155     test('template', function () {
156         var w = new (instance.web.Widget.extend({
157             template: 'test.widget.template'
158         }));
159         w.renderElement();
160
161         equal(w.el.nodeName, 'OL');
162         equal(w.$el.children().length, 5);
163         equal(w.el.textContent, '01234');
164     });
165
166     module('Widget.$', mod);
167     test('basic-alias', function () {
168         var w = new (instance.web.Widget.extend({
169             template: 'test.widget.template'
170         }));
171         w.renderElement();
172
173         ok(w.$('li:eq(3)').is(w.$el.find('li:eq(3)')),
174            "should do the same thing as calling find on the widget root");
175     });
176
177     module('Widget.events', mod);
178     test('delegate', function () {
179         var a = [];
180         var w = new (instance.web.Widget.extend({
181             template: 'test.widget.template',
182             events: {
183                 'click': function () {
184                     a[0] = true;
185                     strictEqual(this, w, "should trigger events in widget")
186                 },
187                 'click li.class-3': 'class3',
188                 'change input': function () { a[2] = true; }
189             },
190             class3: function () { a[1] = true; }
191         }));
192         w.renderElement();
193
194         w.$el.click();
195         w.$('li:eq(3)').click();
196         w.$('input:last').val('foo').change();
197
198         for(var i=0; i<3; ++i) {
199             ok(a[i], "should pass test " + i);
200         }
201     });
202     test('undelegate', function () {
203         var clicked = false, newclicked = false;
204         var w = new (instance.web.Widget.extend({
205             template: 'test.widget.template',
206             events: { 'click li': function () { clicked = true; } }
207         }));
208         w.renderElement();
209         w.$el.on('click', 'li', function () { newclicked = true });
210
211         w.$('li').click();
212         ok(clicked, "should trigger bound events");
213         ok(newclicked, "should trigger bound events");
214         clicked = newclicked = false;
215
216         w.undelegateEvents();
217         w.$('li').click();
218         ok(!clicked, "undelegate should unbind events delegated");
219         ok(newclicked, "undelegate should only unbind events it created");
220     });
221
222     module('Widget.renderElement', mod);
223     asyncTest('repeated', 4, function () {
224         var w = new (instance.web.Widget.extend({
225             template: 'test.widget.template-value'
226         }));
227         w.value = 42;
228         w.appendTo($fix)
229             .always(start)
230             .done(function () {
231                 equal($fix.find('p').text(), '42', "DOM fixture should contain initial value");
232                 equal(w.$el.text(), '42', "should set initial value");
233                 w.value = 36;
234                 w.renderElement();
235                 equal($fix.find('p').text(), '36', "DOM fixture should use new value");
236                 equal(w.$el.text(), '36', "should set new value");
237             });
238     });
239 });