diff options
| author | Vidhin Mehta (OpenERP) <vme@tinyerp.com> | 2012-06-22 14:36:14 +0530 |
|---|---|---|
| committer | Vidhin Mehta (OpenERP) <vme@tinyerp.com> | 2012-06-22 14:36:14 +0530 |
| commit | 790e3d6d9ecb604c5ea7560bbd2869b4b2843a9c (patch) | |
| tree | 5b6304cdad43ff73ff5326b4331b5b984bdc60bc /addons/web/static/src/js | |
| parent | 5053c1a66e78ba3e4ce51e9cd41c2d4c39d5136e (diff) | |
| parent | 5006656a2832816b38790ab87b99969fedaed3c0 (diff) | |
[MERGE]merge with trunk and in testing OK.
bzr revid: vme@tinyerp.com-20120622090614-t0q7djkz62dn1yiq
Diffstat (limited to 'addons/web/static/src/js')
| -rw-r--r-- | addons/web/static/src/js/chrome.js | 54 | ||||
| -rw-r--r-- | addons/web/static/src/js/coresetup.js | 177 | ||||
| -rw-r--r-- | addons/web/static/src/js/formats.js | 4 | ||||
| -rw-r--r-- | addons/web/static/src/js/view_form.js | 133 | ||||
| -rw-r--r-- | addons/web/static/src/js/views.js | 23 |
5 files changed, 235 insertions, 156 deletions
diff --git a/addons/web/static/src/js/chrome.js b/addons/web/static/src/js/chrome.js index 833111c79db..6d3f506b6ab 100644 --- a/addons/web/static/src/js/chrome.js +++ b/addons/web/static/src/js/chrome.js @@ -206,7 +206,14 @@ instance.web.CrashManager = instance.web.CallbackEnabled.extend({ buttons: buttons }).open(); dialog.$element.html(QWeb.render('CrashManager.error', {session: instance.connection, error: error})); - } + }, + on_javascript_exception: function(exception) { + this.on_traceback({ + type: _t("Client Error"), + message: exception, + data: {debug: ""} + }); + }, }); instance.web.Loading = instance.web.Widget.extend({ @@ -575,10 +582,6 @@ instance.web.Menu = instance.web.Widget.extend({ this.renderElement(); this.limit_entries(); this.$secondary_menus.html(QWeb.render("Menu.secondary", { widget : this })); - this.$element.on('click', 'a.oe_menu_more_link', function() { - self.$element.find('.oe_menu_more').toggle(); - return false; - }); this.$element.on('click', 'a[data-menu]', this.on_menu_click); this.$secondary_menus.on('click', 'a[data-menu]', this.on_menu_click); // Hide second level submenus @@ -599,16 +602,12 @@ instance.web.Menu = instance.web.Widget.extend({ $index.after($more); $more.find('.oe_menu_more').append($index.next().nextAll()); } - this.do_hide_more(); }, auto_limit_entries: function() { // TODO: auto detect overflow and bind window on resize var width = $(window).width(); return Math.floor(width / 125); }, - do_hide_more: function() { - this.$element.find('.oe_menu_more').hide(); - }, /** * Opens a given menu by id, as if a user had browsed to that menu by hand * except does not trigger any event on the way @@ -669,7 +668,6 @@ instance.web.Menu = instance.web.Widget.extend({ */ menu_click: function(id) { if (id) { - this.do_hide_more(); // find back the menuitem in dom to get the action var $item = this.$element.find('a[data-menu=' + id + ']'); if (!$item.length) { @@ -701,9 +699,8 @@ instance.web.Menu = instance.web.Widget.extend({ * @param {Event} ev the jquery event */ on_menu_click: function(ev) { + ev.preventDefault(); this.menu_click($(ev.currentTarget).data('menu')); - ev.stopPropagation(); - return false; }, }); @@ -716,20 +713,12 @@ instance.web.UserMenu = instance.web.Widget.extend({ start: function() { var self = this; this._super.apply(this, arguments); - $('html').bind('click', function() { - self.$element.find('.oe_dropdown_options').hide(); - }); - this.$element.find('.oe_dropdown_toggle').click(function() { - self.$element.find('.oe_dropdown_options').toggle(); - return false; - }); - this.$element.on('click', '.oe_dropdown_options li a[data-menu]', function() { + this.$element.on('click', '.oe_dropdown_menu li a[data-menu]', function(ev) { + ev.preventDefault(); var f = self['on_menu_' + $(this).data('menu')]; if (f) { f($(this)); } - self.$element.find('.oe_dropdown_options').hide(); - return false; }); }, change_password :function() { @@ -873,6 +862,27 @@ instance.web.WebClient = instance.web.Widget.extend({ this.$element.on('mouseenter', '.oe_systray > div:not([data-tipsy=true])', function() { $(this).attr('data-tipsy', 'true').tipsy().trigger('mouseenter'); }); + this.$element.on('click', '.oe_dropdown_toggle', function(ev) { + var $menu = $(this).find('.oe_dropdown_menu'); + var state = $menu.is('.oe_opened'); + setTimeout(function() { + // Do not alter propagation + $menu.toggleClass('oe_opened', !state); + if (!state) { + // Move $menu if outside window's edge + var doc_width = $(document).width(); + var offset = $menu.offset(); + var menu_width = $menu.width(); + var x = doc_width - offset.left - menu_width - 15; + if (x < 0) { + $menu.offset({ left: offset.left + x }).width(menu_width); + } + } + }, 0); + }); + instance.web.bus.on('click', this, function() { + self.$element.find('.oe_dropdown_menu.oe_opened').removeClass('oe_opened'); + }); }, show_common: function() { var self = this; diff --git a/addons/web/static/src/js/coresetup.js b/addons/web/static/src/js/coresetup.js index 77355dd163a..955a46e6923 100644 --- a/addons/web/static/src/js/coresetup.js +++ b/addons/web/static/src/js/coresetup.js @@ -224,6 +224,7 @@ instance.web.Session = instance.web.JsonRPC.extend( /** @lends instance.web.Sess } return loaded.then(function() { self.on_modules_loaded(); + self.trigger('module_loaded'); if (!no_session_valid_signal) { self.on_session_valid(); } @@ -400,6 +401,29 @@ instance.web.Session = instance.web.JsonRPC.extend( /** @lends instance.web.Sess } }); +/** + * Event Bus used to bind events scoped in the current instance + */ +instance.web.bus = new (instance.web.Class.extend(instance.web.EventDispatcherMixin, { + init: function() { + instance.web.EventDispatcherMixin.init.call(this, parent); + var self = this; + // TODO fme: allow user to bind keys for some global actions. + // check gtk bindings + // http://unixpapa.com/js/key.html + _.each('click,dblclick,keydown,keypress,keyup'.split(','), function(evtype) { + $('html').on(evtype, self, function(ev) { + self.trigger(evtype, ev); + }); + }); + _.each('resize,scroll'.split(','), function(evtype) { + $(window).on(evtype, self, function(ev) { + self.trigger(evtype, ev); + }); + }); + } +}))(); + /** OpenERP Translations */ instance.web.TranslationDataBase = instance.web.Class.extend(/** @lends instance.web.TranslationDataBase# */{ /** @@ -454,64 +478,6 @@ instance.web.TranslationDataBase = instance.web.Class.extend(/** @lends instance } }); -/** Configure default qweb */ -instance.web._t = new instance.web.TranslationDataBase().build_translation_function(); -/** - * Lazy translation function, only performs the translation when actually - * printed (e.g. inserted into a template) - * - * Useful when defining translatable strings in code evaluated before the - * translation database is loaded, as class attributes or at the top-level of - * an OpenERP Web module - * - * @param {String} s string to translate - * @returns {Object} lazy translation object - */ -instance.web._lt = function (s) { - return {toString: function () { return instance.web._t(s); }} -}; -instance.web.qweb = new QWeb2.Engine(); -instance.web.qweb.debug = ($.deparam($.param.querystring()).debug != undefined); -instance.web.qweb.default_dict = { - '_' : _, - '_t' : instance.web._t -}; -instance.web.qweb.preprocess_node = function() { - // Note that 'this' is the Qweb Node - switch (this.node.nodeType) { - case 3: - case 4: - // Text and CDATAs - var translation = this.node.parentNode.attributes['t-translation']; - if (translation && translation.value === 'off') { - return; - } - var ts = _.str.trim(this.node.data); - if (ts.length === 0) { - return; - } - var tr = instance.web._t(ts); - if (tr !== ts) { - this.node.data = tr; - } - break; - case 1: - // Element - var attr, attrs = ['label', 'title', 'alt', 'placeholder']; - while (attr = attrs.pop()) { - if (this.attributes[attr]) { - this.attributes[attr] = instance.web._t(this.attributes[attr]); - } - } - } -}; - -/** Configure blockui */ -if ($.blockUI) { - $.blockUI.defaults.baseZ = 1100; - $.blockUI.defaults.message = '<img src="/web/static/src/img/throbber2.gif">'; -} - /** Custom jQuery plugins */ $.fn.getAttributes = function() { var o = {}; @@ -541,10 +507,6 @@ $.Mutex = (function() { return Mutex; })(); -/** Setup default session */ -instance.connection = new instance.web.Session(); -instance.web.qweb.default_dict['__debug__'] = instance.connection.debug; - $.async_when = function() { var async = false; var def = $.Deferred(); @@ -580,6 +542,79 @@ $.async_when = function() { return old_async_when.apply(this, arguments); }; +/** Setup blockui */ +if ($.blockUI) { + $.blockUI.defaults.baseZ = 1100; + $.blockUI.defaults.message = '<img src="/web/static/src/img/throbber2.gif">'; +} + +/** Setup default session */ +instance.connection = new instance.web.Session(); + +/** Configure default qweb */ +instance.web._t = new instance.web.TranslationDataBase().build_translation_function(); +/** + * Lazy translation function, only performs the translation when actually + * printed (e.g. inserted into a template) + * + * Useful when defining translatable strings in code evaluated before the + * translation database is loaded, as class attributes or at the top-level of + * an OpenERP Web module + * + * @param {String} s string to translate + * @returns {Object} lazy translation object + */ +instance.web._lt = function (s) { + return {toString: function () { return instance.web._t(s); }} +}; +instance.web.qweb = new QWeb2.Engine(); +instance.web.qweb.default_dict['__debug__'] = instance.connection.debug; // Which one ? +instance.web.qweb.debug = instance.connection.debug; +instance.web.qweb.default_dict = { + '_' : _, + '_t' : instance.web._t +}; +instance.web.qweb.preprocess_node = function() { + // Note that 'this' is the Qweb Node + switch (this.node.nodeType) { + case 3: + case 4: + // Text and CDATAs + var translation = this.node.parentNode.attributes['t-translation']; + if (translation && translation.value === 'off') { + return; + } + var ts = _.str.trim(this.node.data); + if (ts.length === 0) { + return; + } + var tr = instance.web._t(ts); + if (tr !== ts) { + this.node.data = tr; + } + break; + case 1: + // Element + var attr, attrs = ['label', 'title', 'alt', 'placeholder']; + while (attr = attrs.pop()) { + if (this.attributes[attr]) { + this.attributes[attr] = instance.web._t(this.attributes[attr]); + } + } + } +}; + +/** Setup jQuery timeago */ +var timeago_setup = function () { + var s = $.timeago.settings.strings; + _.each(s, function(v,k) { + if(_.isString(v)) { + s[k] = instance.web._t(v); + } + }); +} +instance.connection.on('module_loaded', this, timeago_setup); + /** * Registry for all the client actions key: tag value: widget */ @@ -589,23 +624,27 @@ instance.web.client_actions = new instance.web.Registry(); * Client action to reload the whole interface. * If params has an entry 'menu_id', it opens the given menu entry. */ -instance.web.client_actions.add("reload", "instance.web.Reload"); - instance.web.Reload = instance.web.Widget.extend({ init: function(parent, params) { this._super(parent); this.menu_id = (params && params.menu_id) || false; }, start: function() { + var l = window.location; + var timestamp = new Date().getTime(); + var search = "?ts=" + timestamp; + if (l.search) { + search = l.search + "&ts=" + timestamp; + } + var hash = l.hash; if (this.menu_id) { - // open the given menu id - var url_without_fragment = window.location.toString().split("#", 1)[0]; - window.location = url_without_fragment + "#menu_id=" + this.menu_id; - } else { - window.location.reload(); + hash = "#menu_id=" + this.menu_id; } + var url = l.protocol + "//" + l.host + l.pathname + search + hash; + window.location = url; } }); +instance.web.client_actions.add("reload", "instance.web.Reload"); }; diff --git a/addons/web/static/src/js/formats.js b/addons/web/static/src/js/formats.js index 0f1c71643be..e0ee3359091 100644 --- a/addons/web/static/src/js/formats.js +++ b/addons/web/static/src/js/formats.js @@ -118,7 +118,9 @@ instance.web.format_value = function (value, descriptor, value_if_empty) { return instance.web.insert_thousand_seps( _.str.sprintf('%d', value)); case 'float': - var precision = descriptor.digits ? descriptor.digits[1] : 2; + var digits = descriptor.digits ? descriptor.digits : [69,2]; + digits = typeof digits === "string" ? py.eval(digits) : digits; + var precision = digits[1]; var formatted = _.str.sprintf('%.' + precision + 'f', value).split('.'); formatted[0] = instance.web.insert_thousand_seps(formatted[0]); return formatted.join(l10n.decimal_point); diff --git a/addons/web/static/src/js/view_form.js b/addons/web/static/src/js/view_form.js index 46c66537690..16141ce7be5 100644 --- a/addons/web/static/src/js/view_form.js +++ b/addons/web/static/src/js/view_form.js @@ -33,7 +33,7 @@ instance.web.form.FieldManagerMixin = { }; instance.web.views.add('form', 'instance.web.FormView'); -instance.web.FormView = instance.web.View.extend(_.extend({}, instance.web.form.FieldManagerMixin, { +instance.web.FormView = instance.web.View.extend(instance.web.form.FieldManagerMixin, { /** * Indicates that this view is not searchable, and thus that no search * view should be displayed (if there is one active). @@ -472,7 +472,7 @@ instance.web.FormView = instance.web.View.extend(_.extend({}, instance.web.form. return self.on_processed_onchange(response, processed); } catch(e) { - console.error(e); + instance.webclient.crashmanager.on_javascript_exception(e); return $.Deferred().reject(); } }); @@ -891,7 +891,7 @@ instance.web.FormView = instance.web.View.extend(_.extend({}, instance.web.form. is_create_mode: function() { return !this.datarecord.id; }, -})); +}); /** * Interface to be implemented by rendering engines for the form view. @@ -1438,7 +1438,7 @@ instance.web.form.InvisibilityChangerMixin = { }, }; -instance.web.form.InvisibilityChanger = instance.web.Class.extend(_.extend({}, instance.web.PropertiesMixin, instance.web.form.InvisibilityChangerMixin, { +instance.web.form.InvisibilityChanger = instance.web.Class.extend(instance.web.PropertiesMixin, instance.web.form.InvisibilityChangerMixin, { init: function(parent, field_manager, invisible_domain, $element) { this.setParent(parent); instance.web.PropertiesMixin.init.call(this); @@ -1446,9 +1446,9 @@ instance.web.form.InvisibilityChanger = instance.web.Class.extend(_.extend({}, i this.$element = $element; this.start(); }, -})); +}); -instance.web.form.FormWidget = instance.web.Widget.extend(_.extend({}, instance.web.form.InvisibilityChangerMixin, { +instance.web.form.FormWidget = instance.web.Widget.extend(instance.web.form.InvisibilityChangerMixin, { /** * @constructs instance.web.form.FormWidget * @extends instance.web.Widget @@ -1554,7 +1554,7 @@ instance.web.form.FormWidget = instance.web.Widget.extend(_.extend({}, instance. } return final_domain; } -})); +}); instance.web.form.WidgetButton = instance.web.form.FormWidget.extend({ template: 'WidgetButton', @@ -1652,7 +1652,7 @@ instance.web.form.WidgetButton = instance.web.form.FormWidget.extend({ * - changed_value: triggered to inform the view to check on_changes * */ -instance.web.form.FieldMixin = { +instance.web.form.FieldInterface = { /** * Constructor takes 2 arguments: * - field_manager: Implements FieldManagerMixin @@ -1716,7 +1716,7 @@ instance.web.form.FieldMixin = { }; /** - * Abstract class for classes implementing FieldMixin. + * Abstract class for classes implementing FieldInterface. * * Properties: * - effective_readonly: when it is true, the widget is displayed as readonly. Vary depending @@ -1726,7 +1726,7 @@ instance.web.form.FieldMixin = { * a 'changed_value' event that inform the view to trigger on_changes. * */ -instance.web.form.AbstractField = instance.web.form.FormWidget.extend(_.extend({}, instance.web.form.FieldMixin, { +instance.web.form.AbstractField = instance.web.form.FormWidget.extend(instance.web.form.FieldInterface, { /** * @constructs instance.web.form.AbstractField * @extends instance.web.form.FormWidget @@ -1844,7 +1844,7 @@ instance.web.form.AbstractField = instance.web.form.FormWidget.extend(_.extend({ set_input_id: function(id) { this.id_for_label = id; }, -})); +}); /** * A mixin to apply on any field that has to completely re-render when its readonly state @@ -1883,7 +1883,7 @@ instance.web.form.ReinitializeFieldMixin = { render_value: function() {}, }; -instance.web.form.FieldChar = instance.web.form.AbstractField.extend(_.extend({}, instance.web.form.ReinitializeFieldMixin, { +instance.web.form.FieldChar = instance.web.form.AbstractField.extend(instance.web.form.ReinitializeFieldMixin, { template: 'FieldChar', widget_class: 'oe_form_field_char', init: function (field_manager, node) { @@ -1928,7 +1928,7 @@ instance.web.form.FieldChar = instance.web.form.AbstractField.extend(_.extend({} focus: function() { this.delay_focus(this.$element.find('input:first')); } -})); +}); instance.web.form.FieldID = instance.web.form.FieldChar.extend({ @@ -1995,7 +1995,7 @@ instance.web.form.FieldFloat = instance.web.form.FieldChar.extend({ this._super(field_manager, node); this.set({'value': 0}); if (this.node.attrs.digits) { - this.digits = py.eval(node.attrs.digits); + this.digits = this.node.attrs.digits; } else { this.digits = this.field.digits; } @@ -2094,7 +2094,7 @@ instance.web.DateWidget = instance.web.DateTimeWidget.extend({ type_of_date: "date" }); -instance.web.form.FieldDatetime = instance.web.form.AbstractField.extend(_.extend({}, instance.web.form.ReinitializeFieldMixin, { +instance.web.form.FieldDatetime = instance.web.form.AbstractField.extend(instance.web.form.ReinitializeFieldMixin, { template: "FieldDatetime", build_widget: function() { return new instance.web.DateTimeWidget(this); @@ -2138,7 +2138,7 @@ instance.web.form.FieldDatetime = instance.web.form.AbstractField.extend(_.exten if (this.datewidget && this.datewidget.$input) this.delay_focus(this.datewidget.$input); } -})); +}); instance.web.form.FieldDate = instance.web.form.FieldDatetime.extend({ template: "FieldDate", @@ -2147,7 +2147,7 @@ instance.web.form.FieldDate = instance.web.form.FieldDatetime.extend({ } }); -instance.web.form.FieldText = instance.web.form.AbstractField.extend(_.extend({}, instance.web.form.ReinitializeFieldMixin, { +instance.web.form.FieldText = instance.web.form.AbstractField.extend(instance.web.form.ReinitializeFieldMixin, { template: 'FieldText', initialize_content: function() { this.$textarea = this.$element.find('textarea'); @@ -2207,7 +2207,7 @@ instance.web.form.FieldText = instance.web.form.AbstractField.extend(_.extend({} $div.remove(); $input.height(new_height); }, -})); +}); instance.web.form.FieldBoolean = instance.web.form.AbstractField.extend({ template: 'FieldBoolean', @@ -2256,7 +2256,7 @@ instance.web.form.FieldTextXml = instance.web.form.AbstractField.extend({ // to replace view editor }); -instance.web.form.FieldSelection = instance.web.form.AbstractField.extend(_.extend({}, instance.web.form.ReinitializeFieldMixin, { +instance.web.form.FieldSelection = instance.web.form.AbstractField.extend(instance.web.form.ReinitializeFieldMixin, { template: 'FieldSelection', init: function(field_manager, node) { var self = this; @@ -2324,7 +2324,7 @@ instance.web.form.FieldSelection = instance.web.form.AbstractField.extend(_.exte focus: function() { this.delay_focus(this.$element.find('select:first')); } -})); +}); // jquery autocomplete tweak to allow html (function() { @@ -2409,7 +2409,7 @@ instance.web.form.CompletionFieldMixin = { } // create... values.push({label: _t("<em> Create and Edit...</em>"), action: function() { - self._search_create_popup("form", undefined, {"default_name": search_val}); + self._search_create_popup("form", undefined, {}); }}); return values; @@ -2459,8 +2459,7 @@ instance.web.form.CompletionFieldMixin = { add_id: function(id) {}, }; -instance.web.form.FieldMany2One = instance.web.form.AbstractField.extend(_.extend({}, instance.web.form.ReinitializeFieldMixin, - instance.web.form.CompletionFieldMixin, { +instance.web.form.FieldMany2One = instance.web.form.AbstractField.extend(instance.web.form.CompletionFieldMixin, instance.web.form.ReinitializeFieldMixin, { template: "FieldMany2One", init: function(field_manager, node) { this._super(field_manager, node); @@ -2543,6 +2542,7 @@ instance.web.form.FieldMany2One = instance.web.form.AbstractField.extend(_.exten var tip_delay = 200; var tip_duration = 3000; var anyoneLoosesFocus = function() { + var used = false; if (self.floating) { if (self.last_search.length > 0) { if (self.last_search[0][0] != self.get("value")) { @@ -2550,13 +2550,17 @@ instance.web.form.FieldMany2One = instance.web.form.AbstractField.extend(_.exten self.display_value["" + self.last_search[0][0]] = self.last_search[0][1]; self.set({value: self.last_search[0][0]}); } else { + used = true; self.render_value(); } } else { + used = true; self.set({value: false}); + self.render_value(); } + self.floating = false; } - if (! self.get("value")) { + if (used) { tip_def.reject(); untip_def.reject(); tip_def = $.Deferred(); @@ -2603,7 +2607,8 @@ instance.web.form.FieldMany2One = instance.web.form.AbstractField.extend(_.exten e.preventDefault(); }, html: true, - close: anyoneLoosesFocus, + // disabled to solve a bug, but may cause others + //close: anyoneLoosesFocus, minLength: 0, delay: 0 }); @@ -2680,7 +2685,7 @@ instance.web.form.FieldMany2One = instance.web.form.AbstractField.extend(_.exten focus: function () { this.delay_focus(this.$input); } -})); +}); /* # Values: (0, 0, { fields }) create @@ -2781,9 +2786,11 @@ instance.web.form.FieldOne2Many = instance.web.form.AbstractField.extend({ var views = []; _.each(modes, function(mode) { if (! _.include(["list", "tree", "graph", "kanban"], mode)) { - instance.webclient.notification.warn( - _.str.sprintf("View type '%s' is not supported in One2Many.", mode)); - return; + try { + throw new Error(_.str.sprintf("View type '%s' is not supported in One2Many.", mode)); + } catch(e) { + instance.webclient.crashmanager.on_javascript_exception(e) + } } var view = { view_id: false, @@ -2795,9 +2802,11 @@ instance.web.form.FieldOne2Many = instance.web.form.AbstractField.extend({ } if(view.view_type === "list") { view.options.selectable = self.multi_selection; + view.options.sortable = false; if (self.get("effective_readonly")) { view.options.addable = null; view.options.deletable = null; + view.options.reorderable = false; } } else if (view.view_type === "form") { if (self.get("effective_readonly")) { @@ -2806,7 +2815,6 @@ instance.web.form.FieldOne2Many = instance.web.form.AbstractField.extend({ view.options.not_interactible_on_create = true; } else if (view.view_type === "kanban") { view.options.confirm_on_delete = false; - view.options.sortable = false; if (self.get("effective_readonly")) { view.options.action_buttons = false; view.options.quick_creatable = false; @@ -2819,6 +2827,7 @@ instance.web.form.FieldOne2Many = instance.web.form.AbstractField.extend({ this.views = views; this.viewmanager = new instance.web.form.One2ManyViewManager(this, this.dataset, views, {}); + this.viewmanager.$element.addClass("oe_view_manager_one2many"); this.viewmanager.o2m = self; var once = $.Deferred().then(function() { self.init_form_last_update.resolve(); @@ -3142,8 +3151,7 @@ instance.web.form.One2ManyKanbanView = instance.web_kanban.KanbanView.extend({ }); } -instance.web.form.FieldMany2ManyTags = instance.web.form.AbstractField.extend(_.extend({}, instance.web.form.CompletionFieldMixin, - instance.web.form.ReinitializeFieldMixin, { +instance.web.form.FieldMany2ManyTags = instance.web.form.AbstractField.extend(instance.web.form.CompletionFieldMixin, instance.web.form.ReinitializeFieldMixin, { template: "FieldMany2ManyTags", init: function() { this._super.apply(this, arguments); @@ -3267,7 +3275,7 @@ instance.web.form.FieldMany2ManyTags = instance.web.form.AbstractField.extend(_. add_id: function(id) { this.set({'value': _.uniq(this.get('value').concat([id]))}); }, -})); +}); /* * TODO niv: clean those deferred stuff, it could be better @@ -3328,6 +3336,7 @@ instance.web.form.FieldMany2Many = instance.web.form.AbstractField.extend({ 'deletable': self.get("effective_readonly") ? false : true, 'selectable': self.multi_selection, 'sortable': false, + 'reorderable': false, }); var embedded = (this.field.views || {}).tree; if (embedded) { @@ -3401,7 +3410,7 @@ instance.web.form.Many2ManyListView = instance.web.ListView.extend(/** @lends in } }); -instance.web.form.FieldMany2ManyKanban = instance.web.form.AbstractField.extend(_.extend({}, instance.web.form.CompletionFieldMixin, { +instance.web.form.FieldMany2ManyKanban = instance.web.form.AbstractField.extend(instance.web.form.CompletionFieldMixin, { disable_utility_classes: true, init: function(field_manager, node) { this._super(field_manager, node); @@ -3524,7 +3533,7 @@ instance.web.form.FieldMany2ManyKanban = instance.web.form.AbstractField.extend( add_id: function(id) { this.quick_create.add_id(id); }, -})); +}); function m2m_kanban_lazy_init() { if (instance.web.form.Many2ManyKanbanView) @@ -3877,7 +3886,7 @@ instance.web.form.SelectCreateListView = instance.web.ListView.extend({ } }); -instance.web.form.FieldReference = instance.web.form.AbstractField.extend(_.extend({}, instance.web.form.ReinitializeFieldMixin, { +instance.web.form.FieldReference = instance.web.form.AbstractField.extend(instance.web.form.ReinitializeFieldMixin, { template: 'FieldReference', init: function(field_manager, node) { this._super(field_manager, node); @@ -3969,9 +3978,9 @@ instance.web.form.FieldReference = instance.web.form.AbstractField.extend(_.exte } throw Exception("Should not happen"); }, -})); +}); -instance.web.form.FieldBinary = instance.web.form.AbstractField.extend(_.extend({}, instance.web.form.ReinitializeFieldMixin, { +instance.web.form.FieldBinary = instance.web.form.AbstractField.extend(instance.web.form.ReinitializeFieldMixin, { init: function(field_manager, node) { var self = this; this._super(field_manager, node); @@ -3988,7 +3997,7 @@ instance.web.form.FieldBinary = instance.web.form.AbstractField.extend(_.extend( }, initialize_content: function() { this.$element.find('input.oe-binary-file').change(this.on_file_change); - this.$element.find('button.oe-binary-file-save').click(this.on_save_as); + this.$element.find('button.oe_binary_file_save').click(this.on_save_as); this.$element.find('.oe-binary-file-clear').click(this.on_clear); }, human_filesize : function(size) { @@ -4018,6 +4027,7 @@ instance.web.form.FieldBinary = instance.web.form.AbstractField.extend(_.extend( // TODO: use openerp web crashmanager console.warn("Error while uploading file : ", name); } else { + this.filename = name; this.on_file_uploaded_and_valid.apply(this, arguments); } this.$element.find('.oe-binary-progress').hide(); @@ -4025,20 +4035,33 @@ instance.web.form.FieldBinary = instance.web.form.AbstractField.extend(_.extend( }, on_file_uploaded_and_valid: function(size, name, content_type, file_base64) { }, - on_save_as: function() { - $.blockUI(); - this.session.get_file({ - url: '/web/binary/saveas_ajax', - data: {data: JSON.stringify({ - model: this.view.dataset.model, - id: (this.view.datarecord.id || ''), - field: this.name, - filename_field: (this.node.attrs.filename || ''), - context: this.view.dataset.get_context() - })}, - complete: $.unblockUI, - error: instance.webclient.crashmanager.on_rpc_error - }); + on_save_as: function(ev) { + var value = this.get('value'); + if (!value) { + this.do_warn(_t("Save As..."), _t("The field is empty, there's nothing to save !")); + ev.stopPropagation(); + } else if (this._dirty_flag) { + var link = this.$('.oe_binary_file_save_data')[0]; + link.download = this.filename || "download.bin"; // Works on only on Google Chrome + //link.target = '_blank'; + link.href = "data:application/octet-stream;base64," + value; + } else { + $.blockUI(); + this.session.get_file({ + url: '/web/binary/saveas_ajax', + data: {data: JSON.stringify({ + model: this.view.dataset.model, + id: (this.view.datarecord.id || ''), + field: this.name, + filename_field: (this.node.attrs.filename || ''), + context: this.view.dataset.get_context() + })}, + complete: $.unblockUI, + error: instance.webclient.crashmanager.on_rpc_error + }); + ev.stopPropagation(); + return false; + } }, on_clear: function() { if (this.get('value') !== false) { @@ -4047,7 +4070,7 @@ instance.web.form.FieldBinary = instance.web.form.AbstractField.extend(_.extend( } return false; } -})); +}); instance.web.form.FieldBinaryFile = instance.web.form.FieldBinary.extend({ template: 'FieldBinaryFile', @@ -4260,7 +4283,7 @@ instance.web.form.FieldStatus = instance.web.form.AbstractField.extend({ /** * Registry of form fields, called by :js:`instance.web.FormView`. * - * All referenced classes must implement FieldMixin. Those represent the classes whose instances + * All referenced classes must implement FieldInterface. Those represent the classes whose instances * will substitute to the <field> tags as defined in OpenERP's views. */ instance.web.form.widgets = new instance.web.Registry({ diff --git a/addons/web/static/src/js/views.js b/addons/web/static/src/js/views.js index 4d677364e41..95b87e3cd86 100644 --- a/addons/web/static/src/js/views.js +++ b/addons/web/static/src/js/views.js @@ -77,7 +77,14 @@ instance.web.ActionManager = instance.web.Widget.extend({ }); } else if (state.client_action) { this.null_action(); - this.ir_actions_client(state.client_action); + var action = state.client_action; + if(_.isString(action)) { + action = { + tag: action, + params: state, + }; + } + this.ir_actions_client(action); } $.when(action_loaded || null).then(function() { @@ -150,6 +157,7 @@ instance.web.ActionManager = instance.web.Widget.extend({ this.inner_action = action; this.inner_viewmanager = new instance.web.ViewManagerAction(this, action); this.inner_viewmanager.appendTo(this.$element); + this.inner_viewmanager.$element.addClass("oe_view_manager_global"); } }, ir_actions_act_window_close: function (action, on_closed) { @@ -320,7 +328,7 @@ instance.web.ViewManager = instance.web.Widget.extend({ } this.$element - .find('.oe_view_manager_switch a').parent().removeClass('active') + .find('.oe_view_manager_switch a').parent().removeClass('active'); this.$element .find('.oe_view_manager_switch a').filter('[data-view-type="' + view_type + '"]') .parent().addClass('active'); @@ -329,9 +337,12 @@ instance.web.ViewManager = instance.web.Widget.extend({ _.each(_.keys(self.views), function(view_name) { var controller = self.views[view_name].controller; if (controller) { + var container = self.$element.find(".oe_view_manager_view_" + view_name + ":first"); if (view_name === view_type) { + container.show(); controller.do_show(view_options || {}); } else { + container.hide(); controller.do_hide(); } } @@ -728,14 +739,9 @@ instance.web.Sidebar = instance.web.Widget.extend({ var self = this; this._super(this); this.redraw(); - this.$element.on('click','.oe_dropdown_toggle',function(event) { - $(this).parent().find('ul').toggle(); - return false; - }); this.$element.on('click','.oe_dropdown_menu li a', function(event) { var section = $(this).data('section'); var index = $(this).data('index'); - $(this).closest('ul').hide(); var item = self.items[section][index]; if (item.callback) { item.callback.apply(self, [item]); @@ -744,13 +750,12 @@ instance.web.Sidebar = instance.web.Widget.extend({ } else if (item.url) { return true; } - return false; + event.preventDefault(); }); }, redraw: function() { var self = this; self.$element.html(QWeb.render('Sidebar', {widget: self})); - this.$element.find('ul').hide(); // Hides Sidebar sections when item list is empty this.$('.oe_form_dropdown_section').each(function() { |
