summaryrefslogtreecommitdiff
path: root/addons/web/static/src
diff options
context:
space:
mode:
authorChristophe Simonis <chs@openerp.com>2012-11-28 14:56:44 +0100
committerChristophe Simonis <chs@openerp.com>2012-11-28 14:56:44 +0100
commit79b2e72f07fc5843f682650ba16ea8dbb62b0713 (patch)
tree1614e442bb57823535dcb7bfb9ea38e97f33942b /addons/web/static/src
parente7b2ec50fe8b719d6fae13737e8c34e54eb520ab (diff)
parent2b7559316818906733d0437c05d47cd8c74b2459 (diff)
merge upstream
bzr revid: chs@openerp.com-20121123165044-n5l5nqtm678abb2s bzr revid: chs@openerp.com-20121128135644-iuiynfijiue67uth
Diffstat (limited to 'addons/web/static/src')
-rw-r--r--addons/web/static/src/css/base.css130
-rw-r--r--addons/web/static/src/css/base.sass104
-rw-r--r--addons/web/static/src/img/view_empty_arrow.pngbin4157 -> 2531 bytes
-rw-r--r--addons/web/static/src/js/chrome.js109
-rw-r--r--addons/web/static/src/js/corelib.js148
-rw-r--r--addons/web/static/src/js/coresetup.js5
-rw-r--r--addons/web/static/src/js/search.js14
-rw-r--r--addons/web/static/src/js/view_form.js36
-rw-r--r--addons/web/static/src/js/view_list.js31
-rw-r--r--addons/web/static/src/js/view_list_editable.js6
-rw-r--r--addons/web/static/src/js/views.js25
-rw-r--r--addons/web/static/src/xml/base.xml51
12 files changed, 397 insertions, 262 deletions
diff --git a/addons/web/static/src/css/base.css b/addons/web/static/src/css/base.css
index 9effff12226..9a92d5b7e8b 100644
--- a/addons/web/static/src/css/base.css
+++ b/addons/web/static/src/css/base.css
@@ -652,7 +652,7 @@
cursor: pointer;
}
.openerp .oe_dropdown_toggle {
- color: rgba(0, 0, 0, 0.3);
+ color: #4C4C4C;
font-weight: normal;
}
.openerp .oe_dropdown_hover:hover .oe_dropdown_menu, .openerp .oe_dropdown_menu.oe_opened {
@@ -817,8 +817,6 @@
padding: 0 0 4px 0;
}
.openerp .oe_login button {
- float: right;
- display: inline-block;
cursor: pointer;
padding: 6px 16px;
border: 1px solid #222222;
@@ -1397,60 +1395,6 @@
.openerp .oe_view_manager table.oe_view_manager_header .oe_view_manager_buttons {
white-space: nowrap;
}
-.openerp .oe_view_manager .oe_view_manager_pager {
- line-height: 26px;
-}
-.openerp .oe_view_manager .oe_view_manager_pager .oe_list_pager_single_page .oe_pager_group {
- display: none;
-}
-.openerp .oe_view_manager .oe_pager_value {
- float: left;
- margin-right: 8px;
-}
-.openerp .oe_view_manager ul.oe_pager_group {
- padding: 0;
- margin: 0;
-}
-.openerp .oe_view_manager .oe_pager_group {
- float: left;
- height: 24px;
- line-height: 24px;
- display: inline-block;
- border: 1px solid #ababab;
- cursor: pointer;
- -moz-border-radius: 5px;
- -webkit-border-radius: 5px;
- border-radius: 5px;
-}
-.openerp .oe_view_manager .oe_pager_group li {
- height: 24px;
- line-height: 24px;
- padding: 0;
- margin: 0;
- list-style-type: none;
- float: left;
- border-right: 1px solid #ababab;
-}
-.openerp .oe_view_manager .oe_pager_group li:last-child {
- border: none;
-}
-.openerp .oe_view_manager .oe_pager_group a {
- color: #4c4c4c;
- padding: 0 8px;
-}
-.openerp .oe_view_manager .oe_pager_group a:hover {
- text-decoration: none;
-}
-.openerp .oe_view_manager .oe_pager_group .active {
- background: #999999;
- -moz-box-shadow: 0 1px 4px rgba(0, 0, 0, 0.3) inset;
- -webkit-box-shadow: 0 1px 4px rgba(0, 0, 0, 0.3) inset;
- box-shadow: 0 1px 4px rgba(0, 0, 0, 0.3) inset;
-}
-.openerp .oe_view_manager .oe_pager_group .active a {
- color: white;
- text-shadow: 0 1px 2px rgba(0, 0, 0, 0.4);
-}
.openerp .oe_view_manager .oe_view_manager_switch {
padding: 0;
margin: 0 0 0 8px;
@@ -1499,6 +1443,60 @@
.openerp .oe_view_manager .oe_view_manager_switch .oe_vm_switch_diagram:after {
content: "f";
}
+.openerp .oe_list_pager {
+ line-height: 26px;
+}
+.openerp .oe_pager_value {
+ float: left;
+ margin-right: 8px;
+}
+.openerp ul.oe_pager_group {
+ padding: 0;
+ margin: 0;
+}
+.openerp .oe_pager_group {
+ float: left;
+ height: 24px;
+ line-height: 24px;
+ display: inline-block;
+ border: 1px solid #ababab;
+ cursor: pointer;
+ -moz-border-radius: 5px;
+ -webkit-border-radius: 5px;
+ border-radius: 5px;
+}
+.openerp .oe_pager_group li {
+ height: 24px;
+ line-height: 24px;
+ padding: 0;
+ margin: 0;
+ list-style-type: none;
+ float: left;
+ border-right: 1px solid #ababab;
+}
+.openerp .oe_pager_group li:last-child {
+ border: none;
+}
+.openerp .oe_pager_group a {
+ color: #4c4c4c;
+ padding: 0 8px;
+}
+.openerp .oe_pager_group a:hover {
+ text-decoration: none;
+}
+.openerp .oe_pager_group .active {
+ background: #999999;
+ -moz-box-shadow: 0 1px 4px rgba(0, 0, 0, 0.3) inset;
+ -webkit-box-shadow: 0 1px 4px rgba(0, 0, 0, 0.3) inset;
+ box-shadow: 0 1px 4px rgba(0, 0, 0, 0.3) inset;
+}
+.openerp .oe_pager_group .active a {
+ color: white;
+ text-shadow: 0 1px 2px rgba(0, 0, 0, 0.4);
+}
+.openerp .oe_list_pager.oe_list_pager_single_page .oe_pager_group {
+ display: none;
+}
.openerp .oe_view_manager_current {
height: 100%;
}
@@ -1530,6 +1528,9 @@
.openerp .oe_popup_form > .oe_formview > .oe_form_pager {
display: none !important;
}
+.openerp .oe_popup_list_pager {
+ float: right;
+}
.openerp .oe_searchview {
cursor: text;
position: relative;
@@ -1852,6 +1853,7 @@
padding: 0;
}
.openerp .oe_searchview .oe_searchview_drawer .oe_searchview_advanced li {
+ cursor: pointer;
position: relative;
list-style: none;
margin: 0;
@@ -1918,14 +1920,22 @@
max-width: 700px;
}
.openerp .oe_view_nocontent .oe_view_nocontent_create {
- background: transparent url(/web/static/src/img/view_empty_arrow.png) no-repeat 7px 0;
margin-top: 0;
padding-top: 35px;
- min-height: 28px;
color: #4c4c4c;
}
+.openerp .oe_view_nocontent .oe_view_nocontent_create:before {
+ content: "";
+ display: inline-block;
+ position: absolute;
+ width: 70px;
+ height: 80px;
+ margin-left: -70px;
+ margin-top: -50px;
+ background: transparent url(/web/static/src/img/view_empty_arrow.png) no-repeat 0px 0px;
+}
.openerp .oe_view_nocontent > p {
- padding-left: 95px;
+ padding-left: 78px;
}
.openerp .oe_view_nocontent .oe_empty_custom_dashboard {
background: transparent url(/web/static/src/img/graph_background.png) no-repeat 0 0;
diff --git a/addons/web/static/src/css/base.sass b/addons/web/static/src/css/base.sass
index 9211aec7b0c..d3c3b2d57bf 100644
--- a/addons/web/static/src/css/base.sass
+++ b/addons/web/static/src/css/base.sass
@@ -564,7 +564,7 @@ $sheet-padding: 16px
position: relative
cursor: pointer
.oe_dropdown_toggle
- color: rgba(0,0,0,0.3)
+ color: #4C4C4C
font-weight: normal
.oe_dropdown_hover:hover .oe_dropdown_menu, .oe_dropdown_menu.oe_opened
display: block
@@ -695,8 +695,6 @@ $sheet-padding: 16px
list-style-type: none
padding: 0 0 4px 0
button
- float: right
- display: inline-block
cursor: pointer
padding: 6px 16px
border: 1px solid #222
@@ -1130,47 +1128,6 @@ $sheet-padding: 16px
.oe_view_manager_buttons
white-space: nowrap
// }}}
- // ViewManager.pager {{{
- .oe_view_manager_pager
- line-height: 26px
- .oe_list_pager_single_page .oe_pager_group
- display: none
- .oe_pager_value
- float: left
- margin-right: 8px
- ul.oe_pager_group
- padding: 0
- margin: 0
- .oe_pager_group
- float: left
- height: 24px
- line-height: 24px
- display: inline-block
- border: 1px solid #ababab
- cursor: pointer
- @include radius(5px)
- li
- height: 24px
- line-height: 24px
- padding: 0
- margin: 0
- list-style-type: none
- float: left
- border-right: 1px solid #ababab
- &:last-child
- border: none
- a
- color: #4c4c4c
- padding: 0 8px
- &:hover
- text-decoration: none
- .active
- background: #999
- @include box-shadow(0 1px 4px rgba(0,0,0,0.3) inset)
- a
- color: #fff
- text-shadow: 0 1px 2px rgba(0,0,0,0.4)
- // }}}
// ViewManager.switches {{{
.oe_view_manager_switch
padding: 0
@@ -1211,6 +1168,47 @@ $sheet-padding: 16px
.oe_vm_switch_diagram:after
content: "f"
// }}}
+ // List pager {{{
+ .oe_list_pager
+ line-height: 26px
+ .oe_pager_value
+ float: left
+ margin-right: 8px
+ ul.oe_pager_group
+ padding: 0
+ margin: 0
+ .oe_pager_group
+ float: left
+ height: 24px
+ line-height: 24px
+ display: inline-block
+ border: 1px solid #ababab
+ cursor: pointer
+ @include radius(5px)
+ li
+ height: 24px
+ line-height: 24px
+ padding: 0
+ margin: 0
+ list-style-type: none
+ float: left
+ border-right: 1px solid #ababab
+ &:last-child
+ border: none
+ a
+ color: #4c4c4c
+ padding: 0 8px
+ &:hover
+ text-decoration: none
+ .active
+ background: #999
+ @include box-shadow(0 1px 4px rgba(0,0,0,0.3) inset)
+ a
+ color: #fff
+ text-shadow: 0 1px 2px rgba(0,0,0,0.4)
+ .oe_list_pager.oe_list_pager_single_page .oe_pager_group
+ display: none
+ // }}}
// ViewManager application {{{
.oe_view_manager_current
height: 100%
@@ -1231,9 +1229,11 @@ $sheet-padding: 16px
> .oe_view_manager_header
display: none
// }}}
- // Viewmanager popup {{{
+ // FormPopup {{{
.oe_popup_form > .oe_formview > .oe_form_pager
display: none !important
+ .oe_popup_list_pager
+ float: right
// }}}
// SearchView {{{
.oe_searchview
@@ -1480,6 +1480,7 @@ $sheet-padding: 16px
list-style: none
padding: 0
li
+ cursor: pointer
position: relative
list-style: none
margin: 0
@@ -1542,13 +1543,20 @@ $sheet-padding: 16px
font-size: 125%
max-width: 700px
.oe_view_nocontent_create
- background: transparent url(/web/static/src/img/view_empty_arrow.png) no-repeat 7px 0
margin-top: 0
padding-top: 35px
- min-height: 28px
color: #4c4c4c
+ &:before
+ content: ""
+ display: inline-block
+ position: absolute
+ width: 70px
+ height: 80px
+ margin-left: -70px
+ margin-top: -50px
+ background: transparent url(/web/static/src/img/view_empty_arrow.png) no-repeat 0px 0px
> p
- padding-left: 95px
+ padding-left: 78px
.oe_empty_custom_dashboard
background: transparent url(/web/static/src/img/graph_background.png) no-repeat 0 0
margin-top: -15px
diff --git a/addons/web/static/src/img/view_empty_arrow.png b/addons/web/static/src/img/view_empty_arrow.png
index ef8f3c820d7..99561e3abf3 100644
--- a/addons/web/static/src/img/view_empty_arrow.png
+++ b/addons/web/static/src/img/view_empty_arrow.png
Binary files differ
diff --git a/addons/web/static/src/js/chrome.js b/addons/web/static/src/js/chrome.js
index 878e1bc41a5..2e31b905b31 100644
--- a/addons/web/static/src/js/chrome.js
+++ b/addons/web/static/src/js/chrome.js
@@ -52,8 +52,29 @@ instance.web.dialog = function(element) {
return result;
};
+/**
+ A useful class to handle dialogs.
+
+ Attributes:
+ - $buttons: A jQuery element targeting a dom part where buttons can be added. It always exists
+ during the lifecycle of the dialog.
+*/
instance.web.Dialog = instance.web.Widget.extend({
dialog_title: "",
+ /**
+ Constructor.
+
+ @param {Widget} parent
+ @param {dictionary} options A dictionary that will be forwarded to jQueryUI Dialog. Additionaly, that
+ dictionary can contain the following keys:
+ - buttons: Deprecated. The buttons key is not propagated to jQueryUI Dialog. It must be a dictionary (key = button
+ label, value = click handler) or a list of dictionaries (each element in the dictionary is send to the
+ corresponding method of a jQuery element targeting the <button> tag). It is deprecated because all dialogs
+ in OpenERP must be personalized in some way (button in red, link instead of button, ...) and this
+ feature does not allow that kind of personalization.
+ - destroy_on_close: Default true. If true and the dialog is closed, it is automatically destroyed.
+ @param {jQuery object} content Some content to replace this.$el .
+ */
init: function (parent, options, content) {
var self = this;
this._super(parent);
@@ -83,9 +104,9 @@ instance.web.Dialog = instance.web.Widget.extend({
this.on("closing", this, this._closing);
this.$buttons = $('<div class="ui-dialog-buttonpane ui-widget-content ui-helper-clearfix"><span class="oe_dialog_custom_buttons"/></div>');
},
- _get_options: function(options) {
+ _get_options: function() {
var self = this;
- var o = _.extend({}, this.dialog_options, options || {});
+ var o = _.extend({}, this.dialog_options);
var sizes = {
width: $(window.top).width(),
height: $(window.top).height(),
@@ -121,20 +142,17 @@ instance.web.Dialog = instance.web.Widget.extend({
this._super();
}
},
- open: function(options) {
- var o = this._get_options(options);
- if (o.buttons) {
- this._add_buttons(o.buttons);
- delete(o.buttons);
- }
+ /**
+ Opens the popup. Inits the dialog if it is not already inited.
+
+ @return this
+ */
+ open: function() {
if (!this.dialog_inited) {
- this.init_dialog(o);
+ this.init_dialog();
}
- instance.web.dialog(this.$el, o).dialog('open');
+ this.$el.dialog('open');
this.$el.dialog("widget").append(this.$buttons);
- if (o.height === 'auto' && o.max_height) {
- this.$el.css({ 'max-height': o.max_height, 'overflow-y': 'auto' });
- }
return this;
},
_add_buttons: function(buttons) {
@@ -153,13 +171,29 @@ instance.web.Dialog = instance.web.Widget.extend({
});
});
},
- init_dialog: function(options) {
+ /**
+ Initializes the popup.
+
+ @return The result returned by start().
+ */
+ init_dialog: function() {
+ var options = this._get_options();
+ if (options.buttons) {
+ this._add_buttons(options.buttons);
+ delete(options.buttons);
+ }
this.renderElement();
instance.web.dialog(this.$el, options);
+ if (options.height === 'auto' && options.max_height) {
+ this.$el.css({ 'max-height': options.max_height, 'overflow-y': 'auto' });
+ }
this.dialog_inited = true;
var res = this.start();
return res;
},
+ /**
+ Closes the popup, if destroy_on_close was passed to the constructor, it is also destroyed.
+ */
close: function() {
if (this.dialog_inited && this.$el.is(":data(dialog)")) {
this.$el.dialog('close');
@@ -174,6 +208,9 @@ instance.web.Dialog = instance.web.Widget.extend({
this.__tmp_dialog_closing = undefined;
}
},
+ /**
+ Destroys the popup, also closes it.
+ */
destroy: function () {
this.$buttons.remove();
_.each(this.getChildren(), function(el) {
@@ -729,20 +766,24 @@ instance.web.ChangePassword = instance.web.Widget.extend({
template: "ChangePassword",
start: function() {
var self = this;
- self.$el.validate({
- submitHandler: function (form) {
- self.rpc("/web/session/change_password",{
- 'fields': $(form).serializeArray()
- }).done(function(result) {
- if (result.error) {
- self.display_error(result);
- return;
- } else {
- instance.webclient.on_logout();
- }
- });
- }
- });
+ this.getParent().dialog_title = "Change Password";
+ var $button = self.$el.find('.oe_form_button');
+ $button.appendTo(this.getParent().$buttons);
+ $button.eq(2).click(function(){
+ self.getParent().close();
+ })
+ $button.eq(0).click(function(){
+ self.rpc("/web/session/change_password",{
+ 'fields': $("form[name=change_password_form]").serializeArray()
+ }).done(function(result) {
+ if (result.error) {
+ self.display_error(result);
+ return;
+ } else {
+ instance.webclient.on_logout();
+ }
+ });
+ })
},
display_error: function (error) {
return instance.web.dialog($('<div>'), {
@@ -949,6 +990,14 @@ instance.web.UserMenu = instance.web.Widget.extend({
if(res.company_id[0] > 1)
topbar_name = _.str.sprintf("%s (%s)", topbar_name, res.company_id[1]);
self.$el.find('.oe_topbar_name').text(topbar_name);
+ if(!instance.session.debug) {
+ self.rpc("/web/database/get_list", {}).done( function(result) {
+ if (result.length > 1) {
+ topbar_name = _.str.sprintf("%s (%s)", topbar_name, instance.session.db);
+ }
+ self.$el.find('.oe_topbar_name').text(topbar_name);
+ });
+ }
var avatar_src = self.session.url('/web/binary/image', {model:'res.users', field: 'image_small', id: self.session.uid});
$avatar.attr('src', avatar_src);
});
@@ -1058,9 +1107,7 @@ instance.web.WebClient = instance.web.Client.extend({
start: function() {
var self = this;
return $.when(this._super()).then(function() {
- self.$el.on('click', '.oe_logo', function() {
- self.action_manager.do_action('home');
- });
+ self.$(".oe_logo").attr("href", $.param.fragment("" + window.location, "", 2).slice(0, -1));
if (jQuery.param !== undefined && jQuery.deparam(jQuery.param.querystring()).kitten !== undefined) {
$("body").addClass("kitten-mode-activated");
if ($.blockUI) {
diff --git a/addons/web/static/src/js/corelib.js b/addons/web/static/src/js/corelib.js
index 06b3940f1e1..0a6f4ed3a29 100644
--- a/addons/web/static/src/js/corelib.js
+++ b/addons/web/static/src/js/corelib.js
@@ -430,6 +430,85 @@ instance.web.PropertiesMixin = _.extend({}, instance.web.EventDispatcherMixin, {
// Classes
/**
+ A class containing common utility methods useful when working with OpenERP as well as the PropertiesMixin.
+*/
+instance.web.Controller = instance.web.Class.extend(instance.web.PropertiesMixin, {
+ /**
+ * Constructs the object and sets its parent if a parent is given.
+ *
+ * @param {instance.web.Controller} parent Binds the current instance to the given Controller instance.
+ * When that controller is destroyed by calling destroy(), the current instance will be
+ * destroyed too. Can be null.
+ */
+ init: function(parent) {
+ instance.web.PropertiesMixin.init.call(this);
+ this.setParent(parent);
+ },
+ /**
+ * Proxies a method of the object, in order to keep the right ``this`` on
+ * method invocations.
+ *
+ * This method is similar to ``Function.prototype.bind`` or ``_.bind``, and
+ * even more so to ``jQuery.proxy`` with a fundamental difference: its
+ * resolution of the method being called is lazy, meaning it will use the
+ * method as it is when the proxy is called, not when the proxy is created.
+ *
+ * Other methods will fix the bound method to what it is when creating the
+ * binding/proxy, which is fine in most javascript code but problematic in
+ * OpenERP Web where developers may want to replace existing callbacks with
+ * theirs.
+ *
+ * The semantics of this precisely replace closing over the method call.
+ *
+ * @param {String|Function} method function or name of the method to invoke
+ * @returns {Function} proxied method
+ */
+ proxy: function (method) {
+ var self = this;
+ return function () {
+ var fn = (typeof method === 'string') ? self[method] : method;
+ return fn.apply(self, arguments);
+ }
+ },
+ /**
+ * Informs the action manager to do an action. This supposes that
+ * the action manager can be found amongst the ancestors of the current widget.
+ * If that's not the case this method will simply return `false`.
+ */
+ do_action: function() {
+ var parent = this.getParent();
+ if (parent) {
+ return parent.do_action.apply(parent, arguments);
+ }
+ return false;
+ },
+ do_notify: function() {
+ if (this.getParent()) {
+ return this.getParent().do_notify.apply(this,arguments);
+ }
+ return false;
+ },
+ do_warn: function() {
+ if (this.getParent()) {
+ return this.getParent().do_warn.apply(this,arguments);
+ }
+ return false;
+ },
+ rpc: function(url, data, options) {
+ var def = $.Deferred();
+ var self = this;
+ instance.session.rpc(url, data, options).done(function() {
+ if (!self.isDestroyed())
+ def.resolve.apply(def, arguments);
+ }).fail(function() {
+ if (!self.isDestroyed())
+ def.reject.apply(def, arguments);
+ });
+ return def.promise();
+ }
+});
+
+/**
* Base class for all visual components. Provides a lot of functionalities helpful
* for the management of a part of the DOM.
*
@@ -477,7 +556,7 @@ instance.web.PropertiesMixin = _.extend({}, instance.web.EventDispatcherMixin, {
*
* That will kill the widget in a clean way and erase its content from the dom.
*/
-instance.web.Widget = instance.web.Class.extend(instance.web.PropertiesMixin, {
+instance.web.Widget = instance.web.Controller.extend({
// Backbone-ish API
tagName: 'div',
id: null,
@@ -501,8 +580,7 @@ instance.web.Widget = instance.web.Class.extend(instance.web.PropertiesMixin, {
* destroyed too. Can be null.
*/
init: function(parent) {
- instance.web.PropertiesMixin.init.call(this);
- this.setParent(parent);
+ this._super(parent);
// Bind on_/do_* methods to this
// We might remove this automatic binding in the future
for (var name in this) {
@@ -605,32 +683,6 @@ instance.web.Widget = instance.web.Class.extend(instance.web.PropertiesMixin, {
return $.when();
},
/**
- * Proxies a method of the object, in order to keep the right ``this`` on
- * method invocations.
- *
- * This method is similar to ``Function.prototype.bind`` or ``_.bind``, and
- * even more so to ``jQuery.proxy`` with a fundamental difference: its
- * resolution of the method being called is lazy, meaning it will use the
- * method as it is when the proxy is called, not when the proxy is created.
- *
- * Other methods will fix the bound method to what it is when creating the
- * binding/proxy, which is fine in most javascript code but problematic in
- * OpenERP Web where developers may want to replace existing callbacks with
- * theirs.
- *
- * The semantics of this precisely replace closing over the method call.
- *
- * @param {String|Function} method function or name of the method to invoke
- * @returns {Function} proxied method
- */
- proxy: function (method) {
- var self = this;
- return function () {
- var fn = (typeof method === 'string') ? self[method] : method;
- return fn.apply(self, arguments);
- }
- },
- /**
* Renders the element. The default implementation renders the widget using QWeb,
* `this.template` must be defined. The context given to QWeb contains the "widget"
* key that references `this`.
@@ -749,42 +801,6 @@ instance.web.Widget = instance.web.Class.extend(instance.web.PropertiesMixin, {
*/
$: function(selector) {
return this.$el.find(selector);
- },
- /**
- * Informs the action manager to do an action. This supposes that
- * the action manager can be found amongst the ancestors of the current widget.
- * If that's not the case this method will simply return `false`.
- */
- do_action: function() {
- var parent = this.getParent();
- if (parent) {
- return parent.do_action.apply(parent, arguments);
- }
- return false;
- },
- do_notify: function() {
- if (this.getParent()) {
- return this.getParent().do_notify.apply(this,arguments);
- }
- return false;
- },
- do_warn: function() {
- if (this.getParent()) {
- return this.getParent().do_warn.apply(this,arguments);
- }
- return false;
- },
- rpc: function(url, data, options) {
- var def = $.Deferred();
- var self = this;
- instance.session.rpc(url, data, options).done(function() {
- if (!self.isDestroyed())
- def.resolve.apply(def, arguments);
- }).fail(function() {
- if (!self.isDestroyed())
- def.reject.apply(def, arguments);
- });
- return def.promise();
}
});
@@ -974,7 +990,7 @@ instance.web.JsonRPC = instance.web.Class.extend(instance.web.PropertiesMixin, {
};
date.today = new py.def(function () {
var d = new Date();
- return new date(d.getUTCFullYear(), d.getUTCMonth() + 1, d.getUTCDate());
+ return new date(d.getFullYear(), d.getMonth() + 1, d.getDate());
});
datetime.time = new py.type(function time() {
throw new Error('datetime.time not implemented');
diff --git a/addons/web/static/src/js/coresetup.js b/addons/web/static/src/js/coresetup.js
index a740827c1b5..5ca44c1d80b 100644
--- a/addons/web/static/src/js/coresetup.js
+++ b/addons/web/static/src/js/coresetup.js
@@ -125,6 +125,9 @@ instance.web.Session = instance.web.JsonRPC.extend( /** @lends instance.web.Sess
},
session_logout: function() {
this.set_cookie('session_id', '');
+ var url = "#";
+ $.bbq.pushState(url);
+ window.location.search = "";
return this.rpc("/web/session/destroy", {});
},
get_cookie: function (name) {
@@ -549,12 +552,12 @@ 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.session.debug; // Which one ?
instance.web.qweb.debug = instance.session.debug;
instance.web.qweb.default_dict = {
'_' : _,
'_t' : instance.web._t,
'JSON': JSON,
+ '__debug__': instance.session.debug,
};
instance.web.qweb.preprocess_node = function() {
// Note that 'this' is the Qweb Node
diff --git a/addons/web/static/src/js/search.js b/addons/web/static/src/js/search.js
index 0f25b2484c3..88d45793173 100644
--- a/addons/web/static/src/js/search.js
+++ b/addons/web/static/src/js/search.js
@@ -1893,6 +1893,9 @@ instance.web.search.ExtendedSearchProposition.DateTime = instance.web.search.Ext
get_value: function() {
return this.datewidget.get_value();
},
+ toString: function () {
+ return instance.web.format_value(this.get_value(), { type:"datetime" });
+ },
start: function() {
var ready = this._super();
this.datewidget = new (this.widget())(this);
@@ -1901,7 +1904,10 @@ instance.web.search.ExtendedSearchProposition.DateTime = instance.web.search.Ext
}
});
instance.web.search.ExtendedSearchProposition.Date = instance.web.search.ExtendedSearchProposition.DateTime.extend({
- widget: function () { return instance.web.DateWidget; }
+ widget: function () { return instance.web.DateWidget; },
+ toString: function () {
+ return instance.web.format_value(this.get_value(), { type:"date" });
+ }
});
instance.web.search.ExtendedSearchProposition.Integer = instance.web.search.ExtendedSearchProposition.Field.extend({
template: 'SearchView.extended_search.proposition.integer',
@@ -1918,7 +1924,8 @@ instance.web.search.ExtendedSearchProposition.Integer = instance.web.search.Exte
},
get_value: function() {
try {
- return instance.web.parse_value(this.$el.val(), {'widget': 'integer'});
+ var val =this.$el.val();
+ return instance.web.parse_value(val == "" ? 0 : val, {'widget': 'integer'});
} catch (e) {
return "";
}
@@ -1942,7 +1949,8 @@ instance.web.search.ExtendedSearchProposition.Float = instance.web.search.Extend
},
get_value: function() {
try {
- return instance.web.parse_value(this.$el.val(), {'widget': 'float'});
+ var val =this.$el.val();
+ return instance.web.parse_value(val == "" ? 0.0 : val, {'widget': 'float'});
} catch (e) {
return "";
}
diff --git a/addons/web/static/src/js/view_form.js b/addons/web/static/src/js/view_form.js
index d7b3a6805d9..927d585a5be 100644
--- a/addons/web/static/src/js/view_form.js
+++ b/addons/web/static/src/js/view_form.js
@@ -195,7 +195,6 @@ instance.web.FormView = instance.web.View.extend(instance.web.form.FieldManagerM
this.sidebar.add_items('other', _.compact([
self.is_action_enabled('delete') && { label: _t('Delete'), callback: self.on_button_delete },
self.is_action_enabled('create') && { label: _t('Duplicate'), callback: self.on_button_duplicate },
- { label: _t('Set Default'), callback: function (item) { self.open_defaults_dialog(); } }
]));
}
@@ -1034,7 +1033,8 @@ instance.web.FormView = instance.web.View.extend(instance.web.form.FieldManagerM
|| field.get("readonly")
|| field.field.type === 'one2many'
|| field.field.type === 'many2many'
- || field.field.type === 'binary') {
+ || field.field.type === 'binary'
+ || field.password) {
return false;
}
@@ -1682,11 +1682,11 @@ instance.web.form.compute_domain = function(expr, fields) {
switch (op.toLowerCase()) {
case '=':
case '==':
- stack.push(field_value == val);
+ stack.push(_.isEqual(field_value, val));
break;
case '!=':
case '<>':
- stack.push(field_value != val);
+ stack.push(!_.isEqual(field_value, val));
break;
case '<':
stack.push(field_value < val);
@@ -2247,7 +2247,9 @@ instance.web.form.FieldChar = instance.web.form.AbstractField.extend(instance.we
var self = this;
var $input = this.$el.find('input');
$input.change(function() {
- self.internal_set_value(self.parse_value($input.val()));
+ if(self.is_syntax_valid()){
+ self.internal_set_value(self.parse_value($input.val()));
+ }
});
this.setupFocus($input);
},
@@ -4026,6 +4028,9 @@ instance.web.form.FieldMany2ManyTags = instance.web.form.AbstractField.extend(in
}
this._super(value_);
},
+ is_false: function() {
+ return _(this.get("value")).isEmpty();
+ },
get_value: function() {
var tmp = [commands.replace_with(this.get("value"))];
return tmp;
@@ -4236,16 +4241,14 @@ instance.web.form.FieldMany2ManyKanban = instance.web.form.AbstractField.extend(
var self = this;
self.load_view();
- this.is_loaded.done(function() {
- self.on("change:effective_readonly", self, function() {
- self.is_loaded = self.is_loaded.then(function() {
- self.kanban_view.destroy();
- return $.when(self.load_view()).done(function() {
- self.render_value();
- });
+ self.on("change:effective_readonly", self, function() {
+ self.is_loaded = self.is_loaded.then(function() {
+ self.kanban_view.destroy();
+ return $.when(self.load_view()).done(function() {
+ self.render_value();
});
});
- })
+ });
},
set_value: function(value_) {
value_ = value_ || [];
@@ -4629,6 +4632,7 @@ instance.web.form.SelectCreatePopup = instance.web.form.AbstractFormPopup.extend
'import_enabled': false,
'$buttons': self.$buttonpane,
'disable_editable_mode': true,
+ '$pager': self.$('.oe_popup_list_pager'),
}, self.options.list_view_options || {}));
self.view_list.on('edit:before', self, function (e) {
e.cancel = true;
@@ -4788,6 +4792,7 @@ instance.web.form.FieldBinary = instance.web.form.AbstractField.extend(instance.
this._super(field_manager, node);
this.binary_value = false;
this.useFileAPI = !!window.FileReader;
+ this.max_upload_size = 25 * 1024 * 1024; // 25Mo
if (!this.useFileAPI) {
this.fileupload_id = _.uniqueId('oe_fileupload');
$(window).on(this.fileupload_id, function() {
@@ -4813,6 +4818,11 @@ instance.web.form.FieldBinary = instance.web.form.AbstractField.extend(instance.
if ((this.useFileAPI && file_node.files.length) || (!this.useFileAPI && $(file_node).val() !== '')) {
if (this.useFileAPI) {
var file = file_node.files[0];
+ if (file.size > this.max_upload_size) {
+ var msg = _t("The selected file exceed the maximum file size of %s.");
+ instance.webclient.notification.warn(_t("File upload"), _.str.sprintf(msg, instance.web.human_size(this.max_upload_size)));
+ return false;
+ }
var filereader = new FileReader();
filereader.readAsDataURL(file);
filereader.onloadend = function(upload) {
diff --git a/addons/web/static/src/js/view_list.js b/addons/web/static/src/js/view_list.js
index 55e3c17b494..13c41d48599 100644
--- a/addons/web/static/src/js/view_list.js
+++ b/addons/web/static/src/js/view_list.js
@@ -25,6 +25,9 @@ instance.web.ListView = instance.web.View.extend( /** @lends instance.web.ListVi
'disable_editable_mode': false,
},
view_type: 'tree',
+ events: {
+ 'click thead th.oe_sortable[data-id]': 'sort_by_column'
+ },
/**
* Core class for list-type displays.
*
@@ -264,21 +267,6 @@ instance.web.ListView = instance.web.View.extend( /** @lends instance.web.ListVi
'selected', [selection.ids, selection.records]);
});
- // Sorting columns
- this.$el.find('thead').delegate('th.oe_sortable[data-id]', 'click', function (e) {
- e.stopPropagation();
- var $this = $(this);
- self.dataset.sort($this.data('id'));
- if($this.hasClass("sortdown") || $this.hasClass("sortup")) {
- $this.toggleClass("sortdown").toggleClass("sortup");
- } else {
- $this.toggleClass("sortdown");
- }
- $this.siblings('.oe_sortable').removeClass("sortup sortdown");
-
- self.reload_content();
- });
-
// Add button
if (!this.$buttons) {
this.$buttons = $(QWeb.render("ListView.buttons", {'widget':self}));
@@ -360,6 +348,19 @@ instance.web.ListView = instance.web.View.extend( /** @lends instance.web.ListVi
}
this.trigger('list_view_loaded', data, this.grouped);
},
+ sort_by_column: function (e) {
+ e.stopPropagation();
+ var $column = $(e.currentTarget);
+ this.dataset.sort($column.data('id'));
+ if($column.hasClass("sortdown") || $column.hasClass("sortup")) {
+ $column.toggleClass("sortup sortdown");
+ } else {
+ $column.addClass("sortdown");
+ }
+ $column.siblings('.oe_sortable').removeClass("sortup sortdown");
+
+ this.reload_content();
+ },
/**
* Configures the ListView pager based on the provided dataset's information
*
diff --git a/addons/web/static/src/js/view_list_editable.js b/addons/web/static/src/js/view_list_editable.js
index db7e22e5f32..7fe6a8ec42b 100644
--- a/addons/web/static/src/js/view_list_editable.js
+++ b/addons/web/static/src/js/view_list_editable.js
@@ -63,6 +63,12 @@ openerp.web.list_editable = function (instance) {
}
this._super();
},
+ sort_by_column: function (e) {
+ e.stopPropagation();
+ if (!this.editor.is_editing()) {
+ this._super.apply(this, arguments);
+ }
+ },
/**
* Handles the activation of a record in editable mode (making a record
* editable), called *after* the record has become editable.
diff --git a/addons/web/static/src/js/views.js b/addons/web/static/src/js/views.js
index 006f6768bdd..ddedcdd2ff6 100644
--- a/addons/web/static/src/js/views.js
+++ b/addons/web/static/src/js/views.js
@@ -809,6 +809,9 @@ instance.web.ViewManagerAction = instance.web.ViewManager.extend({
case 'toggle_layout_outline':
current_view.rendering_engine.toggle_layout_debugging();
break;
+ case 'set_defaults':
+ current_view.open_defaults_dialog();
+ break;
case 'translate':
this.do_action({
name: "Technical Translation",
@@ -975,11 +978,7 @@ instance.web.Sidebar = instance.web.Widget.extend({
this.fileupload_id = _.uniqueId('oe_fileupload');
$(window).on(this.fileupload_id, function() {
var args = [].slice.call(arguments).slice(1);
- if (args[0] && args[0].error) {
- alert(args[0].error);
- } else {
- self.do_attachement_update(self.dataset, self.model_id);
- }
+ self.do_attachement_update(self.dataset, self.model_id,args);
instance.web.unblockUI();
});
},
@@ -1089,9 +1088,21 @@ instance.web.Sidebar = instance.web.Widget.extend({
});
});
},
- do_attachement_update: function(dataset, model_id) {
+ do_attachement_update: function(dataset, model_id,args) {
+ var self = this;
this.dataset = dataset;
this.model_id = model_id;
+ if (args && args[0]["erorr"]) {
+ instance.web.dialog($('<div>'),{
+ modal: true,
+ title: "OpenERP " + _.str.capitalize(args[0]["title"]),
+ buttons: [{
+ text: _t("Ok"),
+ click: function(){
+ $(this).dialog("close");
+ }}]
+ }).html(args[0]["erorr"]);
+ }
if (!model_id) {
this.on_attachments_loaded([]);
} else {
@@ -1331,7 +1342,7 @@ instance.web.View = instance.web.Widget.extend({
new instance.web.DataExport(this, this.dataset).open();
},
sidebar_eval_context: function () {
- return $.when();
+ return $.when({});
},
/**
* Asks the view to reload itself, if the reloading is asynchronous should
diff --git a/addons/web/static/src/xml/base.xml b/addons/web/static/src/xml/base.xml
index a2e7a59a989..f601afbbe41 100644
--- a/addons/web/static/src/xml/base.xml
+++ b/addons/web/static/src/xml/base.xml
@@ -71,9 +71,9 @@
</div>
<ul>
<li>Username</li>
- <li><input type="text" name="login" t-att-value="widget.selected_login || ''" autofocus="autofocus"/></li>
+ <li><input name="login" type="text" t-att-value="widget.selected_login || ''" autofocus="autofocus"/></li>
<li>Password</li>
- <li><input type="password" name="password" t-att-value="widget.selected_password || ''"/></li>
+ <li><input name="password" type="password" t-att-value="widget.selected_password || ''"/></li>
<li><button name="submit">Log in</button></li>
</ul>
</form>
@@ -98,7 +98,6 @@
</select>
</t>
-
<t t-name="DatabaseManager">
<div class="oe_view_manager_view_form">
<div class="oe_form">
@@ -315,26 +314,32 @@
<t t-name="ChangePassword">
<form name="change_password_form" method="POST">
+ <div class="oe_form">
<table align="center">
<tr>
- <td><label for="old_pwd">Old Password:</label></td>
- <td><input type="password" name="old_pwd"
+ <td class="oe_form_group_cell oe_form_group_cell_label"><label for="old_pwd" class="oe_form_label">Old Password:</label></td>
+ <td class="oe_form_group_cell"><input type="password" name="old_pwd"
minlength="1" autofocus="autofocus"/></td>
</tr>
<tr>
- <td><label for="new_password">New Password:</label></td>
- <td><input type="password" name="new_password"
+ <td class="oe_form_group_cell oe_form_group_cell_label"><label for="new_password" class="oe_form_label">New Password:</label></td>
+ <td class="oe_form_group_cell"><input type="password" name="new_password"
minlength="1"/></td>
</tr>
<tr>
- <td><label for="confirm_pwd">Confirm Password:</label></td>
- <td><input type="password" name="confirm_pwd"
+ <td class="oe_form_group_cell oe_form_group_cell_label"><label for="confirm_pwd" class="oe_form_label">Confirm New Password:</label></td>
+ <td class="oe_form_group_cell"><input type="password" name="confirm_pwd"
minlength="1"/></td>
</tr>
<tr>
- <td colspan="2" align="right"><button class="oe_button">Change Password</button></td>
+ <td colspan="2" align="right">
+ <button class='oe_button oe_form_button'>Change Password</button>
+ <span class="oe_fade oe_form_button"> or </span>
+ <button type="button" class="oe_button oe_form_button_cancel oe_form_button oe_link" href="javascript:void(0)"><span>Cancel</span></button>
+ </td>
</tr>
</table>
+ </div>
</form>
</t>
@@ -385,7 +390,7 @@
<t t-esc="menu.name"/>
<t t-if="menu.needaction_enabled and menu.needaction_counter">
<div class="oe_tag oe_tag_dark oe_menu_counter">
- <t t-esc="menu.needaction_counter"/>
+ <t t-if="menu.needaction_counter &gt; 99"> 99+ </t><t t-if="menu.needaction_counter &lt;= 99"> <t t-esc="menu.needaction_counter"/> </t>
</div>
</t>
</a>
@@ -501,8 +506,11 @@
</t>
<t t-name="ViewManagerDebug">
<option value="">Debug View#<t t-esc="view.fields_view.view_id"/></option>
- <option t-if="view_manager.active_view === 'form'" value="perm_read" data-views="form,page">View Log (perm_read)</option>
- <option t-if="view_manager.active_view === 'form'" value="toggle_layout_outline">Toggle Form Layout Outline</option>
+ <t t-if="view_manager.active_view === 'form'">
+ <option value="perm_read">View Log (perm_read)</option>
+ <option value="toggle_layout_outline">Toggle Form Layout Outline</option>
+ <option value="set_defaults">Set Defaults</option>
+ </t>
<option value="tests">JS Tests</option>
<option value="fields">View Fields</option>
<option value="fvg">Fields View Get</option>
@@ -673,13 +681,15 @@
</tr>
</tfoot>
</table>
-<div t-name="ListView.buttons" class="oe_list_buttons">
+<t t-name="ListView.buttons">
+ <div class="oe_list_buttons">
<t t-if="!widget.no_leaf and widget.options.action_buttons !== false and widget.options.addable and widget.is_action_enabled('create')">
<button type="button" class="oe_button oe_list_add oe_highlight">
<t t-esc="widget.options.addable"/>
</button>
</t>
-</div>
+ </div>
+</t>
<t t-name="ListView.pager">
<div class="oe_list_pager" t-att-colspan="widget.columns_count">
<t t-if="!widget.no_leaf and widget.options.pager !== false" t-call="ViewPager">
@@ -1025,7 +1035,7 @@
t-att-autofocus="widget.node.attrs.autofocus"
t-att-id="widget.id_for_label">
<t t-foreach="widget.values" t-as="option">
- <option><t t-esc="option[1]"/></option>
+ <option><t t-esc="widget.node.attrs.placeholder" t-if="option[0] == false and widget.node.attrs.placeholder"/><t t-esc="option[1]" t-if="option[0] != false"/></option>
</t>
</select>
</span>
@@ -1303,6 +1313,11 @@
</tr>
<tr style="width:100%">
<td style="width:100%">
+ <div class="oe_popup_list_pager"></div>
+ </td>
+ </tr>
+ <tr style="width:100%">
+ <td style="width:100%">
<div class="oe_popup_list" style="width:100%"></div>
</td>
</tr>
@@ -1589,10 +1604,10 @@
<span/>
</t>
<t t-name="SearchView.extended_search.proposition.integer">
- <input type="number" class="field_integer" step="1"/>
+ <input type="number" class="field_integer" value = "0" step="1"/>
</t>
<t t-name="SearchView.extended_search.proposition.float">
- <input type="number" class="field_float" step="0.01"/>
+ <input type="number" class="field_float" value = "0.0" step="0.01"/>
</t>
<t t-name="SearchView.extended_search.proposition.selection">
<select>