[MERGE] Merge with trunk upto revision no 833.

bzr revid: ysa@tinyerp.com-20110819055354-jupt8bp7zaf4jn7k
This commit is contained in:
Yogesh (OpenERP) 2011-08-19 11:23:54 +05:30
commit cce6a3f6b9
25 changed files with 660 additions and 569 deletions

View File

@ -67,7 +67,6 @@ def manifest_glob(addons, key):
files = []
for addon in addons:
globlist = openerpweb.addons_manifest.get(addon, {}).get(key, [])
print globlist
for pattern in globlist:
for path in glob.glob(os.path.join(openerpweb.path_addons, addon, pattern)):
files.append(path[len(openerpweb.path_addons):])
@ -79,35 +78,36 @@ def concat_files(file_list):
concat: concatenation of file content
timestamp: max(os.path.getmtime of file_list)
"""
root = openerpweb.path_root
files_content = []
files_timestamp = 0
for i in file_list:
fname = os.path.join(root, i)
fname = os.path.join(openerpweb.path_addons, i[1:])
ftime = os.path.getmtime(fname)
if ftime > files_timestamp:
files_timestamp = ftime
files_content = open(fname).read()
files_content.append(open(fname).read())
files_concat = "".join(files_content)
return files_concat
return (files_concat,files_timestamp)
home_template = textwrap.dedent("""<!DOCTYPE html>
<html style="height: 100%%">
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>OpenERP</title>
%(javascript)s
<script type="text/javascript">
$(function() {
QWeb = new QWeb2.Engine();
openerp.init().base.webclient("oe");
});
</script>
<link rel="shortcut icon" href="/base/static/src/img/favicon.ico" type="image/x-icon"/>
%(css)s
<!--[if lte IE 7]>
<link rel="stylesheet" href="/base/static/src/css/base-ie7.css" type="text/css"/>
<![endif]-->
%(javascript)s
<script type="text/javascript">
$(function() {
QWeb = new QWeb2.Engine();
var c = new openerp.init();
var wc = new c.base.WebClient("oe");
wc.start();
});
</script>
</head>
<body id="oe" class="openerp"></body>
</html>
@ -125,31 +125,31 @@ class WebClient(openerpweb.Controller):
@openerpweb.httprequest
def css(self, req, mods='base'):
cherrypy.response.headers['Content-Type'] = 'text/css'
req.httpresponse.headers['Content-Type'] = 'text/css'
files = manifest_glob(mods.split(','), 'css')
concat = concat_files(files)[0]
content,timestamp = concat_files(files)
# TODO request set the Date of last modif and Etag
return concat
return content
@openerpweb.httprequest
def js(self, req, mods='base'):
cherrypy.response.headers['Content-Type'] = 'application/javascript'
req.httpresponse.headers['Content-Type'] = 'application/javascript'
files = manifest_glob(mods.split(','), 'js')
concat = concat_files(files)[0]
content,timestamp = concat_files(files)
# TODO request set the Date of last modif and Etag
return concat
return content
@openerpweb.httprequest
def home(self, req, s_action=None):
# script tags
jslist = ['/base/webclient/js']
if 1: # debug == 1
if req.debug:
jslist = manifest_glob(['base'], 'js')
js = "\n ".join(['<script type="text/javascript" src="%s"></script>'%i for i in jslist])
# css tags
csslist = ['/base/webclient/css']
if 1: # debug == 1
if req.debug:
csslist = manifest_glob(['base'], 'css')
css = "\n ".join(['<link rel="stylesheet" href="%s">'%i for i in csslist])
r = home_template % {
@ -157,7 +157,7 @@ class WebClient(openerpweb.Controller):
'css': css
}
return r
@openerpweb.jsonrequest
def translations(self, req, mods, lang):
lang_model = req.session.model('res.lang')
@ -193,7 +193,6 @@ class WebClient(openerpweb.Controller):
transl["messages"].append({'id': x.id, 'string': x.string})
return {"modules": transs,
"lang_parameters": lang_obj}
class Database(openerpweb.Controller):
_cp_path = "/base/database"
@ -249,16 +248,16 @@ class Database(openerpweb.Controller):
try:
db_dump = base64.decodestring(
req.session.proxy("db").dump(backup_pwd, backup_db))
cherrypy.response.headers['Content-Type'] = "application/octet-stream; charset=binary"
cherrypy.response.headers['Content-Disposition'] = 'attachment; filename="' + backup_db + '.dump"'
cherrypy.response.cookie['fileToken'] = token
cherrypy.response.cookie['fileToken']['path'] = '/'
req.httpresponse.headers['Content-Type'] = "application/octet-stream; charset=binary"
req.httpresponse.headers['Content-Disposition'] = 'attachment; filename="' + backup_db + '.dump"'
req.httpresponse.cookie['fileToken'] = token
req.httpresponse.cookie['fileToken']['path'] = '/'
return db_dump
except xmlrpclib.Fault, e:
if e.faultCode and e.faultCode.split(':')[0] == 'AccessDenied':
return 'Backup Database|' + e.faultCode
return 'Backup Database|Could not generate database backup'
@openerpweb.httprequest
def restore(self, req, db_file, restore_pwd, new_db):
try:
@ -267,9 +266,7 @@ class Database(openerpweb.Controller):
return ''
except xmlrpclib.Fault, e:
if e.faultCode and e.faultCode.split(':')[0] == 'AccessDenied':
raise cherrypy.HTTPError(403)
raise cherrypy.HTTPError()
raise Exception("AccessDenied")
@openerpweb.jsonrequest
def change_password(self, req, fields):
@ -386,10 +383,10 @@ class Session(openerpweb.Controller):
:return: A key identifying the saved action.
:rtype: integer
"""
saved_actions = cherrypy.session.get('saved_actions')
saved_actions = req.httpsession.get('saved_actions')
if not saved_actions:
saved_actions = {"next":0, "actions":{}}
cherrypy.session['saved_actions'] = saved_actions
req.httpsession['saved_actions'] = saved_actions
# we don't allow more than 10 stored actions
if len(saved_actions["actions"]) >= 10:
del saved_actions["actions"][min(saved_actions["actions"].keys())]
@ -409,7 +406,7 @@ class Session(openerpweb.Controller):
:return: The saved action or None.
:rtype: anything
"""
saved_actions = cherrypy.session.get('saved_actions')
saved_actions = req.httpsession.get('saved_actions')
if not saved_actions:
return None
return saved_actions["actions"].get(key)
@ -439,18 +436,16 @@ def clean_action(action, session, context=None):
return action
# values come from the server, we can just eval them
if isinstance(action.get('context'), basestring):
action['context'] = eval(
action['context'],
session.evaluation_context(context=context)) or {}
localvars = session.evaluation_context(context=context)
action['context'] = eval( action['context'], localvars ) or {}
if isinstance(action.get('domain'), basestring):
action['domain'] = eval(
action['domain'],
session.evaluation_context(
action.get('context', {}))) or []
localvars = session.evaluation_context( action.get('context', {}))
action['domain'] = eval( action['domain'], localvars ) or []
return fix_view_modes(action)
# I think generate_views,fix_view_modes should go into js ActionManager
def generate_views(action):
"""
While the server generates a sequence called "views" computing dependencies
@ -947,10 +942,10 @@ class Binary(openerpweb.Controller):
_cp_path = "/base/binary"
@openerpweb.httprequest
def image(self, request, model, id, field, **kw):
cherrypy.response.headers['Content-Type'] = 'image/png'
Model = request.session.model(model)
context = request.session.eval_context(request.context)
def image(self, req, model, id, field, **kw):
req.httpresponse.headers['Content-Type'] = 'image/png'
Model = req.session.model(model)
context = req.session.eval_context(req.context)
try:
if not id:
res = Model.default_get([field], context).get(field, '')
@ -963,26 +958,26 @@ class Binary(openerpweb.Controller):
return open(os.path.join(openerpweb.path_addons, 'base', 'static', 'src', 'img', 'placeholder.png'), 'rb').read()
@openerpweb.httprequest
def saveas(self, request, model, id, field, fieldname, **kw):
Model = request.session.model(model)
context = request.session.eval_context(request.context)
def saveas(self, req, model, id, field, fieldname, **kw):
Model = req.session.model(model)
context = req.session.eval_context(req.context)
res = Model.read([int(id)], [field, fieldname], context)[0]
filecontent = res.get(field, '')
if not filecontent:
raise cherrypy.NotFound
else:
cherrypy.response.headers['Content-Type'] = 'application/octet-stream'
req.httpresponse.headers['Content-Type'] = 'application/octet-stream'
filename = '%s_%s' % (model.replace('.', '_'), id)
if fieldname:
filename = res.get(fieldname, '') or filename
cherrypy.response.headers['Content-Disposition'] = 'attachment; filename=' + filename
req.httpresponse.headers['Content-Disposition'] = 'attachment; filename=' + filename
return base64.decodestring(filecontent)
@openerpweb.httprequest
def upload(self, request, callback, ufile=None):
def upload(self, req, callback, ufile=None):
cherrypy.response.timeout = 500
headers = {}
for key, val in cherrypy.request.headers.iteritems():
for key, val in req.httprequest.headers.iteritems():
headers[key.lower()] = val
size = int(headers.get('content-length', 0))
# TODO: might be useful to have a configuration flag for max-length file uploads
@ -1006,10 +1001,10 @@ class Binary(openerpweb.Controller):
return out % (simplejson.dumps(callback), simplejson.dumps(args))
@openerpweb.httprequest
def upload_attachment(self, request, callback, model, id, ufile=None):
def upload_attachment(self, req, callback, model, id, ufile=None):
cherrypy.response.timeout = 500
context = request.session.eval_context(request.context)
Model = request.session.model('ir.attachment')
context = req.session.eval_context(req.context)
Model = req.session.model('ir.attachment')
try:
out = """<script language="javascript" type="text/javascript">
var win = window.top.window,

