summaryrefslogtreecommitdiff
path: root/addons/web/static/src/js
diff options
context:
space:
mode:
authorSanjay Gohel (Open ERP) <sgo@tinyerp.com>2012-07-27 10:31:54 +0530
committerSanjay Gohel (Open ERP) <sgo@tinyerp.com>2012-07-27 10:31:54 +0530
commit8220b2edf94db13e85b9bb10dd95559be32fd22e (patch)
tree9f2bb2e6247c9cf16fa15ee011cf4877ba4dca40 /addons/web/static/src/js
parent730d5555f6b8766c0f5871d89b5eb8e14d74dfa5 (diff)
parent9128e37231194592b6468ffa7922bbb39b5d7a33 (diff)
[MERGE]merge with trunk
bzr revid: sgo@tinyerp.com-20120727050154-148msw0jzppgc66w
Diffstat (limited to 'addons/web/static/src/js')
-rw-r--r--addons/web/static/src/js/chrome.js81
-rw-r--r--addons/web/static/src/js/corelib.js12
-rw-r--r--addons/web/static/src/js/coresetup.js34
-rw-r--r--addons/web/static/src/js/data_export.js4
-rw-r--r--addons/web/static/src/js/search.js29
-rw-r--r--addons/web/static/src/js/view_form.js168
-rw-r--r--addons/web/static/src/js/view_list.js33
-rw-r--r--addons/web/static/src/js/view_list_editable.js188
-rw-r--r--addons/web/static/src/js/views.js83
9 files changed, 442 insertions, 190 deletions
diff --git a/addons/web/static/src/js/chrome.js b/addons/web/static/src/js/chrome.js
index 71010ef6d74..a1759397e21 100644
--- a/addons/web/static/src/js/chrome.js
+++ b/addons/web/static/src/js/chrome.js
@@ -257,7 +257,7 @@ instance.web.Loading = instance.web.Widget.extend({
// Block UI after 3s
this.long_running_timer = setTimeout(function () {
self.blocked_ui = true;
- $.blockUI();
+ instance.web.blockUI();
}, 3000);
}
@@ -276,7 +276,7 @@ instance.web.Loading = instance.web.Widget.extend({
// Don't unblock if blocked by somebody else
if (self.blocked_ui) {
this.blocked_ui = false;
- $.unblockUI();
+ instance.web.unblockUI();
}
this.$element.fadeOut();
this.getParent().$element.removeClass('oe_wait');
@@ -287,7 +287,7 @@ instance.web.Loading = instance.web.Widget.extend({
instance.web.DatabaseManager = instance.web.Widget.extend({
init: function(parent) {
this._super(parent);
- this.unblockUIFunction = $.unblockUI;
+ this.unblockUIFunction = instance.web.unblockUI;
$.validator.addMethod('matches', function (s, _, re) {
return new RegExp(re).test(s);
}, _t("Invalid database name"));
@@ -354,16 +354,16 @@ instance.web.DatabaseManager = instance.web.Widget.extend({
* from unblocking the UI
*/
blockUI: function () {
- $.blockUI();
- $.unblockUI = function () {};
+ instance.web.blockUI();
+ instance.web.unblockUI = function () {};
},
/**
* Reinstates $.unblockUI so third parties can play with blockUI, and
* unblocks the UI
*/
unblockUI: function () {
- $.unblockUI = this.unblockUIFunction;
- $.unblockUI();
+ instance.web.unblockUI = this.unblockUIFunction;
+ instance.web.unblockUI();
},
/**
* Displays an error dialog resulting from the various RPC communications
@@ -387,8 +387,16 @@ instance.web.DatabaseManager = instance.web.Widget.extend({
var fields = $(form).serializeArray();
self.rpc("/web/database/create", {'fields': fields}, function(result) {
var form_obj = self.to_object(fields);
- self.getParent().do_login( form_obj['db_name'], 'admin', form_obj['create_admin_pwd']);
- self.destroy();
+ var client_action = {
+ type: 'ir.actions.client',
+ tag: 'login',
+ params: {
+ 'db': form_obj['db_name'],
+ 'login': 'admin',
+ 'password': form_obj['create_admin_pwd'],
+ },
+ };
+ self.do_action(client_action);
});
},
@@ -473,19 +481,22 @@ instance.web.DatabaseManager = instance.web.Widget.extend({
});
},
do_exit: function () {
+ this.do_action("login");
}
});
+instance.web.client_actions.add("database_manager", "instance.web.DatabaseManager");
instance.web.Login = instance.web.Widget.extend({
template: "Login",
remember_credentials: true,
_db_list: null,
- init: function(parent) {
+ init: function(parent, params) {
this._super(parent);
this.has_local_storage = typeof(localStorage) != 'undefined';
this.selected_db = null;
this.selected_login = null;
+ this.params = params;
if (this.has_local_storage && this.remember_credentials) {
this.selected_db = localStorage.getItem('last_db_login_success');
@@ -495,26 +506,17 @@ instance.web.Login = instance.web.Widget.extend({
}
}
},
- open_db_manager: function(){
- var self = this;
- self.$element.find('.oe_login_bottom').hide();
- self.$element.find('.oe_login_pane').hide();
- self.databasemanager = new instance.web.DatabaseManager(self);
- self.databasemanager.appendTo(self.$element);
- self.databasemanager.do_exit.add_last(function() {
- self.databasemanager.destroy();
- self.$element.find('.oe_login_bottom').show();
- self.$element.find('.oe_login_pane').show();
- self.load_db_list(true).then(self.on_db_list_loaded);
- });
- },
start: function() {
var self = this;
self.$element.find("form").submit(self.on_submit);
self.$element.find('.oe_login_manage_db').click(function() {
- self.open_db_manager();
+ self.do_action("database_manager");
+ });
+ return self.load_db_list().then(self.on_db_list_loaded).then(function() {
+ if(self.params) {
+ self.do_login(self.params.db, self.params.login, self.params.password);
+ }
});
- return self.load_db_list().then(self.on_db_list_loaded);
},
load_db_list: function (force) {
var d = $.when(), self = this;
@@ -535,7 +537,7 @@ instance.web.Login = instance.web.Widget.extend({
var dbdiv = this.$element.find('div.oe_login_dbpane');
this.$element.find("[name=db]").replaceWith(instance.web.qweb.render('Login.dblist', { db_list: list, selected_db: this.selected_db}));
if(list.length === 0) {
- self.open_db_manager();
+ this.do_action("database_manager");
} else if(list && list.length === 1) {
dbdiv.hide();
} else {
@@ -582,13 +584,14 @@ instance.web.Login = instance.web.Widget.extend({
localStorage.setItem('last_password_login_success', '');
}
}
- self.trigger("login");
+ self.trigger('login_successful');
},function () {
self.$(".oe_login_pane").fadeIn("fast");
self.$element.addClass("oe_login_invalid");
});
}
});
+instance.web.client_actions.add("login", "instance.web.Login");
instance.web.Menu = instance.web.Widget.extend({
template: 'Menu',
@@ -864,7 +867,7 @@ instance.web.UserMenu = instance.web.Widget.extend({
window.location.href, 'debug');
});
instance.web.dialog($help, {autoOpen: true,
- modal: true, width: 960, title: _t("About")});
+ modal: true, width: 580, height: 290, resizable: false, title: _t("About")});
});
},
});
@@ -893,7 +896,7 @@ instance.web.Client = instance.web.Widget.extend({
this.$element.on('click', '.oe_dropdown_toggle', function(ev) {
ev.preventDefault();
var $toggle = $(this);
- var $menu = $toggle.find('.oe_dropdown_menu');
+ var $menu = $toggle.parent().find('.oe_dropdown_menu');
var state = $menu.is('.oe_opened');
setTimeout(function() {
// Do not alter propagation
@@ -903,7 +906,7 @@ instance.web.Client = instance.web.Widget.extend({
var doc_width = $(document).width();
var offset = $menu.offset();
var menu_width = $menu.width();
- var x = doc_width - offset.left - menu_width - 15;
+ var x = doc_width - offset.left - menu_width - 2;
if (x < 0) {
$menu.offset({ left: offset.left + x }).width(menu_width);
}
@@ -964,19 +967,15 @@ instance.web.WebClient = instance.web.Client.extend({
data: {debug: file + ':' + line}
});
};
- // TODO: deprecate and use login client action
- self.login = new instance.web.Login(self);
- self.login.on("login",self,self.show_application);
},
show_login: function() {
- var self = this;
- self.$('.oe_topbar').hide();
- self.login.appendTo(self.$element);
+ this.$('.oe_topbar').hide();
+ this.action_manager.do_action("login");
+ this.action_manager.inner_widget.on('login_successful', this, this.show_application);
},
show_application: function() {
var self = this;
self.$('.oe_topbar').show();
- self.login.$element.hide();
self.menu = new instance.web.Menu(self);
self.menu.replace(this.$element.find('.oe_menu_placeholder'));
self.menu.on('menu_click', this, this.on_menu_action);
@@ -1057,6 +1056,7 @@ instance.web.WebClient = instance.web.Client.extend({
},
do_push_state: function(state) {
this.set_title(state.title);
+ delete state.title;
var url = '#' + $.param(state);
this._current_state = _.clone(state);
$.bbq.pushState(url);
@@ -1083,10 +1083,13 @@ instance.web.WebClient = instance.web.Client.extend({
}
},
set_content_full_screen: function(fullscreen) {
- if (fullscreen)
+ if (fullscreen) {
$(".oe_webclient", this.$element).addClass("oe_content_full_screen");
- else
+ $("body").css({'overflow-y':'hidden'});
+ } else {
$(".oe_webclient", this.$element).removeClass("oe_content_full_screen");
+ $("body").css({'overflow-y':'scroll'});
+ }
}
});
diff --git a/addons/web/static/src/js/corelib.js b/addons/web/static/src/js/corelib.js
index 1ed4c4788e3..a092b670ef1 100644
--- a/addons/web/static/src/js/corelib.js
+++ b/addons/web/static/src/js/corelib.js
@@ -378,7 +378,8 @@ instance.web.PropertiesMixin = _.extend({}, instance.web.EventDispatcherMixin, {
instance.web.EventDispatcherMixin.init.call(this);
this.__getterSetterInternalMap = {};
},
- set: function(map) {
+ set: function(map, options) {
+ options = options || {};
var self = this;
var changed = false;
_.each(map, function(val, key) {
@@ -387,10 +388,11 @@ instance.web.PropertiesMixin = _.extend({}, instance.web.EventDispatcherMixin, {
return;
changed = true;
self.__getterSetterInternalMap[key] = val;
- self.trigger("change:" + key, self, {
- oldValue: tmp,
- newValue: val
- });
+ if (! options.silent)
+ self.trigger("change:" + key, self, {
+ oldValue: tmp,
+ newValue: val
+ });
});
if (changed)
self.trigger("change", self);
diff --git a/addons/web/static/src/js/coresetup.js b/addons/web/static/src/js/coresetup.js
index a5a62b9bcc1..24441dc509f 100644
--- a/addons/web/static/src/js/coresetup.js
+++ b/addons/web/static/src/js/coresetup.js
@@ -550,7 +550,39 @@ $.async_when = function() {
/** Setup blockui */
if ($.blockUI) {
$.blockUI.defaults.baseZ = 1100;
- $.blockUI.defaults.message = '<img src="/web/static/src/img/throbber2.gif">';
+ $.blockUI.defaults.message = '<div class="oe_blockui_spin" style="height: 50px">';
+ $.blockUI.defaults.css.border = '0';
+ $.blockUI.defaults.css["background-color"] = '';
+ $.blockUI.spinners = [];
+}
+instance.web.blockUI = function() {
+ var tmp = $.blockUI.apply($, arguments);
+ var target = $(".oe_blockui_spin")[0];
+ var opts = {
+ lines: 13, // The number of lines to draw
+ length: 7, // The length of each line
+ width: 4, // The line thickness
+ radius: 10, // The radius of the inner circle
+ rotate: 0, // The rotation offset
+ color: '#FFF', // #rgb or #rrggbb
+ speed: 1, // Rounds per second
+ trail: 60, // Afterglow percentage
+ shadow: false, // Whether to render a shadow
+ hwaccel: false, // Whether to use hardware acceleration
+ className: 'spinner', // The CSS class to assign to the spinner
+ zIndex: 2e9, // The z-index (defaults to 2000000000)
+ top: 'auto', // Top position relative to parent in px
+ left: 'auto' // Left position relative to parent in px
+ };
+ var spinner = new Spinner(opts).spin(target);
+ $.blockUI.spinners.push(spinner);
+ return tmp;
+}
+instance.web.unblockUI = function() {
+ _.each($.blockUI.spinners, function(el) {
+ el.stop();
+ });
+ return $.unblockUI.apply($, arguments);
}
/** Setup default session */
diff --git a/addons/web/static/src/js/data_export.js b/addons/web/static/src/js/data_export.js
index ebe82ddb4b4..f8e669e1b4a 100644
--- a/addons/web/static/src/js/data_export.js
+++ b/addons/web/static/src/js/data_export.js
@@ -376,7 +376,7 @@ instance.web.DataExport = instance.web.Dialog.extend({
exported_fields.unshift({name: 'id', label: 'External ID'});
var export_format = this.$element.find("#export_format").val();
- $.blockUI();
+ instance.web.blockUI();
this.session.get_file({
url: '/web/export/' + export_format,
data: {data: JSON.stringify({
@@ -387,7 +387,7 @@ instance.web.DataExport = instance.web.Dialog.extend({
import_compat: Boolean(
this.$element.find("#import_compat").val())
})},
- complete: $.unblockUI
+ complete: instance.web.unblockUI
});
},
close: function() {
diff --git a/addons/web/static/src/js/search.js b/addons/web/static/src/js/search.js
index 504510ef133..c3e7ad72dcb 100644
--- a/addons/web/static/src/js/search.js
+++ b/addons/web/static/src/js/search.js
@@ -330,6 +330,12 @@ instance.web.SearchView = instance.web.Widget.extend(/** @lends instance.web.Sea
});
}
+ // Launch a search on clicking the oe_searchview_search button
+ this.$element.on('click', 'button.oe_searchview_search', function (e) {
+ e.stopImmediatePropagation();
+ self.do_search();
+ });
+
this.$element.on('keydown',
'.oe_searchview_input, .oe_searchview_facet', function (e) {
switch(e.which) {
@@ -510,7 +516,16 @@ instance.web.SearchView = instance.web.Widget.extend(/** @lends instance.web.Sea
this.$element.addClass('oe_focused');
},
childBlurred: function () {
- this.$element.removeClass('oe_focused');
+ var val = this.$element.val();
+ this.$element.val('');
+ var complete = this.$element.data('autocomplete');
+ if ((val && complete.term === undefined) || complete.previous !== undefined) {
+ throw new Error("new jquery.ui version altering implementation" +
+ " details relied on");
+ }
+ delete complete.term;
+ this.$element.removeClass('oe_focused')
+ .trigger('blur');
},
/**
*
@@ -1475,7 +1490,17 @@ instance.web.search.ManyToOneField = instance.web.search.CharField.extend({
facet_for: function (value) {
var self = this;
if (value instanceof Array) {
- return $.when(facet_from(this, value));
+ if (value.length === 2 && _.isString(value[1])) {
+ return $.when(facet_from(this, value));
+ }
+ if (value.length > 1) {
+ // more than one search_default m2o id? Should we OR them?
+ throw new Error(
+ _("M2O search fields do not currently handle multiple default values"));
+ }
+ // there are many cases of {search_default_$m2ofield: [id]}, need
+ // to handle this as if it were a single value.
+ value = value[0];
}
return this.model.call('name_get', [value], {}).pipe(function (names) {
if (_(names).isEmpty()) { return null; }
diff --git a/addons/web/static/src/js/view_form.js b/addons/web/static/src/js/view_form.js
index 070ada62cc4..df7cd081338 100644
--- a/addons/web/static/src/js/view_form.js
+++ b/addons/web/static/src/js/view_form.js
@@ -33,6 +33,11 @@ instance.web.form.FieldManagerMixin = {
};
instance.web.views.add('form', 'instance.web.FormView');
+/**
+ * Properties:
+ * - actual_mode: always "view", "edit" or "create". Read-only property. Determines
+ * the mode used by the view.
+ */
instance.web.FormView = instance.web.View.extend(instance.web.form.FieldManagerMixin, {
/**
* Indicates that this view is not searchable, and thus that no search
@@ -55,6 +60,7 @@ instance.web.FormView = instance.web.View.extend(instance.web.form.FieldManagerM
* @property {instance.web.Registry} registry=instance.web.form.widgets widgets registry for this form view instance
*/
init: function(parent, dataset, view_id, options) {
+ var self = this;
this._super(parent);
this.set_default_options(options);
this.dataset = dataset;
@@ -82,6 +88,13 @@ instance.web.FormView = instance.web.View.extend(instance.web.form.FieldManagerM
this.__blur_timeout = null;
this.rendering_engine = new instance.web.form.FormRenderingEngine(this);
this.qweb = null; // A QWeb instance will be created if the view is a QWeb template
+ self.set({actual_mode: self.options.initial_mode});
+ this.has_been_loaded.then(function() {
+ self.on("change:actual_mode", self, self.check_actual_mode);
+ self.check_actual_mode();
+ self.on("change:actual_mode", self, self.init_pager);
+ self.init_pager();
+ });
},
destroy: function() {
_.each(this.get_widgets(), function(w) {
@@ -125,17 +138,6 @@ instance.web.FormView = instance.web.View.extend(instance.web.form.FieldManagerM
this.$buttons.on('click','.oe_form_button_save',this.on_button_save);
this.$buttons.on('click','.oe_form_button_cancel',this.on_button_cancel);
- this.$pager = $(QWeb.render("FormView.pager", {'widget':self}));
- if (this.options.$pager) {
- this.$pager.appendTo(this.options.$pager);
- } else {
- this.$element.find('.oe_form_pager').replaceWith(this.$pager);
- }
- this.$pager.on('click','a[data-pager-action]',function() {
- var action = $(this).data('pager-action');
- self.on_pager_action(action);
- });
-
this.$sidebar = this.options.$sidebar || this.$element.find('.oe_form_sidebar');
if (!this.sidebar && this.options.$sidebar) {
this.sidebar = new instance.web.Sidebar(this);
@@ -149,8 +151,15 @@ instance.web.FormView = instance.web.View.extend(instance.web.form.FieldManagerM
{ label: _t('Set Default'), callback: function (item) { self.open_defaults_dialog(); } },
]);
}
- this.on("change:mode", this, this.switch_mode);
- this.set({mode: this.options.initial_mode});
+
+ // Add bounce effect on button 'Edit' when click on readonly page view.
+ this.$element.find(".oe_form_field, .oe_form_group_cell").on('click', function (e) {
+ if(self.get("actual_mode") == "view") {
+ var $button = self.options.$buttons.find(".oe_form_button_edit");
+ $button.wrap('<div>').css('margin-right','4px').addClass('oe_left oe_bounce');
+ }
+ });
+
this.has_been_loaded.resolve();
return $.when();
},
@@ -275,7 +284,7 @@ instance.web.FormView = instance.web.View.extend(instance.web.form.FieldManagerM
}
return shown.pipe(function() {
if (options.editable) {
- self.set({mode: "edit"});
+ self.to_edit_mode();
}
self.$element.css('visibility', 'visible');
});
@@ -300,6 +309,7 @@ instance.web.FormView = instance.web.View.extend(instance.web.form.FieldManagerM
return $.Deferred().reject();
}
this.datarecord = record;
+ this._actualize_mode();
this.set({ 'title' : record.id ? record.name : "New record" });
if (this.qweb) {
@@ -377,6 +387,24 @@ instance.web.FormView = instance.web.View.extend(instance.web.form.FieldManagerM
this.reload();
}
},
+ init_pager: function() {
+ var self = this;
+ if (this.$pager)
+ this.$pager.remove();
+ if (this.get("actual_mode") === "create")
+ return;
+ this.$pager = $(QWeb.render("FormView.pager", {'widget':self}));
+ if (this.options.$pager) {
+ this.$pager.appendTo(this.options.$pager);
+ } else {
+ this.$element.find('.oe_form_pager').replaceWith(this.$pager);
+ }
+ this.$pager.on('click','a[data-pager-action]',function() {
+ var action = $(this).data('pager-action');
+ self.on_pager_action(action);
+ });
+ this.do_update_pager();
+ },
do_update_pager: function(hide_index) {
var index = hide_index ? '-' : this.dataset.index + 1;
this.$pager.find('button').prop('disabled', this.dataset.ids.length < 2).end()
@@ -576,9 +604,32 @@ instance.web.FormView = instance.web.View.extend(instance.web.form.FieldManagerM
return $.Deferred().reject();
}
},
- switch_mode: function() {
+ /**
+ * Ask the view to switch to view mode if possible. The view may not do it
+ * if the current record is not yet saved. It will then stay in create mode.
+ */
+ to_view_mode: function() {
+ this._actualize_mode("view");
+ },
+ /**
+ * Ask the view to switch to edit mode if possible. The view may not do it
+ * if the current record is not yet saved. It will then stay in create mode.
+ */
+ to_edit_mode: function() {
+ this._actualize_mode("edit");
+ },
+ /**
+ * Reactualize actual_mode.
+ */
+ _actualize_mode: function(switch_to) {
+ var mode = switch_to || this.get("actual_mode");
+ if (! this.datarecord.id)
+ mode = "create";
+ this.set({actual_mode: mode});
+ },
+ check_actual_mode: function(source, options) {
var self = this;
- if(this.get("mode") == "view") {
+ if(this.get("actual_mode") === "view") {
self.$element.removeClass('oe_form_editable').addClass('oe_form_readonly');
self.$buttons.find('.oe_form_buttons_edit').hide();
self.$buttons.find('.oe_form_buttons_view').show();
@@ -596,11 +647,12 @@ instance.web.FormView = instance.web.View.extend(instance.web.form.FieldManagerM
});
var fields_order = self.fields_order.slice(0);
if (self.default_focus_field) {
- fields_order.unshift(self.default_focus_field);
+ fields_order.unshift(self.default_focus_field.name);
}
for (var i = 0; i < fields_order.length; i += 1) {
var field = self.fields[fields_order[i]];
- if (!field.get('effective_invisible') && !field.get('effective_readonly') && field.focus() !== false) {
+ if (!field.get('effective_invisible') && !field.get('effective_readonly')) {
+ field.focus();
break;
}
}
@@ -609,19 +661,19 @@ instance.web.FormView = instance.web.View.extend(instance.web.form.FieldManagerM
on_button_save: function() {
var self = this;
return this.do_save().then(function(result) {
- self.set({mode: "view"});
+ self.to_view_mode();
});
},
on_button_cancel: function(event) {
if (this.can_be_discarded()) {
- this.set({mode: "view"});
+ this.to_view_mode();
this.on_record_loaded(this.datarecord);
}
return false;
},
on_button_new: function() {
var self = this;
- this.set({mode: "edit"});
+ this.to_edit_mode();
return $.when(this.has_been_loaded).pipe(function() {
if (self.can_be_discarded()) {
return self.load_defaults();
@@ -629,7 +681,7 @@ instance.web.FormView = instance.web.View.extend(instance.web.form.FieldManagerM
});
},
on_button_edit: function() {
- return this.set({mode: "edit"});
+ return this.to_edit_mode();
},
on_button_create: function() {
this.dataset.index = null;
@@ -642,7 +694,7 @@ instance.web.FormView = instance.web.View.extend(instance.web.form.FieldManagerM
self.dataset.call('copy', [self.datarecord.id, {}, self.dataset.context]).then(function(new_id) {
return self.on_created({ result : new_id });
}).then(function() {
- return self.set({mode: "edit"});
+ return self.to_edit_mode();
}).then(function() {
def.resolve();
});
@@ -935,7 +987,7 @@ instance.web.FormView = instance.web.View.extend(instance.web.form.FieldManagerM
register_field: function(field, name) {
this.fields[name] = field;
this.fields_order.push(name);
- if (field.node.attrs.default_focus == '1') {
+ if (JSON.parse(field.node.attrs.default_focus || "0")) {
this.default_focus_field = field;
}
@@ -957,7 +1009,7 @@ instance.web.FormView = instance.web.View.extend(instance.web.form.FieldManagerM
return this.fields_view.fields[field_name];
},
is_create_mode: function() {
- return !this.datarecord.id;
+ return this.get("actual_mode") === "create";
},
open_translate_dialog: function(field) {
return this._super(field);
@@ -1641,10 +1693,13 @@ instance.web.form.WidgetButton = instance.web.form.FormWidget.extend({
this._super(view, node);
this.force_disabled = false;
this.string = (this.node.attrs.string || '').replace(/_/g, '');
- if (this.node.attrs.default_focus == '1') {
+ if (JSON.parse(this.node.attrs.default_focus || "0")) {
// TODO fme: provide enter key binding to widgets
this.view.default_focus_button = this;
}
+ if (this.node.attrs.icon && (! /\//.test(this.node.attrs.icon))) {
+ this.node.attrs.icon = '/web/static/src/img/icons/' + this.node.attrs.icon + '.png';
+ }
this.view.on('view_content_has_changed', this, this.check_disable);
},
start: function() {
@@ -2818,10 +2873,11 @@ instance.web.form.FieldMany2One = instance.web.form.AbstractField.extend(instanc
if (follow)
link += "<br />";
}
- this.$element.find('a')
+ var $link = this.$element.find('.oe_form_uri')
.unbind('click')
- .html(link)
- .click(function () {
+ .html(link);
+ if (! this.get_definition_options().no_open)
+ $link.click(function () {
self.do_action({
type: 'ir.actions.act_window',
res_model: self.field.relation,
@@ -2979,6 +3035,7 @@ instance.web.form.FieldOne2Many = instance.web.form.AbstractField.extend({
}
if(view.view_type === "list") {
_.extend(view.options, {
+ addable: null,
selectable: self.multi_selection,
sortable: false,
import_enabled: false,
@@ -2986,7 +3043,6 @@ instance.web.form.FieldOne2Many = instance.web.form.AbstractField.extend({
});
if (self.get("effective_readonly")) {
_.extend(view.options, {
- addable: null,
deletable: null,
reorderable: false,
});
@@ -3027,8 +3083,11 @@ instance.web.form.FieldOne2Many = instance.web.form.AbstractField.extend({
this.viewmanager.on_controller_inited.add_last(function(view_type, controller) {
controller.o2m = self;
if (view_type == "list") {
- if (self.get("effective_readonly"))
- controller.set_editable(false);
+ if (self.get("effective_readonly")) {
+ controller.on('edit:before', self, function (e) {
+ e.cancel = true;
+ });
+ }
} else if (view_type === "form") {
if (self.get("effective_readonly")) {
$(".oe_form_buttons", controller.$element).children().remove();
@@ -3301,7 +3360,7 @@ instance.web.form.One2ManyListView = instance.web.ListView.extend({
.value();
},
do_add_record: function () {
- if (this.options.editable) {
+ if (this.editable()) {
this._super.apply(this, arguments);
} else {
var self = this;
@@ -3408,6 +3467,34 @@ instance.web.form.One2ManyListView = instance.web.ListView.extend({
this._super.apply(this, arguments);
}
});
+instance.web.form.One2ManyList = instance.web.ListView.List.extend({
+ pad_table_to: function (count) {
+ this._super(count > 0 ? count - 1 : 0);
+
+ // magical invocation of wtf does that do
+ if (this.view.o2m.get('effective_readonly')) {
+ return;
+ }
+
+ var self = this;
+ var columns = _(this.columns).filter(function (column) {
+ return column.invisible !== '1';
+ }).length;
+ if (this.options.selectable) { columns++; }
+ if (this.options.deletable) { columns++; }
+ var $cell = $('<td>', {
+ colspan: columns,
+ 'class': 'oe_form_field_one2many_list_row_add'
+ }).text(_t("Add a row"))
+ .click(function (e) {
+ e.preventDefault();
+ e.stopPropagation();
+ self.view.do_add_record();
+ });
+ this.$current.append(
+ $('<tr>').append($cell))
+ }
+});
instance.web.form.One2ManyFormView = instance.web.FormView.extend({
form_template: 'One2Many.formview',
@@ -3535,12 +3622,13 @@ instance.web.form.FieldMany2ManyTags = instance.web.form.AbstractField.extend(in
render_value: function() {
var self = this;
var dataset = new instance.web.DataSetStatic(this, this.field.relation, self.view.dataset.get_context());
+ var values = self.get("value")
var handle_names = function(data) {
var indexed = {};
_.each(data, function(el) {
indexed[el[0]] = el;
});
- data = _.map(self.get("value"), function(el) { return indexed[el]; });
+ data = _.map(values, function(el) { return indexed[el]; });
if (! self.get("effective_readonly")) {
self.tags.containerElement().children().remove();
$("textarea", self.$element).css("padding-left", "3px");
@@ -3549,8 +3637,8 @@ instance.web.form.FieldMany2ManyTags = instance.web.form.AbstractField.extend(in
self.$element.html(QWeb.render("FieldMany2ManyTag", {elements: data}));
}
};
- if (! self.get('values') || self.get('values').length > 0) {
- this._display_orderer.add(dataset.name_get(self.get("value"))).then(handle_names);
+ if (! values || values.length > 0) {
+ this._display_orderer.add(dataset.name_get(values)).then(handle_names);
} else {
handle_names([]);
}
@@ -4108,10 +4196,12 @@ instance.web.form.SelectCreatePopup = instance.web.form.AbstractFormPopup.extend
self.dataset, false,
_.extend({'deletable': false,
'selectable': !self.options.disable_multiple_selection,
- 'read_only': true,
'import_enabled': false,
'$buttons': self.$buttonpane,
}, self.options.list_view_options || {}));
+ self.view_list.on('edit:before', self, function (e) {
+ e.cancel = true;
+ });
self.view_list.popup = self;
self.view_list.appendTo($(".oe_popup_list", self.$element)).pipe(function() {
self.view_list.do_show();
@@ -4343,7 +4433,7 @@ instance.web.form.FieldBinary = instance.web.form.AbstractField.extend(instance.
//link.target = '_blank';
link.href = "data:application/octet-stream;base64," + value;
} else {
- $.blockUI();
+ instance.web.blockUI();
this.session.get_file({
url: '/web/binary/saveas_ajax',
data: {data: JSON.stringify({
@@ -4353,7 +4443,7 @@ instance.web.form.FieldBinary = instance.web.form.AbstractField.extend(instance.
filename_field: (this.node.attrs.filename || ''),
context: this.view.dataset.get_context()
})},
- complete: $.unblockUI,
+ complete: instance.web.unblockUI,
error: instance.webclient.crashmanager.on_rpc_error
});
ev.stopPropagation();
diff --git a/addons/web/static/src/js/view_list.js b/addons/web/static/src/js/view_list.js
index f68f1354099..9c7bf88db1a 100644
--- a/addons/web/static/src/js/view_list.js
+++ b/addons/web/static/src/js/view_list.js
@@ -21,9 +21,6 @@ instance.web.ListView = instance.web.View.extend( /** @lends instance.web.ListVi
// whether the view rows can be reordered (via vertical drag & drop)
'reorderable': true,
'action_buttons': true,
- // if true, the view can't be editable, ignoring the view's and the context's
- // instructions
- 'read_only': false,
// if true, the 'Import', 'Export', etc... buttons will be shown
'import_enabled': true,
},
@@ -360,6 +357,7 @@ instance.web.ListView = instance.web.View.extend( /** @lends instance.web.ListVi
{ label: _t('Delete'), callback: this.do_delete_selected },
]);
this.sidebar.add_toolbar(this.fields_view.toolbar);
+ this.sidebar.$element.hide();
}
},
/**
@@ -378,6 +376,7 @@ instance.web.ListView = instance.web.View.extend( /** @lends instance.web.ListVi
var total = dataset.size();
var limit = this.limit() || total;
+ this.$pager.toggle(total !== 0);
this.$pager.toggleClass('oe_list_pager_single_page', (total <= limit));
var spager = '-';
if (total) {
@@ -496,9 +495,6 @@ instance.web.ListView = instance.web.View.extend( /** @lends instance.web.ListVi
},
do_show: function () {
this._super();
- if (this.sidebar) {
- this.sidebar.$element.show();
- }
if (this.$buttons) {
this.$buttons.show();
}
@@ -937,7 +933,6 @@ instance.web.ListView.List = instance.web.Class.extend( /** @lends instance.web.
'[data-id=' + record.get('id') + ']');
var index = $row.data('index');
$row.remove();
- self.refresh_zebra(index);
},
'reset': function () { return self.on_records_reset(); },
'change': function (event, record, attribute, value, old_value) {
@@ -972,8 +967,6 @@ instance.web.ListView.List = instance.web.Class.extend( /** @lends instance.web.
'[data-id=' + previous_record.get('id') + ']');
$new_row.insertAfter($previous_sibling);
}
-
- self.refresh_zebra(index, 1);
}
};
_(this.record_callbacks).each(function (callback, event) {
@@ -1113,7 +1106,6 @@ instance.web.ListView.List = instance.web.Class.extend( /** @lends instance.web.
this.$current
.children('tr:not([data-id])').remove().end()
.append(new Array(count - this.records.length + 1).join(row));
- this.refresh_zebra(this.records.length);
},
/**
* Gets the ids of all currently selected records, if any
@@ -1187,25 +1179,6 @@ instance.web.ListView.List = instance.web.Class.extend( /** @lends instance.web.
render_cell: function () {
return self.render_cell.apply(self, arguments); }
});
- },
- /**
- * Fixes fixes the even/odd classes
- *
- * @param {Number} [from_index] index from which to resequence
- * @param {Number} [offset = 0] selection offset for DOM, in case there are rows to ignore in the table
- */
- refresh_zebra: function (from_index, offset) {
- offset = offset || 0;
- from_index = from_index || 0;
- var dom_offset = offset + from_index;
- var sel = dom_offset ? ':gt(' + (dom_offset - 1) + ')' : null;
- this.$current.children(sel).each(function (i, e) {
- var index = from_index + i;
- // reset record-index accelerators on rows and even/odd
- var even = index%2 === 0;
- $(e).toggleClass('even', even)
- .toggleClass('odd', !even);
- });
}
});
instance.web.ListView.Groups = instance.web.Class.extend( /** @lends instance.web.ListView.Groups# */{
@@ -1538,8 +1511,6 @@ instance.web.ListView.Groups = instance.web.Class.extend( /** @lends instance.we
}(dataset, record.get('id'), seq));
record.set('sequence', seq);
}
-
- list.refresh_zebra();
}
});
},
diff --git a/addons/web/static/src/js/view_list_editable.js b/addons/web/static/src/js/view_list_editable.js
index 56df125c98b..ca889f68d8d 100644
--- a/addons/web/static/src/js/view_list_editable.js
+++ b/addons/web/static/src/js/view_list_editable.js
@@ -12,6 +12,8 @@ openerp.web.list_editable = function (instance) {
var self = this;
this._super.apply(this, arguments);
+ this._force_editability = null;
+ this._context_editable = false;
this.editor = this.make_editor();
// Stores records of {field, cell}, allows for re-rendering fields
// depending on cell state during and after resize events
@@ -37,6 +39,11 @@ openerp.web.list_editable = function (instance) {
}
});
+ this.on('edit:before', this, function (event) {
+ if (!self.editable() || self.editor.is_editing()) {
+ event.cancel = true;
+ }
+ });
this.on('edit:after', this, function () {
self.$element.add(self.$buttons).addClass('oe_editing');
});
@@ -62,26 +69,16 @@ openerp.web.list_editable = function (instance) {
do_edit: function (index, id, dataset) {
_.extend(this.dataset, dataset);
},
- /**
- * Sets editability status for the list, based on defaults, view
- * architecture and the provided flag, if any.
- *
- * @param {Boolean} [force] forces the list to editability. Sets new row edition status to "bottom".
- */
- set_editable: function (force) {
- // TODO: fix handling of editability status to be simpler & clearer & more coherent
- // If ``force``, set editability to bottom
- // otherwise rely on view default
- // view' @editable is handled separately as we have not yet
- // fetched and processed the view at this point.
- this.options.editable = (
- ! this.options.read_only && ((force && "bottom") || this.defaults.editable));
+ editable: function () {
+ return this.fields_view.arch.attrs.editable
+ || this._context_editable
+ || this.options.editable;
},
/**
* Replace do_search to handle editability process
*/
do_search: function(domain, context, group_by) {
- this.set_editable(context['set_editable']);
+ this._context_editable = !!context.set_editable;
this._super.apply(this, arguments);
},
/**
@@ -89,7 +86,7 @@ openerp.web.list_editable = function (instance) {
* as an editable row at the top or bottom of the list)
*/
do_add_record: function () {
- if (this.options.editable) {
+ if (this.editable()) {
this.$element.find('table:first').show();
this.$element.find('.oe_view_nocontent').remove();
this.start_edition();
@@ -103,9 +100,8 @@ openerp.web.list_editable = function (instance) {
this.editor.destroy();
}
// tree/@editable takes priority on everything else if present.
- this.options.editable = ! this.options.read_only && (data.arch.attrs.editable || this.options.editable);
var result = this._super(data, grouped);
- if (this.options.editable) {
+ if (this.editable()) {
// FIXME: any hook available to ensure this is only done once?
this.$buttons
.off('click', '.oe_list_save')
@@ -202,12 +198,20 @@ openerp.web.list_editable = function (instance) {
return;
}
+ // FIXME: need better way to get the field back from bubbling (delegated) DOM events somehow
+ field.$element.attr('data-fieldname', field_name);
self.fields_for_resize.push({field: field, cell: cell});
}, options).pipe(function () {
$recordRow.addClass('oe_edition');
self.resize_fields();
return record.attributes;
});
+ }).fail(function () {
+ // if the start_edition event is cancelled and it was a
+ // creation, remove the newly-created empty record
+ if (!record.get('id')) {
+ self.records.remove(record);
+ }
});
});
},
@@ -377,7 +381,7 @@ openerp.web.list_editable = function (instance) {
return this.reload_record(record);
},
prepends_on_create: function () {
- return this.options.editable === 'top';
+ return this.editable() === 'top';
},
setup_events: function () {
var self = this;
@@ -399,18 +403,20 @@ openerp.web.list_editable = function (instance) {
*
* @private
* @param {String} [next_record='succ'] method to call on the records collection to get the next record to edit
+ * @param {Object} [options]
+ * @param {String} [options.focus_field]
* @return {*}
*/
- _next: function (next_record) {
+ _next: function (next_record, options) {
next_record = next_record || 'succ';
var self = this;
return this.save_edition().pipe(function (saveInfo) {
if (saveInfo.created) {
return self.start_edition();
}
- return self.start_edition(
- self.records[next_record](
- saveInfo.record, {wraparound: true}));
+ var record = self.records[next_record](
+ saveInfo.record, {wraparound: true});
+ return self.start_edition(record, options);
});
},
keyup_ENTER: function () {
@@ -419,46 +425,142 @@ openerp.web.list_editable = function (instance) {
keyup_ESCAPE: function () {
return this.cancel_edition();
},
+ /**
+ * Gets the selection range (start, end) for the provided element,
+ * returns ``null`` if it can't get a range.
+ *
+ * @private
+ */
_text_selection_range: function (el) {
- if (el.selectionStart !== undefined) {
+ var selectionStart;
+ try {
+ selectionStart = el.selectionStart;
+ } catch (e) {
+ // radio or checkbox throw on selectionStart access
+ return null;
+ }
+ if (selectionStart !== undefined) {
return {
- start: el.selectionStart,
+ start: selectionStart,
end: el.selectionEnd
};
- } else if(document.body.createTextRange) {
+ } else if (document.body.createTextRange) {
throw new Error("Implement text range handling for MSIE");
var sel = document.body.createTextRange();
if (sel.parentElement() === el) {
}
}
+ // Element without selection ranges (select, div/@contenteditable)
+ return null;
},
_text_cursor: function (el) {
var selection = this._text_selection_range(el);
- if (selection.start !== selection.end) {
+ if (!selection) {
return null;
}
- return selection.start;
+ if (selection.start !== selection.end) {
+ return {position: null, collapsed: false};
+ }
+ return {position: selection.start, collapsed: true};
},
- keydown_UP: function (e) {
+ /**
+ * Checks if the cursor is at the start of the provided el
+ *
+ * @param {HTMLInputElement | HTMLTextAreaElement}
+ * @returns {Boolean}
+ * @private
+ */
+ _at_start: function (cursor, el) {
+ return cursor.collapsed && (cursor.position === 0);
+ },
+ /**
+ * Checks if the cursor is at the end of the provided el
+ *
+ * @param {HTMLInputElement | HTMLTextAreaElement}
+ * @returns {Boolean}
+ * @private
+ */
+ _at_end: function (cursor, el) {
+ return cursor.collapsed && (cursor.position === el.value.length);
+ },
+ /**
+ * @param DOMEvent event
+ * @param {String} record_direction direction to move into to get the next record (pred | succ)
+ * @param {Function} is_valid_move whether the edition should be moved to the next record
+ * @private
+ */
+ _key_move_record: function (event, record_direction, is_valid_move) {
if (!this.editor.is_editing('edit')) { return $.when(); }
- // FIXME: assumes editable widgets are input-type elements
- var index = this._text_cursor(e.target);
- // If selecting or not at the start of the input
- if (index === null || index !== 0) { return $.when(); }
+ var cursor = this._text_cursor(event.target);
+ // if text-based input (has a cursor)
+ // and selecting (not collapsed) or not at a field boundary
+ // don't move to the next record
+ if (cursor && !is_valid_move(event.target, cursor)) { return $.when(); }
- e.preventDefault();
- return this._next('pred');
+ event.preventDefault();
+ var source_field = $(event.target).closest('[data-fieldname]')
+ .attr('data-fieldname');
+ return this._next(record_direction, {focus_field: source_field});
+
+ },
+ keydown_UP: function (e) {
+ var self = this;
+ return this._key_move_record(e, 'pred', function (el, cursor) {
+ return self._at_start(cursor, el);
+ });
},
keydown_DOWN: function (e) {
- if (!this.editor.is_editing('edit')) { return $.when(); }
- // FIXME: assumes editable widgets are input-type elements
- var index = this._text_cursor(e.target);
- // If selecting or not at the end of the input
- if (index === null || index !== e.target.value.length) { return $.when(); }
+ var self = this;
+ return this._key_move_record(e, 'succ', function (el, cursor) {
+ return self._at_end(cursor, el);
+ });
+ },
- e.preventDefault();
- return this._next();
+ keydown_LEFT: function (e) {
+ // If the cursor is at the beginning of the field
+ var source_field = $(e.target).closest('[data-fieldname]')
+ .attr('data-fieldname');
+ var cursor = this._text_cursor(e.target);
+ if (cursor && !this._at_start(cursor, e.target)) { return $.when(); }
+
+ var fields_order = this.editor.form.fields_order;
+ var field_index = _(fields_order).indexOf(source_field);
+
+ // Look for the closest visible form field to the left
+ var fields = this.editor.form.fields;
+ var field;
+ do {
+ if (--field_index < 0) { return $.when(); }
+
+ field = fields[fields_order[field_index]];
+ } while (!field.$element.is(':visible'));
+
+ // and focus it
+ field.focus();
+ return $.when();
+ },
+ keydown_RIGHT: function (e) {
+ // same as above, but with cursor at the end of the field and
+ // looking for new fields at the right
+ var source_field = $(e.target).closest('[data-fieldname]')
+ .attr('data-fieldname');
+ var cursor = this._text_cursor(e.target);
+ if (cursor && !this._at_end(cursor, e.target)) { return $.when(); }
+
+ var fields_order = this.editor.form.fields_order;
+ var field_index = _(fields_order).indexOf(source_field);
+
+ var fields = this.editor.form.fields;
+ var field;
+ do {
+ if (++field_index >= fields_order.length) { return $.when(); }
+
+ field = fields[fields_order[field_index]];
+ } while (!field.$element.is(':visible'));
+
+ field.focus();
+ return $.when();
},
keydown_TAB: function (e) {
var form = this.editor.form;
@@ -642,7 +744,7 @@ openerp.web.list_editable = function (instance) {
instance.web.ListView.List.include(/** @lends instance.web.ListView.List# */{
row_clicked: function (event) {
- if (!this.options.editable) {
+ if (!this.view.editable()) {
return this._super.apply(this, arguments);
}
var record_id = $(event.currentTarget).data('id');
diff --git a/addons/web/static/src/js/views.js b/addons/web/static/src/js/views.js
index ccf34576a1a..10f44a54f11 100644
--- a/addons/web/static/src/js/views.js
+++ b/addons/web/static/src/js/views.js
@@ -120,7 +120,9 @@ instance.web.ActionManager = instance.web.Widget.extend({
if (this.getParent() && this.getParent().do_push_state) {
if (this.inner_action) {
state['title'] = this.inner_action.name;
- state['model'] = this.inner_action.res_model;
+ if(this.inner_action.type == 'ir.actions.act_window') {
+ state['model'] = this.inner_action.res_model;
+ }
if (this.inner_action.id) {
state['action_id'] = this.inner_action.id;
}
@@ -178,7 +180,10 @@ instance.web.ActionManager = instance.web.Widget.extend({
});
},
do_action: function(action, on_close) {
- if (_.isNumber(action) || _.isString(action)) {
+ if (_.isString(action) && instance.web.client_actions.contains(action)) {
+ var action_client = { type: "ir.actions.client", tag: action };
+ return this.do_action(action_client);
+ } else if (_.isNumber(action) || _.isString(action)) {
var self = this;
return self.rpc("/web/action/load", { action_id: action }, function(result) {
self.do_action(result.result, on_close);
@@ -209,21 +214,30 @@ instance.web.ActionManager = instance.web.Widget.extend({
this.dialog_stop();
this.clear_breadcrumbs();
},
- ir_actions_act_window: function (action, on_close) {
- var self = this;
- if (_(['base.module.upgrade', 'base.setup.installer'])
- .contains(action.res_model)) {
- var old_close = on_close;
- on_close = function () {
- instance.webclient.do_reload().then(old_close);
- };
+
+ do_ir_actions_common: function(action, on_close) {
+ var self = this, klass, widget, add_breadcrumb;
+ if (action.type === 'ir.actions.client') {
+ var ClientWidget = instance.web.client_actions.get_object(action.tag);
+ widget = new ClientWidget(this, action.params);
+ klass = 'oe_act_client';
+ add_breadcrumb = function() {
+ self.push_breadcrumb({
+ widget: widget,
+ title: action.name
+ });
+ }
+ } else {
+ widget = new instance.web.ViewManagerAction(this, action);
+ klass = 'oe_act_window';
+ add_breadcrumb = widget.add_breadcrumb
}
if (action.target === 'new') {
if (this.dialog === null) {
// These buttons will be overwrited by <footer> if any
this.dialog = new instance.web.Dialog(this, {
buttons: { "Close": function() { $(this).dialog("close"); }},
- dialogClass: 'oe_act_window'
+ dialogClass: klass
});
if(on_close)
this.dialog.on_close.add(on_close);
@@ -231,7 +245,7 @@ instance.web.ActionManager = instance.web.Widget.extend({
this.dialog_widget.destroy();
}
this.dialog.dialog_title = action.name;
- this.dialog_widget = new instance.web.ViewManagerAction(this, action);
+ this.dialog_widget = widget;
this.dialog_widget.appendTo(this.dialog.$element);
this.dialog.open();
} else {
@@ -242,11 +256,34 @@ instance.web.ActionManager = instance.web.Widget.extend({
});
}
this.inner_action = action;
- var inner_widget = this.inner_widget = new instance.web.ViewManagerAction(this, action);
- inner_widget.add_breadcrumb();
+ this.inner_widget = widget;
+ add_breadcrumb();
this.inner_widget.appendTo(this.$element);
}
},
+
+ ir_actions_act_window: function (action, on_close) {
+ var self = this;
+ if (_(['base.module.upgrade', 'base.setup.installer'])
+ .contains(action.res_model)) {
+ var old_close = on_close;
+ on_close = function () {
+ instance.webclient.do_reload().then(old_close);
+ };
+ }
+ if (action.target !== 'new') {
+ if(action.menu_id) {
+ this.dialog_stop();
+ return this.getParent().do_action(action, function () {
+ instance.webclient.menu.open_menu(action.menu_id);
+ });
+ }
+ }
+ return this.do_ir_actions_common(action, on_close);
+ },
+ ir_actions_client: function (action, on_close) {
+ return this.do_ir_actions_common(action, on_close);
+ },
ir_actions_act_window_close: function (action, on_closed) {
if (!this.dialog && on_closed) {
on_closed();
@@ -262,19 +299,9 @@ instance.web.ActionManager = instance.web.Widget.extend({
self.do_action(action, on_closed)
});
},
- ir_actions_client: function (action) {
- this.dialog_stop();
- var ClientWidget = instance.web.client_actions.get_object(action.tag);
- this.inner_widget = new ClientWidget(this, action.params);
- this.push_breadcrumb({
- widget: this.inner_widget,
- title: action.name
- });
- this.inner_widget.appendTo(this.$element);
- },
ir_actions_report_xml: function(action, on_closed) {
var self = this;
- $.blockUI();
+ instance.web.blockUI();
self.rpc("/web/session/eval_domain_and_context", {
contexts: [action.context],
domains: []
@@ -284,7 +311,7 @@ instance.web.ActionManager = instance.web.Widget.extend({
self.session.get_file({
url: '/web/report',
data: {action: JSON.stringify(action)},
- complete: $.unblockUI,
+ complete: instance.web.unblockUI,
success: function(){
if (!self.dialog && on_closed) {
on_closed();
@@ -841,7 +868,7 @@ instance.web.Sidebar = instance.web.Widget.extend({
} else {
self.do_attachement_update(self.dataset, self.model_id);
}
- $.unblockUI();
+ instance.web.unblockUI();
});
},
start: function() {
@@ -980,7 +1007,7 @@ instance.web.Sidebar = instance.web.Widget.extend({
$e.parent().find('input[type=file]').prop('disabled', true);
$e.parent().find('button').prop('disabled', true).find('img, span').toggle();
this.$('.oe_sidebar_add_attachment span').text(_t('Uploading...'));
- $.blockUI();
+ instance.web.blockUI();
}
},
on_attachment_delete: function(e) {