[MERGE] openerp-web

bzr revid: vda@tinyerp.com-20110622052359-n3tef8f89jo22cs9
This commit is contained in:
Vaibhav (OpenERP)
2011-06-22 10:53:59 +05:30
12 changed files with 196 additions and 80 deletions
+2 -2
View File
@@ -35,10 +35,10 @@ var QWeb2 = {
return (noquotes ? '' : "'") + s.replace(/\r?\n/g, "\\n").replace(/'/g, "\\'") + (noquotes ? '' : "'");
},
html_escape: function(s, attribute) {
if (s === null || s === undefined) {
if (s == null) {
return '';
}
s = (new String(s)).replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
s = String(s).replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
if (attribute) {
s = s.replace(/"/g, '&quot;');
}
+29 -1
View File
@@ -547,11 +547,27 @@ background: linear-gradient(top, #ffffff 0%,#d8d8d8 11%,#afafaf 86%,#333333 91%,
}
.openerp .searchview_extended_group {
border: #696969 solid 1px;
padding: 3px;
margin: 2px;
}
.openerp .searchview_extended_group .oe_adv_filters_and {
border-bottom: 1px solid #8E8E8E;
text-align: center;
margin-top: -10px;
}
.openerp .searchview_extended_group .oe_adv_filters_and span {
background: #F0EEEE;
position: relative;
top: 0.5em;
padding: 0 1em 0 1em;
color: #8E8E8E;
}
.openerp .searchview_extended_group.last_group .oe_adv_filters_and {
display: none;
}
.openerp .oe_search-view-custom-filter-btn span {
background: url(../img/icons/gtk-add.png) repeat-y;
padding-left: 18px;
@@ -565,6 +581,7 @@ background: linear-gradient(top, #ffffff 0%,#d8d8d8 11%,#afafaf 86%,#333333 91%,
.openerp .searchview_extended_delete_group {
float:right;
display: none;
}
.openerp .searchview_extended_delete_group span,
@@ -1042,3 +1059,14 @@ background: linear-gradient(top, #ffffff 0%,#ebe9e9 100%); /* W3C */
.openerp .oe-m2o-disabled-cm {
color: grey;
}
.openerp .oe-dialog-warning {
font-size: 1.2em;
font-weight: bold;
}
.openerp .oe-dialog-warning img {
float: left;
position: relative;
top: -0.5em;
margin:0 7px 7px 0;
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

+72 -38
View File
@@ -739,36 +739,47 @@ openerp.base.Dialog = openerp.base.BaseWidget.extend({
identifier_prefix: 'dialog',
init: function (session, options) {
this._super(null, session);
options = _.extend({
this.options = {
modal: true,
title: this.dialog_title,
width: '700px',
width: 'auto',
min_width: 0,
max_width: '100%',
height: '500px',
height: 'auto',
min_height: 0,
max_height: '100%',
autoOpen: false,
buttons: {}
}, options);
options.width = this.get_width(options.width);
options.min_width = this.get_width(options.min_width);
options.max_width = this.get_width(options.max_width);
options.height = this.get_height(options.height);
options.min_height = this.get_height(options.min_height);
options.max_height = this.get_height(options.max_height);
if (options.width > options.max_width) options.width = options.max_width;
if (options.width < options.min_width) options.width = options.min_width;
if (options.height > options.max_height) options.height = options.max_height;
if (options.height < options.min_height) options.height = options.min_height;
};
for (var f in this) {
if (f.substr(0, 10) == 'on_button_') {
options.buttons[f.substr(10)] = this[f];
this.options.buttons[f.substr(10)] = this[f];
}
}
this.options = options;
if (options) {
this.set_options(options);
}
},
set_options: function(options) {
options = options || {};
options.width = this.get_width(options.width || this.options.width);
options.min_width = this.get_width(options.min_width || this.options.min_width);
options.max_width = this.get_width(options.max_width || this.options.max_width);
options.height = this.get_height(options.height || this.options.height);
options.min_height = this.get_height(options.min_height || this.options.min_height);
options.max_height = this.get_height(options.max_height || this.options.max_width);
if (options.width !== 'auto') {
if (options.width > options.max_width) options.width = options.max_width;
if (options.width < options.min_width) options.width = options.min_width;
}
if (options.height !== 'auto') {
if (options.height > options.max_height) options.height = options.max_height;
if (options.height < options.min_height) options.height = options.min_height;
}
if (!options.title && this.dialog_title) {
options.title = this.dialog_title;
}
_.extend(this.options, options);
},
get_width: function(val) {
return this.get_size(val.toString(), $(window.top).width());
@@ -777,7 +788,7 @@ openerp.base.Dialog = openerp.base.BaseWidget.extend({
return this.get_size(val.toString(), $(window.top).height());
},
get_size: function(val, available_size) {
if (val == 'auto') {
if (val === 'auto') {
return val;
} else if (val.slice(-1) == "%") {
return Math.round(available_size / 100 * parseInt(val.slice(0, -1), 10));
@@ -785,33 +796,55 @@ openerp.base.Dialog = openerp.base.BaseWidget.extend({
return parseInt(val, 10);
}
},
start: function () {
start: function (auto_open) {
this.$dialog = $('<div id="' + this.element_id + '"></div>').dialog(this.options);
if (auto_open !== false) {
this.open();
}
this._super();
},
open: function(options) {
// TODO fme: bind window on resize
if (this.template) {
this.$element.html(this.render());
}
this.set_options(options);
this.$dialog.dialog(this.options).dialog('open');
},
close: function(options) {
this.$dialog.dialog('close');
},
stop: function () {
this.$dialog("destroy").remove();
this.$dialog.dialog('destroy');
}
});
openerp.base.CrashManager = openerp.base.Controller.extend({
init: function(session, element_id) {
this._super(session, element_id);
openerp.base.CrashManager = openerp.base.Dialog.extend({
identifier_prefix: 'dialog_crash',
init: function(session) {
this._super(session);
this.session.on_rpc_error.add(this.on_rpc_error);
},
on_rpc_error: function(error) {
var msg = error.message + "\n" + error.data.debug;
this.display_error(msg);
on_button_Ok: function() {
this.close();
},
display_error: function(message) {
$('<pre></pre>').text(message).dialog({
modal: true,
buttons: {
OK: function() {
$(this).dialog("close");
}
}
});
on_rpc_error: function(error) {
this.error = error;
if (error.code === 200) {
this.dialog_title = "OpenERP Warning";
this.template = 'DialogWarning';
this.open({
width: 'auto',
height: 'auto'
});
} else {
this.dialog_title = "OpenERP Error";
this.template = 'DialogTraceback';
this.open({
width: '80%',
height: '80%'
});
}
}
});
@@ -1041,6 +1074,7 @@ openerp.base.WebClient = openerp.base.Controller.extend({
this.session = new openerp.base.Session("oe_errors");
this.loading = new openerp.base.Loading(this.session, "oe_loading");
this.crashmanager = new openerp.base.CrashManager(this.session);
this.crashmanager.start(false);
// Do you autorize this ?
openerp.base.Controller.prototype.notification = new openerp.base.Notification("oe_notification");
+3 -2
View File
@@ -287,11 +287,12 @@ openerp.base.DataSet = openerp.base.Controller.extend( /** @lends openerp.base.
});
}
},
default_get: function(fields, callback) {
default_get: function(fields, context, callback) {
context = context || this.context;
return this.rpc('/base/dataset/default_get', {
model: this.model,
fields: fields,
context: this.context
context: context
}, callback);
},
create: function(data, callback, error_callback) {
+13 -4
View File
@@ -1,4 +1,3 @@
openerp.base.form = function (openerp) {
openerp.base.views.add('form', 'openerp.base.FormView');
@@ -43,8 +42,12 @@ openerp.base.FormView = openerp.base.View.extend( /** @lends openerp.base.FormV
if (this.embedded_view) {
return $.Deferred().then(this.on_loaded).resolve({fields_view: this.embedded_view});
} else {
var context = new openerp.base.CompoundContext(this.dataset.context);
if (this.view_manager.action && this.view_manager.action.context) {
context.add(this.view_manager.action.context);
}
return this.rpc("/base/formview/load", {"model": this.model, "view_id": this.view_id,
toolbar:!!this.flags.sidebar}, this.on_loaded);
toolbar:!!this.flags.sidebar, context: context}, this.on_loaded);
}
},
on_loaded: function(data) {
@@ -226,8 +229,12 @@ openerp.base.FormView = openerp.base.View.extend( /** @lends openerp.base.FormV
},
on_button_new: function() {
var self = this;
var context = new openerp.base.CompoundContext(this.dataset.context);
if (this.view_manager.action && this.view_manager.action.context) {
context.add(this.view_manager.action.context);
}
$.when(this.has_been_loaded).then(function() {
self.dataset.default_get(_.keys(self.fields_view.fields), function(result) {
self.dataset.default_get(_.keys(self.fields_view.fields), context, function(result) {
self.on_record_loaded(result.result);
});
});
@@ -299,6 +306,7 @@ openerp.base.FormView = openerp.base.View.extend( /** @lends openerp.base.FormV
if (success) {
success(r);
}
this.reload();
}
},
/**
@@ -333,6 +341,7 @@ openerp.base.FormView = openerp.base.View.extend( /** @lends openerp.base.FormV
if (success) {
success(_.extend(r, {created: true}));
}
this.reload();
}
},
do_search: function (domains, contexts, groupbys) {
@@ -995,7 +1004,7 @@ openerp.base.form.FieldSelection = openerp.base.form.Field.extend({
if (value != null && value !== false) {
this.$element.find('select').val(value);
} else {
this.$element.find('select')[0].selectedIndex = 0;
this.$element.find('select').val('false');
}
},
set_value_from_ui: function() {
+1 -1
View File
@@ -571,7 +571,7 @@ openerp.base.ListView.List = Class.extend( /** @lends openerp.base.ListView.List
this.$current.remove();
}
this.$current = this.$_element.clone(true);
this.$current.empty().append($(QWeb.render('ListView.rows', this)));
this.$current.empty().append(QWeb.render('ListView.rows', this));
},
get_fields_view: function () {
// deep copy of view
+26 -8
View File
@@ -731,6 +731,7 @@ openerp.base.search.ExtendedSearch = openerp.base.BaseWidget.extend({
var render = group.render();
this.$element.find('.searchview_extended_groups_list').append(render);
group.start();
this.check_last_element();
},
start: function () {
this._super();
@@ -758,11 +759,9 @@ openerp.base.search.ExtendedSearch = openerp.base.BaseWidget.extend({
on_activate: function() {
this.add_group();
var table = this.$element.closest("table.oe-searchview-render-line");
if(table.css("display") == "none") {
table.css("display", "");
if(this.$element.hasClass("folded")) {
this.$element.toggleClass("folded expanded");
}
table.css("display", "");
if(this.$element.hasClass("folded")) {
this.$element.toggleClass("folded expanded");
}
},
hide: function() {
@@ -771,6 +770,10 @@ openerp.base.search.ExtendedSearch = openerp.base.BaseWidget.extend({
if(this.$element.hasClass("expanded")) {
this.$element.toggleClass("folded expanded");
}
},
check_last_element: function() {
_.each(this.children, function(x) {x.set_last_group(false);});
this.children[this.children.length - 1].set_last_group(true);
}
});
@@ -796,9 +799,6 @@ openerp.base.search.ExtendedSearchGroup = openerp.base.BaseWidget.extend({
});
var delete_btn = this.$element.find('.searchview_extended_delete_group');
delete_btn.click(function (e) {
if (_this.parent.children.length == 1) {
_this.parent.hide();
}
_this.stop();
});
},
@@ -811,6 +811,19 @@ openerp.base.search.ExtendedSearchGroup = openerp.base.BaseWidget.extend({
return [].concat(choice == "none" ? ['!'] : [],
_.map(_.range(_.max([0,props.length - 1])), function() { return op; }),
props);
},
stop: function() {
var parent = this.parent;
if (this.parent.children.length == 1)
this.parent.hide();
this._super();
parent.check_last_element();
},
set_last_group: function(is_last) {
if(is_last)
this.$element.addClass("last_group");
else
this.$element.removeClass("last_group");
}
});
@@ -838,6 +851,11 @@ openerp.base.search.ExtendedSearchProposition = openerp.base.BaseWidget.extend({
_this.stop();
});
},
stop: function() {
if (this.parent.children.length == 1)
this.parent.stop();
this._super();
},
changed: function() {
var nval = this.$element.find(".searchview_extended_prop_field").val();
if(this.attrs.selected == null || nval != this.attrs.selected.name) {
+18 -6
View File
@@ -397,10 +397,22 @@ openerp.base.View = openerp.base.Controller.extend({
*/
execute_action: function (action_data, dataset, action_manager, record_id, on_no_action) {
var handler = function (r) {
if (r.result && r.result.constructor == Object) {
action_manager.do_action(r.result);
var action = r.result;
if (action && action.constructor == Object) {
action.context = action.context || {};
action.context['active_id'] = dataset.ids[dataset.index];
action.context['active_ids'] = [dataset.ids[dataset.index]];
action.context['active_model'] = dataset.model;
action.flags = {
sidebar : false,
search_view : false,
views_switcher : false,
action_buttons : false,
pager : false
};
action_manager.do_action(action);
} else {
on_no_action(r.result);
on_no_action(action);
}
};
@@ -409,12 +421,12 @@ openerp.base.View = openerp.base.Controller.extend({
result : { type: 'ir.actions.act_window_close' }
});
} else {
var context = _.extend({}, dataset.context, action_data.context || {});
var context = new openerp.base.CompoundContext(dataset.context).add(action_data.context || {});
switch(action_data.type) {
case 'object':
return dataset.call(action_data.name, [[record_id], context], handler);
return dataset.call_and_eval(action_data.name, [[record_id], context], null, 1, handler);
case 'action':
return this.rpc('/base/action/load', { action_id: parseInt(action_data.name, 10) }, handler);
return this.rpc('/base/action/load', { action_id: parseInt(action_data.name, 10), context: context }, handler);
default:
return dataset.exec_workflow(record_id, action_data.name, handler);
}
+11 -7
View File
@@ -90,7 +90,7 @@
t-att-value="selected_password || ''"/></td>
</tr>
<tr t-if="has_local_storage">
<td><label for="remember">Rember password:</label></td>
<td><label for="remember">Remember password:</label></td>
<td class="oe_remember">
<t t-if="remember">
<input type="checkbox" name="remember" checked="yes"/>
@@ -804,6 +804,7 @@
</div>
<a class="searchview_extended_add_proposition" href="javascript:void(0)">
<span>Add condition</span></a>
<div class="oe_adv_filters_and"><span>and</span></div>
</div>
</t>
<t t-name="SearchView.extended_search.proposition">
@@ -870,12 +871,15 @@
</div>
</t>
<t t-name="DialogWarning">
<div id="dialog-message" t-att-title="title">
<p>
<span class="ui-icon ui-icon-circle-check" style="float:left; margin:0 7px 50px 0;"></span>
<t t-esc="message"/>
</p>
</div>
<p class="oe-dialog-warning">
<img src="/base/static/src/img/warning.png" class="oe-dialog-icon"/>
<t t-esc="error.data.fault_code.substr(18)"/>
</p>
</t>
<t t-name="DialogTraceback">
<pre><t t-esc="error.message"/></pre>
<hr/>
<pre><t t-esc="error.data.debug"/></pre>
</t>
<t t-name="SelectCreatePopup">
<div t-att-id="element_id">
+20 -10
View File
@@ -6,7 +6,6 @@ can't be sent there themselves).
"""
import binascii
import hashlib
import simplejson.decoder
import simplejson.encoder
__all__ = ['Domain', 'Context', 'NonLiteralEncoder, non_literal_decoder']
@@ -17,6 +16,8 @@ SHORT_HASH_BYTES_SIZE = 6
class NonLiteralEncoder(simplejson.encoder.JSONEncoder):
def default(self, object):
if not isinstance(object, (BaseDomain, BaseContext)):
return super(NonLiteralEncoder, self).default(object)
if isinstance(object, Domain):
return {
'__ref': 'domain',
@@ -30,14 +31,14 @@ class NonLiteralEncoder(simplejson.encoder.JSONEncoder):
elif isinstance(object, CompoundDomain):
return {
'__ref': 'compound_domain',
'__domains': [self.default(el) for el in object.domains]
'__domains': object.domains
}
elif isinstance(object, CompoundContext):
return {
'__ref': 'compound_context',
'__contexts': [self.default(el) for el in object.contexts]
'__contexts': object.contexts
}
return super(NonLiteralEncoder, self).default(object)
raise TypeError('Could not encode unknown non-literal %s' % object)
def non_literal_decoder(dct):
""" Decodes JSON dicts into :class:`Domain` and :class:`Context` based on
@@ -69,7 +70,16 @@ def non_literal_decoder(dct):
return ccontext
return dct
class Domain(object):
# TODO: use abstract base classes if 2.6+?
class BaseDomain(object):
def evaluate(self, context=None):
raise NotImplementedError('Non literals must implement evaluate()')
class BaseContext(object):
def evaluate(self, context=None):
raise NotImplementedError('Non literals must implement evaluate()')
class Domain(BaseDomain):
def __init__(self, session, domain_string=None, key=None):
""" Uses session information to store the domain string and map it to a
domain key, which can be safely round-tripped to the client.
@@ -113,7 +123,7 @@ class Domain(object):
ctx.update(self.own)
return eval(self.get_domain_string(), ctx)
class Context(object):
class Context(BaseContext):
def __init__(self, session, context_string=None, key=None):
""" Uses session information to store the context string and map it to
a key (stored in a secret location under a secret mountain), which can
@@ -159,7 +169,7 @@ class Context(object):
return eval(self.get_context_string(),
ctx)
class CompoundDomain:
class CompoundDomain(BaseDomain):
def __init__(self, *domains):
self.domains = []
self.session = None
@@ -169,7 +179,7 @@ class CompoundDomain:
def evaluate(self, context=None):
final_domain = []
for domain in self.domains:
if not isinstance(domain, (list, Domain, CompoundDomain)):
if not isinstance(domain, (list, BaseDomain)):
raise TypeError("Domain %r is not a list or a nonliteral Domain",
domain)
@@ -188,7 +198,7 @@ class CompoundDomain:
self.domains.append(domain)
return self
class CompoundContext:
class CompoundContext(BaseContext):
def __init__(self, *contexts):
self.contexts = []
self.session = None
@@ -199,7 +209,7 @@ class CompoundContext:
ctx = dict(context or {})
final_context = {}
for context_to_eval in self.contexts:
if not isinstance(context_to_eval, (dict, Context, CompoundContext)):
if not isinstance(context_to_eval, (dict, BaseContext)):
raise TypeError("Context %r is not a dict or a nonliteral Context",
context_to_eval)
+1 -1
View File
@@ -77,7 +77,7 @@ class TestOpenERPSession(unittest2.TestCase):
def test_eval_empty_domains(self):
self.assertEqual(
self.session.eval_domain(CompoundDomain(*[])),
self.session.eval_domain(CompoundDomain()),
[])
def test_eval_literal_domains(self):