@@ -439,9 +439,9 @@ class DataSet(openerpweb.Controller):
|
||||
return Model.unlink(ids)
|
||||
|
||||
@openerpweb.jsonrequest
|
||||
def call(self, req, model, method, ids, args):
|
||||
def call(self, req, model, method, args):
|
||||
m = req.session.model(model)
|
||||
r = getattr(m, method)(ids, *args)
|
||||
r = getattr(m, method)(*args)
|
||||
return {'result': r}
|
||||
|
||||
@openerpweb.jsonrequest
|
||||
@@ -456,9 +456,9 @@ class DataSet(openerpweb.Controller):
|
||||
return {'result': r}
|
||||
|
||||
@openerpweb.jsonrequest
|
||||
def name_search(self, req, model, search_str, domain=[], context={}):
|
||||
def name_search(self, req, model, search_str, domain=[], context={}, limit=False):
|
||||
m = req.session.model(model)
|
||||
r = m.name_search(search_str+'%', domain, '=ilike', context)
|
||||
r = m.name_search(search_str, domain, 'ilike', context, limit)
|
||||
return {'result': r}
|
||||
|
||||
class DataGroup(openerpweb.Controller):
|
||||
|
||||
@@ -0,0 +1,126 @@
|
||||
(function($) {
|
||||
var menu,shadow,trigger,content,hash,currentTarget;
|
||||
var defaults= {
|
||||
menuStyle: {
|
||||
listStyle:'none',
|
||||
padding:'1px',
|
||||
margin:'0px',
|
||||
backgroundColor:'#fff',
|
||||
border:'1px solid #999',
|
||||
width:'100px'
|
||||
},
|
||||
itemStyle: {
|
||||
margin:'0px',
|
||||
color:'#000',
|
||||
display:'block',
|
||||
cursor:'default',
|
||||
padding:'3px',
|
||||
border:'1px solid #fff',
|
||||
backgroundColor:'transparent'
|
||||
},
|
||||
itemHoverStyle: {
|
||||
border:'1px solid #0a246a',
|
||||
backgroundColor:'#b6bdd2'
|
||||
},
|
||||
eventPosX:'pageX',
|
||||
eventPosY:'pageY',
|
||||
shadow:true,
|
||||
onContextMenu:null,
|
||||
onShowMenu:null
|
||||
};
|
||||
$.fn.contextMenu= function(id,options) {
|
||||
if(!menu) {
|
||||
menu=$('<div id="jqContextMenu"></div>').hide().css({
|
||||
position:'absolute',
|
||||
zIndex:'500'
|
||||
}).appendTo('body').bind('click', function(e) {
|
||||
e.stopPropagation()
|
||||
})
|
||||
}
|
||||
if(!shadow) {
|
||||
shadow=$('<div></div>').css({
|
||||
backgroundColor:'#000',
|
||||
position:'absolute',
|
||||
opacity:0.2,
|
||||
zIndex:499
|
||||
}).appendTo('body').hide()
|
||||
}
|
||||
hash=hash||[];
|
||||
hash.push({
|
||||
id:id,
|
||||
menuStyle:$.extend({},defaults.menuStyle,options.menuStyle|| {}),
|
||||
itemStyle:$.extend({},defaults.itemStyle,options.itemStyle|| {}),
|
||||
itemHoverStyle:$.extend({},defaults.itemHoverStyle,options.itemHoverStyle|| {}),
|
||||
bindings:options.bindings|| {},
|
||||
shadow:options.shadow||options.shadow===false?options.shadow:defaults.shadow,
|
||||
onContextMenu:options.onContextMenu||defaults.onContextMenu,
|
||||
onShowMenu:options.onShowMenu||defaults.onShowMenu,
|
||||
eventPosX:options.eventPosX||defaults.eventPosX,
|
||||
eventPosY:options.eventPosY||defaults.eventPosY
|
||||
});
|
||||
var index=hash.length-1;
|
||||
var callback = function(e) {
|
||||
var bShowContext=(!!hash[index].onContextMenu)?hash[index].onContextMenu(e):true;
|
||||
if(bShowContext)
|
||||
display(index,this,e,options);
|
||||
return false;
|
||||
};
|
||||
$(this).bind('contextmenu', callback);
|
||||
if(options.leftClickToo) {
|
||||
$(this).click(callback);
|
||||
}
|
||||
return this
|
||||
};
|
||||
function display(index,trigger,e,options) {
|
||||
var cur=hash[index];
|
||||
content=$('#'+cur.id).find('ul:first').clone(true);
|
||||
content.css(cur.menuStyle).find('li').css(cur.itemStyle).hover( function() {
|
||||
$(this).css(cur.itemHoverStyle)
|
||||
}, function() {
|
||||
$(this).css(cur.itemStyle)
|
||||
}).find('img').css({
|
||||
verticalAlign:'middle',
|
||||
paddingRight:'2px'
|
||||
});
|
||||
menu.html(content);
|
||||
if(!!cur.onShowMenu)
|
||||
menu=cur.onShowMenu(e,menu);
|
||||
$.each(cur.bindings, function(id,func) {
|
||||
$('#'+id,menu).bind('click', function(e) {
|
||||
hide();
|
||||
func(trigger,currentTarget)
|
||||
})
|
||||
});
|
||||
menu.css({
|
||||
'left':e[cur.eventPosX],
|
||||
'top':e[cur.eventPosY]
|
||||
}).show();
|
||||
if(cur.shadow)
|
||||
shadow.css({
|
||||
width:menu.width(),
|
||||
height:menu.height(),
|
||||
left:e.pageX+2,
|
||||
top:e.pageY+2
|
||||
}).show();
|
||||
$(document).one('click',hide)
|
||||
}
|
||||
|
||||
function hide() {
|
||||
menu.hide();
|
||||
shadow.hide()
|
||||
}
|
||||
|
||||
$.contextMenu= {
|
||||
defaults: function(userDefaults) {
|
||||
$.each(userDefaults, function(i,val) {
|
||||
if(typeof val=='object'&&defaults[i]) {
|
||||
$.extend(defaults[i],val)
|
||||
} else
|
||||
defaults[i]=val
|
||||
})
|
||||
}
|
||||
}
|
||||
})(jQuery);
|
||||
$( function() {
|
||||
$('div.contextMenu').hide()
|
||||
});
|
||||
@@ -19,6 +19,7 @@
|
||||
<script type="text/javascript" src="/base/static/lib/jquery.superfish/js/hoverIntent.js"></script>
|
||||
<script type="text/javascript" src="/base/static/lib/jquery.superfish/js/superfish.js"></script>
|
||||
<script type="text/javascript" src="/base/static/lib/jquery.ba-bbq/jquery.ba-bbq.js"></script>
|
||||
<script type="text/javascript" src="/base/static/lib/jquery.contextmenu/jquery.contextmenu.r2.packed.js"></script>
|
||||
<script type="text/javascript" src="/base/static/lib/datejs/date-en-US.js"></script>
|
||||
<script type="text/javascript" src="/base/static/lib/json/json2.js"></script>
|
||||
<script type="text/javascript" src="/base/static/src/js/base.js"></script>
|
||||
@@ -28,9 +29,9 @@
|
||||
<script type="text/javascript" src="/base/static/src/js/views.js"></script>
|
||||
<script type="text/javascript" src="/base/static/src/js/form.js"></script>
|
||||
<script type="text/javascript" src="/base/static/src/js/list.js"></script>
|
||||
<script type="text/javascript" src="/base/static/src/js/list-editable.js"></script>
|
||||
<script type="text/javascript" src="/base/static/src/js/tree.js"></script>
|
||||
<script type="text/javascript" src="/base/static/src/js/search.js"></script>
|
||||
<script type="text/javascript" src="/base/static/src/js/m2o.js"></script>
|
||||
|
||||
<link rel="stylesheet" type="text/css" media="screen" href="/base/static/lib/jquery.ui/css/smoothness/jquery-ui-1.8.9.custom.css" />
|
||||
<link rel="stylesheet" type="text/css" media="screen" href="/base/static/lib/jquery.ui.notify/css/ui.notify.css" />
|
||||
|
||||
@@ -27,6 +27,10 @@ body.openerp {
|
||||
overflow-y: scroll;
|
||||
}
|
||||
|
||||
.openerp .oe-number {
|
||||
text-align: right !important;
|
||||
}
|
||||
|
||||
/* STATES */
|
||||
.openerp .on_logged {
|
||||
display: none;
|
||||
@@ -94,6 +98,12 @@ body.openerp {
|
||||
.openerp .login .oe_box2 td select {
|
||||
width: 100%;
|
||||
}
|
||||
.openerp .login .oe_box2 td.oe_remember {
|
||||
text-align:left;
|
||||
}
|
||||
.openerp .login .oe_box2 td.oe_remember input {
|
||||
width: inherit;
|
||||
}
|
||||
.openerp .login .oe_login_right_pane {
|
||||
padding:70px 35px 5px 10px;
|
||||
min-width: 200px;
|
||||
@@ -596,6 +606,7 @@ background: linear-gradient(top, #ffffff 0%,#d8d8d8 11%,#afafaf 86%,#333333 91%,
|
||||
padding: 0;
|
||||
border: none;
|
||||
background: none;
|
||||
width: 100%;
|
||||
}
|
||||
.openerp .oe-listview .oe-field-cell button:active {
|
||||
opacity: 0.5;
|
||||
@@ -1000,60 +1011,18 @@ background: linear-gradient(top, #ffffff 0%,#ebe9e9 100%); /* W3C */
|
||||
border-color: #828282;
|
||||
}
|
||||
|
||||
/* Many2one Autosearch */
|
||||
.openerp .ui_combo {
|
||||
height: 19px;
|
||||
top: 6px;
|
||||
width: 20px;
|
||||
position: relative;
|
||||
margin-left: -26px;
|
||||
}
|
||||
|
||||
.openerp img.m2o_open {
|
||||
vertical-align: middle;
|
||||
cursor: pointer;
|
||||
}
|
||||
/*----- End Many2one Autosearch ------- */
|
||||
|
||||
/* Many2one Contextmenu */
|
||||
.openerp div.m2o_contextmenu {
|
||||
background-color: #444;
|
||||
border: 1px solid #000;
|
||||
.openerp .oe-m2o {
|
||||
padding-right: 16px;
|
||||
white-space: nowrap;
|
||||
position: absolute;
|
||||
padding: 2px;
|
||||
z-index: 100;
|
||||
}
|
||||
|
||||
.openerp div.m2o_contextmenu a,
|
||||
.openerp div.m2o_contextmenu span {
|
||||
display: block;
|
||||
text-align: left;
|
||||
text-decoration: none;
|
||||
white-space: nowrap;
|
||||
padding: 2px;
|
||||
color: #FFF;
|
||||
cursor: pointer;
|
||||
.openerp .oe-m2o-drop-down-button {
|
||||
margin-left: -23px;
|
||||
}
|
||||
|
||||
.openerp div.m2o_contextmenu hr {
|
||||
margin: 1px 0 !important;
|
||||
.openerp .oe-m2o-drop-down-button img,
|
||||
.openerp .oe-m2o-cm-button img {
|
||||
margin-bottom: -4px;
|
||||
}
|
||||
|
||||
.openerp div.m2o_contextmenu td {
|
||||
padding: 1px;
|
||||
.openerp .oe-m2o-disabled-cm {
|
||||
color: grey;
|
||||
}
|
||||
|
||||
.openerp div.m2o_contextmenu a:hover,
|
||||
.openerp div.m2o_contextmenu span:hover {
|
||||
color: #FFF;
|
||||
background-color: #505050;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.openerp div.m2o_contextmenu a.disabled,
|
||||
.openerp div.m2o_contextmenu span.disabled {
|
||||
color: #C0C0C0;
|
||||
}
|
||||
|
||||
/*----- End Many2one Contextmenu ------- */
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 263 B |
@@ -149,6 +149,16 @@ openerp.base.Registry = Class.extend( /** @lends openerp.base.Registry# */ {
|
||||
add: function (key, object_path) {
|
||||
this.map[key] = object_path;
|
||||
return this;
|
||||
},
|
||||
/**
|
||||
* Creates and returns a copy of the current mapping, with the provided
|
||||
* mapping argument added in (replacing existing keys if needed)
|
||||
*
|
||||
* @param {Object} [mapping={}] a mapping of keys to object-paths
|
||||
*/
|
||||
clone: function (mapping) {
|
||||
return new openerp.base.Registry(
|
||||
_.extend({}, this.map, mapping || {}));
|
||||
}
|
||||
});
|
||||
|
||||
@@ -776,6 +786,17 @@ openerp.base.Database = openerp.base.Controller.extend({
|
||||
openerp.base.Login = openerp.base.Controller.extend({
|
||||
init: function(session, element_id) {
|
||||
this._super(session, element_id);
|
||||
this.has_local_storage = typeof(localStorage) != 'undefined';
|
||||
this.selected_db = null;
|
||||
this.selected_login = null;
|
||||
this.selected_password = null;
|
||||
this.remember = false;
|
||||
if (this.has_local_storage && localStorage.getItem('remember_creditentials') === 'true') {
|
||||
this.remember = true;
|
||||
this.selected_db = localStorage.getItem('last_db_login_success');
|
||||
this.selected_login = localStorage.getItem('last_login_login_success');
|
||||
this.selected_password = localStorage.getItem('last_password_login_success');
|
||||
}
|
||||
},
|
||||
start: function() {
|
||||
var self = this;
|
||||
@@ -786,10 +807,10 @@ openerp.base.Login = openerp.base.Controller.extend({
|
||||
self.display();
|
||||
});
|
||||
},
|
||||
display: function() {
|
||||
display: function() {
|
||||
this.$element.html(QWeb.render("Login", this));
|
||||
this.$element.find("form").submit(this.on_submit);
|
||||
},
|
||||
},
|
||||
on_login_invalid: function() {
|
||||
this.$element.closest(".openerp").addClass("login-mode");
|
||||
},
|
||||
@@ -803,10 +824,24 @@ openerp.base.Login = openerp.base.Controller.extend({
|
||||
var db = $e.find("form [name=db]").val();
|
||||
var login = $e.find("form input[name=login]").val();
|
||||
var password = $e.find("form input[name=password]").val();
|
||||
var remember = $e.find("form input[name=remember]").attr('checked');
|
||||
//$e.hide();
|
||||
// Should hide then call callback
|
||||
this.session.session_login(db, login, password, function() {
|
||||
if(self.session.session_is_valid()) {
|
||||
if (self.has_local_storage) {
|
||||
if(remember) {
|
||||
localStorage.setItem('remember_creditentials', 'true');
|
||||
localStorage.setItem('last_db_login_success', db);
|
||||
localStorage.setItem('last_login_login_success', login);
|
||||
localStorage.setItem('last_password_login_success', password);
|
||||
} else {
|
||||
localStorage.setItem('remember_creditentials', '');
|
||||
localStorage.setItem('last_db_login_success', '');
|
||||
localStorage.setItem('last_login_login_success', '');
|
||||
localStorage.setItem('last_password_login_success', '');
|
||||
}
|
||||
}
|
||||
self.on_login_valid();
|
||||
} else {
|
||||
self.$element.addClass("login_invalid");
|
||||
|
||||
@@ -259,7 +259,7 @@ openerp.base.DataSet = openerp.base.Controller.extend( /** @lends openerp.base.
|
||||
*/
|
||||
read_ids: function (ids, fields, callback) {
|
||||
var self = this;
|
||||
this.rpc('/base/dataset/get', {
|
||||
return this.rpc('/base/dataset/get', {
|
||||
model: this.model,
|
||||
ids: ids,
|
||||
fields: fields
|
||||
@@ -279,10 +279,10 @@ openerp.base.DataSet = openerp.base.Controller.extend( /** @lends openerp.base.
|
||||
*/
|
||||
read_index: function (fields, callback) {
|
||||
if (_.isEmpty(this.ids)) {
|
||||
callback([]);
|
||||
return $.Deferred().reject().promise();
|
||||
} else {
|
||||
fields = fields || false;
|
||||
this.read_ids([this.ids[this.index]], fields, function(records) {
|
||||
return this.read_ids([this.ids[this.index]], fields, function(records) {
|
||||
callback(records[0]);
|
||||
});
|
||||
}
|
||||
@@ -313,25 +313,21 @@ openerp.base.DataSet = openerp.base.Controller.extend( /** @lends openerp.base.
|
||||
// to implement in children
|
||||
this.notification.notify("Unlink", ids);
|
||||
},
|
||||
call: function (method, ids, args, callback) {
|
||||
this.notification.notify(
|
||||
"Calling", this.model + '#' + method + '(' + ids + ')');
|
||||
ids = ids || [];
|
||||
args = args || [];
|
||||
call: function (method, args, callback, error_callback) {
|
||||
return this.rpc('/base/dataset/call', {
|
||||
model: this.model,
|
||||
method: method,
|
||||
ids: ids,
|
||||
args: args
|
||||
}, callback);
|
||||
args: args || []
|
||||
}, callback, error_callback);
|
||||
},
|
||||
name_search: function (search_str, callback) {
|
||||
name_search: function (search_str, limit, callback) {
|
||||
search_str = search_str || '';
|
||||
return this.rpc('/base/dataset/name_search', {
|
||||
model: this.model,
|
||||
search_str: search_str,
|
||||
domain: this.domain || [],
|
||||
context: this.context
|
||||
context: this.context,
|
||||
limit: limit || false
|
||||
}, callback);
|
||||
},
|
||||
exec_workflow: function (id, signal, callback) {
|
||||
|
||||
@@ -8,12 +8,15 @@ openerp.base.FormView = openerp.base.View.extend( /** @lends openerp.base.FormV
|
||||
* view should be displayed (if there is one active).
|
||||
*/
|
||||
searchable: false,
|
||||
template: "FormView",
|
||||
/**
|
||||
* @constructs
|
||||
* @param {openerp.base.Session} session the current openerp session
|
||||
* @param {String} element_id this view's root element id
|
||||
* @param {openerp.base.DataSet} dataset the dataset this view will work with
|
||||
* @param {String} view_id the identifier of the OpenERP view object
|
||||
*
|
||||
* @property {openerp.base.Registry} registry=openerp.base.form.widgets widgets registry for this form view instance
|
||||
*/
|
||||
init: function(view_manager, session, element_id, dataset, view_id) {
|
||||
this._super(session, element_id);
|
||||
@@ -29,7 +32,8 @@ openerp.base.FormView = openerp.base.View.extend( /** @lends openerp.base.FormV
|
||||
this.ready = false;
|
||||
this.show_invalid = true;
|
||||
this.touched = false;
|
||||
this.flags = this.view_manager.flags || {};
|
||||
this.flags = this.view_manager.action.flags || {};
|
||||
this.registry = openerp.base.form.widgets;
|
||||
},
|
||||
start: function() {
|
||||
//this.log('Starting FormView '+this.model+this.view_id)
|
||||
@@ -44,9 +48,9 @@ openerp.base.FormView = openerp.base.View.extend( /** @lends openerp.base.FormV
|
||||
var self = this;
|
||||
this.fields_view = data.fields_view;
|
||||
|
||||
var frame = new openerp.base.form.WidgetFrame(this, this.fields_view.arch);
|
||||
var frame = new (this.registry.get_object('frame'))(this, this.fields_view.arch);
|
||||
|
||||
this.$element.html(QWeb.render("FormView", { 'frame': frame, 'view': this }));
|
||||
this.$element.html(QWeb.render(this.template, { 'frame': frame, 'view': this }));
|
||||
_.each(this.widgets, function(w) {
|
||||
w.start();
|
||||
});
|
||||
@@ -220,7 +224,15 @@ openerp.base.FormView = openerp.base.View.extend( /** @lends openerp.base.FormV
|
||||
self.on_record_loaded(result.result);
|
||||
});
|
||||
},
|
||||
do_save: function(success) {
|
||||
/**
|
||||
* Triggers saving the form's record. Chooses between creating a new
|
||||
* record or saving an existing one depending on whether the record
|
||||
* already has an id property.
|
||||
*
|
||||
* @param {Function} success callback on save success
|
||||
* @param {Boolean} [prepend_on_create=false] if ``do_save`` creates a new record, should that record be inserted at the start of the dataset (by default, records are added at the end)
|
||||
*/
|
||||
do_save: function(success, prepend_on_create) {
|
||||
var self = this;
|
||||
if (!this.ready) {
|
||||
return false;
|
||||
@@ -243,7 +255,7 @@ openerp.base.FormView = openerp.base.View.extend( /** @lends openerp.base.FormV
|
||||
this.log("About to save", values);
|
||||
if (!this.datarecord.id) {
|
||||
this.dataset.create(values, function(r) {
|
||||
self.on_created(r, success);
|
||||
self.on_created(r, success, prepend_on_create);
|
||||
});
|
||||
} else {
|
||||
this.dataset.write(this.datarecord.id, values, function(r) {
|
||||
@@ -281,19 +293,37 @@ openerp.base.FormView = openerp.base.View.extend( /** @lends openerp.base.FormV
|
||||
}
|
||||
}
|
||||
},
|
||||
on_created: function(r, success) {
|
||||
/**
|
||||
* Updates the form' dataset to contain the new record:
|
||||
*
|
||||
* * Adds the newly created record to the current dataset (at the end by
|
||||
* default)
|
||||
* * Selects that record (sets the dataset's index to point to the new
|
||||
* record's id).
|
||||
* * Updates the pager and sidebar displays
|
||||
*
|
||||
* @param {Object} r
|
||||
* @param {Function} success callback to execute after having updated the dataset
|
||||
* @param {Boolean} [prepend_on_create=false] adds the newly created record at the beginning of the dataset instead of the end
|
||||
*/
|
||||
on_created: function(r, success, prepend_on_create) {
|
||||
if (!r.result) {
|
||||
this.notification.warn("Record not created", "Problem while creating record.");
|
||||
} else {
|
||||
this.datarecord.id = arguments[0].result;
|
||||
this.dataset.ids.push(this.datarecord.id);
|
||||
this.dataset.index = this.dataset.ids.length - 1;
|
||||
this.datarecord.id = r.result;
|
||||
if (!prepend_on_create) {
|
||||
this.dataset.ids.push(this.datarecord.id);
|
||||
this.dataset.index = this.dataset.ids.length - 1;
|
||||
} else {
|
||||
this.dataset.ids.unshift(this.datarecord.id);
|
||||
this.dataset.index = 0;
|
||||
}
|
||||
this.dataset.count++;
|
||||
this.do_update_pager();
|
||||
this.do_update_sidebar();
|
||||
this.notification.notify("Record created", "The record has been created with id #" + this.datarecord.id);
|
||||
if (success) {
|
||||
success(r);
|
||||
success(_.extend(r, {created: true}));
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -422,6 +452,7 @@ openerp.base.form.compute_domain = function(expr, fields) {
|
||||
};
|
||||
|
||||
openerp.base.form.Widget = openerp.base.Controller.extend({
|
||||
template: 'Widget',
|
||||
init: function(view, node) {
|
||||
this.view = view;
|
||||
this.node = node;
|
||||
@@ -435,7 +466,6 @@ openerp.base.form.Widget = openerp.base.Controller.extend({
|
||||
this.view.widgets[this.element_id] = this;
|
||||
this.children = node.children;
|
||||
this.colspan = parseInt(node.attrs.colspan || 1);
|
||||
this.template = "Widget";
|
||||
|
||||
this.string = this.string || node.attrs.string;
|
||||
this.help = this.help || node.attrs.help;
|
||||
@@ -460,9 +490,9 @@ openerp.base.form.Widget = openerp.base.Controller.extend({
|
||||
});
|
||||
|
||||
openerp.base.form.WidgetFrame = openerp.base.form.Widget.extend({
|
||||
template: 'WidgetFrame',
|
||||
init: function(view, node) {
|
||||
this._super(view, node);
|
||||
this.template = "WidgetFrame";
|
||||
this.columns = node.attrs.col || 4;
|
||||
this.x = 0;
|
||||
this.y = 0;
|
||||
@@ -504,9 +534,9 @@ openerp.base.form.WidgetFrame = openerp.base.form.Widget.extend({
|
||||
handle_node: function(node) {
|
||||
var type = this.view.fields_view.fields[node.attrs.name] || {};
|
||||
var widget_type = node.attrs.widget || type.type || node.tag;
|
||||
var widget = new (openerp.base.form.widgets.get_object(widget_type)) (this.view, node);
|
||||
var widget = new (this.view.registry.get_object(widget_type)) (this.view, node);
|
||||
if (node.tag == 'field' && node.attrs.nolabel != '1') {
|
||||
var label = new (openerp.base.form.widgets.get_object('label')) (this.view, node);
|
||||
var label = new (this.view.registry.get_object('label')) (this.view, node);
|
||||
label["for"] = widget;
|
||||
this.add_widget(label);
|
||||
}
|
||||
@@ -949,45 +979,232 @@ openerp.base.form.FieldSelection = openerp.base.form.Field.extend({
|
||||
}
|
||||
});
|
||||
|
||||
openerp.base.form.FieldMany2OneDatasSet = openerp.base.DataSetStatic.extend({
|
||||
start: function() {
|
||||
},
|
||||
write: function (id, data, callback) {
|
||||
this._super(id, data, callback);
|
||||
// jquery autocomplete tweak to allow html
|
||||
(function(x) {
|
||||
var proto = $.ui.autocomplete.prototype,
|
||||
initSource = proto._initSource;
|
||||
|
||||
function filter( array, term ) {
|
||||
var matcher = new RegExp( $.ui.autocomplete.escapeRegex(term), "i" );
|
||||
return $.grep( array, function(value) {
|
||||
return matcher.test( $( "<div>" ).html( value.label || value.value || value ).text() );
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
$.extend( proto, {
|
||||
_initSource: function() {
|
||||
if ( this.options.html && $.isArray(this.options.source) ) {
|
||||
this.source = function( request, response ) {
|
||||
response( filter( this.options.source, request.term ) );
|
||||
};
|
||||
} else {
|
||||
initSource.call( this );
|
||||
}
|
||||
},
|
||||
|
||||
_renderItem: function( ul, item) {
|
||||
return $( "<li></li>" )
|
||||
.data( "item.autocomplete", item )
|
||||
.append( $( "<a></a>" )[ this.options.html ? "html" : "text" ]( item.label ) )
|
||||
.appendTo( ul );
|
||||
}
|
||||
});
|
||||
})(null);
|
||||
|
||||
openerp.base.form.FieldMany2One = openerp.base.form.Field.extend({
|
||||
init: function(view, node) {
|
||||
this._super(view, node);
|
||||
this.template = "FieldMany2One";
|
||||
this.is_field_m2o = true;
|
||||
this.limit = 7;
|
||||
this.value = null;
|
||||
this.cm_id = _.uniqueId('m2o_cm_');
|
||||
this.last_search = [];
|
||||
},
|
||||
start: function() {
|
||||
this.$element = $('#' + this.element_id);
|
||||
this.dataset = new openerp.base.form.FieldMany2OneDatasSet(this.session, this.field.relation);
|
||||
var views = [ [false,"list"], [false,"form"] ];
|
||||
new openerp.base.m2o(this.$element, this.field.relation, this.dataset, this.session)
|
||||
this.$element.find('input').change(this.on_ui_change);
|
||||
},
|
||||
set_value: function(value) {
|
||||
this._super.apply(this, arguments);
|
||||
var show_value = '';
|
||||
if (value != null && value !== false) {
|
||||
show_value = value[1];
|
||||
this.value = value[0];
|
||||
this._super();
|
||||
var self = this;
|
||||
this.$input = this.$element.find("input");
|
||||
this.$drop_down = this.$element.find(".oe-m2o-drop-down-button");
|
||||
this.$menu_btn = this.$element.find(".oe-m2o-cm-button");
|
||||
|
||||
// context menu
|
||||
var bindings = {};
|
||||
bindings[this.cm_id + "_search"] = function() {
|
||||
self._search_create_popup("search");
|
||||
};
|
||||
bindings[this.cm_id + "_create"] = function() {
|
||||
self._search_create_popup("form");
|
||||
};
|
||||
bindings[this.cm_id + "_open"] = function() {
|
||||
if (!self.value) {
|
||||
return;
|
||||
}
|
||||
self.session.action_manager.do_action({
|
||||
"res_model": self.field.relation,
|
||||
"views":[[false,"form"]],
|
||||
"res_id": self.value[0],
|
||||
"type":"ir.actions.act_window",
|
||||
"view_type":"form",
|
||||
"view_mode":"form",
|
||||
"target":"new"
|
||||
});
|
||||
};
|
||||
var cmenu = this.$menu_btn.contextMenu(this.cm_id, {'leftClickToo': true,
|
||||
bindings: bindings, itemStyle: {"color": ""},
|
||||
onContextMenu: function() {
|
||||
if(self.value) {
|
||||
$("#" + self.cm_id + "_open").removeClass("oe-m2o-disabled-cm");
|
||||
} else {
|
||||
$("#" + self.cm_id + "_open").addClass("oe-m2o-disabled-cm");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
// some behavior for input
|
||||
this.$input.keyup(function() {
|
||||
if (self.$input.val() === "") {
|
||||
self._change_int_value(null);
|
||||
} else if (self.value === null || (self.value && self.$input.val() !== self.value[1])) {
|
||||
self._change_int_value(undefined);
|
||||
}
|
||||
});
|
||||
this.$drop_down.click(function() {
|
||||
if (self.$input.autocomplete("widget").is(":visible")) {
|
||||
self.$input.autocomplete("close");
|
||||
} else {
|
||||
if (self.value) {
|
||||
self.$input.autocomplete("search", "");
|
||||
} else {
|
||||
self.$input.autocomplete("search");
|
||||
}
|
||||
self.$input.focus();
|
||||
}
|
||||
});
|
||||
var anyoneLoosesFocus = function() {
|
||||
if (!self.$input.is(":focus") &&
|
||||
!self.$input.autocomplete("widget").is(":visible") &&
|
||||
!self.value) {
|
||||
if(self.value === undefined && self.last_search.length > 0) {
|
||||
self._change_int_ext_value(self.last_search[0]);
|
||||
} else {
|
||||
self._change_int_ext_value(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
this.$element.find('input').val(show_value);
|
||||
this.$element.find('input').attr('m2o_id', this.value);
|
||||
this.$input.focusout(anyoneLoosesFocus);
|
||||
|
||||
// autocomplete
|
||||
this.$input.autocomplete({
|
||||
source: function(req, resp) { self.get_search_result(req, resp); },
|
||||
select: function(event, ui) {
|
||||
var item = ui.item;
|
||||
if (item.id) {
|
||||
self._change_int_value([item.id, item.name]);
|
||||
} else if (item.action) {
|
||||
self._change_int_value(undefined);
|
||||
item.action();
|
||||
return false;
|
||||
}
|
||||
},
|
||||
focus: function(e, ui) {
|
||||
e.preventDefault();
|
||||
},
|
||||
html: true,
|
||||
close: anyoneLoosesFocus,
|
||||
minLength: 0,
|
||||
delay: 0
|
||||
});
|
||||
},
|
||||
// autocomplete component content handling
|
||||
get_search_result: function(request, response) {
|
||||
var search_val = request.term;
|
||||
var self = this;
|
||||
|
||||
var dataset = new openerp.base.DataSetStatic(this.session, this.field.relation, []);
|
||||
|
||||
dataset.name_search(search_val, this.limit + 1, function(data) {
|
||||
self.last_search = data.result;
|
||||
// possible selections for the m2o
|
||||
var values = _.map(data.result, function(x) {
|
||||
return {label: $('<span />').text(x[1]).html(), name:x[1], id:x[0]};
|
||||
});
|
||||
|
||||
// additional selections, actions that open popup
|
||||
if (values.length > self.limit) {
|
||||
values = values.slice(0, self.limit);
|
||||
values.push({label: "<em> Search More...</em>", action: function() {
|
||||
dataset.name_search(search_val, false, function(data) {
|
||||
self._change_int_value(null);
|
||||
self._search_create_popup("search", data.result);
|
||||
});
|
||||
}});
|
||||
}
|
||||
if (self.value === undefined) {
|
||||
values.push({label: '<em> Create "<strong>' +
|
||||
$('<span />').text(search_val).html() + '</strong>"</em>', action: function() {
|
||||
self._quick_create(search_val);
|
||||
}});
|
||||
}
|
||||
values.push({label: "<em> Create and Edit...</em>", action: function() {
|
||||
self._change_int_value(null);
|
||||
self._search_create_popup("form");
|
||||
}});
|
||||
|
||||
response(values);
|
||||
});
|
||||
},
|
||||
_quick_create: function(name) {
|
||||
var self = this;
|
||||
var dataset = new openerp.base.DataSetStatic(this.session, this.field.relation, []);
|
||||
dataset.call("name_create", [name, {}], function(data) {
|
||||
self._change_int_ext_value(data.result);
|
||||
}, function(a, b) {
|
||||
self._change_int_value(null);
|
||||
self._search_create_popup("form");
|
||||
});
|
||||
},
|
||||
// all search/create popup handling
|
||||
_search_create_popup: function(view, ids) {
|
||||
var dataset = new openerp.base.DataSetStatic(this.session, this.field.relation, []);
|
||||
var self = this;
|
||||
var pop = new openerp.base.form.Many2XSelectPopup(null, self.view.session);
|
||||
pop.select_element(self.field.relation, ids ? _.map(ids, function(x) {return x[0]}) : undefined, view);
|
||||
pop.on_select_element.add(function(element_id) {
|
||||
dataset.call("name_get", [element_id], function(data) {
|
||||
self._change_int_ext_value(data.result[0]);
|
||||
pop.stop();
|
||||
});
|
||||
});
|
||||
},
|
||||
_change_int_ext_value: function(value) {
|
||||
this._change_int_value(value);
|
||||
this.$input.val(this.value ? this.value[1] : "");
|
||||
},
|
||||
_change_int_value: function(value) {
|
||||
this.value = value;
|
||||
if (this.original_value === undefined || (this.value !== undefined &&
|
||||
((this.original_value ? this.original_value[0] : null) !== (this.value ? this.value[0] : null)))) {
|
||||
this.original_value = undefined;
|
||||
this.on_ui_change();
|
||||
}
|
||||
},
|
||||
set_value_from_ui: function() {},
|
||||
set_value: function(value) {
|
||||
this._super(value);
|
||||
this.original_value = value;
|
||||
this._change_int_ext_value(value);
|
||||
},
|
||||
|
||||
get_value: function() {
|
||||
var val = this.$element.find('input').attr('m2o_id') || this.value
|
||||
return val;
|
||||
if (this.value === undefined)
|
||||
throw "theorically unreachable state";
|
||||
return this.value ? this.value[0] : false;
|
||||
},
|
||||
|
||||
on_ui_change: function() {
|
||||
this.touched = this.view.touched = true;
|
||||
validate: function() {
|
||||
this.invalid = false;
|
||||
if (this.value === null) {
|
||||
this.invalid = this.required;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -1131,9 +1348,10 @@ openerp.base.form.Many2ManyListView = openerp.base.ListView.extend({
|
||||
openerp.base.form.Many2XSelectPopup = openerp.base.BaseWidget.extend({
|
||||
identifier_prefix: "many2xselectpopup",
|
||||
template: "Many2XSelectPopup",
|
||||
select_element: function(model, dataset) {
|
||||
select_element: function(model, initial_ids, initial_view) {
|
||||
this.model = model;
|
||||
this.dataset = dataset;
|
||||
this.initial_ids = initial_ids;
|
||||
this.initial_view = initial_view || "search";
|
||||
jQuery(this.render()).dialog({title: '',
|
||||
modal: true,
|
||||
minWidth: 800});
|
||||
@@ -1141,10 +1359,12 @@ openerp.base.form.Many2XSelectPopup = openerp.base.BaseWidget.extend({
|
||||
},
|
||||
start: function() {
|
||||
this._super();
|
||||
if (!this.dataset) {
|
||||
this.dataset = new openerp.base.DataSetSearch(this.session, this.model);
|
||||
this.dataset = new openerp.base.DataSetSearch(this.session, this.model);
|
||||
if (this.initial_view == "search") {
|
||||
this.setup_search_view();
|
||||
} else { // "form"
|
||||
this.new_object();
|
||||
}
|
||||
this.setup_search_view();
|
||||
},
|
||||
setup_search_view: function() {
|
||||
var self = this;
|
||||
@@ -1154,8 +1374,12 @@ openerp.base.form.Many2XSelectPopup = openerp.base.BaseWidget.extend({
|
||||
this.searchview = new openerp.base.SearchView(null, this.session,
|
||||
this.element_id + "_search", this.dataset, false, {});
|
||||
this.searchview.on_search.add(function(domains, contexts, groupbys) {
|
||||
self.view_list.do_search.call(
|
||||
self, domains, contexts, groupbys);
|
||||
if (self.initial_ids) {
|
||||
self.view_list.do_search.call(self, [[["id", "in", self.initial_ids]]], contexts, groupbys);
|
||||
self.initial_ids = undefined;
|
||||
} else {
|
||||
self.view_list.do_search.call(self, domains, contexts, groupbys);
|
||||
}
|
||||
});
|
||||
this.searchview.on_loaded.add_last(function () {
|
||||
var $buttons = self.searchview.$element.find(".oe_search-view-buttons");
|
||||
@@ -1173,13 +1397,8 @@ openerp.base.form.Many2XSelectPopup = openerp.base.BaseWidget.extend({
|
||||
{'deletable': false});
|
||||
self.view_list.popup = self;
|
||||
self.view_list.do_show();
|
||||
self.view_list.start();
|
||||
var tmphack = {"loaded": false};
|
||||
self.view_list.on_loaded.add_last(function() {
|
||||
if ( !tmphack.loaded ) {
|
||||
self.searchview.do_search();
|
||||
tmphack.loaded = true;
|
||||
};
|
||||
self.view_list.start().then(function() {
|
||||
self.searchview.do_search();
|
||||
});
|
||||
});
|
||||
this.searchview.start();
|
||||
@@ -1188,8 +1407,12 @@ openerp.base.form.Many2XSelectPopup = openerp.base.BaseWidget.extend({
|
||||
},
|
||||
new_object: function() {
|
||||
var self = this;
|
||||
this.searchview.hide();
|
||||
this.view_list.$element.hide();
|
||||
if (this.searchview) {
|
||||
this.searchview.hide();
|
||||
}
|
||||
if (this.view_list) {
|
||||
this.view_list.$element.hide();
|
||||
}
|
||||
this.dataset.index = null;
|
||||
this.view_form = new openerp.base.FormView(null, this.session,
|
||||
this.element_id + "_view_form", this.dataset, false);
|
||||
@@ -1369,6 +1592,7 @@ openerp.base.form.FieldBinaryImage = openerp.base.form.FieldBinary.extend({
|
||||
* Registry of form widgets, called by :js:`openerp.base.FormView`
|
||||
*/
|
||||
openerp.base.form.widgets = new openerp.base.Registry({
|
||||
'frame' : 'openerp.base.form.WidgetFrame',
|
||||
'group' : 'openerp.base.form.WidgetFrame',
|
||||
'notebook' : 'openerp.base.form.WidgetNotebook',
|
||||
'separator' : 'openerp.base.form.WidgetSeparator',
|
||||
|
||||
@@ -0,0 +1,260 @@
|
||||
/**
|
||||
* @namespace handles editability case for lists, because it depends on form and forms already depends on lists it had to be split out
|
||||
*/
|
||||
openerp.base.list.editable = function (openerp) {
|
||||
var KEY_RETURN = 13,
|
||||
KEY_ESCAPE = 27;
|
||||
|
||||
// editability status of list rows
|
||||
openerp.base.ListView.prototype.defaults.editable = null;
|
||||
|
||||
var old_init = openerp.base.ListView.prototype.init,
|
||||
old_actual_search = openerp.base.ListView.prototype.do_actual_search,
|
||||
old_add_record = openerp.base.ListView.prototype.do_add_record,
|
||||
old_on_loaded = openerp.base.ListView.prototype.on_loaded;
|
||||
// TODO: not sure second @lends on existing item is correct, to check
|
||||
_.extend(openerp.base.ListView.prototype, /** @lends openerp.base.ListView# */{
|
||||
init: function () {
|
||||
var self = this;
|
||||
old_init.apply(this, arguments);
|
||||
$(this.groups).bind({
|
||||
'edit': function (e, id, dataset) {
|
||||
self.do_edit(dataset.index, id, dataset);
|
||||
},
|
||||
'saved': function () {
|
||||
if (self.groups.get_selection().length) {
|
||||
return;
|
||||
}
|
||||
self.compute_aggregates();
|
||||
}
|
||||
})
|
||||
},
|
||||
/**
|
||||
* Handles the activation of a record in editable mode (making a record
|
||||
* editable), called *after* the record has become editable.
|
||||
*
|
||||
* The default behavior is to setup the listview's dataset to match
|
||||
* whatever dataset was provided by the editing List
|
||||
*
|
||||
* @param {Number} index index of the record in the dataset
|
||||
* @param {Object} id identifier of the record being edited
|
||||
* @param {openerp.base.DataSet} dataset dataset in which the record is available
|
||||
*/
|
||||
do_edit: function (index, id, dataset) {
|
||||
_.extend(this.dataset, dataset);
|
||||
},
|
||||
/**
|
||||
* Sets editability status for the list, based on defaults, view
|
||||
* architecture and the provided flag, if any.
|
||||
*
|
||||
* @param {Boolean} [force] forces the list to editability. Sets new row edition status to "bottom".
|
||||
*/
|
||||
set_editable: function (force) {
|
||||
// If ``force``, set editability to bottom
|
||||
// otherwise rely on view default
|
||||
// view' @editable is handled separately as we have not yet
|
||||
// fetched and processed the view at this point.
|
||||
this.options.editable = (
|
||||
(force && "bottom")
|
||||
|| this.defaults.editable);
|
||||
},
|
||||
/**
|
||||
* Replace do_actual_search to handle editability process
|
||||
*/
|
||||
do_actual_search: function (results) {
|
||||
this.set_editable(results.context['set_editable']);
|
||||
old_actual_search.call(this, results);
|
||||
},
|
||||
/**
|
||||
* Replace do_add_record to handle editability (and adding new record
|
||||
* as an editable row at the top or bottom of the list)
|
||||
*/
|
||||
do_add_record: function () {
|
||||
if (this.options.editable) {
|
||||
this.groups.new_record();
|
||||
} else {
|
||||
old_add_record.call(this);
|
||||
}
|
||||
},
|
||||
on_loaded: function (data, grouped) {
|
||||
// tree/@editable takes priority on everything else if present.
|
||||
this.options.editable = data.fields_view.arch.attrs.editable || this.options.editable;
|
||||
return old_on_loaded.call(this, data, grouped);
|
||||
}
|
||||
});
|
||||
|
||||
_.extend(openerp.base.ListView.Groups.prototype, /** @lends openerp.base.ListView.Groups# */{
|
||||
passtrough_events: openerp.base.ListView.Groups.prototype.passtrough_events + " edit saved",
|
||||
new_record: function () {
|
||||
// TODO: handle multiple children
|
||||
this.children[null].new_record();
|
||||
}
|
||||
});
|
||||
|
||||
var old_list_row_clicked = openerp.base.ListView.List.prototype.row_clicked;
|
||||
_.extend(openerp.base.ListView.List.prototype, /** @lends openerp.base.ListView.List */{
|
||||
row_clicked: function (event) {
|
||||
if (!this.options.editable) {
|
||||
return old_list_row_clicked.call(this, event);
|
||||
}
|
||||
this.edit_record();
|
||||
},
|
||||
/**
|
||||
* Checks if a record is being edited, and if so cancels it
|
||||
*/
|
||||
cancel_pending_edition: function () {
|
||||
if (!this.edition) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.edition_index !== null) {
|
||||
this.reload_record(this.edition_index);
|
||||
}
|
||||
this.edition_form.stop();
|
||||
this.edition_form.$element.remove();
|
||||
delete this.edition_form;
|
||||
delete this.edition_index;
|
||||
delete this.edition;
|
||||
},
|
||||
render_row_as_form: function (row) {
|
||||
this.cancel_pending_edition();
|
||||
|
||||
var self = this;
|
||||
var $new_row = $('<tr>', {
|
||||
id: _.uniqueId('oe-editable-row-'),
|
||||
'class': $(row).attr('class'),
|
||||
click: function (e) {e.stopPropagation();}
|
||||
})
|
||||
.keyup(function (e) {
|
||||
switch (e.which) {
|
||||
case KEY_RETURN:
|
||||
self.save_row(true);
|
||||
break;
|
||||
case KEY_ESCAPE:
|
||||
self.cancel_edition();
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
})
|
||||
.delegate('button.oe-edit-row-save', 'click', function () {
|
||||
self.save_row();
|
||||
})
|
||||
.delegate('button.oe-edit-row-cancel', 'click', function () {
|
||||
self.cancel_edition();
|
||||
});
|
||||
if (row) {
|
||||
$new_row.replaceAll(row);
|
||||
} else if (this.options.editable === 'top') {
|
||||
this.$current.prepend($new_row);
|
||||
} else if (this.options.editable) {
|
||||
this.$current.append($new_row);
|
||||
}
|
||||
this.edition = true;
|
||||
this.edition_index = this.dataset.index;
|
||||
this.edition_form = _.extend(new openerp.base.FormView(
|
||||
null, this.group.view.session, $new_row.attr('id'),
|
||||
this.dataset, false), {
|
||||
template: 'ListView.row.form',
|
||||
registry: openerp.base.list.form.widgets
|
||||
});
|
||||
$.when(this.edition_form.on_loaded({fields_view: this.get_fields_view()})).then(function () {
|
||||
// put in $.when just in case FormView.on_loaded becomes asynchronous
|
||||
$new_row.find('td')
|
||||
.addClass('oe-field-cell')
|
||||
.removeAttr('width')
|
||||
.end()
|
||||
.find('td:first').removeClass('oe-field-cell').end()
|
||||
.find('td:last').removeClass('oe-field-cell').end();
|
||||
// pad in case of groupby
|
||||
_(self.columns).each(function (column) {
|
||||
if (column.meta) {
|
||||
$new_row.prepend('<td>');
|
||||
}
|
||||
});
|
||||
|
||||
self.edition_form.do_show();
|
||||
});
|
||||
},
|
||||
/**
|
||||
* Saves the current row, and triggers the edition of its following
|
||||
* sibling if asked.
|
||||
*
|
||||
* @param {Boolean} [edit_next=false] should the next row become editable
|
||||
*/
|
||||
save_row: function (edit_next) {
|
||||
var self = this;
|
||||
this.edition_form.do_save(function (result) {
|
||||
self.reload_record(self.dataset.index, true).then(function () {
|
||||
self.edition_form.stop();
|
||||
delete self.edition_form;
|
||||
delete self.edition_index;
|
||||
delete self.edition;
|
||||
|
||||
$(self).trigger('saved', [self.dataset]);
|
||||
if (!edit_next) {
|
||||
return;
|
||||
}
|
||||
if (result.created) {
|
||||
self.new_record();
|
||||
return;
|
||||
}
|
||||
self.dataset.next();
|
||||
self.edit_record();
|
||||
});
|
||||
}, this.options.editable === 'top');
|
||||
},
|
||||
/**
|
||||
* Cancels the edition of the row for the current dataset index
|
||||
*/
|
||||
cancel_edition: function () {
|
||||
this.cancel_pending_edition();
|
||||
},
|
||||
/**
|
||||
* Edits record currently selected via dataset
|
||||
*/
|
||||
edit_record: function () {
|
||||
this.render_row_as_form(
|
||||
this.$current.children(
|
||||
_.sprintf('[data-index=%d]',
|
||||
this.dataset.index)));
|
||||
$(this).trigger(
|
||||
'edit',
|
||||
[this.rows[this.dataset.index].data.id.value, this.dataset]);
|
||||
},
|
||||
new_record: function () {
|
||||
this.dataset.index = null;
|
||||
this.render_row_as_form();
|
||||
}
|
||||
});
|
||||
openerp.base.list = {form: {}};
|
||||
openerp.base.list.form.WidgetFrame = openerp.base.form.WidgetFrame.extend({
|
||||
template: 'ListView.row.frame'
|
||||
});
|
||||
var form_widgets = openerp.base.form.widgets;
|
||||
openerp.base.list.form.widgets = form_widgets.clone({
|
||||
'frame': 'openerp.base.list.form.WidgetFrame'
|
||||
});
|
||||
// All form widgets inherit a problematic behavior from
|
||||
// openerp.base.form.WidgetFrame: the cell itself is removed when invisible
|
||||
// whether it's @invisible or @attrs[invisible]. In list view, only the
|
||||
// former should completely remove the cell. We need to override update_dom
|
||||
// on all widgets since we can't just hit on widget itself (I think)
|
||||
var list_form_widgets = openerp.base.list.form.widgets;
|
||||
_(list_form_widgets.map).each(function (widget_path, key) {
|
||||
if (key === 'frame') { return; }
|
||||
var new_path = 'openerp.base.list.form.' + key;
|
||||
|
||||
openerp.base.list.form[key] = (form_widgets.get_object(key)).extend({
|
||||
update_dom: function () {
|
||||
this.$element.children().css('visibility', '');
|
||||
if (this.invisible && this.node.attrs.invisible !== '1') {
|
||||
this.$element.children().css('visibility', 'hidden');
|
||||
} else {
|
||||
this._super();
|
||||
}
|
||||
}
|
||||
});
|
||||
list_form_widgets.add(key, new_path);
|
||||
});
|
||||
};
|
||||
+221
-145
@@ -83,8 +83,8 @@ openerp.base.ListView = openerp.base.View.extend( /** @lends openerp.base.ListVi
|
||||
'action': function (e, action_name, id, callback) {
|
||||
self.do_action(action_name, id, callback);
|
||||
},
|
||||
'row_link': function (e, index, id, dataset) {
|
||||
self.do_activate_record(index, id, dataset);
|
||||
'row_link': function (e, id, dataset) {
|
||||
self.do_activate_record(dataset.index, id, dataset);
|
||||
}
|
||||
});
|
||||
},
|
||||
@@ -134,9 +134,11 @@ openerp.base.ListView = openerp.base.View.extend( /** @lends openerp.base.ListVi
|
||||
this.$element.html(QWeb.render("ListView", this));
|
||||
|
||||
// Head hook
|
||||
this.$element.find('#oe-list-add').click(this.do_add_record);
|
||||
this.$element.find('#oe-list-add')
|
||||
.click(this.do_add_record)
|
||||
.attr('disabled', grouped && this.options.editable);
|
||||
this.$element.find('#oe-list-delete')
|
||||
.hide()
|
||||
.attr('disabled', true)
|
||||
.click(this.do_delete_selected);
|
||||
this.$element.find('thead').delegate('th[data-id]', 'click', function (e) {
|
||||
e.stopPropagation();
|
||||
@@ -199,18 +201,24 @@ openerp.base.ListView = openerp.base.View.extend( /** @lends openerp.base.ListVi
|
||||
return column.invisible !== '1';
|
||||
});
|
||||
|
||||
this.aggregate_columns = _(this.columns).chain()
|
||||
.filter(function (column) {
|
||||
return column['sum'] || column['avg'];})
|
||||
this.aggregate_columns = _(this.visible_columns)
|
||||
.map(function (column) {
|
||||
var func = column['sum'] ? 'sum' : 'avg';
|
||||
if (column.type !== 'integer' && column.type !== 'float') {
|
||||
return {};
|
||||
}
|
||||
var aggregation_func = column['group_operator'] || 'sum';
|
||||
|
||||
if (!column[aggregation_func]) {
|
||||
return {};
|
||||
}
|
||||
|
||||
return {
|
||||
field: column.id,
|
||||
type: column.type,
|
||||
'function': func,
|
||||
label: column[func]
|
||||
'function': aggregation_func,
|
||||
label: column[aggregation_func]
|
||||
};
|
||||
}).value();
|
||||
});
|
||||
},
|
||||
/**
|
||||
* Used to handle a click on a table row, if no other handler caught the
|
||||
@@ -267,6 +275,7 @@ openerp.base.ListView = openerp.base.View.extend( /** @lends openerp.base.ListVi
|
||||
return this.rpc('/base/listview/load', {
|
||||
model: this.model,
|
||||
view_id: this.view_id,
|
||||
context: this.dataset.context,
|
||||
toolbar: !!this.flags.sidebar
|
||||
}, callback);
|
||||
}
|
||||
@@ -289,25 +298,32 @@ openerp.base.ListView = openerp.base.View.extend( /** @lends openerp.base.ListVi
|
||||
* @returns {$.Deferred} fold request evaluation promise
|
||||
*/
|
||||
do_search: function (domains, contexts, groupbys) {
|
||||
var self = this;
|
||||
return this.rpc('/base/session/eval_domain_and_context', {
|
||||
domains: domains,
|
||||
contexts: contexts,
|
||||
group_by_seq: groupbys
|
||||
}, function (results) {
|
||||
self.dataset.context = results.context;
|
||||
self.dataset.domain = results.domain;
|
||||
self.groups.datagroup = new openerp.base.DataGroup(
|
||||
self.session, self.model,
|
||||
results.domain, results.context,
|
||||
results.group_by);
|
||||
}, $.proxy(this, 'do_actual_search'));
|
||||
},
|
||||
/**
|
||||
* Handler for the result of eval_domain_and_context, actually perform the
|
||||
* searching
|
||||
*
|
||||
* @param {Object} results results of evaluating domain and process for a search
|
||||
*/
|
||||
do_actual_search: function (results) {
|
||||
this.dataset.context = results.context;
|
||||
this.dataset.domain = results.domain;
|
||||
this.groups.datagroup = new openerp.base.DataGroup(
|
||||
this.session, this.model,
|
||||
results.domain, results.context,
|
||||
results.group_by);
|
||||
|
||||
if (_.isEmpty(results.group_by) && !results.context['group_by_no_leaf']) {
|
||||
results.group_by = null;
|
||||
}
|
||||
self.reload_view(!!results.group_by).then(
|
||||
$.proxy(self, 'reload_content'));
|
||||
});
|
||||
if (_.isEmpty(results.group_by) && !results.context['group_by_no_leaf']) {
|
||||
results.group_by = null;
|
||||
}
|
||||
|
||||
this.reload_view(!!results.group_by).then(
|
||||
$.proxy(this, 'reload_content'));
|
||||
},
|
||||
/**
|
||||
* Handles the signal to delete a line from the DOM
|
||||
@@ -349,13 +365,15 @@ openerp.base.ListView = openerp.base.View.extend( /** @lends openerp.base.ListVi
|
||||
*/
|
||||
do_select: function (ids, records) {
|
||||
this.$element.find('#oe-list-delete')
|
||||
.toggle(!!ids.length);
|
||||
.attr('disabled', !ids.length);
|
||||
|
||||
if (!records.length) {
|
||||
this.compute_aggregates();
|
||||
return;
|
||||
}
|
||||
this.compute_aggregates(records);
|
||||
this.compute_aggregates(_(records).map(function (record) {
|
||||
return {count: 1, values: record};
|
||||
}));
|
||||
},
|
||||
/**
|
||||
* Handles action button signals on a record
|
||||
@@ -382,7 +400,7 @@ openerp.base.ListView = openerp.base.View.extend( /** @lends openerp.base.ListVi
|
||||
*
|
||||
* @param {Number} index index of the record in the dataset
|
||||
* @param {Object} id identifier of the activated record
|
||||
* @param {openobject.base.DataSet} dataset dataset in which the record is available (may not be the listview's dataset in case of nested groups)
|
||||
* @param {openerp.base.DataSet} dataset dataset in which the record is available (may not be the listview's dataset in case of nested groups)
|
||||
*/
|
||||
do_activate_record: function (index, id, dataset) {
|
||||
var self = this;
|
||||
@@ -420,75 +438,56 @@ openerp.base.ListView = openerp.base.View.extend( /** @lends openerp.base.ListVi
|
||||
* @param {Array} [records]
|
||||
*/
|
||||
compute_aggregates: function (records) {
|
||||
if (_.isEmpty(this.aggregate_columns)) {
|
||||
return;
|
||||
}
|
||||
var columns = _(this.aggregate_columns).filter(function (column) {
|
||||
return column['function']; });
|
||||
|
||||
if (_.isEmpty(columns)) { return; }
|
||||
|
||||
if (_.isEmpty(records)) {
|
||||
records = this.groups.get_records();
|
||||
}
|
||||
|
||||
var aggregator = this.build_aggregator(this.aggregate_columns);
|
||||
this.display_aggregates(
|
||||
_(records).reduce(aggregator, aggregator).value());
|
||||
},
|
||||
/**
|
||||
* Creates a stateful callable aggregator object, which can be reduced over
|
||||
* a collection of records in order to build the aggregations described
|
||||
* by the parameter
|
||||
*
|
||||
* @param {Array} aggregation_descriptors
|
||||
*/
|
||||
build_aggregator: function (aggregation_descriptors) {
|
||||
var values = {};
|
||||
var descriptors = {};
|
||||
_(aggregation_descriptors).each(function (descriptor) {
|
||||
values[descriptor.field] = [];
|
||||
descriptors[descriptor.field] = descriptor;
|
||||
});
|
||||
|
||||
var aggregator = function (_i, record) {
|
||||
_(values).each(function (collection, key) {
|
||||
collection.push(record[key]);
|
||||
});
|
||||
|
||||
return aggregator;
|
||||
};
|
||||
aggregator.value = function () {
|
||||
var result = {};
|
||||
|
||||
_(values).each(function (collection, key) {
|
||||
var value;
|
||||
switch(descriptors[key]['function']) {
|
||||
case 'avg':
|
||||
value = (_(collection).chain()
|
||||
.filter(function (item) {
|
||||
return !_.isUndefined(item); })
|
||||
.reduce(function (total, item) {
|
||||
return total + item; }, 0).value()
|
||||
/ collection.length);
|
||||
break;
|
||||
var count = 0, sums = {};
|
||||
_(columns).each(function (column) { sums[column.field] = 0; });
|
||||
_(records).each(function (record) {
|
||||
count += record.count || 1;
|
||||
_(columns).each(function (column) {
|
||||
var field = column.field;
|
||||
switch (column['function']) {
|
||||
case 'sum':
|
||||
value = (_(collection).chain()
|
||||
.filter(function (item) {
|
||||
return !_.isUndefined(item); })
|
||||
.reduce(function (total, item) {
|
||||
return total + item; }, 0).value());
|
||||
sums[field] += record.values[field];
|
||||
break;
|
||||
case 'avg':
|
||||
sums[field] += record.count * record.values[field];
|
||||
break;
|
||||
}
|
||||
result[key] = value;
|
||||
});
|
||||
});
|
||||
|
||||
return result;
|
||||
};
|
||||
return aggregator;
|
||||
var aggregates = {};
|
||||
_(columns).each(function (column) {
|
||||
var field = column.field;
|
||||
switch (column['function']) {
|
||||
case 'sum':
|
||||
aggregates[field] = sums[field];
|
||||
break;
|
||||
case 'avg':
|
||||
aggregates[field] = sums[field] / count;
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
||||
this.display_aggregates(aggregates);
|
||||
},
|
||||
display_aggregates: function (aggregation) {
|
||||
var $footer = this.$element.find('.oe-list-footer').empty();
|
||||
var $footer_cells = this.$element.find('.oe-list-footer');
|
||||
_(this.aggregate_columns).each(function (column) {
|
||||
$(_.sprintf(
|
||||
"<span>%s: %.2f</span>",
|
||||
column.label, aggregation[column.field]))
|
||||
.appendTo($footer);
|
||||
if (!column['function']) {
|
||||
return;
|
||||
}
|
||||
var pattern = (column.type == 'integer') ? '%d' : '%.2f';
|
||||
$footer_cells.filter(_.sprintf('[data-field=%s]', column.field))
|
||||
.text(_.sprintf(pattern, aggregation[column.field]));
|
||||
});
|
||||
}
|
||||
// TODO: implement reorder (drag and drop rows)
|
||||
@@ -521,8 +520,9 @@ openerp.base.ListView.List = Class.extend( /** @lends openerp.base.ListView.List
|
||||
* @constructs
|
||||
* @param {Object} opts display options, identical to those of :js:class:`openerp.base.ListView`
|
||||
*/
|
||||
init: function (opts) {
|
||||
init: function (group, opts) {
|
||||
var self = this;
|
||||
this.group = group;
|
||||
|
||||
this.options = opts.options;
|
||||
this.columns = opts.columns;
|
||||
@@ -546,19 +546,26 @@ openerp.base.ListView.List = Class.extend( /** @lends openerp.base.ListView.List
|
||||
e.stopPropagation();
|
||||
var $target = $(e.currentTarget),
|
||||
field = $target.closest('td').data('field'),
|
||||
record_id = self.row_id($target.closest('tr'));
|
||||
$row = $target.closest('tr'),
|
||||
record_id = self.row_id($row),
|
||||
index = self.row_position($row);
|
||||
|
||||
$(self).trigger('action', [field, record_id]);
|
||||
$(self).trigger('action', [field, record_id, function () {
|
||||
self.reload_record(index, true);
|
||||
}]);
|
||||
})
|
||||
.delegate('tr', 'click', function (e) {
|
||||
e.stopPropagation();
|
||||
$(self).trigger(
|
||||
'row_link',
|
||||
[self.row_position(e.currentTarget),
|
||||
self.row_id(e.currentTarget),
|
||||
self.dataset]);
|
||||
self.dataset.index = self.row_position(e.currentTarget);
|
||||
self.row_clicked(e);
|
||||
});
|
||||
},
|
||||
row_clicked: function () {
|
||||
$(this).trigger(
|
||||
'row_link',
|
||||
[this.rows[this.dataset.index].data.id.value,
|
||||
this.dataset]);
|
||||
},
|
||||
render: function () {
|
||||
if (this.$current) {
|
||||
this.$current.remove();
|
||||
@@ -566,6 +573,18 @@ openerp.base.ListView.List = Class.extend( /** @lends openerp.base.ListView.List
|
||||
this.$current = this.$_element.clone(true);
|
||||
this.$current.empty().append($(QWeb.render('ListView.rows', this)));
|
||||
},
|
||||
get_fields_view: function () {
|
||||
// deep copy of view
|
||||
var view = $.extend(true, {}, this.group.view.fields_view);
|
||||
_(view.arch.children).each(function (widget) {
|
||||
widget.attrs.nolabel = true;
|
||||
if (widget.tag === 'button') {
|
||||
delete widget.attrs.string;
|
||||
}
|
||||
});
|
||||
view.arch.attrs.col = 2 * view.arch.children.length;
|
||||
return view;
|
||||
},
|
||||
/**
|
||||
* Gets the ids of all currently selected records, if any
|
||||
* @returns {Object} object with the keys ``ids`` and ``records``, holding respectively the ids of all selected records and the records themselves.
|
||||
@@ -579,7 +598,7 @@ openerp.base.ListView.List = Class.extend( /** @lends openerp.base.ListView.List
|
||||
this.$current.find('th.oe-record-selector input:checked')
|
||||
.closest('tr').each(function () {
|
||||
var record = {};
|
||||
_(rows[$(this).prevAll().length].data).each(function (obj, key) {
|
||||
_(rows[$(this).data('index')].data).each(function (obj, key) {
|
||||
record[key] = obj.value;
|
||||
});
|
||||
result.ids.push(record.id);
|
||||
@@ -594,7 +613,7 @@ openerp.base.ListView.List = Class.extend( /** @lends openerp.base.ListView.List
|
||||
* @returns {Number} the position of the row in this.rows
|
||||
*/
|
||||
row_position: function (row) {
|
||||
return $(row).prevAll().length;
|
||||
return $(row).data('index');
|
||||
},
|
||||
/**
|
||||
* Returns the identifier of the object displayed in the provided table
|
||||
@@ -621,13 +640,86 @@ openerp.base.ListView.List = Class.extend( /** @lends openerp.base.ListView.List
|
||||
_(row.data).each(function (obj, key) {
|
||||
record[key] = obj.value;
|
||||
});
|
||||
return record;
|
||||
return {count: 1, values: record};
|
||||
});
|
||||
},
|
||||
/**
|
||||
* Transforms a record from what is returned by a dataset read (a simple
|
||||
* mapping of ``$fieldname: $value``) to the format expected by list rows
|
||||
* and form views:
|
||||
*
|
||||
* data: {
|
||||
* $fieldname: {
|
||||
* value: $value
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* This format allows for the insertion of a bunch of metadata (names,
|
||||
* colors, etc...)
|
||||
*
|
||||
* @param {Object} record original record, in dataset format
|
||||
* @returns {Object} record displayable in a form or list view
|
||||
*/
|
||||
transform_record: function (record) {
|
||||
// TODO: colors handling
|
||||
var form_data = {},
|
||||
form_record = {data: form_data};
|
||||
|
||||
_(record).each(function (value, key) {
|
||||
form_data[key] = {value: value};
|
||||
});
|
||||
|
||||
return form_record;
|
||||
},
|
||||
/**
|
||||
* Reloads the record at index ``row_index`` in the list's rows.
|
||||
*
|
||||
* By default, simply re-renders the record. If the ``fetch`` parameter is
|
||||
* provided and ``true``, will first fetch the record anew.
|
||||
*
|
||||
* @param {Number} record_index index of the record to reload
|
||||
* @param {Boolean} fetch fetches the record from remote before reloading it
|
||||
*/
|
||||
reload_record: function (record_index, fetch) {
|
||||
var self = this;
|
||||
var read_p = null;
|
||||
if (fetch) {
|
||||
// save index to restore it later, if already set
|
||||
var old_index = this.dataset.index;
|
||||
this.dataset.index = record_index;
|
||||
read_p = this.dataset.read_index(
|
||||
_.filter(_.pluck(this.columns, 'name'), _.identity),
|
||||
function (record) {
|
||||
var form_record = self.transform_record(record);
|
||||
self.rows.splice(record_index, 1, form_record);
|
||||
self.dataset.index = old_index;
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
return $.when(read_p).then(function () {
|
||||
self.$current.children().eq(record_index)
|
||||
.replaceWith(self.render_record(record_index)); })
|
||||
},
|
||||
/**
|
||||
* Renders a list record to HTML
|
||||
*
|
||||
* @param {Number} record_index index of the record to render in ``this.rows``
|
||||
* @returns {String} QWeb rendering of the selected record
|
||||
*/
|
||||
render_record: function (record_index) {
|
||||
return QWeb.render('ListView.row', {
|
||||
columns: this.columns,
|
||||
options: this.options,
|
||||
row: this.rows[record_index],
|
||||
row_parity: (record_index % 2 === 0) ? 'even' : 'odd',
|
||||
row_index: record_index
|
||||
});
|
||||
}
|
||||
// drag and drop
|
||||
// editable?
|
||||
});
|
||||
openerp.base.ListView.Groups = Class.extend( /** @lends openerp.base.ListView.Groups# */{
|
||||
passtrough_events: 'action deleted row_link',
|
||||
/**
|
||||
* Grouped display for the ListView. Handles basic DOM events and interacts
|
||||
* with the :js:class:`~openerp.base.DataGroup` bound to it.
|
||||
@@ -679,24 +771,11 @@ openerp.base.ListView.Groups = Class.extend( /** @lends openerp.base.ListView.Gr
|
||||
}
|
||||
return red_letter_tboday;
|
||||
},
|
||||
open_group: function (e, group) {
|
||||
var row = e.currentTarget;
|
||||
|
||||
if (this.children[group.value]) {
|
||||
this.children[group.value].apoptosis();
|
||||
delete this.children[group.value];
|
||||
}
|
||||
var prospekt = this.children[group.value] = new openerp.base.ListView.Groups(this.view, {
|
||||
options: this.options,
|
||||
columns: this.columns
|
||||
});
|
||||
this.bind_child_events(prospekt);
|
||||
prospekt.datagroup = group;
|
||||
prospekt.render().insertAfter(
|
||||
this.point_insertion(row));
|
||||
$(row).find('span.ui-icon')
|
||||
.removeClass('ui-icon-triangle-1-e')
|
||||
.addClass('ui-icon-triangle-1-s');
|
||||
open: function (point_insertion) {
|
||||
this.render().insertAfter(point_insertion);
|
||||
},
|
||||
close: function () {
|
||||
this.apoptosis();
|
||||
},
|
||||
/**
|
||||
* Prefixes ``$node`` with floated spaces in order to indent it relative
|
||||
@@ -716,18 +795,32 @@ openerp.base.ListView.Groups = Class.extend( /** @lends openerp.base.ListView.Gr
|
||||
var self = this;
|
||||
var placeholder = this.make_fragment();
|
||||
_(datagroups).each(function (group) {
|
||||
if (self.children[group.value]) {
|
||||
self.children[group.value].apoptosis();
|
||||
delete self.children[group.value];
|
||||
}
|
||||
var child = self.children[group.value] = new openerp.base.ListView.Groups(self.view, {
|
||||
options: self.options,
|
||||
columns: self.columns
|
||||
});
|
||||
self.bind_child_events(child);
|
||||
child.datagroup = group;
|
||||
|
||||
var $row = $('<tr>');
|
||||
if (group.openable) {
|
||||
$row.click(function (e) {
|
||||
if (!$row.data('open')) {
|
||||
$row.data('open', true);
|
||||
self.open_group(e, group);
|
||||
$row.data('open', true)
|
||||
.find('span.ui-icon')
|
||||
.removeClass('ui-icon-triangle-1-e')
|
||||
.addClass('ui-icon-triangle-1-s');
|
||||
child.open(self.point_insertion(e.currentTarget));
|
||||
} else {
|
||||
$row.removeData('open')
|
||||
.find('span.ui-icon')
|
||||
.removeClass('ui-icon-triangle-1-s')
|
||||
.addClass('ui-icon-triangle-1-e');
|
||||
_(self.children).each(function (child) {child.apoptosis();});
|
||||
child.close();
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -779,21 +872,7 @@ openerp.base.ListView.Groups = Class.extend( /** @lends openerp.base.ListView.Gr
|
||||
// can have selections spanning multiple links
|
||||
var selection = self.get_selection();
|
||||
$this.trigger(e, [selection.ids, selection.records]);
|
||||
}).bind('action', function (e, name, id, callback) {
|
||||
if (!callback) {
|
||||
callback = function () {
|
||||
var $prev = child.$current.prev();
|
||||
if (!$prev.is('tbody')) {
|
||||
// ungrouped
|
||||
$(self.elements[0]).replaceWith(self.render());
|
||||
} else {
|
||||
// ghetto reload child (and its siblings)
|
||||
$prev.children().last().click();
|
||||
}
|
||||
};
|
||||
}
|
||||
$this.trigger(e, [name, id, callback]);
|
||||
}).bind('deleted row_link', function (e) {
|
||||
}).bind(this.passtrough_events, function (e) {
|
||||
// additional positional parameters are provided to trigger as an
|
||||
// Array, following the event type or event object, but are
|
||||
// provided to the .bind event handler as *args.
|
||||
@@ -806,7 +885,7 @@ openerp.base.ListView.Groups = Class.extend( /** @lends openerp.base.ListView.Gr
|
||||
},
|
||||
render_dataset: function (dataset) {
|
||||
var rows = [],
|
||||
list = new openerp.base.ListView.List({
|
||||
list = new openerp.base.ListView.List(this, {
|
||||
options: this.options,
|
||||
columns: this.columns,
|
||||
dataset: dataset,
|
||||
@@ -819,17 +898,8 @@ openerp.base.ListView.Groups = Class.extend( /** @lends openerp.base.ListView.Gr
|
||||
_.filter(_.pluck(this.columns, 'name'), _.identity),
|
||||
0, false,
|
||||
function (records) {
|
||||
var form_records = _(records).map(function (record) {
|
||||
// TODO: colors handling
|
||||
var form_data = {},
|
||||
form_record = {data: form_data};
|
||||
|
||||
_(record).each(function (value, key) {
|
||||
form_data[key] = {value: value};
|
||||
});
|
||||
|
||||
return form_record;
|
||||
});
|
||||
var form_records = _(records).map(
|
||||
$.proxy(list, 'transform_record'));
|
||||
|
||||
rows.splice(0, rows.length);
|
||||
rows.push.apply(rows, form_records);
|
||||
@@ -881,6 +951,12 @@ openerp.base.ListView.Groups = Class.extend( /** @lends openerp.base.ListView.Gr
|
||||
return this;
|
||||
},
|
||||
get_records: function () {
|
||||
if (_(this.children).isEmpty()) {
|
||||
return {
|
||||
count: this.datagroup.length,
|
||||
values: this.datagroup.aggregates
|
||||
}
|
||||
}
|
||||
return _(this.children).chain()
|
||||
.map(function (child) {
|
||||
return child.get_records();
|
||||
|
||||
@@ -1,4 +1,16 @@
|
||||
openerp.base.m2o = function(openerp){
|
||||
|
||||
/*
|
||||
<input type="text"
|
||||
t-att-name="widget.name"
|
||||
t-att-id="widget.element_id + '_field'"
|
||||
t-att-class="'field_' + widget.type"
|
||||
t-att-type="widget.type"
|
||||
style="width: 100%;"/>
|
||||
<span type='button' t-att-class="'ui_combo'" tabindex="'-1'" title="'Show All Items'"></span>
|
||||
<img t-att-id="widget.name + '_open'" t-att-alt="'Open'" t-att-title="'Create'"
|
||||
t-att-src="'/base/static/src/img/iconset-d-drop.gif'" t-att-class="'m2o_open'"/>
|
||||
*/
|
||||
|
||||
openerp.base.m2o = openerp.base.Controller.extend({
|
||||
init: function(element_id, model, dataset, session){
|
||||
|
||||
@@ -9,7 +9,7 @@ openerp.base.ActionManager = openerp.base.Controller.extend({
|
||||
init: function(session, element_id) {
|
||||
this._super(session, element_id);
|
||||
this.viewmanager = null;
|
||||
this.dialog_stack = []
|
||||
this.dialog_stack = [];
|
||||
// Temporary linking view_manager to session.
|
||||
// Will use controller_parent to find it when implementation will be done.
|
||||
session.action_manager = this;
|
||||
@@ -33,8 +33,7 @@ openerp.base.ActionManager = openerp.base.Controller.extend({
|
||||
case 'ir.actions.act_window':
|
||||
if (action.target == 'new') {
|
||||
var element_id = _.uniqueId("act_window_dialog");
|
||||
var dialog = $('<div id="' + element_id + '"></div>');
|
||||
dialog.dialog({
|
||||
$('<div>', {id: element_id}).dialog({
|
||||
title: action.name,
|
||||
modal: true,
|
||||
width: '50%',
|
||||
@@ -347,7 +346,7 @@ openerp.base.Sidebar = openerp.base.BaseWidget.extend({
|
||||
var action = self.sections[index[0]].elements[index[1]];
|
||||
action.flags = {
|
||||
new_window : true
|
||||
}
|
||||
};
|
||||
self.session.action_manager.do_action(action);
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
@@ -392,7 +391,7 @@ openerp.base.View = openerp.base.Controller.extend({
|
||||
var context = _.extend({}, dataset.context, action_data.context || {});
|
||||
switch(action_data.type) {
|
||||
case 'object':
|
||||
return dataset.call(action_data.name, [record_id], [context], handler);
|
||||
return dataset.call(action_data.name, [[record_id], context], handler);
|
||||
case 'action':
|
||||
return this.rpc('/base/action/load', { action_id: parseInt(action_data.name, 10) }, handler);
|
||||
default:
|
||||
|
||||
@@ -60,14 +60,20 @@
|
||||
<table align="center" cellspacing="2px" cellpadding="0">
|
||||
<tr>
|
||||
<td><label for="db">Database:</label></td>
|
||||
<td class="oe_field_value">
|
||||
<td>
|
||||
<t t-if="!db_list">
|
||||
<input type="text" name="db" value="trunk" autofocus="true"/>
|
||||
</t>
|
||||
<t t-if="db_list">
|
||||
<select name="db">
|
||||
<t t-foreach="db_list" t-as="db">
|
||||
<option t-att-value="db" t-att-selected="db == 'trunk'"><t t-esc="db"/></option>
|
||||
<t t-if="selected_db === db">
|
||||
<option t-att-value="db" selected="true">
|
||||
<t t-esc="db"/></option>
|
||||
</t>
|
||||
<t t-if="selected_db !== db">
|
||||
<option t-att-value="db"><t t-esc="db"/></option>
|
||||
</t>
|
||||
</t>
|
||||
</select>
|
||||
</t>
|
||||
@@ -75,15 +81,28 @@
|
||||
</tr>
|
||||
<tr>
|
||||
<td><label for="login">User:</label></td>
|
||||
<td class="oe_field_value"><input type="text" name="login" value="admin" autofocus="true"/></td>
|
||||
<td><input type="text" name="login"
|
||||
t-att-value="selected_login || ''" autofocus="true"/></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><label for="password">Password:</label></td>
|
||||
<td class="oe_field_value"><input type="password" name="password" value="a"/></td>
|
||||
<td><input type="password" name="password"
|
||||
t-att-value="selected_password || ''"/></td>
|
||||
</tr>
|
||||
<tr t-if="has_local_storage">
|
||||
<td><label for="remember">Rember password:</label></td>
|
||||
<td class="oe_remember">
|
||||
<t t-if="remember">
|
||||
<input type="checkbox" name="remember" checked="yes"/>
|
||||
</t>
|
||||
<t t-if="!remember">
|
||||
<input type="checkbox" name="remember"/>
|
||||
</t>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td class="oe_field_value">
|
||||
<td>
|
||||
<button type="submit" name="submit">Login</button>
|
||||
</td>
|
||||
</tr>
|
||||
@@ -281,11 +300,13 @@
|
||||
<th t-if="options.deletable"/>
|
||||
</tr>
|
||||
</thead>
|
||||
<tfoot class="ui-widget-header" t-if="aggregate_columns.length">
|
||||
<tfoot class="ui-widget-header">
|
||||
<tr>
|
||||
<td t-att-colspan="columns_count" class='oe-list-footer'>
|
||||
|
||||
<td t-if="options.selectable"/>
|
||||
<td t-foreach="aggregate_columns" t-as="column" class="oe-list-footer oe-number"
|
||||
t-att-data-field="column.field" t-att-title="column.label">
|
||||
</td>
|
||||
<td t-if="options.deletable"/>
|
||||
</tr>
|
||||
</tfoot>
|
||||
</table>
|
||||
@@ -297,7 +318,8 @@
|
||||
</t-if>
|
||||
</t>
|
||||
</t>
|
||||
<tr t-name="ListView.row" t-att-style="style" t-att-class="row_parity">
|
||||
<tr t-name="ListView.row" t-att-style="style" t-att-class="row_parity"
|
||||
t-att-data-index="row_index">
|
||||
<t t-foreach="columns" t-as="column">
|
||||
<td t-if="column.meta">
|
||||
|
||||
@@ -307,8 +329,10 @@
|
||||
<input type="checkbox"/>
|
||||
</th>
|
||||
<t t-foreach="columns" t-as="column">
|
||||
<t t-set="align" t-value="column.type === 'integer' or column.type == 'float'"/>
|
||||
<td t-if="!column.meta and column.invisible !== '1'" t-att-title="column.help"
|
||||
class="oe-field-cell" t-att-data-field="column.id">
|
||||
t-att-class="'oe-field-cell' + (align ? ' oe-number' : '')"
|
||||
t-att-data-field="column.id">
|
||||
<t t-set="attrs" t-value="column.attrs_for(row.data)"/>
|
||||
<t t-if="!attrs.invisible">
|
||||
<t t-set="is_button" t-value="column.tag === 'button'"/>
|
||||
@@ -329,6 +353,9 @@
|
||||
<button type="button" name="delete">♻</button>
|
||||
</td>
|
||||
</tr>
|
||||
<t t-name="ListView.row.form">
|
||||
<t t-raw="frame.render()"/>
|
||||
</t>
|
||||
<t t-name="FormView">
|
||||
<h2 class="oe_view_title"><t t-esc="view.fields_view.arch.attrs.string"/></h2>
|
||||
<div class="oe_form_header" t-att-id="view.element_id + '_header'">
|
||||
@@ -498,15 +525,17 @@
|
||||
</select>
|
||||
</t>
|
||||
<t t-name="FieldMany2One">
|
||||
<div style="padding-right: 16px;white-space: nowrap;">
|
||||
<input type="text"
|
||||
t-att-name="widget.name"
|
||||
t-att-id="widget.element_id + '_field'"
|
||||
t-att-class="'field_' + widget.type"
|
||||
t-att-type="widget.type"
|
||||
style="width: 100%;"/>
|
||||
<span type='button' t-att-class="'ui_combo'" tabindex="'-1'" title="'Show All Items'"></span>
|
||||
<img t-att-id="widget.name + '_open'" t-att-alt="'Open'" t-att-title="'Create'" t-att-src="'/base/static/src/img/iconset-d-drop.gif'" t-att-class="'m2o_open'"/>
|
||||
<div t-att-id="widget.element_id" class="oe-m2o">
|
||||
<input t-att-id="widget.element_id + '_input'" type="text" style="width: 100%;"/>
|
||||
<span class="oe-m2o-drop-down-button" t-att-id="widget.element_id + '_drop_down'">
|
||||
<img src="/base/static/src/img/down-arrow.png" /></span>
|
||||
<span class="oe-m2o-cm-button" t-att-id="widget.name + '_open'">
|
||||
<img src="/base/static/src/img/icons/gtk-index.png"/></span>
|
||||
<div t-att-id="widget.cm_id" class="contextMenu" style="display:none"><ul>
|
||||
<li t-att-id="widget.cm_id + '_search'">Search</li>
|
||||
<li t-att-id="widget.cm_id + '_create'">Create New</li>
|
||||
<li t-att-id="widget.cm_id + '_open'" style="color:grey">Open</li>
|
||||
</ul></div>
|
||||
</div>
|
||||
</t>
|
||||
<t t-name="FieldOne2Many">
|
||||
@@ -863,4 +892,23 @@
|
||||
<button type="button" class="oe_many2xselectpopup-form-save">Save</button>
|
||||
<button type="button" class="oe_many2xselectpopup-form-close">Close</button>
|
||||
</t>
|
||||
|
||||
<t t-name="ListView.row.frame" t-extend="WidgetFrame">
|
||||
<t t-jquery="tr">
|
||||
$(document.createElement('t'))
|
||||
.append(this.contents())
|
||||
.attr({
|
||||
't-foreach': this.attr('t-foreach'),
|
||||
't-as': this.attr('t-as')
|
||||
})
|
||||
.replaceAll(this)
|
||||
.after($(document.createElement('td')).append(
|
||||
$(document.createElement('button')).attr({
|
||||
'class': 'oe-edit-row-save', 'type': 'button'}).text('Save')))
|
||||
.before($(document.createElement('td')).append(
|
||||
$(document.createElement('button')).attr({
|
||||
'class': 'oe-edit-row-cancel', 'type': 'button'}).text('Cancel')))
|
||||
.unwrap();
|
||||
</t>
|
||||
</t>
|
||||
</templates>
|
||||
|
||||
Reference in New Issue
Block a user