summaryrefslogtreecommitdiff
path: root/addons/web/static/src/js
diff options
context:
space:
mode:
authorVidhin Mehta (OpenERP) <vme@tinyerp.com>2012-06-22 14:36:14 +0530
committerVidhin Mehta (OpenERP) <vme@tinyerp.com>2012-06-22 14:36:14 +0530
commit790e3d6d9ecb604c5ea7560bbd2869b4b2843a9c (patch)
tree5b6304cdad43ff73ff5326b4331b5b984bdc60bc /addons/web/static/src/js
parent5053c1a66e78ba3e4ce51e9cd41c2d4c39d5136e (diff)
parent5006656a2832816b38790ab87b99969fedaed3c0 (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.js54
-rw-r--r--addons/web/static/src/js/coresetup.js177
-rw-r--r--addons/web/static/src/js/formats.js4
-rw-r--r--addons/web/static/src/js/view_form.js133
-rw-r--r--addons/web/static/src/js/views.js23
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() {