summaryrefslogtreecommitdiff
path: root/addons/web/static/src/js
diff options
context:
space:
mode:
authorKunal Chavda (OpenERP) <kch@tinyerp.com>2011-09-13 11:14:06 +0530
committerKunal Chavda (OpenERP) <kch@tinyerp.com>2011-09-13 11:14:06 +0530
commitdf1edc236b17979df7a7ef54f59341bb4d1070cd (patch)
tree3aabeb3647e6bab3287f284ebda97fed10e26868 /addons/web/static/src/js
parent55e3e348726287e59decf47077965b1eb5b5cb42 (diff)
parenta3a09a6229e251d5d861f11f9e654cd2100483ad (diff)
[MERGE]Merge with trunk upto revision no 1011.
bzr revid: kch@tinyerp.com-20110913054406-yrjafv0qdzzijizz
Diffstat (limited to 'addons/web/static/src/js')
-rw-r--r--addons/web/static/src/js/boot.js4
-rw-r--r--addons/web/static/src/js/chrome.js99
-rw-r--r--addons/web/static/src/js/core.js78
-rw-r--r--addons/web/static/src/js/data.js20
-rw-r--r--addons/web/static/src/js/form.js107
-rw-r--r--addons/web/static/src/js/list-editable.js16
-rw-r--r--addons/web/static/src/js/list.js76
-rw-r--r--addons/web/static/src/js/search.js63
-rw-r--r--addons/web/static/src/js/view_tree.js18
-rw-r--r--addons/web/static/src/js/views.js26
10 files changed, 396 insertions, 111 deletions
diff --git a/addons/web/static/src/js/boot.js b/addons/web/static/src/js/boot.js
index 1846a2727ae..10c8de096b2 100644
--- a/addons/web/static/src/js/boot.js
+++ b/addons/web/static/src/js/boot.js
@@ -5,7 +5,6 @@
/**
* @name openerp
* @namespace openerp
- * @namespace window.openerp
*/
(function() {
if (this.openerp)
@@ -48,6 +47,9 @@
* OpenERP Web web module split
*---------------------------------------------------------*/
+/**
+ * @namespace
+ */
openerp.web = function(instance) {
openerp.web.core(instance);
if (openerp.web.dates) {
diff --git a/addons/web/static/src/js/chrome.js b/addons/web/static/src/js/chrome.js
index 4d19287ed33..582ef512f83 100644
--- a/addons/web/static/src/js/chrome.js
+++ b/addons/web/static/src/js/chrome.js
@@ -5,7 +5,14 @@
openerp.web.chrome = function(openerp) {
var QWeb = openerp.web.qweb;
-openerp.web.Notification = openerp.web.Widget.extend({
+openerp.web.Notification = openerp.web.Widget.extend(/** @lends openerp.web.Notification# */{
+ /**
+ * @constructs openerp.web.Notification
+ * @extends openerp.web.Widget
+ *
+ * @param parent
+ * @param element_id
+ */
init: function(parent, element_id) {
this._super(parent, element_id);
this.$element.notify({
@@ -27,9 +34,16 @@ openerp.web.Notification = openerp.web.Widget.extend({
}
});
-openerp.web.Dialog = openerp.web.OldWidget.extend({
+openerp.web.Dialog = openerp.web.OldWidget.extend(/** @lends openerp.web.Dialog# */{
dialog_title: "",
identifier_prefix: 'dialog',
+ /**
+ * @constructs openerp.web.Dialog
+ * @extends openerp.web.OldWidget
+ *
+ * @param parent
+ * @param dialog_options
+ */
init: function (parent, dialog_options) {
var self = this;
this._super(parent);
@@ -118,8 +132,14 @@ openerp.web.Dialog = openerp.web.OldWidget.extend({
}
});
-openerp.web.CrashManager = openerp.web.Dialog.extend({
+openerp.web.CrashManager = openerp.web.Dialog.extend(/** @lends openerp.web.CrashManager# */{
identifier_prefix: 'dialog_crash',
+ /**
+ * @constructs opener.web.CrashManager
+ * @extends openerp.web.Dialog
+ *
+ * @param parent
+ */
init: function(parent) {
this._super(parent);
this.session.on_rpc_error.add(this.on_rpc_error);
@@ -130,7 +150,7 @@ openerp.web.CrashManager = openerp.web.Dialog.extend({
on_rpc_error: function(error) {
this.error = error;
if (error.data.fault_code) {
- var split = error.data.fault_code.split('\n')[0].split(' -- ');
+ var split = ("" + error.data.fault_code).split('\n')[0].split(' -- ');
if (split.length > 1) {
error.type = split.shift();
error.data.fault_code = error.data.fault_code.substr(error.type.length + 4);
@@ -154,7 +174,14 @@ openerp.web.CrashManager = openerp.web.Dialog.extend({
}
});
-openerp.web.Loading = openerp.web.Widget.extend({
+openerp.web.Loading = openerp.web.Widget.extend(/** @lends openerp.web.Loading# */{
+ /**
+ * @constructs openerp.web.Loading
+ * @extends openerp.web.Widget
+ *
+ * @param parent
+ * @param element_id
+ */
init: function(parent, element_id) {
this._super(parent, element_id);
this.count = 0;
@@ -173,7 +200,15 @@ openerp.web.Loading = openerp.web.Widget.extend({
}
});
-openerp.web.Database = openerp.web.Widget.extend({
+openerp.web.Database = openerp.web.Widget.extend(/** @lends openerp.web.Database# */{
+ /**
+ * @constructs openerp.web.Database
+ * @extends openerp.web.Widget
+ *
+ * @param parent
+ * @param element_id
+ * @param option_id
+ */
init: function(parent, element_id, option_id) {
this._super(parent, element_id);
this.$option_id = $('#' + option_id);
@@ -426,8 +461,15 @@ openerp.web.Database = openerp.web.Widget.extend({
}
});
-openerp.web.Login = openerp.web.Widget.extend({
+openerp.web.Login = openerp.web.Widget.extend(/** @lends openerp.web.Login# */{
remember_creditentials: true,
+ /**
+ * @constructs openerp.web.Login
+ * @extends openerp.web.Widget
+ *
+ * @param parent
+ * @param element_id
+ */
init: function(parent, element_id) {
this._super(parent, element_id);
@@ -526,9 +568,15 @@ openerp.web.Login = openerp.web.Widget.extend({
}
});
-openerp.web.Header = openerp.web.Widget.extend({
+openerp.web.Header = openerp.web.Widget.extend(/** @lends openerp.web.Header# */{
template: "Header",
identifier_prefix: 'oe-app-header-',
+ /**
+ * @constructs openerp.web.Header
+ * @extends openerp.web.Widget
+ *
+ * @param parent
+ */
init: function(parent) {
this._super(parent);
this.qs = "?" + jQuery.param.querystring();
@@ -539,6 +587,9 @@ openerp.web.Header = openerp.web.Widget.extend({
},
do_update: function () {
var self = this;
+ this.$content.remove();
+ if (! this.session.uid)
+ return;
var func = new openerp.web.Model(self.session, "res.users").get_func("read");
func(self.session.uid, ["name", "company_id"]).then(function(res) {
self.$content = $(QWeb.render("Header-content", {widget: self, user: res}));
@@ -557,9 +608,6 @@ openerp.web.Header = openerp.web.Widget.extend({
modal: true, width: 960, title: "About"});
});
},
- do_reset: function() {
- this.$content.remove();
- },
shortcut_load :function(){
var self = this,
sc = self.session.shortcuts,
@@ -706,11 +754,18 @@ openerp.web.Header = openerp.web.Widget.extend({
}).html(error.error);
},
on_logout: function() {
- this.$element.find('.oe-shortcuts ul').empty();
}
});
-openerp.web.Menu = openerp.web.Widget.extend({
+openerp.web.Menu = openerp.web.Widget.extend(/** @lends openerp.web.Menu# */{
+ /**
+ * @constructs openerp.web.Menu
+ * @extends openerp.web.Widget
+ *
+ * @param parent
+ * @param element_id
+ * @param secondary_menu_id
+ */
init: function(parent, element_id, secondary_menu_id) {
this._super(parent, element_id);
this.secondary_menu_id = secondary_menu_id;
@@ -792,13 +847,13 @@ openerp.web.Menu = openerp.web.Widget.extend({
}
});
-openerp.web.Homepage = openerp.web.Widget.extend({
-});
-
-openerp.web.Preferences = openerp.web.Widget.extend({
-});
-
-openerp.web.WebClient = openerp.web.Widget.extend({
+openerp.web.WebClient = openerp.web.Widget.extend(/** @lends openerp.web.WebClient */{
+ /**
+ * @constructs openerp.web.WebClient
+ * @extends openerp.web.Widget
+ *
+ * @param element_id
+ */
init: function(element_id) {
this._super(null, element_id);
openerp.webclient = this;
@@ -826,7 +881,7 @@ openerp.web.WebClient = openerp.web.Widget.extend({
this.session.on_session_invalid.add(this.login.do_ask_login);
this.session.on_session_valid.add_last(this.header.do_update);
- this.session.on_session_invalid.add_last(this.header.do_reset);
+ this.session.on_session_invalid.add_last(this.header.do_update);
this.session.on_session_valid.add_last(this.on_logged);
this.menu = new openerp.web.Menu(this, "oe_menu", "oe_secondary_menu");
@@ -837,7 +892,7 @@ openerp.web.WebClient = openerp.web.Widget.extend({
this.session.start();
this.login.start();
this.menu.start();
- this.notification.notify("OpenERP Client", "The openerp client has been initialized.");
+ console.debug("The openerp client has been initialized.");
},
on_logged: function() {
if(this.action_manager)
diff --git a/addons/web/static/src/js/core.js b/addons/web/static/src/js/core.js
index da2afae3680..77b48820e83 100644
--- a/addons/web/static/src/js/core.js
+++ b/addons/web/static/src/js/core.js
@@ -4,6 +4,7 @@
openerp.web.core = function(openerp) {
openerp.web.qweb = new QWeb2.Engine();
+openerp.web.qweb.debug = (window.location.search.indexOf('?debug') !== -1);
/**
* John Resig Class with factory improvement
*/
@@ -12,11 +13,17 @@ openerp.web.qweb = new QWeb2.Engine();
fnTest = /xyz/.test(function(){xyz;}) ? /\b_super\b/ : /.*/;
// The web Class implementation (does nothing)
/**
+ * Extended version of John Resig's Class pattern
+ *
* @class
*/
openerp.web.Class = function(){};
- // Create a new Class that inherits from this class
+ /**
+ * Subclass an existing class
+ *
+ * @param {Object} prop class-level properties (class attributes and instance methods) to set on the new class
+ */
openerp.web.Class.extend = function(prop) {
var _super = this.prototype;
@@ -157,7 +164,7 @@ openerp.web.callback = function(obj, method) {
* that does nothing and always return undefined).
*
* @param {Class} claz
- * @param {dict} add Additional functions to override.
+ * @param {Object} add Additional functions to override.
* @return {Class}
*/
openerp.web.generate_null_object_class = function(claz, add) {
@@ -188,7 +195,7 @@ openerp.web.KeyNotFound = openerp.web.NotFound.extend( /** @lends openerp.web.Ke
/**
* Thrown when a key could not be found in a mapping
*
- * @constructs
+ * @constructs openerp.web.KeyNotFound
* @extends openerp.web.NotFound
* @param {String} key the key which could not be found
*/
@@ -204,7 +211,7 @@ openerp.web.ObjectNotFound = openerp.web.NotFound.extend( /** @lends openerp.web
* Thrown when an object path does not designate a valid class or object
* in the openerp hierarchy.
*
- * @constructs
+ * @constructs openerp.web.ObjectNotFound
* @extends openerp.web.NotFound
* @param {String} path the invalid object path
*/
@@ -228,7 +235,7 @@ openerp.web.Registry = openerp.web.Class.extend( /** @lends openerp.web.Registry
* object pointed to (e.g. ``"openerp.web.Session"`` for an OpenERP
* session object).
*
- * @constructs
+ * @constructs openerp.web.Registry
* @param {Object} mapping a mapping of keys to object-paths
*/
init: function (mapping) {
@@ -309,7 +316,11 @@ openerp.web.Registry = openerp.web.Class.extend( /** @lends openerp.web.Registry
}
});
-openerp.web.CallbackEnabled = openerp.web.Class.extend({
+openerp.web.CallbackEnabled = openerp.web.Class.extend(/** @lends openerp.web.CallbackEnabled# */{
+ /**
+ * @constructs openerp.web.CallbackEnabled
+ * @extends openerp.web.Class
+ */
init: function() {
// Transform on_* method into openerp.web.callbacks
for (var name in this) {
@@ -326,9 +337,11 @@ openerp.web.CallbackEnabled = openerp.web.Class.extend({
openerp.web.Session = openerp.web.CallbackEnabled.extend( /** @lends openerp.web.Session# */{
/**
- * @constructs
- * @param server
- * @param port
+ * @constructs openerp.web.Session
+ * @extends openerp.web.CallbackEnabled
+ *
+ * @param {String} [server] JSON-RPC endpoint hostname
+ * @param {String} [port] JSON-RPC endpoint port
*/
init: function(server, port) {
this._super();
@@ -576,9 +589,10 @@ openerp.web.Session = openerp.web.CallbackEnabled.extend( /** @lends openerp.web
});
},
do_load_css: function (files) {
+ var self = this;
_.each(files, function (file) {
$('head').append($('<link>', {
- 'href': file,
+ 'href': file + (self.debug ? '?debug=' + (new Date().getTime()) : ''),
'rel': 'stylesheet',
'type': 'text/css'
}));
@@ -590,7 +604,7 @@ openerp.web.Session = openerp.web.CallbackEnabled.extend( /** @lends openerp.web
var file = files.shift();
var tag = document.createElement('script');
tag.type = 'text/javascript';
- tag.src = file;
+ tag.src = file + (this.debug ? '?debug=' + (new Date().getTime()) : '');
tag.onload = tag.onreadystatechange = function() {
if ( (tag.readyState && tag.readyState != "loaded" && tag.readyState != "complete") || tag.onload_done )
return;
@@ -708,13 +722,18 @@ openerp.web.Session = openerp.web.CallbackEnabled.extend( /** @lends openerp.web
}
});
-/**
- * Utility class that any class is allowed to extend to easy common manipulations.
- *
- * It provides rpc calls, callback on all methods preceded by "on_" or "do_" and a
- * logging facility.
- */
-openerp.web.SessionAware = openerp.web.CallbackEnabled.extend({
+openerp.web.SessionAware = openerp.web.CallbackEnabled.extend(/** @lends openerp.web.SessionAware# */{
+ /**
+ * Utility class that any class is allowed to extend to easy common manipulations.
+ *
+ * It provides rpc calls, callback on all methods preceded by "on_" or "do_" and a
+ * logging facility.
+ *
+ * @constructs openerp.web.SessionAware
+ * @extends openerp.web.CallbackEnabled
+ *
+ * @param {openerp.web.Session} session
+ */
init: function(session) {
this._super();
this.session = session;
@@ -758,15 +777,12 @@ openerp.web.SessionAware = openerp.web.CallbackEnabled.extend({
if(body) {
$('<pre></pre>').text(v).appendTo($('body'));
}
- if(notify && this.notification) {
- this.notification.notify("Logging:",v);
- }
}
}
}
});
-openerp.web.Widget = openerp.web.SessionAware.extend({
+openerp.web.Widget = openerp.web.SessionAware.extend(/** @lends openerp.web.Widget# */{
/**
* The name of the QWeb template that will be used for rendering. Must be
* redefined in subclasses or the default render() method can not be used.
@@ -784,7 +800,9 @@ openerp.web.Widget = openerp.web.SessionAware.extend({
/**
* Construct the widget and set its parent if a parent is given.
*
- * @constructs
+ * @constructs openerp.web.Widget
+ * @extends openerp.web.SessionAware
+ *
* @param {openerp.web.Widget} parent Binds the current instance to the given Widget instance.
* When that widget is destroyed by calling stop(), the current instance will be
* destroyed too. Can be null.
@@ -860,8 +878,10 @@ openerp.web.Widget = openerp.web.SessionAware.extend({
if (target instanceof openerp.web.Widget)
target = target.$element;
insertion(target);
+ this.on_inserted(this.$element, this);
return this.start();
},
+ on_inserted: function(element, widget) {},
/**
* Renders the widget using QWeb, `this.template` must be defined.
* The context given to QWeb contains the "widget" key that references `this`.
@@ -941,17 +961,23 @@ openerp.web.Widget = openerp.web.SessionAware.extend({
});
/**
+ * @class
+ * @extends openerp.web.Widget
* @deprecated
* For retro compatibility only, the only difference with is that render() uses
- * directly `this` instead of context with a "widget" key.
+ * directly ``this`` instead of context with a ``widget`` key.
*/
-openerp.web.OldWidget = openerp.web.Widget.extend({
+openerp.web.OldWidget = openerp.web.Widget.extend(/** @lends openerp.web.OldWidget# */{
render: function (additional) {
return openerp.web.qweb.render(this.template, _.extend(_.extend({}, this), additional || {}));
}
});
-openerp.web.TranslationDataBase = openerp.web.Class.extend({
+openerp.web.TranslationDataBase = openerp.web.Class.extend(/** @lends openerp.web.TranslationDataBase# */{
+ /**
+ * @constructs openerp.web.TranslationDataBase
+ * @extends openerp.web.Class
+ */
init: function() {
this.db = {};
this.parameters = {"direction": 'ltr',
diff --git a/addons/web/static/src/js/data.js b/addons/web/static/src/js/data.js
index 4b4523a2723..1eb57241fa6 100644
--- a/addons/web/static/src/js/data.js
+++ b/addons/web/static/src/js/data.js
@@ -29,7 +29,7 @@ openerp.web.DataGroup = openerp.web.Widget.extend( /** @lends openerp.web.DataG
* :js:func:`~openerp.web.DataGroup.list`, which is used to read the
* content of the current grouping level.
*
- * @constructs
+ * @constructs openerp.web.DataGroup
* @extends openerp.web.Widget
*
* @param {openerp.web.Session} session Current OpenERP session
@@ -60,7 +60,7 @@ openerp.web.DataGroup = openerp.web.Widget.extend( /** @lends openerp.web.DataG
openerp.web.ContainerDataGroup = openerp.web.DataGroup.extend( /** @lends openerp.web.ContainerDataGroup# */ {
/**
*
- * @constructs
+ * @constructs openerp.web.ContainerDataGroup
* @extends openerp.web.DataGroup
*
* @param session
@@ -197,7 +197,7 @@ openerp.web.ContainerDataGroup = openerp.web.DataGroup.extend( /** @lends opener
openerp.web.GrouplessDataGroup = openerp.web.DataGroup.extend( /** @lends openerp.web.GrouplessDataGroup# */ {
/**
*
- * @constructs
+ * @constructs openerp.web.GrouplessDataGroup
* @extends openerp.web.DataGroup
*
* @param session
@@ -220,7 +220,7 @@ openerp.web.StaticDataGroup = openerp.web.GrouplessDataGroup.extend( /** @lends
* A specialization of groupless data groups, relying on a single static
* dataset as its records provider.
*
- * @constructs
+ * @constructs openerp.web.StaticDataGroup
* @extends openerp.web.GrouplessDataGroup
* @param {openep.web.DataSetStatic} dataset a static dataset backing the groups
*/
@@ -237,7 +237,7 @@ openerp.web.DataSet = openerp.web.Widget.extend( /** @lends openerp.web.DataSet
* DateaManagement interface between views and the collection of selected
* OpenERP records (represents the view's state?)
*
- * @constructs
+ * @constructs openerp.web.DataSet
* @extends openerp.web.Widget
*
* @param {String} model the OpenERP model this dataset will manage
@@ -505,9 +505,10 @@ openerp.web.DataSetStatic = openerp.web.DataSet.extend({
this.set_ids(_.without.apply(null, [this.ids].concat(ids)));
}
});
-openerp.web.DataSetSearch = openerp.web.DataSet.extend({
+openerp.web.DataSetSearch = openerp.web.DataSet.extend(/** @lends openerp.web.DataSetSearch */{
/**
- * @constructs
+ * @constructs openerp.web.DataSetSearch
+ * @extends openerp.web.DataSet
*
* @param {Object} parent
* @param {String} model
@@ -612,11 +613,12 @@ openerp.web.BufferedDataSet = openerp.web.DataSetStatic.extend({
var cached = {id:_.uniqueId(this.virtual_id_prefix), values: data};
this.to_create.push(cached);
this.cache.push(cached);
+ this.on_change();
var to_return = $.Deferred().then(callback);
to_return.resolve({result: cached.id});
return to_return.promise();
},
- write: function (id, data, callback) {
+ write: function (id, data, options, callback) {
var self = this;
var record = _.detect(this.to_create, function(x) {return x.id === id;});
record = record || _.detect(this.to_write, function(x) {return x.id === id;});
@@ -721,7 +723,7 @@ openerp.web.ReadOnlyDataSetSearch = openerp.web.DataSetSearch.extend({
return to_return.promise();
},
on_create: function(data) {},
- write: function (id, data, callback) {
+ write: function (id, data, options, callback) {
this.on_write(id, data);
var to_return = $.Deferred().then(callback);
setTimeout(function () {to_return.resolve({"result": true});}, 0);
diff --git a/addons/web/static/src/js/form.js b/addons/web/static/src/js/form.js
index 4f88edb0a53..9858433db32 100644
--- a/addons/web/static/src/js/form.js
+++ b/addons/web/static/src/js/form.js
@@ -12,7 +12,9 @@ openerp.web.FormView = openerp.web.View.extend( /** @lends openerp.web.FormView#
searchable: false,
template: "FormView",
/**
- * @constructs
+ * @constructs openerp.web.FormView
+ * @extends openerp.web.View
+ *
* @param {openerp.web.Session} session the current openerp session
* @param {String} element_id this view's root element id
* @param {openerp.web.DataSet} dataset the dataset this view will work with
@@ -382,9 +384,9 @@ openerp.web.FormView = openerp.web.View.extend( /** @lends openerp.web.FormView#
},
on_saved: function(r, success) {
if (!r.result) {
- this.notification.warn("Record not saved", "Problem while saving record.");
+ // should not happen in the server, but may happen for internal purpose
} else {
- this.notification.notify("Record saved", "The record #" + this.datarecord.id + " has been saved.");
+ console.debug(_.sprintf("The record #%s has been saved.", this.datarecord.id));
if (success) {
success(r);
}
@@ -406,7 +408,7 @@ openerp.web.FormView = openerp.web.View.extend( /** @lends openerp.web.FormView#
*/
on_created: function(r, success, prepend_on_create) {
if (!r.result) {
- this.notification.warn("Record not created", "Problem while creating record.");
+ // should not happen in the server, but may happen for internal purpose
} else {
this.datarecord.id = r.result;
if (!prepend_on_create) {
@@ -420,7 +422,7 @@ openerp.web.FormView = openerp.web.View.extend( /** @lends openerp.web.FormView#
if (this.sidebar) {
this.sidebar.attachments.do_update();
}
- this.notification.notify("Record created", "The record has been created with id #" + this.datarecord.id);
+ console.debug("The record has been created with id #" + this.datarecord.id);
if (success) {
success(_.extend(r, {created: true}));
}
@@ -428,13 +430,13 @@ openerp.web.FormView = openerp.web.View.extend( /** @lends openerp.web.FormView#
}
},
do_search: function (domains, contexts, groupbys) {
- this.notification.notify("Searching form");
+ console.debug("Searching form");
},
on_action: function (action) {
- this.notification.notify('Executing action ' + action);
+ console.debug('Executing action', action);
},
do_cancel: function () {
- this.notification.notify("Cancelling form");
+ console.debug("Cancelling form");
},
reload: function() {
if (this.dataset.index == null || this.dataset.index < 0) {
@@ -480,7 +482,7 @@ openerp.web.FormDialog = openerp.web.Dialog.extend({
self.form.on_record_loaded(records[0]);
});
},
- on_form_dialog_saved: function() {
+ on_form_dialog_saved: function(r) {
this.close();
}
});
@@ -599,8 +601,15 @@ openerp.web.form.compute_domain = function(expr, fields) {
return _.all(stack, _.identity);
};
-openerp.web.form.Widget = openerp.web.Widget.extend({
+openerp.web.form.Widget = openerp.web.Widget.extend(/** @lends openerp.web.form.Widget# */{
template: 'Widget',
+ /**
+ * @constructs openerp.web.form.Widget
+ * @extends openerp.web.Widget
+ *
+ * @param view
+ * @param node
+ */
init: function(view, node) {
this.view = view;
this.node = node;
@@ -877,7 +886,14 @@ openerp.web.form.WidgetLabel = openerp.web.form.Widget.extend({
}
});
-openerp.web.form.Field = openerp.web.form.Widget.extend({
+openerp.web.form.Field = openerp.web.form.Widget.extend(/** @lends openerp.web.form.Field# */{
+ /**
+ * @constructs openerp.web.form.Field
+ * @extends openerp.web.form.Widget
+ *
+ * @param view
+ * @param node
+ */
init: function(view, node) {
this.name = node.attrs.name;
this.value = undefined;
@@ -1852,7 +1868,7 @@ openerp.web.form.FieldOne2Many = openerp.web.form.Field.extend({
this.viewmanager.views[this.viewmanager.active_view].controller) {
var view = this.viewmanager.views[this.viewmanager.active_view].controller;
if (this.viewmanager.active_view === "form") {
- var res = view.do_save();
+ var res = $.when(view.do_save());
if (res === false) {
// ignore
} else if (res.isRejected()) {
@@ -2004,7 +2020,11 @@ openerp.web.form.Many2ManyDataSet = openerp.web.DataSetStatic.extend({
}
});
-openerp.web.form.Many2ManyListView = openerp.web.ListView.extend({
+/**
+ * @class
+ * @extends openerp.web.ListView
+ */
+openerp.web.form.Many2ManyListView = openerp.web.ListView.extend(/** @lends openerp.web.form.Many2ManyListView# */{
do_add_record: function () {
var pop = new openerp.web.form.SelectCreatePopup(this);
pop.select_element(this.model, {},
@@ -2031,7 +2051,11 @@ openerp.web.form.Many2ManyListView = openerp.web.ListView.extend({
}
});
-openerp.web.form.SelectCreatePopup = openerp.web.OldWidget.extend({
+/**
+ * @class
+ * @extends openerp.web.OldWidget
+ */
+openerp.web.form.SelectCreatePopup = openerp.web.OldWidget.extend(/** @lends openerp.web.form.SelectCreatePopup# */{
identifier_prefix: "selectcreatepopup",
template: "SelectCreatePopup",
/**
@@ -2200,7 +2224,11 @@ openerp.web.form.SelectCreateListView = openerp.web.ListView.extend({
}
});
-openerp.web.form.FormOpenPopup = openerp.web.OldWidget.extend({
+/**
+ * @class
+ * @extends openerp.web.OldWidget
+ */
+openerp.web.form.FormOpenPopup = openerp.web.OldWidget.extend(/** @lends openerp.web.form.FormOpenPopup# */{
identifier_prefix: "formopenpopup",
template: "FormOpenPopup",
/**
@@ -2384,7 +2412,7 @@ openerp.web.form.FieldBinary = openerp.web.form.Field.extend({
if (size === false) {
this.notification.warn("File Upload", "There was a problem while uploading your file");
// TODO: use openerp web crashmanager
- this.log("Error while uploading file : ", name);
+ console.warn("Error while uploading file : ", name);
} else {
this.on_file_uploaded_and_valid.apply(this, arguments);
this.on_ui_change();
@@ -2478,6 +2506,50 @@ openerp.web.form.FieldBinaryImage = openerp.web.form.FieldBinary.extend({
}
});
+openerp.web.form.FieldStatus = openerp.web.form.Field.extend({
+ template: "FieldStatus",
+ start: function() {
+ this._super();
+ this.selected_value = null;
+
+ this.render_list();
+ },
+ set_value: function(value) {
+ this._super(value);
+ this.selected_value = value;
+
+ this.render_list();
+ },
+ render_list: function() {
+ var self = this;
+ var shown = _.map(((this.node.attrs || {}).statusbar_visible || "").split(","),
+ function(x) { return x.trim(); });
+
+ if (shown.length == 0) {
+ this.to_show = this.field.selection;
+ } else {
+ this.to_show = _.select(this.field.selection, function(x) {
+ return _.indexOf(shown, x[0]) !== -1 || x[0] === self.selected_value;
+ });
+ }
+
+ var content = openerp.web.qweb.render("FieldStatus.content", {widget: this, _:_});
+ this.$element.html(content);
+
+ var colors = JSON.parse((this.node.attrs || {}).statusbar_colors || "{}");
+ var color = colors[this.selected_value];
+ if (color) {
+ var elem = this.$element.find("li.oe-arrow-list-selected span");
+ elem.css("border-color", color);
+ elem = this.$element.find("li.oe-arrow-list-selected .oe-arrow-list-before");
+ elem.css("border-left-color", "rgba(0,0,0,0)");
+ elem = this.$element.find("li.oe-arrow-list-selected .oe-arrow-list-after");
+ elem.css("border-color", "rgba(0,0,0,0)");
+ elem.css("border-left-color", color);
+ }
+ }
+});
+
/**
* Registry of form widgets, called by :js:`openerp.web.FormView`
*/
@@ -2507,7 +2579,8 @@ openerp.web.form.widgets = new openerp.web.Registry({
'float_time': 'openerp.web.form.FieldFloat',
'progressbar': 'openerp.web.form.FieldProgressBar',
'image': 'openerp.web.form.FieldBinaryImage',
- 'binary': 'openerp.web.form.FieldBinaryFile'
+ 'binary': 'openerp.web.form.FieldBinaryFile',
+ 'statusbar': 'openerp.web.form.FieldStatus'
});
};
diff --git a/addons/web/static/src/js/list-editable.js b/addons/web/static/src/js/list-editable.js
index ab78e5e0139..c38c43a4c9c 100644
--- a/addons/web/static/src/js/list-editable.js
+++ b/addons/web/static/src/js/list-editable.js
@@ -1,5 +1,6 @@
/**
- * @namespace handles editability case for lists, because it depends on form and forms already depends on lists it had to be split out
+ * handles editability case for lists, because it depends on form and forms already depends on lists it had to be split out
+ * @namespace
*/
openerp.web.list_editable = function (openerp) {
var KEY_RETURN = 13,
@@ -87,7 +88,7 @@ openerp.web.list_editable = function (openerp) {
}
});
- openerp.web.ListView.List.include(/** @lends openerp.web.ListView.List */{
+ openerp.web.ListView.List.include(/** @lends openerp.web.ListView.List# */{
row_clicked: function (event) {
if (!this.options.editable) {
return this._super(event);
@@ -112,6 +113,7 @@ openerp.web.list_editable = function (openerp) {
cancelled.resolve();
}
cancelled.then(function () {
+ self.view.unpad_columns();
self.edition_form.stop();
self.edition_form.$element.remove();
delete self.edition_form;
@@ -197,6 +199,16 @@ openerp.web.list_editable = function (openerp) {
$new_row.prepend('<td>');
}
});
+ // Add columns for the cancel and save buttons, if
+ // there are none in the list
+ if (!self.options.selectable) {
+ self.view.pad_columns(
+ 1, {except: $new_row, position: 'before'});
+ }
+ if (!self.options.deletable) {
+ self.view.pad_columns(
+ 1, {except: $new_row});
+ }
self.edition_form.do_show();
});
diff --git a/addons/web/static/src/js/list.js b/addons/web/static/src/js/list.js
index 6029b30f866..b9df9e8e2df 100644
--- a/addons/web/static/src/js/list.js
+++ b/addons/web/static/src/js/list.js
@@ -27,7 +27,9 @@ openerp.web.ListView = openerp.web.View.extend( /** @lends openerp.web.ListView#
* See constructor parameters and method documentations for information on
* the default behaviors and possible options for the list view.
*
- * @constructs
+ * @constructs openerp.web.ListView
+ * @extends openerp.web.View
+ *
* @param parent parent object
* @param element_id the id of the DOM elements this view should link itself to
* @param {openerp.web.DataSet} dataset the dataset the view should work with
@@ -49,6 +51,7 @@ openerp.web.ListView = openerp.web.View.extend( /** @lends openerp.web.ListView#
this.dataset = dataset;
this.model = dataset.model;
this.view_id = view_id;
+ this.previous_colspan = null;
this.columns = [];
@@ -346,7 +349,7 @@ openerp.web.ListView = openerp.web.View.extend( /** @lends openerp.web.ListView#
if (this.sidebar) {
this.sidebar.$element.show();
}
- if (this.hidden) {
+ if (!_(this.dataset.ids).isEmpty()) {
this.reload_content();
}
},
@@ -355,7 +358,6 @@ openerp.web.ListView = openerp.web.View.extend( /** @lends openerp.web.ListView#
if (this.sidebar) {
this.sidebar.$element.hide();
}
- this.hidden = true;
},
/**
* Reloads the list view based on the current settings (dataset & al)
@@ -603,6 +605,49 @@ openerp.web.ListView = openerp.web.View.extend( /** @lends openerp.web.ListView#
get_selected_ids: function() {
var ids = this.groups.get_selection().ids;
return ids;
+ },
+ /**
+ * Adds padding columns at the start or end of all table rows (including
+ * field names row)
+ *
+ * @param {Number} count number of columns to add
+ * @param {Object} options
+ * @param {"before"|"after"} [position="after"] insertion position for the new columns
+ * @param {Object} [except] content row to not pad
+ */
+ pad_columns: function (count, options) {
+ options = options || {};
+ // padding for action/pager header
+ var $first_header = this.$element.find('thead tr:first th');
+ var colspan = $first_header.attr('colspan');
+ if (colspan) {
+ if (!this.previous_colspan) {
+ this.previous_colspan = colspan;
+ }
+ $first_header.attr('colspan', parseInt(colspan, 10) + count);
+ }
+ // Padding for column titles, footer and data rows
+ var $rows = this.$element
+ .find('.oe-listview-header-columns, tr:not(thead tr)')
+ .not(options['except']);
+ var newcols = new Array(count+1).join('<td class="oe-listview-padding"></td>');
+ if (options.position === 'before') {
+ $rows.prepend(newcols);
+ } else {
+ $rows.append(newcols);
+ }
+ },
+ /**
+ * Removes all padding columns of the table
+ */
+ unpad_columns: function () {
+ this.$element.find('.oe-listview-padding').remove();
+ if (this.previous_colspan) {
+ this.$element
+ .find('thead tr:first th')
+ .attr('colspan', this.previous_colspan);
+ this.previous_colspan = null;
+ }
}
});
openerp.web.ListView.List = openerp.web.Class.extend( /** @lends openerp.web.ListView.List# */{
@@ -630,7 +675,9 @@ openerp.web.ListView.List = openerp.web.Class.extend( /** @lends openerp.web.Lis
* Triggered when a row of the table is clicked, provides the index (in
* the rows array) and id of the selected record to the handle function.
*
- * @constructs
+ * @constructs openerp.web.ListView.List
+ * @extends openerp.web.Class
+ *
* @param {Object} opts display options, identical to those of :js:class:`openerp.web.ListView`
*/
init: function (group, opts) {
@@ -835,7 +882,9 @@ openerp.web.ListView.Groups = openerp.web.Class.extend( /** @lends openerp.web.L
* Provides events similar to those of
* :js:class:`~openerp.web.ListView.List`
*
- * @constructs
+ * @constructs openerp.web.ListView.Groups
+ * @extends openerp.web.Class
+ *
* @param {openerp.web.ListView} view
* @param {Object} [options]
* @param {Collection} [options.records]
@@ -1168,10 +1217,9 @@ openerp.web.ListView.Groups = openerp.web.Class.extend( /** @lends openerp.web.L
});
/**
- * @class
- * @extends openerp.web.Class
+ * @mixin Events
*/
-var Events = {
+var Events = /** @lends Events# */{
/**
* @param {String} event event to listen to on the current object, null for all events
* @param {Function} handler event handler to bind to the relevant event
@@ -1221,10 +1269,10 @@ var Events = {
};
var Record = openerp.web.Class.extend(/** @lends Record# */{
/**
- * @constructs
+ * @constructs Record
* @extends openerp.web.Class
- * @borrows Events#bind as this.bind
- * @borrows Events#trigger as this.trigger
+ *
+ * @mixes Events
* @param {Object} [data]
*/
init: function (data) {
@@ -1288,10 +1336,10 @@ var Collection = openerp.web.Class.extend(/** @lends Collection# */{
* Using a "dumb" array of records makes synchronization between the
* various serious
*
- * @constructs
+ * @constructs Collection
* @extends openerp.web.Class
- * @borrows Events#bind as this.bind
- * @borrows Events#trigger as this.trigger
+ *
+ * @mixes Events
* @param {Array} [records] records to initialize the collection with
* @param {Object} [options]
*/
diff --git a/addons/web/static/src/js/search.js b/addons/web/static/src/js/search.js
index 272e96b7d01..21f397c0867 100644
--- a/addons/web/static/src/js/search.js
+++ b/addons/web/static/src/js/search.js
@@ -1,7 +1,17 @@
openerp.web.search = function(openerp) {
var QWeb = openerp.web.qweb;
-openerp.web.SearchView = openerp.web.Widget.extend({
+openerp.web.SearchView = openerp.web.Widget.extend(/** @lends openerp.web.SearchView# */{
+ /**
+ * @constructs openerp.web.SearchView
+ * @extends openerp.web.Widget
+ *
+ * @param parent
+ * @param element_id
+ * @param dataset
+ * @param view_id
+ * @param defaults
+ */
init: function(parent, element_id, dataset, view_id, defaults) {
this._super(parent, element_id);
this.dataset = dataset;
@@ -380,7 +390,9 @@ openerp.web.search.Invalid = openerp.web.Class.extend( /** @lends openerp.web.se
* Exception thrown by search widgets when they hold invalid values,
* which they can not return when asked.
*
- * @constructs
+ * @constructs openerp.web.search.Invalid
+ * @extends openerp.web.Class
+ *
* @param field the name of the field holding an invalid value
* @param value the invalid value
* @param message validation failure message
@@ -400,7 +412,7 @@ openerp.web.search.Widget = openerp.web.Widget.extend( /** @lends openerp.web.se
/**
* Root class of all search widgets
*
- * @constructs
+ * @constructs openerp.web.search.Widget
* @extends openerp.web.Widget
*
* @param view the ancestor view of this widget
@@ -452,8 +464,18 @@ openerp.web.search.Widget = openerp.web.Widget.extend( /** @lends openerp.web.se
}));
}
});
-openerp.web.search.FilterGroup = openerp.web.search.Widget.extend({
+openerp.web.search.FilterGroup = openerp.web.search.Widget.extend(/** @lends openerp.web.search.FilterGroup# */{
template: 'SearchView.filters',
+ /**
+ * Inclusive group of filters, creates a continuous "button" with clickable
+ * sections (the normal display for filters is to be a self-contained button)
+ *
+ * @constructs openerp.web.search.FilterGroup
+ * @extends openerp.web.search.Widget
+ *
+ * @param {Array<openerp.web.search.Filter>} filters elements of the group
+ * @param {openerp.web.SearchView} view view in which the filters are contained
+ */
init: function (filters, view) {
this._super(view);
this.filters = filters;
@@ -494,7 +516,7 @@ openerp.web.search.Group = openerp.web.search.Widget.extend({
openerp.web.search.Input = openerp.web.search.Widget.extend( /** @lends openerp.web.search.Input# */{
/**
- * @constructs
+ * @constructs openerp.web.search.Input
* @extends openerp.web.search.Widget
*
* @param view
@@ -512,8 +534,18 @@ openerp.web.search.Input = openerp.web.search.Widget.extend( /** @lends openerp.
"get_domain not implemented for widget " + this.attrs.type);
}
});
-openerp.web.search.Filter = openerp.web.search.Input.extend({
+openerp.web.search.Filter = openerp.web.search.Input.extend(/** @lends openerp.web.search.Filter# */{
template: 'SearchView.filter',
+ /**
+ * Implementation of the OpenERP filters (button with a context and/or
+ * a domain sent as-is to the search view)
+ *
+ * @constructs openerp.web.search.Filter
+ * @extends openerp.web.search.Input
+ *
+ * @param node
+ * @param view
+ */
init: function (node, view) {
this._super(view);
this.attrs = node.attrs;
@@ -566,7 +598,7 @@ openerp.web.search.Field = openerp.web.search.Input.extend( /** @lends openerp.w
template: 'SearchView.field',
default_operator: '=',
/**
- * @constructs
+ * @constructs openerp.web.search.Field
* @extends openerp.web.search.Input
*
* @param view_section
@@ -694,7 +726,7 @@ openerp.web.search.SelectionField = openerp.web.search.Field.extend(/** @lends o
});
openerp.web.search.BooleanField = openerp.web.search.SelectionField.extend(/** @lends openerp.web.search.BooleanField# */{
/**
- * @constructs
+ * @constructs openerp.web.search.BooleanField
* @extends openerp.web.search.BooleanField
*/
init: function () {
@@ -729,7 +761,11 @@ openerp.web.search.BooleanField = openerp.web.search.SelectionField.extend(/** @
}
}
});
-openerp.web.search.DateField = openerp.web.search.Field.extend( /** @lends openerp.web.search.DateField# */{
+/**
+ * @class
+ * @extends openerp.web.search.DateField
+ */
+openerp.web.search.DateField = openerp.web.search.Field.extend(/** @lends openerp.web.search.DateField# */{
/**
* enables date picker on the HTML widgets
*/
@@ -944,9 +980,16 @@ openerp.web.search.ExtendedSearchGroup = openerp.web.OldWidget.extend({
}
});
-openerp.web.search.ExtendedSearchProposition = openerp.web.OldWidget.extend({
+openerp.web.search.ExtendedSearchProposition = openerp.web.OldWidget.extend(/** @lends openerp.web.search.ExtendedSearchProposition# */{
template: 'SearchView.extended_search.proposition',
identifier_prefix: 'extended-search-proposition',
+ /**
+ * @constructs openerp.web.search.ExtendedSearchProposition
+ * @extends openerp.web.OldWidget
+ *
+ * @param parent
+ * @param fields
+ */
init: function (parent, fields) {
this._super(parent);
this.fields = _(fields).chain()
diff --git a/addons/web/static/src/js/view_tree.js b/addons/web/static/src/js/view_tree.js
index a71e4010fcf..2a314f57fa8 100644
--- a/addons/web/static/src/js/view_tree.js
+++ b/addons/web/static/src/js/view_tree.js
@@ -6,16 +6,24 @@ openerp.web.view_tree = function(openerp) {
var QWeb = openerp.web.qweb;
openerp.web.views.add('tree', 'openerp.web.TreeView');
-/**
- * Genuine tree view (the one displayed as a tree, not the list)
- */
-openerp.web.TreeView = openerp.web.View.extend({
+openerp.web.TreeView = openerp.web.View.extend(/** @lends openerp.web.TreeView# */{
/**
* Indicates that this view is not searchable, and thus that no search
* view should be displayed (if there is one active).
*/
searchable : false,
-
+ /**
+ * Genuine tree view (the one displayed as a tree, not the list)
+ *
+ * @constructs openerp.web.TreeView
+ * @extends openerp.web.View
+ *
+ * @param parent
+ * @param element_id
+ * @param dataset
+ * @param view_id
+ * @param options
+ */
init: function(parent, element_id, dataset, view_id, options) {
this._super(parent, element_id);
this.dataset = dataset;
diff --git a/addons/web/static/src/js/views.js b/addons/web/static/src/js/views.js
index 5e211d0b0cd..258ea92ad03 100644
--- a/addons/web/static/src/js/views.js
+++ b/addons/web/static/src/js/views.js
@@ -115,7 +115,7 @@ openerp.web.ActionManager = openerp.web.Widget.extend({
var self = this;
this.rpc('/web/action/run', {
action_id: action.id,
- context: {active_id: 66, active_ids: [66], active_model: 'ir.ui.menu'}
+ context: action.context || {}
}).then(function (action) {
self.do_action(action, on_closed)
});
@@ -135,8 +135,17 @@ openerp.web.ActionManager = openerp.web.Widget.extend({
}
});
-openerp.web.ViewManager = openerp.web.Widget.extend({
+openerp.web.ViewManager = openerp.web.Widget.extend(/** @lends openerp.web.ViewManager# */{
identifier_prefix: "viewmanager",
+ template: "ViewManager",
+ /**
+ * @constructs openerp.web.ViewManager
+ * @extends openerp.web.Widget
+ *
+ * @param parent
+ * @param dataset
+ * @param views
+ */
init: function(parent, dataset, views) {
this._super(parent);
this.model = dataset.model;
@@ -149,7 +158,7 @@ openerp.web.ViewManager = openerp.web.Widget.extend({
this.registry = openerp.web.views;
},
render: function() {
- return QWeb.render("ViewManager", {"prefix": this.element_id, views: this.views_src})
+ return QWeb.render(this.template, {"prefix": this.element_id, views: this.views_src})
},
/**
* @returns {jQuery.Deferred} initial view loading promise
@@ -289,7 +298,8 @@ openerp.web.ViewManager = openerp.web.Widget.extend({
});
openerp.web.ViewManagerAction = openerp.web.ViewManager.extend({
- init: function(parent, action) {
+ template: "ViewManagerAction",
+ init: function(parent, action) {
this.session = parent.session;
this.action = action;
var dataset;
@@ -444,6 +454,7 @@ openerp.web.Sidebar = openerp.web.Widget.extend({
if (item.action) {
var ids = self.widget_parent.get_selected_ids();
if (ids.length == 0) {
+ //TODO: make prettier warning?
$("<div />").text(_t("You must choose at least one record.")).dialog({
title: _t("Warning"),
modal: true
@@ -616,7 +627,11 @@ openerp.web.TranslateDialog = openerp.web.Dialog.extend({
}
});
-openerp.web.View = openerp.web.Widget.extend({
+/**
+ * @class
+ * @extends openerp.web.Widget
+ */
+openerp.web.View = openerp.web.Widget.extend(/** @lends openerp.web.View# */{
set_default_options: function(options) {
this.options = options || {};
_.defaults(this.options, {
@@ -656,6 +671,7 @@ openerp.web.View = openerp.web.Widget.extend({
active_ids: [record_id || false],
active_model: dataset.model
});
+ action.context = new openerp.web.CompoundContext(dataset.get_context(), action.context);
self.do_action(action, on_closed);
} else if (on_closed) {
on_closed(action);