View File

@ -1,11 +1,17 @@
/* TODO: separate openerp web client page css from openerp views css */
body {
body.openerp {
padding: 0;
margin: 0;
font-family: helvetica, arial, sans-serif;
height: 100%;
min-width: 1000px;
overflow-y: scroll;
font-size: 80%;
}
body.openerp, .openerp textarea, .openerp input, .openerp select, .openerp option, .openerp button, .openerp .ui-widget {
font-family: Ubuntu, Helvetica, sans-serif;
}
.oe_box {
border: 1px solid #aaf;
padding: 2px;
@ -20,13 +26,6 @@ body {
margin: 0;
}
body.openerp {
height: 100%;
min-width: 1000px;
overflow-y: scroll;
}
.openerp .oe-number {
text-align: right !important;
}
@ -120,7 +119,6 @@ body.openerp {
-moz-border-radius: 3px;
-webkit-border-radius: 3px;
color: white;
font-family: Ubuntu, Helvetica, sans-serif;
font-size: 16px;
font-weight: bold;
padding: 5px;
@ -381,7 +379,7 @@ label.error {
/* Header */
.openerp .header {
height: 65px;
background: url("../img/header-background.png") repeat-x scroll left top transparent;
background: url("/base/static/src/img/header-background.png") repeat-x scroll left top transparent;
color: #FFFFFF;
letter-spacing: 0.5px;
text-shadow: 0 1px 0 #333333;
@ -497,7 +495,6 @@ label.error {
color: #666666;
font-weight: bold;
font-size: 0.8em;
font-family: Ubuntu, Helvetica, sans-serif;
text-align: center;
}
.openerp div.oe_footer p.oe_footer_powered a {
@ -515,7 +512,6 @@ label.error {
.openerp h2.oe_view_title {
font-size: 175%;
font-weight: normal;
font-family: Ubuntu, Helvetica, sans-serif;
margin: 2px 0;
color: #252424;
text-shadow: white 0 1px 0;
@ -859,7 +855,7 @@ label.error {
-webkit-box-sizing: border-box;
-ms-box-sizing: border-box;
box-sizing: border-box;
padding: 2px;
padding: 0 2px 0 2px;
border: 1px solid #999;
-moz-border-radius: 3px;
-webkit-border-radius: 3px;
@ -988,7 +984,6 @@ label.error {
margin: 0;
width: 180px;
height: 100%;
font-family: Ubuntu, Helvetica, sans-serif;
font-size: 0.9em;
}
@ -1046,7 +1041,6 @@ label.error {
.openerp .view-manager-main-sidebar h2 {
margin:0;
font-family: Ubuntu, Helvetica, sans-serif;
font-size: 1.15em;
color: #8E8E8E;
text-shadow: white 0 1px 0;

View File

@ -12,10 +12,7 @@
return;
var session_counter = 0;
/** @lends openerp */
var openerp = this.openerp = {
// debug flag
debug: true,
// Per session namespace
// openerp.<module> will map to
// openerp.sessions.sessionname.<module> using a closure
@ -44,7 +41,6 @@
}
return new_instance;
}
// TODO add initrpc to init core only for RPC
};
})();
@ -57,32 +53,11 @@ openerp.base = function(instance) {
openerp.base.formats(instance);
openerp.base.chrome(instance);
openerp.base.data(instance);
if (openerp.base.views) {
openerp.base.views(instance);
}
if (openerp.base.search) {
openerp.base.search(instance);
}
if (openerp.base.list) {
openerp.base.list(instance);
}
if (openerp.base. m2o) {
openerp.base.m2o(instance);
}
if (openerp.base.form) {
openerp.base.form(instance);
}
if (openerp.base.list && openerp.base.list.editable) {
openerp.base.list.editable(instance);
}
if (openerp.web_mobile) {
openerp.web_mobile(instance);
}
if (openerp.base.view_tree) {
openerp.base.view_tree(instance);
}
if (openerp.base.data_export) {
openerp.base.data_export(instance);
files = ["views","search","list","form","list_editable","web_mobile","view_tree","data_export"];
for(i=0; i<files.length; i++) {
if(openerp.base[files[i]]) {
openerp.base[files[i]](instance);
}
}
};

View File

@ -291,8 +291,7 @@ openerp.base.Database = openerp.base.Widget.extend({
},
do_create: function() {
var self = this;
self.$option_id.html(QWeb.render("CreateDB", self));
self.$option_id.html(QWeb.render("Database.CreateDB", self));
self.$option_id.find("form[name=create_db_form]").validate({
submitHandler: function (form) {
var fields = $(form).serializeArray();
@ -314,11 +313,9 @@ openerp.base.Database = openerp.base.Widget.extend({
}
});
},
do_drop: function() {
var self = this;
self.$option_id.html(QWeb.render("DropDB", self));
self.$option_id.find("form[name=drop_db_form]").validate({
submitHandler: function (form) {
var $form = $(form),
@ -341,7 +338,6 @@ openerp.base.Database = openerp.base.Widget.extend({
}
});
},
wait_for_file: function (token, cleanup) {
var self = this,
cookie_name = 'fileToken',
@ -362,7 +358,7 @@ openerp.base.Database = openerp.base.Widget.extend({
if (cleanup) { cleanup(); }
}
}, 100);
}, 200);
},
do_backup: function() {
var self = this;
@ -402,7 +398,6 @@ openerp.base.Database = openerp.base.Widget.extend({
}
});
},
do_restore: function() {
var self = this;
self.$option_id.html(QWeb.render("RestoreDB", self));
@ -441,7 +436,6 @@ openerp.base.Database = openerp.base.Widget.extend({
}
});
},
do_change_password: function() {
var self = this;
self.$option_id.html(QWeb.render("Change_DB_Pwd", self));
@ -836,13 +830,6 @@ openerp.base.WebClient = openerp.base.Widget.extend({
}
});
openerp.base.webclient = function(element_id) {
// TODO Helper to start webclient rename it openerp.base.webclient
var client = new openerp.base.WebClient(element_id);
client.start();
return client;
};
};
// vim:et fdc=0 fdl=0 foldnestmax=3 fdm=syntax:

View File

@ -320,6 +320,293 @@ openerp.base.CallbackEnabled = openerp.base.Class.extend({
}
});
openerp.base.Session = openerp.base.CallbackEnabled.extend( /** @lends openerp.base.Session# */{
/**
* @constructs
* @param server
* @param port
*/
init: function(server, port) {
this._super();
this.server = (server == undefined) ? location.hostname : server;
this.port = (port == undefined) ? location.port : port;
this.rpc_mode = (server == location.hostname) ? "ajax" : "jsonp";
this.debug = (window.location.search.indexOf('?debug') !== -1);
this.db = "";
this.login = "";
this.password = "";
this.user_context= {};
this.uid = false;
this.session_id = false;
this.module_list = [];
this.module_loaded = {"base": true};
this.context = {};
this.shortcuts = [];
this.active_id = null;
this.session = this;
},
start: function() {
this.session_restore();
},
/**
* Executes an RPC call, registering the provided callbacks.
*
* Registers a default error callback if none is provided, and handles
* setting the correct session id and session context in the parameter
* objects
*
* @param {String} url RPC endpoint
* @param {Object} params call parameters
* @param {Function} success_callback function to execute on RPC call success
* @param {Function} error_callback function to execute on RPC call failure
* @returns {jQuery.Deferred} jquery-provided ajax deferred
*/
rpc: function(url, params, success_callback, error_callback) {
var self = this;
// Construct a JSON-RPC2 request, method is currently unused
params.session_id = this.session_id;
// Call using the rpc_mode
var deferred = $.Deferred();
this.rpc_ajax(url, {
jsonrpc: "2.0",
method: "call",
params: params,
id:null
}).then(function () {deferred.resolve.apply(deferred, arguments);},
function(error) {deferred.reject(error, $.Event());});
return deferred.fail(function() {
deferred.fail(function(error, event) {
if (!event.isDefaultPrevented()) {
self.on_rpc_error(error, event);
}
});
}).then(success_callback, error_callback).promise();
},
/**
* Raw JSON-RPC call
*
* @returns {jQuery.Deferred} ajax-based deferred object
*/
rpc_ajax: function(url, payload) {
var self = this;
this.on_rpc_request();
// url can be an $.ajax option object
if (_.isString(url)) {
url = {
url: url
}
}
var ajax = _.extend({
type: "POST",
url: url,
dataType: 'json',
contentType: 'application/json',
data: JSON.stringify(payload),
processData: false
}, url);
var deferred = $.Deferred();
$.ajax(ajax).done(function(response, textStatus, jqXHR) {
self.on_rpc_response();
if (!response.error) {
deferred.resolve(response["result"], textStatus, jqXHR);
return;
}
if (response.error.data.type !== "session_invalid") {
deferred.reject(response.error);
return;
}
self.uid = false;
self.on_session_invalid(function() {
self.rpc(url, payload.params,
function() {
deferred.resolve.apply(deferred, arguments);
},
function(error, event) {
event.preventDefault();
deferred.reject.apply(deferred, arguments);
});
});
}).fail(function(jqXHR, textStatus, errorThrown) {
self.on_rpc_response();
var error = {
code: -32098,
message: "XmlHttpRequestError " + errorThrown,
data: {type: "xhr"+textStatus, debug: jqXHR.responseText, objects: [jqXHR, errorThrown] }
};
deferred.reject(error);
});
return deferred.promise();
},
on_rpc_request: function() {
},
on_rpc_response: function() {
},
on_rpc_error: function(error) {
},
/**
* The session is validated either by login or by restoration of a previous session
*/
on_session_valid: function() {
if(!openerp._modules_loaded)
this.load_modules();
},
on_session_invalid: function(contination) {
},
session_is_valid: function() {
return this.uid;
},
session_login: function(db, login, password, success_callback) {
var self = this;
this.db = db;
this.login = login;
this.password = password;
var params = { db: this.db, login: this.login, password: this.password };
this.rpc("/base/session/login", params, function(result) {
self.session_id = result.session_id;
self.uid = result.uid;
self.user_context = result.context;
self.session_save();
self.on_session_valid();
if (success_callback)
success_callback();
});
},
session_logout: function() {
this.uid = false;
},
/**
* Reloads uid and session_id from local storage, if they exist
*/
session_restore: function () {
this.uid = this.get_cookie('uid');
this.session_id = this.get_cookie('session_id');
this.db = this.get_cookie('db');
this.login = this.get_cookie('login');
this.user_context = this.get_cookie("user_context");
// we should do an rpc to confirm that this session_id is valid and if it is retrieve the information about db and login
// then call on_session_valid
this.on_session_valid();
},
/**
* Saves the session id and uid locally
*/
session_save: function () {
this.set_cookie('uid', this.uid);
this.set_cookie('session_id', this.session_id);
this.set_cookie('db', this.db);
this.set_cookie('login', this.login);
this.set_cookie('user_context', this.user_context);
},
logout: function() {
delete this.uid;
delete this.session_id;
delete this.db;
delete this.login;
this.set_cookie('uid', '');
this.set_cookie('session_id', '');
this.set_cookie('db', '');
this.set_cookie('login', '');
this.on_session_invalid(function() {});
},
/**
* Fetches a cookie stored by an openerp session
*
* @private
* @param name the cookie's name
*/
get_cookie: function (name) {
var nameEQ = this.element_id + '|' + name + '=';
var cookies = document.cookie.split(';');
for(var i=0; i<cookies.length; ++i) {
var cookie = cookies[i].replace(/^\s*/, '');
if(cookie.indexOf(nameEQ) === 0) {
return JSON.parse(decodeURIComponent(cookie.substring(nameEQ.length)));
}
}
return null;
},
/**
* Create a new cookie with the provided name and value
*
* @private
* @param name the cookie's name
* @param value the cookie's value
* @param ttl the cookie's time to live, 1 year by default, set to -1 to delete
*/
set_cookie: function (name, value, ttl) {
ttl = ttl || 24*60*60*365;
document.cookie = [
this.element_id + '|' + name + '=' + encodeURIComponent(JSON.stringify(value)),
'max-age=' + ttl,
'expires=' + new Date(new Date().getTime() + ttl*1000).toGMTString()
].join(';');
},
/**
* Load additional web addons of that instance and init them
*/
load_modules: function() {
var self = this;
this.rpc('/base/session/modules', {}, function(result) {
self.module_list = result;
var lang = self.user_context.lang;
params = { mods: ["base"].concat(result), lang: lang};
self.rpc('/base/webclient/translations',params).then(function(transs) {
openerp.base._t.database.set_bundle(transs);
var modules = self.module_list.join(',');
if(self.debug) {
self.rpc('/base/webclient/csslist', {"mods": modules}, self.do_load_css);
self.rpc('/base/webclient/jslist', {"mods": modules}, self.do_load_js);
} else {
self.do_load_css(["/base/webclient/css?mods="+modules]);
self.do_load_js(["/base/webclient/js?mods="+modules]);
}
openerp._modules_loaded = true;
});
});
},
do_load_css: function (files) {
_.each(files, function (file) {
$('head').append($('<link>', {
'href': file,
'rel': 'stylesheet',
'type': 'text/css'
}));
});
},
do_load_js: function(files) {
var self = this;
if(files.length != 0) {
var file = files.shift();
var tag = document.createElement('script');
tag.type = 'text/javascript';
tag.src = file;
tag.onload = tag.onreadystatechange = function() {
if ( (tag.readyState && tag.readyState != "loaded" && tag.readyState != "complete") || tag.onload_done )
return;
tag.onload_done = true;
self.do_load_js(files);
};
document.head.appendChild(tag);
} else {
this.on_modules_loaded();
}
},
on_modules_loaded: function() {
for(var j=0; j<this.module_list.length; j++) {
var mod = this.module_list[j];
if(this.module_loaded[mod])
continue;
openerp[mod] = {};
// init module mod
if(openerp._openerp[mod] != undefined) {
openerp._openerp[mod](openerp);
this.module_loaded[mod] = true;
}
}
}
});
/**
* Utility class that any class is allowed to extend to easy common manipulations.
*
@ -352,7 +639,7 @@ openerp.base.SessionAware = openerp.base.CallbackEnabled.extend({
this.on_log.apply(this,args);
},
on_log: function() {
if(window.openerp.debug || (window.location.search.indexOf('?debug') !== -1)) {
if(this.session.debug) {
var notify = false;
var body = false;
if(window.console) {
@ -613,295 +900,6 @@ openerp.base.TranslationDataBase = openerp.base.Class.extend({
openerp.base._t = new openerp.base.TranslationDataBase().build_translation_function();
openerp.base.Session = openerp.base.CallbackEnabled.extend( /** @lends openerp.base.Session# */{
/**
* @constructs
* @param element_id to use for exception reporting
* @param server
* @param port
*/
init: function(server, port) {
this._super();
this.server = (server == undefined) ? location.hostname : server;
this.port = (port == undefined) ? location.port : port;
this.rpc_mode = (server == location.hostname) ? "ajax" : "jsonp";
this.debug = true;
this.db = "";
this.login = "";
this.password = "";
this.user_context= {};
this.uid = false;
this.session_id = false;
this.module_list = [];
this.module_loaded = {"base": true};
this.context = {};
this.shortcuts = [];
this.active_id = null;
},
start: function() {
this.session_restore();
},
/**
* Executes an RPC call, registering the provided callbacks.
*
* Registers a default error callback if none is provided, and handles
* setting the correct session id and session context in the parameter
* objects
*
* @param {String} url RPC endpoint
* @param {Object} params call parameters
* @param {Function} success_callback function to execute on RPC call success
* @param {Function} error_callback function to execute on RPC call failure
* @returns {jQuery.Deferred} jquery-provided ajax deferred
*/
rpc: function(url, params, success_callback, error_callback) {
var self = this;
// Construct a JSON-RPC2 request, method is currently unused
params.session_id = this.session_id;
// Call using the rpc_mode
var deferred = $.Deferred();
this.rpc_ajax(url, {
jsonrpc: "2.0",
method: "call",
params: params,
id:null
}).then(function () {deferred.resolve.apply(deferred, arguments);},
function(error) {deferred.reject(error, $.Event());});
return deferred.fail(function() {
deferred.fail(function(error, event) {
if (!event.isDefaultPrevented()) {
self.on_rpc_error(error, event);
}
});
}).then(success_callback, error_callback).promise();
},
/**
* Raw JSON-RPC call
*
* @returns {jQuery.Deferred} ajax-based deferred object
*/
rpc_ajax: function(url, payload) {
var self = this;
this.on_rpc_request();
// url can be an $.ajax option object
if (_.isString(url)) {
url = {
url: url
}
}
var ajax = _.extend({
type: "POST",
url: url,
dataType: 'json',
contentType: 'application/json',
data: JSON.stringify(payload),
processData: false
}, url);
var deferred = $.Deferred();
$.ajax(ajax).done(function(response, textStatus, jqXHR) {
self.on_rpc_response();
if (!response.error) {
deferred.resolve(response["result"], textStatus, jqXHR);
return;
}
if (response.error.data.type !== "session_invalid") {
deferred.reject(response.error);
return;
}
self.uid = false;
self.on_session_invalid(function() {
self.rpc(url, payload.params,
function() {
deferred.resolve.apply(deferred, arguments);
},
function(error, event) {
event.preventDefault();
deferred.reject.apply(deferred, arguments);
});
});
}).fail(function(jqXHR, textStatus, errorThrown) {
self.on_rpc_response();
var error = {
code: -32098,
message: "XmlHttpRequestError " + errorThrown,
data: {type: "xhr"+textStatus, debug: jqXHR.responseText, objects: [jqXHR, errorThrown] }
};
deferred.reject(error);
});
return deferred.promise();
},
on_rpc_request: function() {
},
on_rpc_response: function() {
},
on_rpc_error: function(error) {
},
/**
* The session is validated either by login or by restoration of a previous session
*/
on_session_valid: function() {
if(!openerp._modules_loaded)
this.load_modules();
},
on_session_invalid: function(contination) {
},
session_is_valid: function() {
return this.uid;
},
session_login: function(db, login, password, success_callback) {
var self = this;
this.db = db;
this.login = login;
this.password = password;
var params = { db: this.db, login: this.login, password: this.password };
this.rpc("/base/session/login", params, function(result) {
self.session_id = result.session_id;
self.uid = result.uid;
self.user_context = result.context;
self.session_save();
self.on_session_valid();
if (success_callback)
success_callback();
});
},
session_logout: function() {
this.uid = false;
},
/**
* Reloads uid and session_id from local storage, if they exist
*/
session_restore: function () {
this.uid = this.get_cookie('uid');
this.session_id = this.get_cookie('session_id');
this.db = this.get_cookie('db');
this.login = this.get_cookie('login');
this.user_context = this.get_cookie("user_context");
// we should do an rpc to confirm that this session_id is valid and if it is retrieve the information about db and login
// then call on_session_valid
this.on_session_valid();
},
/**
* Saves the session id and uid locally
*/
session_save: function () {
this.set_cookie('uid', this.uid);
this.set_cookie('session_id', this.session_id);
this.set_cookie('db', this.db);
this.set_cookie('login', this.login);
this.set_cookie('user_context', this.user_context);
},
logout: function() {
delete this.uid;
delete this.session_id;
delete this.db;
delete this.login;
this.set_cookie('uid', '');
this.set_cookie('session_id', '');
this.set_cookie('db', '');
this.set_cookie('login', '');
this.on_session_invalid(function() {});
},
/**
* Fetches a cookie stored by an openerp session
*
* @private
* @param name the cookie's name
*/
get_cookie: function (name) {
var nameEQ = this.element_id + '|' + name + '=';
var cookies = document.cookie.split(';');
for(var i=0; i<cookies.length; ++i) {
var cookie = cookies[i].replace(/^\s*/, '');
if(cookie.indexOf(nameEQ) === 0) {
return JSON.parse(decodeURIComponent(cookie.substring(nameEQ.length)));
}
}
return null;
},
/**
* Create a new cookie with the provided name and value
*
* @private
* @param name the cookie's name
* @param value the cookie's value
* @param ttl the cookie's time to live, 1 year by default, set to -1 to delete
*/
set_cookie: function (name, value, ttl) {
ttl = ttl || 24*60*60*365;
document.cookie = [
this.element_id + '|' + name + '=' + encodeURIComponent(JSON.stringify(value)),
'max-age=' + ttl,
'expires=' + new Date(new Date().getTime() + ttl*1000).toGMTString()
].join(';');
},
/**
* Load additional web addons of that instance and init them
*/
load_modules: function() {
var self = this;
this.rpc('/base/session/modules', {}, function(result) {
self.module_list = result;
var lang = self.user_context.lang;
self.rpc('/base/webclient/translations',{
mods: ["base"].concat(result),
lang: lang})
.then(function(transs) {
openerp.base._t.database.set_bundle(transs);
var modules = self.module_list.join(',');
if(self.debug || true) {
self.rpc('/base/webclient/csslist', {"mods": modules}, self.do_load_css);
self.rpc('/base/webclient/jslist', {"mods": modules}, self.do_load_js);
} else {
self.do_load_css(["/base/webclient/css?mods="+modules]);
self.do_load_js(["/base/webclient/js?mods="+modules]);
}
openerp._modules_loaded = true;
});
});
},
do_load_css: function (files) {
_.each(files, function (file) {
$('head').append($('<link>', {
'href': file,
'rel': 'stylesheet',
'type': 'text/css'
}));
});
},
do_load_js: function(files) {
var self = this;
if(files.length != 0) {
var file = files.shift();
var tag = document.createElement('script');
tag.type = 'text/javascript';
tag.src = file;
tag.onload = tag.onreadystatechange = function() {
if ( (tag.readyState && tag.readyState != "loaded" && tag.readyState != "complete") || tag.onload_done )
return;
tag.onload_done = true;
self.do_load_js(files);
};
document.head.appendChild(tag);
} else {
this.on_modules_loaded();
}
},
on_modules_loaded: function() {
for(var j=0; j<this.module_list.length; j++) {
var mod = this.module_list[j];
if(this.module_loaded[mod])
continue;
openerp[mod] = {};
// init module mod
if(openerp._openerp[mod] != undefined) {
openerp._openerp[mod](openerp);
this.module_loaded[mod] = true;
}
}
}
});
};
// vim:et fdc=0 fdl=0 foldnestmax=3 fdm=syntax:

View File

@ -286,14 +286,16 @@ openerp.base.DataSet = openerp.base.Widget.extend( /** @lends openerp.base.Data
* Read a slice of the records represented by this DataSet, based on its
* domain and context.
*
* @param {Array} [fields] fields to read and return, by default all fields are returned
* @params {Object} options
* @param {Array} [options.fields] fields to read and return, by default all fields are returned
* @param {Number} [options.offset=0] The index from which selected records should be returned
* @param {Number} [options.limit=null] The maximum number of records to return
* @param {Function} callback function called with read_slice result
* @returns {$.Deferred}
*/
read_slice: function (options, callback) { return null; },
read_slice: function (fields, options, callback) {
return null;
},
/**
* Reads the current dataset record (from its index)
*
@ -478,11 +480,12 @@ openerp.base.DataSetStatic = openerp.base.DataSet.extend({
// all local records
this.ids = ids || [];
},
read_slice: function (options, callback) {
read_slice: function (fields, options, callback) {
// TODO remove fields from options
var self = this,
offset = options.offset || 0,
limit = options.limit || false,
fields = options.fields || false;
fields = fields || false;
var end_pos = limit && limit !== -1 ? offset + limit : undefined;
return this.read_ids(this.ids.slice(offset, end_pos), fields, callback);
},
@ -532,12 +535,13 @@ openerp.base.DataSetSearch = openerp.base.DataSet.extend({
* @param {Function} callback function called with read_slice result
* @returns {$.Deferred}
*/
read_slice: function (options, callback) {
read_slice: function (fields, options, callback) {
var self = this;
var options = options || {};
var offset = options.offset || 0;
return this.rpc('/base/dataset/search_read', {
model: this.model,
fields: options.fields || false,
fields: fields || false,
domain: this.get_domain(options.domain),
context: this.get_context(options.context),
sort: this.sort(),

View File

@ -1,5 +1,5 @@
openerp.base.form = function (openerp) {
var _t = openerp.base._t;
openerp.base.views.add('form', 'openerp.base.FormView');
@ -458,9 +458,7 @@ openerp.base.form.SidebarAttachments = openerp.base.Widget.extend({
['res_model', '=', this.view.dataset.model],
['res_id', '=', this.view.datarecord.id],
['type', 'in', ['binary', 'url']]
])).read_slice(
{fields: ['name', 'url', 'type']},
this.on_attachments_loaded);
])).read_slice(['name', 'url', 'type'], this.on_attachments_loaded);
}
},
on_attachments_loaded: function(attachments) {
@ -812,6 +810,7 @@ openerp.base.form.WidgetLabel = openerp.base.form.Widget.extend({
this.$element.find("label").dblclick(function() {
var widget = self['for'] || self;
self.log(widget.element_id , widget);
window.w = widget;
});
}
});
@ -842,9 +841,12 @@ openerp.base.form.Field = openerp.base.form.Widget.extend({
this.value = value;
this.invalid = false;
this.update_dom();
this.on_value_changed();
},
set_value_from_ui: function() {
this.value = undefined;
this.on_value_changed();
},
on_value_changed: function() {
},
get_value: function() {
return this.value;
@ -943,6 +945,7 @@ openerp.base.form.FieldChar = openerp.base.form.Field.extend({
},
set_value_from_ui: function() {
this.value = this.$element.find('input').val();
this._super();
},
validate: function() {
this.invalid = false;
@ -1017,6 +1020,7 @@ openerp.base.form.FieldFloat = openerp.base.form.FieldChar.extend({
},
set_value_from_ui: function() {
this.value = Number(this.$element.find('input').val().replace(/,/g, '.'));
this._super();
}
});
@ -1037,6 +1041,7 @@ openerp.base.form.FieldInteger = openerp.base.form.FieldFloat.extend({
},
set_value_from_ui: function() {
this.value = Number(this.$element.find('input').val());
this._super();
}
});
@ -1074,6 +1079,7 @@ openerp.base.form.FieldDatetime = openerp.base.form.Field.extend({
if (this.value) {
this.value = this.format(this.value);
}
this._super();
},
update_dom: function() {
this._super.apply(this, arguments);
@ -1125,6 +1131,7 @@ openerp.base.form.FieldFloatTime = openerp.base.form.FieldChar.extend({
set_value_from_ui: function() {
var time = this.$element.find('input').val().split(':');
this.set_value(parseInt(time[0], 10) + parseInt(time[1], 10) / 60);
this._super();
}
});
@ -1149,6 +1156,7 @@ openerp.base.form.FieldText = openerp.base.form.Field.extend({
},
set_value_from_ui: function() {
this.value = this.$element.find('textarea').val();
this._super();
},
validate: function() {
this.invalid = false;
@ -1184,6 +1192,7 @@ openerp.base.form.FieldBoolean = openerp.base.form.Field.extend({
},
set_value_from_ui: function() {
this.value = this.$element.find('input').is(':checked');
this._super();
},
update_dom: function() {
this._super.apply(this, arguments);
@ -1266,6 +1275,7 @@ openerp.base.form.FieldSelection = openerp.base.form.Field.extend({
var ikey = this.$element.find('select').val();
var option = _.detect(this.field_index, function(x) {return x.ikey === ikey;});
this.value = option === undefined ? false : option.ekey;
this._super();
},
update_dom: function() {
this._super.apply(this, arguments);
@ -1530,7 +1540,6 @@ openerp.base.form.FieldMany2One = openerp.base.form.Field.extend({
this.on_ui_change();
}
},
set_value_from_ui: function() {},
set_value: function(value) {
value = value || null;
var self = this;
@ -1698,7 +1707,6 @@ openerp.base.form.FieldOne2Many = openerp.base.form.Field.extend({
});
}
},
set_value_from_ui: function() {},
set_value: function(value) {
value = value || [];
var self = this;
@ -1919,7 +1927,6 @@ openerp.base.form.FieldMany2Many = openerp.base.form.Field.extend({
get_value: function() {
return [commands.replace_with(this.dataset.ids)];
},
set_value_from_ui: function() {},
validate: function() {
this.invalid = false;
// TODO niv
@ -2193,10 +2200,67 @@ openerp.base.form.FormOpenPopup = openerp.base.OldWidget.extend({
}
});
openerp.base.form.FieldReference = openerp.base.form.FieldChar.extend({
openerp.base.form.FieldReference = openerp.base.form.Field.extend({
init: function(view, node) {
this._super(view, node);
//this.template = "FieldReference";
this.template = "FieldReference";
this.fields_view = {
fields: {
selection: {
selection: view.fields_view.fields[this.name].selection
},
m2o: {
relation: null
}
}
}
this.get_fields_values = view.get_fields_values;
this.do_onchange = this.on_form_changed = this.on_nop;
this.widgets = {};
this.fields = {};
this.selection = new openerp.base.form.FieldSelection(this, { attrs: {
name: 'selection',
widget: 'selection'
}});
this.selection.on_value_changed.add_last(this.on_selection_changed);
this.m2o = new openerp.base.form.FieldMany2One(this, { attrs: {
name: 'm2o',
widget: 'many2one'
}});
},
on_nop: function() {
},
on_selection_changed: function() {
this.m2o.field.relation = this.selection.get_value();
this.m2o.set_value(null);
},
start: function() {
this._super();
this.selection.start();
this.m2o.start();
},
is_valid: function() {
return this.required === false || typeof(this.get_value()) === 'string';
},
is_dirty: function() {
return this.selection.is_dirty() || this.m2o.is_dirty();
},
set_value: function(value) {
this._super(value);
if (typeof(value) === 'string') {
var vals = value.split(',');
this.selection.set_value(vals[0]);
this.m2o.set_value(parseInt(vals[1], 10));
}
},
get_value: function() {
var model = this.selection.get_value(),
id = this.m2o.get_value();
if (typeof(model) === 'string' && typeof(id) === 'number') {
return model + ',' + id;
} else {
return false;
}
}
});
@ -2212,8 +2276,6 @@ openerp.base.form.FieldBinary = openerp.base.form.Field.extend({
this.$element.find('button.oe-binary-file-save').click(this.on_save_as);
this.$element.find('.oe-binary-file-clear').click(this.on_clear);
},
set_value_from_ui: function() {
},
update_dom: function() {
this._super.apply(this, arguments);
this.$element.find('.oe-binary').toggle(!this.readonly);

View File

@ -1,7 +1,7 @@
/**
* @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) {
openerp.base.list_editable = function (openerp) {
var KEY_RETURN = 13,
KEY_ESCAPE = 27;

View File

@ -476,7 +476,8 @@ openerp.base.ListView = openerp.base.View.extend( /** @lends openerp.base.ListVi
*/
do_activate_record: function (index, id, dataset) {
var self = this;
this.dataset.read_slice({
// TODO is it needed ?
this.dataset.read_slice([],{
context: dataset.get_context(),
domain: dataset.get_domain()
}, function () {
@ -1034,11 +1035,9 @@ openerp.base.ListView.Groups = openerp.base.Class.extend( /** @lends openerp.bas
d = new $.Deferred(),
page = this.datagroup.openable ? this.page : view.page;
dataset.read_slice({
fields: _.pluck(_.select(this.columns, function(x) {return x.tag == "field"}), 'name'),
offset: page * limit,
limit: limit
}, function (records) {
var fields = _.pluck(_.select(this.columns, function(x) {return x.tag == "field"}), 'name');
var options = { offset: page * limit, limit: limit };
dataset.read_slice(fields, options , function (records) {
if (!self.datagroup.openable) {
view.configure_pager(dataset);
} else {

View File

@ -72,7 +72,7 @@ openerp.base.TreeView = openerp.base.View.extend({
'toolbar': has_toolbar
}));
this.dataset.read_slice({fields: this.fields_list()}, function (records) {
this.dataset.read_slice(this.fields_list(), {}, function (records) {
if (!has_toolbar) {
// WARNING: will do a second read on the same ids, but only on
// first load so not very important

View File

@ -17,6 +17,7 @@ openerp.base.ActionManager = openerp.base.Widget.extend({
this.dialog = null;
this.dialog_viewmanager = null;
this.client_widget = null;
this.url = {}
},
render: function() {
return "<div id='"+this.element_id+"'></div>";
@ -35,7 +36,29 @@ openerp.base.ActionManager = openerp.base.Widget.extend({
this.inner_viewmanager = null;
}
},
do_action: function(action, on_closed) {
url_update: function(action) {
// this.url = {
// "model": action.model,
// "domain": action.domain,
// };
// action.res_model
// action.domain
// action.context
// after
// action.views
// action.res_id
// mode
// menu
},
url_stringify: function(action) {
},
url_parse: function(action) {
},
on_url_update: function(url) {
},
do_url_action: function(url) {
},
do_action: function(action, on_close) {
var type = action.type.replace(/\./g,'_');
var popup = action.target === 'new';
action.flags = _.extend({
@ -49,7 +72,7 @@ openerp.base.ActionManager = openerp.base.Widget.extend({
this.log("Action manager can't handle action of type " + action.type, action);
return;
}
this[type](action, on_closed);
this[type](action, on_close);
},
ir_actions_act_window: function (action, on_close) {
if (action.target === 'new') {
@ -69,6 +92,7 @@ openerp.base.ActionManager = openerp.base.Widget.extend({
this.inner_stop();
this.inner_viewmanager = new openerp.base.ViewManagerAction(this, action);
this.inner_viewmanager.appendTo(this.$element);
this.url_update(action);
}
/* new window code
this.rpc("/base/session/save_session_action", { the_action : action}, function(key) {
@ -285,7 +309,7 @@ openerp.base.ViewManagerAction = openerp.base.ViewManager.extend({
var searchview_loaded = this.setup_search_view(
searchview_id || false, search_defaults);
// schedule auto_search
if (searchview_loaded != null && this.action['auto_search']) {
$.when(searchview_loaded, inital_view_loaded)

View File

@ -67,7 +67,7 @@
<li id="back-to-login">Back to Login</li>
</ul>
</t>
<t t-name="CreateDB">
<t t-name="Database.CreateDB">
<form name="create_db_form" class="oe_forms" method="POST">
<table width="100%">
<tr>
@ -79,8 +79,7 @@
<table align="center" class="db_option_table">
<tr>
<td><label for="super_admin_pwd">Master password:</label></td>
<td><input type="password" name="super_admin_pwd"
class="required" autofocus="autofocus"/></td>
<td><input type="password" name="super_admin_pwd" class="required" value="admin"/></td>
</tr>
<tr>
<td><label for="db_name">New database name:</label></td>
@ -95,9 +94,7 @@
<td>
<select name="db_lang" t-if="lang_list">
<t t-foreach="lang_list" t-as="lang">
<option t-att-value="lang[0]"
t-att-selected="lang[0] === 'en_US' ? 'selected' : undefined">
<t t-esc="lang[1]"/></option>
<option t-att-value="lang[0]" t-att-selected="lang[0] === 'en_US' ? 'selected' : undefined"><t t-esc="lang[1]"/></option>
</t>
</select>
</td>
@ -367,7 +364,6 @@
t-att-data-shortcut-id="shortcut.id"
><t t-esc="shortcut.name"/></li>
</ul>
<t t-name="Menu">
<table align="center">
<tr>
@ -784,7 +780,16 @@
<div t-att-id="widget.list_id"></div>
</t>
<t t-name="FieldReference">
<input type="text" t-att-name="widget.name" t-att-id="widget.element_id" t-att-class="'field_' + widget.type" style="width: 100%" placeholder="Widget Reference"/>
<table border="0" width="100%" cellpadding="0" cellspacing="0" class="oe_frame oe_forms">
<tr>
<td t-att-id="widget.selection.element_id" class="oe_form_frame_cell oe_form_selection">
<t t-raw="widget.selection.render()"/>
</td>
<td t-att-id="widget.m2o.element_id" class="oe_form_frame_cell oe_form_many2one" nowrap="true">
<t t-raw="widget.m2o.render()"/>
</td>
</tr>
</table>
</t>
<t t-name="FieldBoolean">
<input type="checkbox"
@ -1166,7 +1171,6 @@
<t t-name="ExportView">
<a id="exportview" href="javascript: void(0)" style="text-decoration: none;color: #3D3D3D;">Export</a>
</t>
<t t-name="ExportTreeView">
<table class="view" style="background-color: #F3F3F3;">
<tr>

View File

@ -26,6 +26,7 @@ openerp.base_calendar.CalendarView = openerp.base.View.extend({
'#fcaf3e', '#ef2929', '#ff00c9', '#ad7fa8', '#729fcf', '#8ae234', '#e9b96e', '#fce94f',
'#ff8e00', '#ff0000', '#b0008c', '#9000ff', '#0078ff', '#00ff00', '#e6ff00', '#ffff00',
'#905000', '#9b0000', '#840067', '#510090', '#0000c9', '#009b00', '#9abe00', '#ffc900' ];
this.color_map = {};
},
start: function() {
this.rpc("/base_calendar/calendarview/load", {"model": this.model, "view_id": this.view_id, 'toolbar': true}, this.on_loaded);
@ -136,17 +137,21 @@ openerp.base_calendar.CalendarView = openerp.base.View.extend({
reload_event: function(id) {
this.dataset.read_ids([id], _.keys(this.fields), this.on_events_loaded);
},
get_color: function(index) {
index = index % this.COLOR_PALETTE.length;
return this.COLOR_PALETTE[index];
get_color: function(key) {
if (this.color_map[key]) {
return this.color_map[key];
}
var index = _.keys(this.color_map).length % this.COLOR_PALETTE.length;
var color = this.COLOR_PALETTE[index];
this.color_map[key] = color;
return color;
},
on_events_loaded: function(events, fn_filter, no_filter_reload) {
var self = this;
//To parse Events we have to convert date Format
var res_events = [],
sidebar_items = [],
sidebar_ids = [];
sidebar_items = {};
for (var e = 0; e < events.length; e++) {
var evt = events[e];
if (!evt[this.date_start]) {
@ -157,21 +162,19 @@ openerp.base_calendar.CalendarView = openerp.base.View.extend({
if (this.color_field) {
var filter = evt[this.color_field];
if (filter) {
var filter_item = {
value: (typeof filter === 'object') ? filter[0] : filter,
label: (typeof filter === 'object') ? filter[1] : filter
}
if (typeof(fn_filter) === 'function' && !fn_filter(filter_item.value)) {
var filter_value = (typeof filter === 'object') ? filter[0] : filter;
if (typeof(fn_filter) === 'function' && !fn_filter(filter_value)) {
continue;
}
var filter_index = _.indexOf(sidebar_ids, filter_item.value);
if (filter_index === -1) {
evt.color = filter_item.color = this.get_color(sidebar_ids.length);
sidebar_items.push(filter_item);
sidebar_ids.push(filter_item.value);
} else {
evt.color = this.get_color(filter_index);
var filter_item = {
value: filter_value,
label: (typeof filter === 'object') ? filter[1] : filter,
color: this.get_color(filter_value)
}
if (!sidebar_items[filter_value]) {
sidebar_items[filter_value] = filter_item;
}
evt.color = filter_item.color;
evt.textColor = '#ffffff';
}
}
@ -299,8 +302,7 @@ openerp.base_calendar.CalendarView = openerp.base.View.extend({
// TODO: handle non-empty results.group_by with read_group
self.dataset.context = self.context = results.context;
self.dataset.domain = self.domain = results.domain;
self.dataset.read_slice({
fields: _.keys(self.fields),
self.dataset.read_slice(_.keys(self.fields), {
offset:0,
limit: self.limit
}, function(events) {

View File

@ -18,9 +18,9 @@
</div>
</t>
<t t-name="CalendarView.sidebar.responsible">
<div t-foreach="filters" t-as="filter" class="oe_calendar_responsible" t-attf-style="background: #{filter.color}">
<input type="checkbox" name="selection" t-att-value="filter.value"/>
<span><t t-esc="filter.label"/></span>
<div t-foreach="filters" class="oe_calendar_responsible" t-attf-style="background: #{filters_value.color}">
<input type="checkbox" name="selection" t-att-value="filters_value.value"/>
<span><t t-esc="filters_value.label"/></span>
</div>
</t>
</template>

View File

@ -290,7 +290,7 @@ openerp.base_dashboard.ConfigOverview = openerp.base.View.extend({
this.dataset.domain = [['type', '=', 'manual']];
},
start: function () {
$.when(this.dataset.read_slice({fields: ['state', 'action_id', 'category_id']}),
$.when(this.dataset.read_slice(['state', 'action_id', 'category_id']),
this.dataset.call('progress'))
.then(this.on_records_loaded);
},
@ -352,9 +352,7 @@ openerp.base_dashboard.ApplicationTiles = openerp.base.View.extend({
},
start: function () {
var self = this;
this.dataset.read_slice(
{fields: ['name', 'web_icon_data', 'web_icon_hover_data']},
function (applications) {
this.dataset.read_slice( ['name', 'web_icon_data', 'web_icon_hover_data'], {}, function (applications) {
// Create a matrix of 3*x applications
var rows = [];
while (applications.length) {
@ -384,9 +382,7 @@ openerp.base_dashboard.Widgets = openerp.base.View.extend({
this.widgets = new openerp.base.DataSetSearch(this, 'res.widget');
},
start: function () {
this.user_widgets.read_slice(
{fields: ['widget_id', 'user_id']},
this.on_widgets_list_loaded);
this.user_widgets.read_slice(['widget_id', 'user_id'], {}, this.on_widgets_list_loaded);
},
on_widgets_list_loaded: function (user_widgets) {
var self = this;

View File

@ -1,24 +1,21 @@
.oe-static-home {
padding: 0.5em 0.5em;
text-align: center;
}
.oe-static-home h1 {
margin: 0 0 0.3em
}
.oe-static-home-banner {
display: inline-block;
margin: 0.5em 0;
margin: auto 0;
padding: 0.5em 5em;
border: 1px inset #808080;
background-color: #e6e3e3;
-moz-border-radius: 2em;
-webkit-border-radius: 2em;
border-radius: 2em;
text-align: left;
}
.oe-static-home-banner h1 {
margin: 0 0 0.3em
.oe-static-home-banner li {
font-size: 150%;
font-weight: bold;
}
.oe-static-home-banner p {
}
.oe-static-home-banner address {
.oe-static-home address {
font-style: normal;
padding-left: 2em;
}

View File

@ -78,15 +78,13 @@ openerp.base_default_home = function (openerp) {
});
},
install_module: function (module_name) {
var Modules = new openerp.base.DataSetSearch(
this, 'ir.module.module', null,
[['name', '=', module_name], ['state', '=', 'uninstalled']]),
Upgrade = new openerp.base.DataSet(this, 'base.module.upgrade');
var Modules = new openerp.base.DataSetSearch( this, 'ir.module.module', null, [['name', '=', module_name], ['state', '=', 'uninstalled']]);
var Upgrade = new openerp.base.DataSet(this, 'base.module.upgrade');
$.blockUI({
message: '<img src="/base_default_home/static/src/img/throbber.gif">'
});
Modules.read_slice({fields: ['id']}, function (records) {
Modules.read_slice(['id'], {}, function (records) {
if (!(records.length === 1)) { return; }
Modules.call('state_update',
[_.pluck(records, 'id'), 'to install', ['uninstalled']],

View File

@ -1,17 +1,11 @@
<template>
<div t-name="StaticHome" class="oe-static-home">
<h1>Welcome to your new OpenERP instance.</h1>
<div class="oe-static-home-banner">
<h1>Welcome to OpenERP</h1>
<p>
Don't forget to bookmark your application address to come back
later:
</p>
<address>
URL: <a t-att-href="url"><t t-esc="url"/></a><br/>
login: <t t-esc="session.login"/>
</address>
<li>Bookmark this <a t-att-href="url">page</a></li>
<li>Remember your login: <i><t t-esc="session.login"/></i></li>
<li>Choose the first OpenERP Application you want to install..</li>
</div>
<div class="oe-static-home-tiles">
<table width="100%">
<tr t-foreach="rows" t-as="row">
@ -27,9 +21,7 @@
<div class="oe-static-home-tile-text">
<h2><t t-esc="application.name"/></h2>
<p><t t-esc="application.help"/></p>
<button type="button"
t-att-value="application.module">
Install</button>
<button type="button" t-att-value="application.module"> Install</button>
</div>
</td>
</tr>

View File

@ -79,7 +79,7 @@ init: function(parent, element_id, dataset, view_id) {
get_events: function() {
var self = this;
this.dataset.read_slice({}, function(result) {
this.dataset.read_slice([],{}, function(result) {
self.load_event(result);
});
@ -498,7 +498,7 @@ init: function(parent, element_id, dataset, view_id) {
reload_gantt: function() {
var self = this;
this.dataset.read_slice({}, function(response) {
this.dataset.read_slice([],{}, function(response) {
ganttChartControl.clearAll();
jQuery("#GanttDiv").children().remove();
self.load_event(response);

View File

@ -89,7 +89,7 @@ openerp.base_graph.GraphView = openerp.base.View.extend({
}
this.dataset.domain = domain;
this.dataset.context = this.view_manager.dataset.context;
this.dataset.read_slice({fields: _(this.fields).keys()}, function(res) {
this.dataset.read_slice(_(this.fields).keys(),{}, function(res) {
self.schedule_chart(res);
});
}
@ -468,7 +468,7 @@ openerp.base_graph.GraphView = openerp.base.View.extend({
}
self.dataset.context = results.context;
self.dataset.domain = results.domain;
self.dataset.read_slice({}, $.proxy(self, 'load_chart'));
self.dataset.read_slice([],{}, $.proxy(self, 'load_chart'));
});
}
});

View File

@ -12,7 +12,7 @@ openerp.web_mobile.FormView = openerp.base.Widget.extend({
view_id = this.action.views[1][0];
this.dataset = new openerp.base.DataSetSearch(this.session, this.action.res_model, null, null);
this.dataset.read_slice({}, function (result) {
this.dataset.read_slice([],{}, function (result) {
for (var i = 0; i < result.length; i++) {
if (result[i].id == id) {

View File

View File

@ -0,0 +1,21 @@
{
"name" : "OpenERP Web base",
"version" : "2.0",
"depends" : [],
'active': False,
'js' : [
"../base/static/lib/datejs/date-en-US.js",
"../base/static/lib/jquery/jquery-1.6.2.js",
"../base/static/lib/json/json2.js",
"../base/static/lib/qweb/qweb2.js",
"../base/static/lib/underscore/underscore.js",
"../base/static/lib/underscore/underscore.string.js",
"../base/static/src/js/boot.js",
"../base/static/src/js/core.js",
"../base/static/src/js/formats.js",
"../base/static/src/js/chrome.js",
"../base/static/src/js/data.js",
],
'css' : [
],
}

View File

@ -0,0 +1,51 @@
<!DOCTYPE html>
<html style="height: 100%">
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>OpenERP web_rpc example</title>
<style type="text/css">
pre.run {
border: 1px solid black; margin:0;padding:4px;
}
</style>
<script type="text/javascript" src="/base/webclient/js?mods=web_rpc"></script>
<script type="text/javascript">
$(function() {
$("#ex1but").bind("click",function(){
eval($("#ex1").text());
});
});
</script>
</head>
<body>
<h1>OpenERP web_rpc examples</h1>
<h2>Example 1: Display a list of defined ir.model <button id="ex1but">Run it !</button> </h2>
<h3>Code: </h3>
<pre>
&lt;script type="text/javascript" src="/base/webclient/js?mods=web_rpc"&gt;&lt;/script&gt;
&lt;script type="text/javascript"&gt;
<pre id="ex1" class="run">
var c = openerp.init(); // get a new webclient
c._modules_loaded = true; // Hack to prevent loading of additional modules
var s = new c.base.Session(); // setup a Session
s.session_login("web-trunk", "admin", "admin", function() {
var ds = new c.base.DataSetSearch(s, "ir.model"); // DataSetSearch used to search, read
ds.read_slice(['name','model'], {}, function(users){
for(var i in users) {
$("#ex1res").append("&lt;li&gt;" + users[i].model + " (" + users[i].name + ") &lt;/li&gt;")
}
});
}
);
</pre>&lt;/script&gt;
</pre>
<h3>Div for output:</h3>
<div id="ex1res" style="border: 1px solid black;">
&nbsp;
</div>
<h2>Help me to complete this example page on <a href="http://bazaar.launchpad.net/~openerp/openerp-web/trunk/view/head:/addons/web_rpc/static/src/example.html">launchpad</a></h2>
</body>
</html>

View File

@ -233,7 +233,27 @@ class OpenERPSession(object):
#----------------------------------------------------------
# OpenERP Web RequestHandler
#----------------------------------------------------------
class JsonRequest(object):
class CherryPyRequest(object):
""" CherryPy request handling
"""
def init(self,params):
self.params = params
# Move cherrypy thread local objects to attributes
self.applicationsession = applicationsession
self.httprequest = cherrypy.request
self.httpresponse = cherrypy.response
self.httpsession = cherrypy.session
self.httpsession_id = "cookieid"
# OpenERP session setup
self.session_id = self.params.pop("session_id", None) or uuid.uuid4().hex
host = cherrypy.config['openerp.server.host']
port = cherrypy.config['openerp.server.port']
self.session = self.httpsession.setdefault(self.session_id, OpenERPSession(host, port))
# Request attributes
self.context = self.params.pop('context', None)
self.debug = self.params.pop('debug',False) != False
class JsonRequest(CherryPyRequest):
""" JSON-RPC2 over HTTP.
Sucessful request::
@ -267,48 +287,28 @@ class JsonRequest(object):
"""
def parse(self, request):
self.request = request
self.params = request.get("params", {})
self.applicationsession = applicationsession
self.httprequest = cherrypy.request
self.httpresponse = cherrypy.response
self.httpsession = cherrypy.session
self.httpsession_id = "cookieid"
self.httpsession = cherrypy.session
self.session_id = self.params.pop("session_id", None) or uuid.uuid4().hex
host = cherrypy.config['openerp.server.host']
port = cherrypy.config['openerp.server.port']
self.session = self.httpsession.setdefault(self.session_id, OpenERPSession(host, port))
self.context = self.params.pop('context', None)
return self.params
def dispatch(self, controller, method, requestf=None, request=None):
""" Calls the method asked for by the JSON-RPC2 request
:param controller: the instance of the controller which received the request
:type controller: type
:param method: the method which received the request
:type method: callable
:param requestf: a file-like object containing an encoded JSON-RPC2 request
:type requestf: <read() -> bytes>
:param request: an encoded JSON-RPC2 request
:type request: bytes
:param request: a JSON-RPC2 request
:returns: a string-encoded JSON-RPC2 reply
:rtype: bytes
:returns: an utf8 encoded JSON-RPC2 reply
"""
# Read POST content or POST Form Data named "request"
if requestf:
request = simplejson.load(requestf, object_hook=nonliterals.non_literal_decoder)
else:
request = simplejson.loads(request, object_hook=nonliterals.non_literal_decoder)
response = {"jsonrpc": "2.0", "id": request.get('id')}
response = {"jsonrpc": "2.0" }
error = None
try:
print "--> %s.%s %s" % (controller.__class__.__name__, method.__name__, request)
error = None
self.parse(request)
# Read POST content or POST Form Data named "request"
if requestf:
self.jsonrequest = simplejson.load(requestf, object_hook=nonliterals.non_literal_decoder)
else:
self.jsonrequest = simplejson.loads(request, object_hook=nonliterals.non_literal_decoder)
self.init(self.jsonrequest.get("params", {}))
if self.debug or 1:
print "--> %s.%s %s" % (controller.__class__.__name__, method.__name__, self.jsonrequest)
response['id'] = self.jsonrequest.get('id')
response["result"] = method(controller, self, **self.params)
except OpenERPUnboundException:
error = {
@ -344,8 +344,9 @@ class JsonRequest(object):
if error:
response["error"] = error
print "<--", response
print
if self.debug or 1:
print "<--", response
print
content = simplejson.dumps(response, cls=nonliterals.NonLiteralEncoder)
cherrypy.response.headers['Content-Type'] = 'application/json'
@ -357,41 +358,32 @@ def jsonrequest(f):
@functools.wraps(f)
def json_handler(controller):
return JsonRequest().dispatch(controller, f, requestf=cherrypy.request.body)
return json_handler
class HttpRequest(object):
class HttpRequest(CherryPyRequest):
""" Regular GET/POST request
"""
def dispatch(self, controller, f, request, **kw):
self.request = request
self.applicationsession = applicationsession
self.httpsession_id = "cookieid"
self.httpsession = cherrypy.session
self.context = kw.get('context', {})
host = cherrypy.config['openerp.server.host']
port = cherrypy.config['openerp.server.port']
self.session_id = kw.pop('session_id', None)
self.session = self.httpsession.setdefault(self.session_id, OpenERPSession(host, port))
self.result = ""
if request.method == 'GET':
print "GET --> %s.%s %s %r" % (controller.__class__.__name__, f.__name__, request, kw)
else:
akw = dict([(key, kw[key] if isinstance(kw[key], basestring) else type(kw[key])) for key in kw.keys()])
print "POST --> %s.%s %s %r" % (controller.__class__.__name__, f.__name__, request, akw)
r = f(controller, self, **kw)
if isinstance(r, str):
print "<--", len(r), 'bytes'
else:
print "<--", len(r), 'characters'
print
def dispatch(self, controller, method, **kw):
self.init(kw)
akw = {}
for key in kw.keys():
if isinstance(kw[key], basestring) and len(kw[key]) < 1024:
akw[key] = kw[key]
else:
akw[key] = type(kw[key])
if self.debug or 1:
print "%s --> %s.%s %r" % (self.httprequest.method, controller.__class__.__name__, method.__name__, akw)
r = method(controller, self, **kw)
if self.debug or 1:
print "<--", 'size:', len(r)
print
return r
def httprequest(f):
# check cleaner wrapping:
# functools.wraps(f)(lambda x: JsonRequest().dispatch(x, f))
def http_handler(self,*l, **kw):
return HttpRequest().dispatch(self, f, cherrypy.request, **kw)
def http_handler(controller,*l, **kw):
return HttpRequest().dispatch(controller, f, **kw)
http_handler.exposed = 1
return http_handler