Merge lp:~xmo-deactivatedaccount/openobject-client-web/code-cleanups into lp:~openerp-dev/openobject-client-web/trunk-dev-web

Proposed by Xavier (Open ERP)
Status: Merged
Merged at revision: 2979
Proposed branch: lp:~xmo-deactivatedaccount/openobject-client-web/code-cleanups
Merge into: lp:~openerp-dev/openobject-client-web/trunk-dev-web
Prerequisite: lp:~xmo-deactivatedaccount/openobject-client-web/html-tags-fixes
Diff against target: 1488 lines (+412/-366) (has conflicts)
4 files modified
addons/openerp/controllers/tree.py (+56/-81)
addons/openerp/static/javascript/form.js (+327/-261)
addons/openerp/static/javascript/menubar.js (+28/-21)
openobject/controllers/templates/base.mako (+1/-3)
Text conflict in addons/openerp/static/javascript/form.js
To merge this branch: bzr merge lp:~xmo-deactivatedaccount/openobject-client-web/code-cleanups
Reviewer Review Type Date Requested Status
Navrang Oza Pending
Review via email: mp+22519@code.launchpad.net

Description of the change

A few style (python) & intellij warnings (js, mostly) fixes, removal of duplicate js link in base mako template.

To post a comment you must log in.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'addons/openerp/controllers/tree.py'
2--- addons/openerp/controllers/tree.py 2010-03-16 20:07:12 +0000
3+++ addons/openerp/controllers/tree.py 2010-03-31 08:25:34 +0000
4@@ -40,17 +40,24 @@
5
6 from openobject.tools import url, expose
7
8-
9 DT_FORMAT = '%Y-%m-%d'
10 DHM_FORMAT = '%Y-%m-%d %H:%M:%S'
11
12+FORMATTERS = {
13+ 'integer': lambda value, _i: str(value),
14+ 'float': lambda value, _i: '%.02f' % (value),
15+ 'date': lambda value, _i: time.strftime('%x', time.strptime(value, DT_FORMAT)),
16+ 'datetime': lambda value, _i: time.strftime('%x', time.strptime(value, DHM_FORMAT)),
17+ 'one2one': lambda value, _i: value[1],
18+ 'many2one': lambda value, _i: value[1],
19+ 'selection': lambda value, info: info['selection'].get(value, ''),
20+}
21+
22 class Tree(SecuredController):
23-
24 _cp_path = "/tree"
25
26 @expose(template="templates/tree.mako")
27 def create(self, params):
28-
29 view_id = (params.view_ids or False) and params.view_ids[0]
30 domain = params.domain
31 context = params.context
32@@ -59,7 +66,9 @@
33 model = params.model
34
35 if view_id:
36- view_base = rpc.session.execute('object', 'execute', 'ir.ui.view', 'read', [view_id], ['model', 'type'], context)[0]
37+ view_base = rpc.session.execute(
38+ 'object', 'execute', 'ir.ui.view', 'read', [view_id],
39+ ['model', 'type'], context)[0]
40 model = view_base['model']
41 view = cache.fields_view_get(model, view_id, view_base['type'], context)
42 else:
43@@ -67,9 +76,8 @@
44
45 tree = tree_view.ViewTree(view, model, res_id, domain=domain, context=context, action="/tree/action")
46 if tree.toolbar:
47-
48 proxy = rpc.RPCProxy(model)
49-
50+
51 for tool in tree.toolbar:
52 if tool.get('icon'):
53 tool['icon'] = icons.get_icon(tool['icon'])
54@@ -78,8 +86,8 @@
55 id = tool['id']
56 ids = proxy.read([id], [tree.field_parent])[0][tree.field_parent]
57 tool['ids'] = ids
58-
59- return dict(tree=tree, model=model)
60+
61+ return {'tree': tree, 'model': model}
62
63 @expose()
64 def default(self, id, model, view_id, domain, context):
65@@ -87,7 +95,8 @@
66
67 try:
68 view_id = int(view_id)
69- except:
70+ except TypeError:
71+ # if view_id is None
72 view_id = False
73
74 params.ids = id
75@@ -101,7 +110,7 @@
76 def sort_callback(self, item1, item2, field, sort_order="asc", type=None):
77 a = item1[field]
78 b = item2[field]
79-
80+
81 if type == 'many2one' and isinstance(a, (tuple, list)):
82 a = a[1]
83 b = b[1]
84@@ -112,16 +121,15 @@
85 return cmp(a, b)
86
87 @expose('json')
88- def data(self, ids, model, fields, field_parent=None, icon_name=None, domain=[], context={}, sort_by=None, sort_order="asc"):
89-
90+ def data(self, ids, model, fields, field_parent=None, icon_name=None,
91+ domain=[], context={}, sort_by=None, sort_order="asc"):
92 ids = ids or []
93
94- if isinstance(ids, basestring):
95- ids = [int(id) for id in ids.split(',')]
96-
97- if isinstance(ids, list):
98- ids = [int(id) for id in ids]
99-
100+ if isinstance(ids, basestring):
101+ ids = map(int, ids.split(','))
102+ elif isinstance(ids, list):
103+ ids = map(int, ids)
104+
105 if isinstance(fields, basestring):
106 fields = eval(fields)
107
108@@ -136,8 +144,8 @@
109
110 proxy = rpc.RPCProxy(model)
111
112- ctx = context or {}
113- ctx.update(rpc.session.context.copy())
114+ ctx = dict(context,
115+ **rpc.session.context)
116
117 if icon_name:
118 fields.append(icon_name)
119@@ -148,56 +156,29 @@
120 if sort_by:
121 result.sort(lambda a,b: self.sort_callback(a, b, sort_by, sort_order, type=fields_info[sort_by]['type']))
122
123- # formate the data
124+ # format the data
125 for field in fields:
126-
127- if fields_info[field]['type'] in ('integer'):
128- for x in result:
129- if x[field]:
130- x[field] = '%s'%(x[field])
131-
132- if fields_info[field]['type'] in ('float'):
133- for x in result:
134- if x[field]:
135- x[field] = '%.02f'%(round(x[field], 2))
136-
137- if fields_info[field]['type'] in ('date',):
138- for x in result:
139- if x[field]:
140- date = time.strptime(x[field], DT_FORMAT)
141- x[field] = time.strftime('%x', date)
142-
143- if fields_info[field]['type'] in ('datetime',):
144- for x in result:
145- if x[field]:
146- date = time.strptime(x[field], DHM_FORMAT)
147- x[field] = time.strftime('%x %H:%M:%S', date)
148-
149- if fields_info[field]['type'] in ('one2one', 'many2one'):
150- for x in result:
151- if x[field]:
152- x[field] = x[field][1]
153-
154- if fields_info[field]['type'] in ('selection'):
155- for x in result:
156- if x[field]:
157- x[field] = dict(fields_info[field]['selection']).get(x[field], '')
158+ field_info = fields_info[field]
159+ formatter = FORMATTERS.get(field_info['type'])
160+ for x in result:
161+ if x[field]:
162+ x[field] = formatter(x[field], field_info)
163
164 records = []
165 for item in result:
166-
167- # empty string instead of bool and None
168+ # empty string instead of False or None
169 for k, v in item.items():
170- if v==None or (v==False and type(v)==bool):
171+ if v is None or v is False:
172 item[k] = ''
173
174- record = {}
175-
176- record['id'] = item.pop('id')
177- record['action'] = url('/tree/open', model=model, id=record['id'])
178- record['target'] = None
179-
180- record['icon'] = None
181+ record = {
182+ 'id': item.pop('id'),
183+ 'action': url('/tree/open', model=model, id=record['id']),
184+ 'target': None,
185+ 'icon': None,
186+ 'children': [],
187+ 'items': item
188+ }
189
190 if icon_name and item.get(icon_name):
191 icon = item.pop(icon_name)
192@@ -207,16 +188,12 @@
193 record['action'] = None
194 record['target'] = None
195
196- record['children'] = []
197-
198 if field_parent and field_parent in item:
199 record['children'] = item.pop(field_parent) or None
200
201- record['items'] = item
202+ records.append(record)
203
204- records += [record]
205-
206- return dict(records=records)
207+ return {'records': records}
208
209 def do_action(self, name, adds={}, datas={}):
210 params, data = TinyDict.split(datas)
211@@ -234,7 +211,9 @@
212 id = (ids or False) and ids[0]
213
214 if ids:
215- return actions.execute_by_keyword(name, adds=adds, model=model, id=id, ids=ids, context=ctx, report_type='pdf')
216+ return actions.execute_by_keyword(
217+ name, adds=adds, model=model, id=id, ids=ids, context=ctx,
218+ report_type='pdf')
219 else:
220 raise common.message(_("No record selected!"))
221
222@@ -260,11 +239,10 @@
223
224 @expose()
225 def switch(self, **kw):
226-
227 params, data = TinyDict.split(kw)
228
229- ids = params.selection or []
230- if len(ids):
231+ ids = params.selection or []
232+ if ids:
233 import actions
234 return actions.execute_window(False, res_id=ids, model=params.model, domain=params.domain)
235 else:
236@@ -272,11 +250,8 @@
237
238 @expose()
239 def open(self, **kw):
240- datas = {'_terp_model': kw.get('model'),
241- '_terp_context': kw.get('context', {}),
242- '_terp_domain': kw.get('domain', []),
243- 'ids': kw.get('id')}
244-
245- return self.do_action('tree_but_open', datas=datas)
246-
247-# vim: ts=4 sts=4 sw=4 si et
248+ return self.do_action('tree_but_open', datas={
249+ '_terp_model': kw.get('model'),
250+ '_terp_context': kw.get('context', {}),
251+ '_terp_domain': kw.get('domain', []),
252+ 'ids': kw.get('id')})
253
254=== modified file 'addons/openerp/static/javascript/form.js'
255--- addons/openerp/static/javascript/form.js 2010-03-31 07:22:59 +0000
256+++ addons/openerp/static/javascript/form.js 2010-03-31 08:25:34 +0000
257@@ -27,25 +27,25 @@
258 //
259 ////////////////////////////////////////////////////////////////////////////////
260
261-function get_form_action(action, params){
262-
263+function get_form_action(action, params) {
264+
265 var act = typeof(form_controller) == 'undefined' ? '/form' : form_controller;
266 act = action && action.indexOf('/') == 0 ? action : act + '/' + action;
267 return openobject.http.getURL(act, params);
268 }
269
270-var openRecord = function(id, src, target, readonly){
271+function openRecord(id, src, target, readonly) {
272
273 var kind = getNodeAttribute(src + '_set', 'kind');
274-
275+
276 if (!kind && openobject.dom.get('_o2m_' + src)) {
277 kind = "one2many";
278 }
279-
280+
281 if (kind == "one2many") {
282 return new One2Many(src).edit(id, readonly);
283 }
284-
285+
286 var prefix = src && src != '_terp_list' ? src + '/' : '';
287
288 var model = openobject.dom.get(prefix + '_terp_model').value;
289@@ -67,6 +67,7 @@
290 var search_data = openobject.dom.get('_terp_search_data');
291 search_data = search_data ? search_data.value : null;
292
293+<<<<<<< TREE
294 var args = {'model': model,
295 'id': id ? id : 'False',
296 'ids': ids,
297@@ -80,12 +81,28 @@
298 'search_domain': search_domain,
299 'search_data':search_data};
300
301+=======
302+ var args = {
303+ 'model': model,
304+ 'id': id ? id : 'False',
305+ 'ids': ids,
306+ 'view_ids': view_ids,
307+ 'view_mode': view_mode,
308+ 'domain': domain,
309+ 'context': context,
310+ 'offset': offset,
311+ 'limit': limit,
312+ 'count': count,
313+ 'search_domain': search_domain
314+ };
315+
316+>>>>>>> MERGE-SOURCE
317 var action = readonly ? 'view' : 'edit';
318-
319+
320 if (target == '_blank') {
321 return window.open(get_form_action(action, args));
322 }
323-
324+
325 if (kind == 'many2many') {
326 args['source'] = src;
327 return openobject.tools.openWindow(get_form_action('/openm2m/edit', args));
328@@ -94,41 +111,52 @@
329 window.location.href = get_form_action(action, args);
330 }
331
332-var editRecord = function(id, src, target){
333+function editRecord(id, src, target) {
334 return openRecord(id, src, target, false);
335 }
336
337-var viewRecord = function(id, src){
338+function viewRecord(id, src) {
339 return openRecord(id, src, null, true);
340 }
341
342-var editSelectedRecord = function() {
343+function editSelectedRecord() {
344
345 var lst = new ListView('_terp_list');
346 var ids = lst.getSelectedRecords();
347-
348+
349 if (ids && ids.length > 5) {
350 var msg = _('You selected to open %(tabs)s tabs - do you want to continue?');
351 msg = msg.replace('%(tabs)s', ids.length);
352- if (!confirm(msg)) return;
353+ if (!confirm(msg)) {
354+ return;
355+ }
356 }
357
358- forEach(ids, function(id){
359+ forEach(ids, function(id) {
360 editRecord(id, '_terp_list', '_blank');
361 });
362 }
363
364-var switchView = function(view_type, src){
365-
366+function switchView(view_type, src) {
367+
368+<<<<<<< TREE
369+=======
370+ var search_filter_data = getElement('search_filter_data')
371+ if (search_filter_data) {
372+ search_filter_data.style.display = "none";
373+ appendChildNodes(parent.window.document.body, search_filter_data);
374+ }
375+
376+>>>>>>> MERGE-SOURCE
377 var prefix = src ? src + '/' : '';
378 var form = document.forms['view_form'];
379
380 var params = {
381 '_terp_source': src,
382 '_terp_source_view_type': view_type
383- }
384+ };
385
386- if (openobject.dom.get('_terp_list')){
387+ if (openobject.dom.get('_terp_list')) {
388 var ids = new ListView('_terp_list').getSelectedRecords();
389 if (ids.length > 0) {
390 openobject.dom.get('_terp_id').value = ids[0];
391@@ -138,43 +166,43 @@
392 submit_form(get_form_action('switch', params));
393 }
394
395-var switch_O2M = function(view_type, src){
396-
397- if (openobject.http.AJAX_COUNT > 0){
398+function switch_O2M(view_type, src) {
399+
400+ if (openobject.http.AJAX_COUNT > 0) {
401 return;
402 }
403-
404+
405 var prefix = src ? src + '/' : '';
406 var form = document.forms['view_form'];
407-
408+
409 var params = getFormParams();
410-
411+
412 params['_terp_source'] = src;
413 params['_terp_source_view_type'] = view_type;
414-
415- if (openobject.dom.get('_terp_list')){
416+
417+ if (openobject.dom.get('_terp_list')) {
418 var ids = new ListView('_terp_list').getSelectedRecords();
419 if (ids.length > 0) {
420 openobject.dom.get('_terp_id').value = ids[0];
421 }
422 }
423-
424+
425 req = openobject.http.post('/form/switch_o2m', params);
426- req.addCallback(function(xmlHttp){
427-
428+ req.addCallback(function(xmlHttp) {
429+
430 var text = xmlHttp.responseText;
431 if (text.indexOf('ERROR: ') == 0) {
432 text = text.replace('ERROR: ', '');
433 return alert(text);
434 }
435
436- var frm = openobject.dom.get('_o2m_'+src);
437-
438+ var frm = openobject.dom.get('_o2m_' + src);
439+
440 var d = DIV();
441 d.innerHTML = text;
442-
443+
444 var newo2m = d.getElementsByTagName('table')[0];
445-
446+
447 swapDOM(frm, newo2m);
448
449 var ua = navigator.userAgent.toLowerCase();
450@@ -182,43 +210,46 @@
451 if ((navigator.appName != 'Netscape') || (ua.indexOf('safari') != -1)) {
452 // execute JavaScript
453 var scripts = openobject.dom.select('script', newo2m);
454- forEach(scripts, function(s){
455+ forEach(scripts, function(s) {
456 eval(s.innerHTML);
457 });
458 }
459 });
460 }
461
462-var show_process_view = function() {
463+function show_process_view() {
464 var model = openobject.dom.get('_terp_model').value;
465 var id = openobject.dom.get('_terp_id').value;
466
467 if (openobject.dom.get('_terp_list')) {
468 var list = new ListView('_terp_list');
469 var ids = list.getSelectedRecords();
470- if (ids.length)
471+ if (ids.length) {
472 id = ids[0];
473+ }
474 }
475
476 id = parseInt(id) || null;
477 window.location.href = openobject.http.getURL('/process', {res_model: model, res_id: id})
478 }
479
480-var validate_required = function(form) {
481+function validate_required(form) {
482
483 if (typeof form == 'string') {
484- form = document.forms[form];
485+ form = document.forms[form];
486 }
487
488- if (!form) return true;
489+ if (!form) {
490+ return true;
491+ }
492
493 var elements = MochiKit.Base.filter(function(el) {
494- return !el.disabled && el.id && el.name && el.id.indexOf('_terp_listfields/') == -1 && hasElementClass(el, 'requiredfield');
495+ return !el.disabled && el.id && el.name && el.id.indexOf('_terp_listfields/') == -1 && hasElementClass(el, 'requiredfield');
496 }, form.elements);
497
498 var result = true;
499
500- for (var i=0; i<elements.length; i++){
501+ for (var i = 0; i < elements.length; i++) {
502
503 var elem = elem2 = elements[i];
504 var value = elem.value;
505@@ -240,7 +271,7 @@
506 removeElementClass(elem2, 'errorfield');
507 }
508 }
509-
510+
511 if (!result) {
512 alert(_("Invalid form, correct red fields !"));
513 }
514@@ -248,8 +279,8 @@
515 return result;
516 }
517
518-var submit_form = function(action, src, target){
519-
520+function submit_form(action, src, target) {
521+
522 if (openobject.http.AJAX_COUNT > 0) {
523 return callLater(1, submit_form, action, src, target);
524 }
525@@ -266,54 +297,54 @@
526 var args = {
527 _terp_source: source
528 };
529-
530- if (target == "new" || target == "_blank"){
531+
532+ if (target == "new" || target == "_blank") {
533 setNodeAttribute(form, 'target', '_blank');
534 }
535-
536- if (action == 'save_and_edit'){
537+
538+ if (action == 'save_and_edit') {
539 action = 'save';
540 args['_terp_return_edit'] = 1;
541 }
542
543 action = get_form_action(action, args);
544
545- if (/\/save(\?|\/)?/.test(action) && !validate_required(form)){
546+ if (/\/save(\?|\/)?/.test(action) && !validate_required(form)) {
547 return false;
548 }
549-
550- form.attributes['action'].value = action;
551+
552+ form.attributes['action'].value = action;
553 form.submit();
554 }
555
556-var pager_action = function(action, src) {
557+function pager_action(action, src) {
558 return src ? new ListView(src).go(action) : submit_form(action ? action : 'find');
559 }
560
561-var buttonClicked = function(name, btype, model, id, sure, target){
562+function buttonClicked(name, btype, model, id, sure, target) {
563
564- if (sure && !confirm(sure)){
565+ if (sure && !confirm(sure)) {
566 return;
567 }
568
569- var params = {};
570+ var params = {
571+ '_terp_button/name': name,
572+ '_terp_button/btype': btype,
573+ '_terp_button/model': model,
574+ '_terp_button/id': id
575+ };
576
577- params['_terp_button/name'] = name;
578- params['_terp_button/btype'] = btype;
579- params['_terp_button/model'] = model;
580- params['_terp_button/id'] = id;
581-
582 var act = get_form_action(btype == 'cancel' ? 'cancel' : 'save', params);
583 submit_form(act, null, target);
584 }
585
586-var onBooleanClicked = function(name) {
587+function onBooleanClicked(name) {
588
589 var source = openobject.dom.get(name + '_checkbox_');
590 var target = openobject.dom.get(name);
591
592 target.value = source.checked ? 1 : '';
593- MochiKit.Signal.signal(target, 'onchange');
594+ MochiKit.Signal.signal(target, 'onchange');
595 }
596
597 /**
598@@ -324,64 +355,65 @@
599 * 2 then give form data with type info + required flag
600 * else gives simple key-value pairs
601 */
602-var getFormData = function(extended) {
603+function getFormData(extended) {
604
605 var parentNode = openobject.dom.get('_terp_list') || document.forms['view_form'];
606
607 var frm = {};
608 var fields = [];
609-
610+
611 var is_editable = openobject.dom.get('_terp_editable').value == 'True';
612-
613+
614 if (is_editable) {
615- fields = openobject.dom.select("input, textarea, select", parentNode);
616+ fields = openobject.dom.select("input, textarea, select", parentNode);
617 } else {
618- fields = fields.concat(openobject.dom.select('kind=value'));
619- fields = fields.concat(openobject.dom.select('[name$=/__id]'));
620+ fields = fields.concat(openobject.dom.select('kind=value'));
621+ fields = fields.concat(openobject.dom.select('[name$=/__id]'));
622 }
623-
624- fields = fields.concat(filter(function(e){
625- return getNodeAttribute(e,'kind')=='picture';
626+
627+ fields = fields.concat(filter(function(e) {
628+ return getNodeAttribute(e, 'kind') == 'picture';
629 }, openobject.dom.select('img', parentNode)));
630-
631- for(var i=0; i<fields.length; i++) {
632-
633+
634+ for (var i = 0; i < fields.length; i++) {
635+
636 var e = fields[i];
637 var n = is_editable ? e.name : e.id;
638-
639- if (e.tagName.toLowerCase() != 'img' && !n)
640+
641+ if (e.tagName.toLowerCase() != 'img' && !n) {
642 continue;
643+ }
644
645- var n = n.replace('_terp_listfields/', '');
646+ n = n.replace('_terp_listfields/', '');
647
648 // don't include _terp_ fields except _terp_id
649- if (/_terp_/.test(n) && ! /_terp_id$/.test(n))
650+ if (/_terp_/.test(n) && ! /_terp_id$/.test(n)) {
651 continue;
652+ }
653
654- // work arround to skip o2m values (list mode)
655+ // work around to skip o2m values (list mode)
656+ var value;
657 if (n.indexOf('/__id') > 0) {
658-
659+
660 n = n.replace('/__id', '');
661
662 if (openobject.dom.get(n + '/_terp_view_type').value == 'form') {
663- frm[n+'/__id'] = openobject.dom.get(n+'/__id').value;
664+ frm[n + '/__id'] = openobject.dom.get(n + '/__id').value;
665 continue;
666 }
667 // skip if editable list's editors are visible
668 if (openobject.dom.select("[name^=_terp_listfields/" + n + "]").length) {
669 continue;
670 }
671-
672-
673- var value = openobject.dom.get(n + '/_terp_ids').value;
674
675+ value = openobject.dom.get(n + '/_terp_ids').value;
676 if (extended) {
677- value = {'value': value,
678- 'type': 'one2many',
679- 'relation': openobject.dom.get(n + '/_terp_model').value};
680+ value = {'value': value,
681+ 'type': 'one2many',
682+ 'relation': openobject.dom.get(n + '/_terp_model').value};
683 value = serializeJSON(value);
684 }
685-
686+
687 frm[n] = value;
688 continue;
689 }
690@@ -389,8 +421,8 @@
691 if (extended && n.indexOf('/__id') == -1) {
692
693 var attrs = {};
694-
695- var value = (is_editable ? e.value : getNodeAttribute(e, 'value')) || "";
696+
697+ value = (is_editable ? e.value : getNodeAttribute(e, 'value')) || "";
698 var kind = getNodeAttribute(e, 'kind') || "char";
699
700 //take care of _terp_id
701@@ -399,42 +431,44 @@
702 // only the resource id and all O2M
703 n = n.replace(/_terp_id$/, '');
704 if (n && !openobject.dom.get(n + '__id')) {
705- continue;
706+ continue;
707 }
708
709 n = n + 'id';
710-
711+
712 if (!openobject.dom.get(n)) {
713- continue;
714+ continue;
715 }
716-
717+
718 kind = 'integer';
719 value = value == 'False' ? '' : value;
720 }
721
722 attrs['value'] = typeof(value) == "undefined" ? '' : value;
723
724- if (kind)
725+ if (kind) {
726 attrs['type'] = kind;
727-
728- if (extended && (kind == 'many2one' || kind == 'many2many')){
729+ }
730+
731+ if (extended && (kind == 'many2one' || kind == 'many2many')) {
732 attrs['relation'] = getNodeAttribute(e, 'relation');
733 }
734
735- if (extended > 1 && hasElementClass(e, 'requiredfield'))
736- attrs['required'] = 1;
737+ if (extended > 1 && hasElementClass(e, 'requiredfield')) {
738+ attrs['required'] = 1;
739+ }
740
741 if (kind == "picture") {
742 n = e.id;
743 }
744
745 if (kind == 'text_html') {
746- attrs['value'] = tinyMCE.get(e.name).getContent();
747+ attrs['value'] = tinyMCE.get(e.name).getContent();
748 }
749
750 // stringify the attr object
751 frm[n] = serializeJSON(attrs);
752-
753+
754 } else {
755 frm[n] = e.value;
756 }
757@@ -447,17 +481,18 @@
758 * get key-value pair of form params (_terp_)
759 * @param name: only return values for given param
760 */
761-var getFormParams = function(name){
762+function getFormParams(name) {
763
764 var parentNode = document.forms['view_form'];
765
766 var frm = {};
767 var fields = openobject.dom.select('input', parentNode);
768
769- forEach(fields, function(e){
770+ forEach(fields, function(e) {
771
772- if (!e.name || e.name.indexOf('_terp_listfields/') > -1 || e.name.indexOf('_terp_') == -1)
773+ if (!e.name || e.name.indexOf('_terp_listfields/') > -1 || e.name.indexOf('_terp_') == -1) {
774 return
775+ }
776
777 if (name && e.name != name) {
778 return;
779@@ -473,19 +508,19 @@
780 return frm;
781 }
782
783-var onChange = function(name) {
784+function onChange(name) {
785
786 var caller = openobject.dom.get(name);
787 var callback = getNodeAttribute(caller, 'callback');
788 var change_default = getNodeAttribute(caller, 'change_default');
789-
790+
791 if (!(callback || change_default) || caller.__lock_onchange) {
792 return;
793 }
794-
795+
796 var is_list = caller.id.indexOf('_terp_listfields') == 0;
797 var prefix = caller.name || caller.id;
798- prefix = prefix.slice(0, prefix.lastIndexOf('/')+1);
799+ prefix = prefix.slice(0, prefix.lastIndexOf('/') + 1);
800
801 var params = getFormData(1);
802 var model = is_list ? openobject.dom.get(prefix.slice(17) + '_terp_model').value : openobject.dom.get(prefix + '_terp_model').value;
803@@ -498,33 +533,35 @@
804 params['_terp_context'] = context;
805 params['_terp_value'] = caller.value;
806 params['id'] = id;
807-
808+
809 var req = openobject.http.postJSON(callback ? '/form/on_change' : '/form/change_default_get', params);
810
811- req.addCallback(function(obj){
812+ req.addCallback(function(obj) {
813
814 if (obj.error) {
815 return alert(obj.error);
816 }
817-
818+
819 values = obj['value'];
820 domains = obj['domain'];
821
822 domains = domains ? domains : {};
823
824- for(var k in domains){
825- fld = openobject.dom.get(prefix + k);
826- if (fld){
827- setNodeAttribute(fld, 'domain', domains[k]);
828+ for (var domain in domains) {
829+ fld = openobject.dom.get(prefix + domain);
830+ if (fld) {
831+ setNodeAttribute(fld, 'domain', domains[domain]);
832 }
833 }
834
835- for(var k in values){
836-
837+ for (var k in values) {
838+
839 flag = false;
840 fld = openobject.dom.get(prefix + k);
841
842- if (!fld) continue;
843+ if (!fld) {
844+ continue;
845+ }
846
847 value = values[k];
848 value = value === false || value === null ? '' : value;
849@@ -532,7 +569,7 @@
850 // prevent recursive onchange
851 fld.__lock_onchange = true;
852
853- if (openobject.dom.get(prefix + k + '_id')){
854+ if (openobject.dom.get(prefix + k + '_id')) {
855 fld = openobject.dom.get(prefix + k + '_id');
856 flag = true;
857 }
858@@ -541,36 +578,39 @@
859 fld.value = value;
860
861 var kind = getNodeAttribute(fld, 'kind');
862-
863- if (kind == 'picture') {
864- fld.src = value;
865- }
866-
867- if (kind == 'many2one'){
868- fld.value = value[0] || '';
869- try {
870- openobject.dom.get(prefix + k + '_text').value = value[1] || '';
871- }catch(e){}
872- }
873-
874- if (kind == 'boolean') {
875- openobject.dom.get(prefix + k + '_checkbox_').checked = value || false;
876- }
877-
878- if (kind=='text_html') {
879- tinyMCE.execInstanceCommand(k, 'mceSetContent', false, value || '')
880- }
881-
882- if (kind=='selection') {
883- var opts = [];
884- opts.push(OPTION({'value': ''}))
885-
886- for (i in value) {
887- var item = value[i];
888- opts.push(OPTION({'value': item[0]}, item[1]));
889- }
890- MochiKit.DOM.replaceChildNodes(fld, map(function(x){return x;}, opts));
891- }
892+
893+ switch (kind) {
894+ case 'picture':
895+ fld.src = value;
896+ break;
897+ case 'many2one':
898+ fld.value = value[0] || '';
899+ try {
900+ openobject.dom.get(prefix + k + '_text').value = value[1] || '';
901+ } catch(e) {
902+ }
903+ break;
904+ case 'boolean':
905+ openobject.dom.get(prefix + k + '_checkbox_').checked = value || false;
906+ break;
907+ case 'text_html':
908+ tinyMCE.execInstanceCommand(k, 'mceSetContent', false, value || '');
909+ break;
910+ case 'selection':
911+ var opts = [];
912+ opts.push(OPTION({'value': ''}));
913+
914+ for (i in value) {
915+ var item = value[i];
916+ opts.push(OPTION({'value': item[0]}, item[1]));
917+ }
918+ MochiKit.DOM.replaceChildNodes(fld, map(function(x) {
919+ return x;
920+ }, opts));
921+ break;
922+ default:
923+ // do nothing on default
924+ }
925
926 MochiKit.Signal.signal(fld, 'onchange');
927 }
928@@ -592,27 +632,27 @@
929 *
930 * @return string
931 */
932-function getName(name, relation){
933+function getName(name, relation) {
934
935 var value_field = openobject.dom.get(name);
936 var text_field = openobject.dom.get(value_field.name + '_text');
937
938 relation = relation ? relation : getNodeAttribute(value_field, 'relation');
939
940- if (value_field.value == ''){
941+ if (value_field.value == '') {
942 text_field.value = ''
943 }
944
945- if (value_field.value){
946+ if (value_field.value) {
947 var req = openobject.http.getJSON('/search/get_name', {model: relation, id : value_field.value});
948- req.addCallback(function(obj){
949+ req.addCallback(function(obj) {
950 text_field.value = obj.name;
951 });
952 }
953 }
954
955-function eval_domain_context_request(options){
956-
957+function eval_domain_context_request(options) {
958+
959 if ((!options.domain || options.domain == '[]') && (!options.context || options.context == '{}')) {
960 return new MochiKit.Async.succeed(-1);
961 }
962@@ -621,39 +661,40 @@
963 prefix.pop();
964
965 // editable listview fields
966- if (prefix[0] == '_terp_listfields'){
967+ if (prefix[0] == '_terp_listfields') {
968 prefix.shift();
969 }
970 prefix = prefix.join('/');
971
972 var params = getFormData(1);
973-
974+
975 params['_terp_domain'] = options.domain;
976 params['_terp_context'] = options.context;
977- params['_terp_prefix'] = prefix;
978+ params['_terp_prefix'] = prefix;
979 params['_terp_active_id'] = prefix ? openobject.dom.get(prefix + '/_terp_id').value : openobject.dom.get('_terp_id').value;
980 params['_terp_active_ids'] = prefix ? openobject.dom.get(prefix + '/_terp_ids').value : openobject.dom.get('_terp_ids').value;
981-
982+
983 if (options.active_id) {
984 params['_terp_active_id'] = options.active_id;
985 params['_terp_active_ids'] = options.active_ids;
986 }
987-
988+
989 var parent_context = prefix ? openobject.dom.get(prefix + '/_terp_context') : openobject.dom.get('_terp_context');
990-
991- if (parent_context){
992+
993+ if (parent_context) {
994 params['_terp_parent_context'] = parent_context.value;
995 }
996-
997+
998 var req = openobject.http.postJSON('/search/eval_domain_and_context', params);
999- return req.addCallback(function(obj){
1000+ return req.addCallback(function(obj) {
1001
1002 if (obj.error_field) {
1003
1004 var fld = openobject.dom.get(obj.error_field) || openobject.dom.get('_terp_listfields/' + obj.error_field);
1005
1006- if (fld && getNodeAttribute(fld, 'kind') == 'many2one')
1007- fld = openobject.dom.get(fld.id + '_text');
1008+ if (fld && getNodeAttribute(fld, 'kind') == 'many2one') {
1009+ fld = openobject.dom.get(fld.id + '_text');
1010+ }
1011
1012 if (fld) {
1013 fld.focus();
1014@@ -671,32 +712,36 @@
1015
1016 function open_search_window(relation, domain, context, source, kind, text) {
1017
1018- var req = eval_domain_context_request({source: source,
1019- domain: domain,
1020- context: context});
1021+ var req = eval_domain_context_request({
1022+ 'source': source,
1023+ 'domain': domain,
1024+ 'context': context
1025+ });
1026
1027 if (kind == 2 && source.indexOf('_terp_listfields/') == 0) {
1028 text = "";
1029 }
1030
1031- req.addCallback(function(obj){
1032- openobject.tools.openWindow(openobject.http.getURL('/search/new', {model: relation,
1033- domain: obj.domain,
1034- context: obj.context,
1035- source: source,
1036- kind: kind,
1037- text: text}));
1038+ req.addCallback(function(obj) {
1039+ openobject.tools.openWindow(openobject.http.getURL('/search/new', {
1040+ 'model': relation,
1041+ 'domain': obj.domain,
1042+ 'context': obj.context,
1043+ 'source': source,
1044+ 'kind': kind,
1045+ 'text': text
1046+ }));
1047 });
1048 }
1049
1050-var showCustomizeMenu = function(src, elem) {
1051+function showCustomizeMenu(src, elem) {
1052 var elem = openobject.dom.get(elem);
1053-
1054+
1055 var frame = window.frameElement ? window.frameElement : null;
1056 if (frame) {
1057- frame.style.height = elementDimensions(openobject.dom.get('main_form_body')).h + 70 + 'px';
1058+ frame.style.height = elementDimensions(openobject.dom.get('main_form_body')).h + 70 + 'px';
1059 }
1060-
1061+
1062 MochiKit.Visual.appear(elem, {from: 0, duration: 0.4});
1063 }
1064
1065@@ -710,42 +755,46 @@
1066 var model = prefix ? openobject.dom.get(prefix + '_terp_model').value : openobject.dom.get('_terp_model').value;
1067
1068 var params = {'model': model, 'field': id, 'kind': kind, 'relation': relation, 'value': val};
1069-
1070+
1071 var req = openobject.http.postJSON(act, params);
1072
1073 req.addCallback(function(obj) {
1074
1075 var rows = [];
1076
1077- for(var r in obj.defaults) {
1078- var o = obj.defaults[r];
1079+ for (var r in obj.defaults) {
1080+ var o = obj.defaults[r];
1081 var a = SPAN({onclick: 'hideElement("contextmenu"); return ' + o.action}, o.text);
1082 rows = rows.concat(a);
1083 }
1084
1085- if(obj.actions.length > 0) {
1086+ if (obj.actions.length > 0) {
1087 rows = rows.concat(HR());
1088
1089- for(var r in obj.actions) {
1090+ for (var r in obj.actions) {
1091 var o = obj.actions[r];
1092
1093- var a = SPAN({'class': o.action ? '' : 'disabled',
1094- 'onclick': o.action ? 'hideElement("contextmenu"); return ' + o.action : ''}, o.text);
1095+ var a = SPAN({
1096+ 'class': o.action ? '' : 'disabled',
1097+ 'onclick': o.action ? 'hideElement("contextmenu"); return ' + o.action : ''
1098+ }, o.text);
1099
1100 rows = rows.concat(a);
1101 }
1102 }
1103
1104- if(obj.relates.length > 0) {
1105- rows = rows.concat(HR())
1106+ if (obj.relates.length > 0) {
1107+ rows = rows.concat(HR());
1108
1109- for(var r in obj.relates) {
1110+ for (var r in obj.relates) {
1111 var o = obj.relates[r];
1112-
1113- var a = SPAN({'class': o.action ? '' : 'disabled',
1114- 'onclick': o.action ? 'hideElement(\'contextmenu\'); return ' + o.action : '',
1115- 'domain': o.domain,
1116- 'context': o.context}, o.text);
1117+
1118+ var a = SPAN({
1119+ 'class': o.action ? '' : 'disabled',
1120+ 'onclick': o.action ? 'hideElement(\'contextmenu\'); return ' + o.action : '',
1121+ 'domain': o.domain,
1122+ 'context': o.context
1123+ }, o.text);
1124
1125 rows = rows.concat(a);
1126 }
1127@@ -753,8 +802,10 @@
1128
1129 openobject.dom.get('contextmenu').innerHTML = '';
1130
1131- var tbl = TABLE({'cellpadding': 0, 'cellspacing' : 0},
1132- TBODY(null, map(function(r){return TR(null, TD(null, r));}, rows)));
1133+ var tbl = TABLE({'cellpadding': 0, 'cellspacing' : 0},
1134+ TBODY(null, map(function(r) {
1135+ return TR(null, TD(null, r));
1136+ }, rows)));
1137
1138 appendChildNodes('contextmenu', tbl);
1139
1140@@ -770,7 +821,7 @@
1141 x -= x + md.w - vd.w;
1142 openobject.dom.get('contextmenu').style.left = x + 'px';
1143 }
1144-
1145+
1146 if ((y + md.h) > vd.h) {
1147 y -= y + md.h - vd.h;
1148 openobject.dom.get('contextmenu').style.top = y + 'px';
1149@@ -780,14 +831,14 @@
1150 });
1151 }
1152
1153-var showContextMenu = function(){
1154+function showContextMenu() {
1155
1156 var menu = openobject.dom.get('contextmenu');
1157 var ifrm = openobject.dom.get('contextmenu_frm');
1158
1159 showElement(menu);
1160
1161- if (ifrm){
1162+ if (ifrm) {
1163
1164 ifrm.style.left = menu.offsetLeft + "px";
1165 ifrm.style.top = menu.offsetTop + "px";
1166@@ -799,21 +850,21 @@
1167 }
1168 }
1169
1170-var hideContextMenu = function(){
1171+function hideContextMenu() {
1172 var menu = openobject.dom.get('contextmenu');
1173 var ifrm = openobject.dom.get('contextmenu_frm');
1174
1175- if (ifrm){
1176+ if (ifrm) {
1177 hideElement(ifrm);
1178 }
1179
1180 hideElement(menu);
1181 }
1182
1183-function set_to_default(field, model){
1184+function set_to_default(field, model) {
1185
1186 var kind = getNodeAttribute(openobject.dom.get(field), 'kind');
1187-
1188+
1189 var act = get_form_action('get_default_value');
1190 var params = {'model': model, 'field': field};
1191
1192@@ -825,25 +876,27 @@
1193 });
1194 }
1195
1196-function set_as_default(field, model){
1197+function set_as_default(field, model) {
1198
1199 var kind = getNodeAttribute(openobject.dom.get(field), 'kind');
1200
1201 var args = getFormData(1);
1202-
1203+
1204 args['_terp_model'] = model;
1205 args['_terp_field'] = field;
1206
1207 var req = openobject.http.postJSON('/fieldpref/get', args);
1208
1209- req.addCallback(function(obj){
1210+ req.addCallback(function(obj) {
1211 var text = obj.text;
1212- var params = {'_terp_model': model,
1213- '_terp_field/name': field,
1214- '_terp_field/string': text,
1215- '_terp_field/value': openobject.dom.get(field).value,
1216- '_terp_deps': obj.deps};
1217-
1218+ var params = {
1219+ '_terp_model': model,
1220+ '_terp_field/name': field,
1221+ '_terp_field/string': text,
1222+ '_terp_field/value': openobject.dom.get(field).value,
1223+ '_terp_deps': obj.deps
1224+ };
1225+
1226 openobject.tools.openWindow(openobject.http.getURL('/fieldpref', params), {width: 500, height: 350});
1227 });
1228 }
1229@@ -859,15 +912,15 @@
1230 }
1231
1232 function do_action(action_id, field, relation, src) {
1233-
1234+
1235 var params = {};
1236-
1237+
1238 if (openobject.dom.get('_terp_list')) {
1239 var list = new ListView('_terp_list');
1240 var ids = list.getSelectedRecords();
1241
1242 if (ids.length == 0) {
1243- return alert(_('You must select at least one record.'));
1244+ return alert(_('You must select at least one record.'));
1245 }
1246
1247 params['_terp_selection'] = '[' + ids.join(',') + ']';
1248@@ -876,107 +929,118 @@
1249 var id = openobject.dom.get(field).value;
1250 var domain = getNodeAttribute(src, 'domain');
1251 var context = getNodeAttribute(src, 'context');
1252-
1253- var req = eval_domain_context_request({source: openobject.dom.get(field).id,
1254- active_id: id,
1255- active_ids: params['_terp_selection'],
1256- domain: domain,
1257- context: context});
1258-
1259- req.addCallback(function(obj){
1260-
1261+
1262+ var req = eval_domain_context_request({
1263+ 'source': openobject.dom.get(field).id,
1264+ 'active_id': id,
1265+ 'active_ids': params['_terp_selection'],
1266+ 'domain': domain,
1267+ 'context': context
1268+ });
1269+
1270+ req.addCallback(function(obj) {
1271+
1272 var act = get_form_action('action');
1273 MochiKit.Base.update(params, {
1274 '_terp_action': action_id,
1275- '_terp_domain': obj.domain,
1276- '_terp_context': obj.context,
1277+ '_terp_domain': obj.domain,
1278+ '_terp_context': obj.context,
1279 '_terp_id': id,
1280- '_terp_model': relation});
1281-
1282+ '_terp_model': relation
1283+ });
1284+
1285 window.open(openobject.http.getURL(act, params));
1286
1287 });
1288 }
1289
1290-function on_context_menu(evt) {
1291-
1292- if(! evt.modifier().ctrl)
1293+function on_context_menu(evt) {
1294+
1295+ if (! evt.modifier().ctrl) {
1296 return;
1297-
1298+ }
1299+
1300 var target = evt.target();
1301 var kind = getNodeAttribute(target, 'kind');
1302-
1303- if(! kind || target.disabled)
1304+
1305+ if (! kind || target.disabled) {
1306 return;
1307+ }
1308
1309 var menu = openobject.dom.get('contextmenu');
1310
1311 if (!menu) {
1312
1313- menu = DIV({'id': 'contextmenu',
1314- 'class' : 'contextmenu',
1315- 'onmouseout' : 'hideContextMenu()',
1316- 'onmouseover' : 'showContextMenu()',
1317- 'style' : 'position: absolute; display: none;'});
1318+ menu = DIV({
1319+ 'id': 'contextmenu',
1320+ 'class': 'contextmenu',
1321+ 'onmouseout': 'hideContextMenu()',
1322+ 'onmouseover': 'showContextMenu()',
1323+ 'style': 'position: absolute; display: none;'
1324+ });
1325
1326 appendChildNodes(document.body, menu);
1327
1328 if (/msie/.test(navigator.userAgent.toLowerCase())) {
1329- var ifrm = createDOM('IFRAME', {'id' : 'contextmenu_frm',
1330- 'src' : '#', 'frameborder': '0', 'scrolling' :'no',
1331- 'style':'position: absolute; display: none;'});
1332+ var ifrm = createDOM('IFRAME', {
1333+ 'id': 'contextmenu_frm',
1334+ 'src': '#', 'frameborder': '0', 'scrolling' :'no',
1335+ 'style':'position: absolute; display: none;'
1336+ });
1337
1338 appendChildNodes(document.body, ifrm);
1339 }
1340 }
1341
1342 var src = target.id;
1343-
1344+
1345 if (kind == 'many2one') {
1346 src = src.slice(0, -5);
1347 }
1348-
1349+
1350 var val = openobject.dom.get(src).value;
1351 var relation = getNodeAttribute(src, 'relation');
1352
1353 hideElement(menu);
1354
1355 var p = evt.mouse().page;
1356-
1357+
1358 setElementPosition(menu, p);
1359
1360- makeContextMenu(src, kind, relation, val);
1361-
1362+ makeContextMenu(src, kind, relation, val);
1363+
1364 evt.stop();
1365 }
1366
1367-function open_url(site){
1368+function open_url(site) {
1369 var web_site;
1370
1371 isIE = /msie/.test(navigator.userAgent.toLowerCase());
1372-
1373- if(isIE && site.indexOf('@') > -1) {
1374+
1375+ if (isIE && site.indexOf('@') > -1) {
1376 site = site.split('@');
1377 site = site[1]
1378 }
1379-
1380- if(site.indexOf("://")== -1)
1381- web_site='http://'+site;
1382- else
1383+
1384+ if (site.indexOf("://") == -1) {
1385+ web_site = 'http://' + site;
1386+ } else {
1387 web_site = site;
1388+ }
1389
1390- if(site.length > 0) {
1391+ if (site.length > 0) {
1392 window.open(web_site);
1393 }
1394 }
1395
1396 function submenu_action(action_id, model) {
1397- window.location.href = openobject.http.getURL("/form/action_submenu", {
1398- _terp_action_id: action_id,
1399- _terp_model: model,
1400- _terp_id: $('_terp_id').value
1401- });
1402+ window.location.href = openobject.http.getURL("/form/action_submenu", {
1403+ _terp_action_id: action_id,
1404+ _terp_model: model,
1405+ _terp_id: $('_terp_id').value
1406+ });
1407 }
1408+<<<<<<< TREE
1409
1410 function show_wkf() {
1411
1412@@ -995,3 +1059,5 @@
1413 }
1414 // vim: ts=4 sts=4 sw=4 si et
1415
1416+=======
1417+>>>>>>> MERGE-SOURCE
1418
1419=== modified file 'addons/openerp/static/javascript/menubar.js'
1420--- addons/openerp/static/javascript/menubar.js 2010-03-16 19:33:17 +0000
1421+++ addons/openerp/static/javascript/menubar.js 2010-03-31 08:25:34 +0000
1422@@ -1,22 +1,29 @@
1423-
1424-function adjustAppFrame(evt){
1425-
1426- var $ = jQuery;
1427-
1428- var h = $("#appFrame").contents().find("body").height();
1429- var w = $("#appFrame").contents().width();
1430-
1431- $("#menubar").width(250);
1432- $("#appFrame").height(Math.max(0, h));
1433-
1434- var mh = $("#menubar").height();
1435- var ww = $(window).width();
1436- var tw = $("#menubar").width() + w;
1437- var rw = ww - $("#menubar").width();
1438-
1439- var w = tw > ww ? w : rw - 16;
1440-
1441- $("#appFrame").width(Math.max(0, w));
1442- $("table#contents").height(Math.max(h, mh));
1443+/**
1444+ * Allowable width for the left-hand menu (for the current application)
1445+ */
1446+var MENU_WIDTH = 250;
1447+/**
1448+ * Tries to fit the size of the #appFrame frame to better fit its current
1449+ * content.extend
1450+ * Has to be called from the document outside of the frame itself.
1451+ *
1452+ * Probably won't get it exactly right, you might want to call it
1453+ * several times
1454+ */
1455+function adjustAppFrame() {
1456+ var frameHeight = jQuery("#appFrame").contents().find("body").height();
1457+ var frameWidth = jQuery("#appFrame").contents().width();
1458+
1459+ jQuery("#menubar").width(MENU_WIDTH);
1460+ jQuery("#appFrame").height(Math.max(0, frameHeight));
1461+
1462+ var menuWidth = jQuery("#menubar").height();
1463+ var windowWidth = jQuery(window).width();
1464+ var totalWidth = jQuery("#menubar").width() + frameWidth;
1465+ var rw = windowWidth - jQuery("#menubar").width();
1466+
1467+ var newWidth = totalWidth > windowWidth ? frameWidth : rw - 16;
1468+
1469+ jQuery("#appFrame").width(Math.max(0, newWidth));
1470+ jQuery("table#contents").height(Math.max(frameHeight, menuWidth));
1471 }
1472-
1473
1474=== modified file 'openobject/controllers/templates/base.mako'
1475--- openobject/controllers/templates/base.mako 2010-03-16 19:43:23 +0000
1476+++ openobject/controllers/templates/base.mako 2010-03-31 08:25:34 +0000
1477@@ -10,10 +10,8 @@
1478 <script type="text/javascript" src="/openobject/static/javascript/MochiKit/MochiKit.js"></script>
1479 <script type="text/javascript" src="/openobject/static/javascript/MochiKit/DragAndDrop.js"></script>
1480 <script type="text/javascript" src="/openobject/static/javascript/MochiKit/Resizable.js"></script>
1481-
1482- <script type="text/javascript" src="/openobject/static/javascript/MochiKit/Resizable.js"></script>
1483 <script type="text/javascript" src="/openobject/static/javascript/MochiKit/Sortable.js"></script>
1484-
1485+
1486 <script type="text/javascript" src="/openobject/static/javascript/jQuery/jquery-1.4.2.js"></script>
1487 <script type="text/javascript">
1488 jQuery.noConflict();

Subscribers

People subscribed via source and target branches