[MERGE]Merge with trunk upto revision no 833.

bzr revid: kch@tinyerp.com-20110817050802-2y0a3osy7jk52xps
bzr revid: kch@tinyerp.com-20110819055525-vrklylpqm8ck7pci
This commit is contained in:
Kunal Chavda (OpenERP) 2011-08-19 11:25:25 +05:30
commit d974c7a916
42 changed files with 1923 additions and 736 deletions

View File

@ -18,6 +18,7 @@ import openerpweb
import openerpweb.ast
import openerpweb.nonliterals
from babel.messages.pofile import read_po
# Should move to openerpweb.Xml2Json
class Xml2Json:
@ -66,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):])
@ -78,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>
@ -124,32 +125,32 @@ 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 % {
@ -158,6 +159,42 @@ class WebClient(openerpweb.Controller):
}
return r
@openerpweb.jsonrequest
def translations(self, req, mods, lang):
lang_model = req.session.model('res.lang')
ids = lang_model.search([("code", "=", lang)])
if ids:
lang_obj = lang_model.read(ids[0], ["direction", "date_format", "time_format",
"grouping", "decimal_point", "thousands_sep"])
else:
lang_obj = None
if lang.count("_") > 0:
separator = "_"
else:
separator = "@"
langs = lang.split(separator)
langs = [separator.join(langs[:x]) for x in range(1, len(langs) + 1)]
transs = {}
for addon_name in mods:
transl = {"messages":[]}
transs[addon_name] = transl
for l in langs:
f_name = os.path.join(openerpweb.path_addons, addon_name, "po", l + ".po")
if not os.path.exists(f_name):
continue
try:
with open(f_name) as t_file:
po = read_po(t_file)
except:
continue
for x in po:
if x.id and x.string:
transl["messages"].append({'id': x.id, 'string': x.string})
return {"modules": transs,
"lang_parameters": lang_obj}
class Database(openerpweb.Controller):
_cp_path = "/base/database"
@ -212,10 +249,10 @@ 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':
@ -230,9 +267,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):
@ -252,16 +287,18 @@ class Session(openerpweb.Controller):
@openerpweb.jsonrequest
def login(self, req, db, login, password):
req.session.login(db, login, password)
ctx = req.session.get_context()
return {
"session_id": req.session_id,
"uid": req.session._uid,
"context": ctx
}
@openerpweb.jsonrequest
def sc_list(self, req):
return req.session.model('ir.ui.view_sc').get_sc(req.session._uid, "ir.ui.menu",
req.session.eval_context(req.context))
return req.session.model('ir.ui.view_sc').get_sc(
req.session._uid, "ir.ui.menu", req.session.eval_context(req.context))
@openerpweb.jsonrequest
def get_lang_list(self, req):
@ -347,10 +384,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())]
@ -370,7 +407,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)
@ -400,18 +437,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
@ -908,10 +943,10 @@ class Binary(openerpweb.Controller):
_cp_path = "/base/binary"
@openerpweb.httprequest
def image(self, request, session_id, 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, '')
@ -924,26 +959,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, session_id, 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, session_id, 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
@ -967,10 +1002,10 @@ class Binary(openerpweb.Controller):
return out % (simplejson.dumps(callback), simplejson.dumps(args))
@openerpweb.httprequest
def upload_attachment(self, request, session_id, 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,

482
addons/base/po/base.pot Normal file
View File

@ -0,0 +1,482 @@
# Translations template for PROJECT.
# Copyright (C) 2011 ORGANIZATION
# This file is distributed under the same license as the PROJECT project.
# FIRST AUTHOR <EMAIL@ADDRESS>, 2011.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: PROJECT VERSION\n"
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
"POT-Creation-Date: 2011-08-17 13:28+0200\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Generated-By: Babel 0.9.6\n"
#: addons/base/static/src/js/form.js:1459
msgid "<em>   Search More...</em>"
msgstr ""
#: addons/base/static/src/js/form.js:1472
#, python-format
msgid "<em>   Create \"<strong>%s</strong>\"</em>"
msgstr ""
#: addons/base/static/src/js/form.js:1478
msgid "<em>   Create and Edit...</em>"
msgstr ""
#: addons/base/static/src/xml/base.xml:0
msgid "x"
msgstr ""
#: addons/base/static/src/xml/base.xml:0
msgid "#{title}"
msgstr ""
#: addons/base/static/src/xml/base.xml:0
msgid "#{text}"
msgstr ""
#: addons/base/static/src/xml/base.xml:0
msgid "Powered by"
msgstr ""
#: addons/base/static/src/xml/base.xml:0
msgid "openerp.com"
msgstr ""
#: addons/base/static/src/xml/base.xml:0
msgid "."
msgstr ""
#: addons/base/static/src/xml/base.xml:0
msgid "Loading..."
msgstr ""
#: addons/base/static/src/xml/base.xml:0
msgid "Create"
msgstr ""
#: addons/base/static/src/xml/base.xml:0
msgid "Drop"
msgstr ""
#: addons/base/static/src/xml/base.xml:0
msgid "Backup"
msgstr ""
#: addons/base/static/src/xml/base.xml:0
msgid "Restore"
msgstr ""
#: addons/base/static/src/xml/base.xml:0
msgid "Password"
msgstr ""
#: addons/base/static/src/xml/base.xml:0
msgid "Back to Login"
msgstr ""
#: addons/base/static/src/xml/base.xml:0
msgid "CREATE DATABASE"
msgstr ""
#: addons/base/static/src/xml/base.xml:0
msgid "Master password:"
msgstr ""
#: addons/base/static/src/xml/base.xml:0
msgid "New database name:"
msgstr ""
#: addons/base/static/src/xml/base.xml:0
msgid "Load Demonstration data:"
msgstr ""
#: addons/base/static/src/xml/base.xml:0
msgid "Default language:"
msgstr ""
#: addons/base/static/src/xml/base.xml:0
msgid "Admin password:"
msgstr ""
#: addons/base/static/src/xml/base.xml:0
msgid "Confirm password:"
msgstr ""
#: addons/base/static/src/xml/base.xml:0
msgid "DROP DATABASE"
msgstr ""
#: addons/base/static/src/xml/base.xml:0
msgid "Database:"
msgstr ""
#: addons/base/static/src/xml/base.xml:0
msgid "Master Password:"
msgstr ""
#: addons/base/static/src/xml/base.xml:0
msgid "BACKUP DATABASE"
msgstr ""
#: addons/base/static/src/xml/base.xml:0
msgid "RESTORE DATABASE"
msgstr ""
#: addons/base/static/src/xml/base.xml:0
msgid "File:"
msgstr ""
#: addons/base/static/src/xml/base.xml:0
msgid "CHANGE MASTER PASSWORD"
msgstr ""
#: addons/base/static/src/xml/base.xml:0
msgid "New master password:"
msgstr ""
#: addons/base/static/src/xml/base.xml:0
msgid "Confirm new master password:"
msgstr ""
#: addons/base/static/src/xml/base.xml:0
msgid "User:"
msgstr ""
#: addons/base/static/src/xml/base.xml:0
msgid "Password:"
msgstr ""
#: addons/base/static/src/xml/base.xml:0
msgid "Database"
msgstr ""
#: addons/base/static/src/xml/base.xml:0
msgid "Login"
msgstr ""
#: addons/base/static/src/xml/base.xml:0
msgid "Bad username or password"
msgstr ""
#: addons/base/static/src/xml/base.xml:0
msgid ""
"We think that daily job activities can be more intuitive, efficient, "
"automated, .. and even fun."
msgstr ""
#: addons/base/static/src/xml/base.xml:0
msgid "OpenERP's vision to be:"
msgstr ""
#: addons/base/static/src/xml/base.xml:0
msgid "Full featured"
msgstr ""
#: addons/base/static/src/xml/base.xml:0
msgid ""
"Today's enterprise challenges are multiple. We provide one module for "
"each need."
msgstr ""
#: addons/base/static/src/xml/base.xml:0
msgid "Open Source"
msgstr ""
#: addons/base/static/src/xml/base.xml:0
msgid ""
"To Build a great product, we rely on the knowledge of thousands of "
"contributors."
msgstr ""
#: addons/base/static/src/xml/base.xml:0
msgid "User Friendly"
msgstr ""
#: addons/base/static/src/xml/base.xml:0
msgid "In order to be productive, people need clean and easy to use interface."
msgstr ""
#: addons/base/static/src/xml/base.xml:0
msgid "-"
msgstr ""
#: addons/base/static/src/xml/base.xml:0
msgid "rpc_session_id:"
msgstr ""
#: addons/base/static/src/xml/base.xml:0
msgid "1"
msgstr ""
#: addons/base/static/src/xml/base.xml:0
msgid "LOGOUT"
msgstr ""
#: addons/base/static/src/xml/base.xml:0
msgid "h3"
msgstr ""
#: addons/base/static/src/xml/base.xml:0
msgid "<"
msgstr ""
#: addons/base/static/src/xml/base.xml:0
msgid ">"
msgstr ""
#: addons/base/static/src/xml/base.xml:0
msgid "</"
msgstr ""
#: addons/base/static/src/xml/base.xml:0
msgid "h4"
msgstr ""
#: addons/base/static/src/xml/base.xml:0
msgid "Delete"
msgstr ""
#: addons/base/static/src/xml/base.xml:0
msgid "First"
msgstr ""
#: addons/base/static/src/xml/base.xml:0
msgid "Last"
msgstr ""
#: addons/base/static/src/xml/base.xml:0
msgid "♻"
msgstr ""
#: addons/base/static/src/xml/base.xml:0
msgid "xml"
msgstr ""
#: addons/base/static/src/xml/base.xml:0
msgid "Save & Edit"
msgstr ""
#: addons/base/static/src/xml/base.xml:0
msgid "Create & Edit"
msgstr ""
#: addons/base/static/src/xml/base.xml:0
msgid "New"
msgstr ""
#: addons/base/static/src/xml/base.xml:0
msgid "<<"
msgstr ""
#: addons/base/static/src/xml/base.xml:0
msgid "0"
msgstr ""
#: addons/base/static/src/xml/base.xml:0
msgid "/"
msgstr ""
#: addons/base/static/src/xml/base.xml:0
msgid ">>"
msgstr ""
#: addons/base/static/src/xml/base.xml:0
msgid "Add"
msgstr ""
#: addons/base/static/src/xml/base.xml:0
msgid "Unhandled widget"
msgstr ""
#: addons/base/static/src/xml/base.xml:0
msgid "?"
msgstr ""
#: addons/base/static/src/xml/base.xml:0
msgid ":"
msgstr ""
#: addons/base/static/src/xml/base.xml:0
msgid "Open..."
msgstr ""
#: addons/base/static/src/xml/base.xml:0
msgid "Create..."
msgstr ""
#: addons/base/static/src/xml/base.xml:0
msgid "Search..."
msgstr ""
#: addons/base/static/src/xml/base.xml:0
msgid "One2Many widget"
msgstr ""
#: addons/base/static/src/xml/base.xml:0
msgid "Uploading ..."
msgstr ""
#: addons/base/static/src/xml/base.xml:0
msgid "Select"
msgstr ""
#: addons/base/static/src/xml/base.xml:0
msgid "Save As"
msgstr ""
#: addons/base/static/src/xml/base.xml:0
msgid "Clear"
msgstr ""
#: addons/base/static/src/xml/base.xml:0
msgid "Advanced Filter"
msgstr ""
#: addons/base/static/src/xml/base.xml:0
msgid "-- Filters --"
msgstr ""
#: addons/base/static/src/xml/base.xml:0
msgid "-- Actions --"
msgstr ""
#: addons/base/static/src/xml/base.xml:0
msgid "Save Filter"
msgstr ""
#: addons/base/static/src/xml/base.xml:0
msgid "Manage Filters"
msgstr ""
#: addons/base/static/src/xml/base.xml:0
msgid "Filter Name:"
msgstr ""
#: addons/base/static/src/xml/base.xml:0
msgid "(Any existing filter with the same name will be replaced)"
msgstr ""
#: addons/base/static/src/xml/base.xml:0
msgid "(?)"
msgstr ""
#: addons/base/static/src/xml/base.xml:0
msgid "Any of the following conditions must match"
msgstr ""
#: addons/base/static/src/xml/base.xml:0
msgid "All the following conditions must match"
msgstr ""
#: addons/base/static/src/xml/base.xml:0
msgid "None of the following conditions must match"
msgstr ""
#: addons/base/static/src/xml/base.xml:0
msgid "Add condition"
msgstr ""
#: addons/base/static/src/xml/base.xml:0
msgid "and"
msgstr ""
#: addons/base/static/src/xml/base.xml:0
msgid "Cancel"
msgstr ""
#: addons/base/static/src/xml/base.xml:0
msgid "Save"
msgstr ""
#: addons/base/static/src/xml/base.xml:0
msgid "Save & New"
msgstr ""
#: addons/base/static/src/xml/base.xml:0
msgid "Save & Close"
msgstr ""
#: addons/base/static/src/xml/base.xml:0
msgid "Export"
msgstr ""
#: addons/base/static/src/xml/base.xml:0
msgid ""
"This wizard will export all data that matches the current search criteria"
" to a CSV file.\n"
" You can export all data or only the fields that can be "
"reimported after modification."
msgstr ""
#: addons/base/static/src/xml/base.xml:0
msgid "Export Type:"
msgstr ""
#: addons/base/static/src/xml/base.xml:0
msgid "Import Compatible Export"
msgstr ""
#: addons/base/static/src/xml/base.xml:0
msgid "Export all Data"
msgstr ""
#: addons/base/static/src/xml/base.xml:0
msgid "Export Format"
msgstr ""
#: addons/base/static/src/xml/base.xml:0
msgid "CSV"
msgstr ""
#: addons/base/static/src/xml/base.xml:0
msgid "Excel"
msgstr ""
#: addons/base/static/src/xml/base.xml:0
msgid "Available fields"
msgstr ""
#: addons/base/static/src/xml/base.xml:0
msgid "Fields to export"
msgstr ""
#: addons/base/static/src/xml/base.xml:0
msgid "Save fields list"
msgstr ""
#: addons/base/static/src/xml/base.xml:0
msgid "Remove"
msgstr ""
#: addons/base/static/src/xml/base.xml:0
msgid "Remove All"
msgstr ""
#: addons/base/static/src/xml/base.xml:0
msgid "Name"
msgstr ""
#: addons/base/static/src/xml/base.xml:0
msgid "&nbsp;"
msgstr ""
#: addons/base/static/src/xml/base.xml:0
msgid "Save as:"
msgstr ""
#: addons/base/static/src/xml/base.xml:0
msgid "Ok"
msgstr ""
#: addons/base/static/src/xml/base.xml:0
msgid "Saved exports:"
msgstr ""

33
addons/base/po/fr_FR.po Normal file
View File

@ -0,0 +1,33 @@
# Translations template for PROJECT.
# Copyright (C) 2011 ORGANIZATION
# This file is distributed under the same license as the PROJECT project.
# niv <nicolas.vanhoren@openerp.com>, 2011.
#
msgid ""
msgstr ""
"Project-Id-Version: PROJECT VERSION\n"
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
"POT-Creation-Date: 2011-08-09 17:30+0200\n"
"PO-Revision-Date: 2011-08-09 17:31+0200\n"
"Last-Translator: niv <nicolas.vanhoren@openerp.com>\n"
"Language-Team: French\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Generated-By: Babel 0.9.4\n"
"Language: fr\n"
"Plural-Forms: nplurals=2; plural=(n > 1);\n"
#: addons/base/static/src/js/form.js:1459
msgid "<em>   Search More...</em>"
msgstr "<em>   Chercher plus...</em>"
#: addons/base/static/src/js/form.js:1472
#, python-format
msgid "<em>   Create \"<strong>%s</strong>\"</em>"
msgstr "<em>   Créer \"<strong>%s</strong>\"</em>"
#: addons/base/static/src/js/form.js:1478
msgid "<em>   Create and Edit...</em>"
msgstr "<em>   Créer et éditer...</em>"

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;
@ -264,7 +262,7 @@ label.error {
background: -ms-linear-gradient(top, #bd5e54 0%,#90322a 60%); /* IE10+ */
filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#BD5E54', endColorstr='#90322A',GradientType=0 ); /* IE6-9 */
background: linear-gradient(top, #bd5e54 0%,#90322a 60%); /* W3C */
border: 1px solid #6E2A24;
border-radius: 4px;
-moz-border-radius: 4px;
@ -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;
@ -1054,14 +1048,14 @@ label.error {
padding-right: 21px;
height: 21px;
background: #ffffff; /* Old browsers */
background: -moz-linear-gradient(top, #ffffff 0%, #ebe9e9 100%); /* FF3.6+ */
background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#ffffff), color-stop(100%,#ebe9e9)); /* Chrome,Safari4+ */
background: -webkit-linear-gradient(top, #ffffff 0%,#ebe9e9 100%); /* Chrome10+,Safari5.1+ */
background: -o-linear-gradient(top, #ffffff 0%,#ebe9e9 100%); /* Opera11.10+ */
background: -ms-linear-gradient(top, #ffffff 0%,#ebe9e9 100%); /* IE10+ */
filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#FFFFFF', endColorstr='#EBE9E9',GradientType=0 ); /* IE6-9 */
background: linear-gradient(top, #ffffff 0%,#ebe9e9 100%); /* W3C */
background: #ffffff; /* Old browsers */
background: -moz-linear-gradient(top, #ffffff 0%, #ebe9e9 100%); /* FF3.6+ */
background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#ffffff), color-stop(100%,#ebe9e9)); /* Chrome,Safari4+ */
background: -webkit-linear-gradient(top, #ffffff 0%,#ebe9e9 100%); /* Chrome10+,Safari5.1+ */
background: -o-linear-gradient(top, #ffffff 0%,#ebe9e9 100%); /* Opera11.10+ */
background: -ms-linear-gradient(top, #ffffff 0%,#ebe9e9 100%); /* IE10+ */
filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#FFFFFF', endColorstr='#EBE9E9',GradientType=0 ); /* IE6-9 */
background: linear-gradient(top, #ffffff 0%,#ebe9e9 100%); /* W3C */
border: 1px solid #D2CFCF;
border-right-width: 0;
@ -1170,6 +1164,7 @@ background: linear-gradient(top, #ffffff 0%,#ebe9e9 100%); /* W3C */
.parent_top {
vertical-align: text-top;
}
.openerp .oe-dialog-warning p {
padding-left: 1em;
font-size: 1.2em;
@ -1182,7 +1177,6 @@ background: linear-gradient(top, #ffffff 0%,#ebe9e9 100%); /* W3C */
-webkit-box-shadow: none;
box-shadow: none;
}
.openerp .oe-treeview-table {
width: 100%;
}
@ -1209,3 +1203,52 @@ background: linear-gradient(top, #ffffff 0%,#ebe9e9 100%); /* W3C */
text-align: left;
vertical-align: top;
}
/* Shortcuts*/
.oe-shortcut-toggle {
height: 20px;
padding: 0;
width: 24px;
cursor: pointer;
display: block;
background: url(/base/static/src/img/add-shortcut.png) no-repeat bottom;
float: left;
}
.oe-shortcut-remove{
background: url(/base/static/src/img/remove-shortcut.png) no-repeat bottom;
}
/* ================ */
.oe-shortcuts {
position: absolute;
margin: 0;
padding: 6px 5px;
top: 37px;
left: 197px;
right: 0;
height: 17px;
line-height: 1.2;
}
.oe-shortcuts ul {
display: block;
overflow: hidden;
list-style: none;
white-space: nowrap;
padding: 0;
margin: 0;
}
.oe-shortcuts li {
cursor: pointer;
display: -moz-inline-stack;
display: inline-block;
display: inline; /*IE7 */
color: #fff;
text-align: center;
border-left: 1px solid #909090;
padding: 4px;
font-size: 90%;
font-weight: normal;
}
.oe-shortcuts li:first-child {
border-left: none;
padding-left: 0;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 395 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 559 B

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);
}
}
if (openerp.base.data_import){
openerp.base.data_import(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));
@ -573,13 +567,66 @@ openerp.base.Header = openerp.base.Widget.extend({
this._super(parent, element_id);
},
start: function() {
this.do_update();
return this.do_update();
},
do_update: function() {
do_update: function () {
this.$element.html(QWeb.render("Header", this));
this.$element.find(".logout").click(this.on_logout);
return this.shortcut_load();
},
on_logout: function() {}
shortcut_load :function(){
var self = this,
sc = self.session.shortcuts,
shortcuts_ds = new openerp.base.DataSet(this, 'ir.ui.view_sc');
// TODO: better way to communicate between sections.
// sc.bindings, because jquery does not bind/trigger on arrays...
if (!sc.binding) {
sc.binding = {};
$(sc.binding).bind({
'add': function (e, attrs) {
var $shortcut = $('<li>', {
'data-id': attrs.res_id
}).text(attrs.name)
.appendTo(self.$element.find('.oe-shortcuts ul'));
shortcuts_ds.create(attrs, function (out) {
$shortcut.data('shortcut-id', out.result);
});
},
'remove-current': function () {
var menu_id = self.session.active_id;
var $shortcut = self.$element
.find('.oe-shortcuts li[data-id=' + menu_id + ']');
var shortcut_id = $shortcut.data('shortcut-id');
$shortcut.remove();
shortcuts_ds.unlink([shortcut_id]);
}
});
}
return this.rpc('/base/session/sc_list', {}, function(shortcuts) {
sc.splice(0, sc.length);
sc.push.apply(sc, shortcuts);
self.$element.find('.oe-shortcuts')
.html(QWeb.render('Shortcuts', {'shortcuts': shortcuts}))
.undelegate('li', 'click')
.delegate('li', 'click', function(e) {
e.stopPropagation();
var id = $(this).data('id');
self.session.active_id = id;
self.rpc('/base/menu/action', {'menu_id':id}, function(ir_menu_data) {
if (ir_menu_data.action.length){
self.on_action(ir_menu_data.action[0][2]);
}
});
});
});
},
on_action: function(action) {
},
on_logout: function() {
this.$element.find('.oe-shortcuts ul').empty();
}
});
openerp.base.Menu = openerp.base.Widget.extend({
@ -641,6 +688,7 @@ openerp.base.Menu = openerp.base.Widget.extend({
$secondary.show();
if (id) {
this.session.active_id = id;
this.rpc('/base/menu/action', {'menu_id': id},
this.on_menu_action_loaded);
}
@ -681,7 +729,7 @@ openerp.base.WebClient = openerp.base.Widget.extend({
}
this.$element.html(QWeb.render("Interface", params));
this.session = new openerp.base.Session(this,"oe_errors");
this.session = new openerp.base.Session();
this.loading = new openerp.base.Loading(this,"oe_loading");
this.crashmanager = new openerp.base.CrashManager(this);
this.crashmanager.start();
@ -699,7 +747,7 @@ openerp.base.WebClient = openerp.base.Widget.extend({
this.menu = new openerp.base.Menu(this, "oe_menu", "oe_secondary_menu");
this.menu.on_action.add(this.on_menu_action);
this.header.on_action.add(this.on_menu_action);
},
start: function() {
this.session.start();
@ -752,7 +800,7 @@ openerp.base.WebClient = openerp.base.Widget.extend({
self.execute_home_action(home_action[0], ds);
})
},
default_home: function () {
default_home: function () {
},
/**
* Bundles the execution of the home action
@ -782,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

@ -305,16 +305,8 @@ openerp.base.Registry = openerp.base.Class.extend( /** @lends openerp.base.Regis
}
});
/**
* Utility class that any class is allowed to extend to easy common manipulations.
*
* It provides rpc calls, callback on all methods preceded by "on_" or "do_" and a
* logging facility.
*/
openerp.base.SessionAware = openerp.base.Class.extend({
init: function(session) {
this.session = session;
openerp.base.CallbackEnabled = openerp.base.Class.extend({
init: function() {
// Transform on_* method into openerp.base.callbacks
for (var name in this) {
if(typeof(this[name]) == "function") {
@ -325,6 +317,306 @@ openerp.base.SessionAware = 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.
*
* It provides rpc calls, callback on all methods preceded by "on_" or "do_" and a
* logging facility.
*/
openerp.base.SessionAware = openerp.base.CallbackEnabled.extend({
init: function(session) {
this._super();
this.session = session;
},
/**
* Performs a JSON-RPC call
@ -347,7 +639,7 @@ openerp.base.SessionAware = openerp.base.Class.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) {
@ -558,282 +850,56 @@ openerp.base.OldWidget = openerp.base.Widget.extend({
}
});
openerp.base.Session = openerp.base.Widget.extend( /** @lends openerp.base.Session# */{
/**
* @constructs
* @param element_id to use for exception reporting
* @param server
* @param port
*/
init: function(parent, element_id, server, port) {
this._super(parent, element_id);
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.uid = false;
this.session_id = false;
this.module_list = [];
this.module_loaded = {"base": true};
this.context = {};
openerp.base.TranslationDataBase = openerp.base.Class.extend({
init: function() {
this.db = {};
this.parameters = {"direction": 'ltr',
"date_format": '%m/%d/%Y',
"time_format": '%H:%M:%S',
"grouping": "[]",
"decimal_point": ".",
"thousands_sep": ","};
},
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) {
set_bundle: function(translation_bundle) {
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
}
this.db = {};
var modules = _.keys(translation_bundle.modules).sort();
if (_.include(modules, "base")) {
modules = ["base"].concat(_.without(modules, "base"));
}
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);
_.each(modules, function(name) {
self.add_module_translation(translation_bundle.modules[name]);
});
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.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');
// 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);
},
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 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();
if (translation_bundle.lang_parameters) {
this.parameters = translation_bundle.lang_parameters;
}
},
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;
add_module_translation: function(mod) {
var self = this;
_.each(mod.messages, function(message) {
if (self.db[message.id] === undefined) {
self.db[message.id] = message.string;
}
});
},
build_translation_function: function() {
var self = this;
var fcnt = function(str) {
var tmp = self.get(str);
return tmp === undefined ? str : tmp;
}
fcnt.database = this;
return fcnt;
},
get: function(key) {
if (this.db[key])
return this.db[key];
return undefined;
}
});
openerp.base._t = new openerp.base.TranslationDataBase().build_translation_function();
};
// 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,7 @@
openerp.base.form = function (openerp) {
var _t = openerp.base._t;
openerp.base.views.add('form', 'openerp.base.FormView');
openerp.base.FormView = openerp.base.View.extend( /** @lends openerp.base.FormView# */{
/**
@ -456,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) {
@ -809,6 +809,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;
});
}
});
@ -839,9 +840,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;
@ -940,6 +944,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;
@ -1014,6 +1019,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();
}
});
@ -1034,6 +1040,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();
}
});
@ -1071,6 +1078,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);
@ -1122,6 +1130,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();
}
});
@ -1146,6 +1155,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;
@ -1181,6 +1191,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);
@ -1263,6 +1274,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);
@ -1454,7 +1466,7 @@ openerp.base.form.FieldMany2One = openerp.base.form.Field.extend({
// search more... if more results that max
if (values.length > self.limit) {
values = values.slice(0, self.limit);
values.push({label: "<em>   Search More...</em>", action: function() {
values.push({label: _t("<em>   Search More...</em>"), action: function() {
dataset.name_search(search_val, self.build_domain(), 'ilike'
, false, function(data) {
self._change_int_value(null);
@ -1467,13 +1479,13 @@ openerp.base.form.FieldMany2One = openerp.base.form.Field.extend({
if (search_val.length > 0 &&
!_.include(raw_result, search_val) &&
(!self.value || search_val !== self.value[1])) {
values.push({label: '<em>   Create "<strong>' +
$('<span />').text(search_val).html() + '</strong>"</em>', action: function() {
values.push({label: _.sprintf(_t('<em>   Create "<strong>%s</strong>"</em>'),
$('<span />').text(search_val).html()), action: function() {
self._quick_create(search_val);
}});
}
// create...
values.push({label: "<em>   Create and Edit...</em>", action: function() {
values.push({label: _t("<em>   Create and Edit...</em>"), action: function() {
self._change_int_value(null);
self._search_create_popup("form", undefined, {"default_name": search_val});
}});
@ -1527,7 +1539,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;
@ -1695,7 +1706,6 @@ openerp.base.form.FieldOne2Many = openerp.base.form.Field.extend({
});
}
},
set_value_from_ui: function() {},
set_value: function(value) {
value = value || [];
var self = this;
@ -1916,7 +1926,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
@ -2190,10 +2199,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;
}
}
});
@ -2209,8 +2275,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,6 +36,28 @@ openerp.base.ActionManager = openerp.base.Widget.extend({
this.inner_viewmanager = null;
}
},
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';
@ -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) {
@ -92,7 +116,7 @@ openerp.base.ActionManager = openerp.base.Widget.extend({
ir_actions_client: function (action) {
this.client_widget = openerp.base.client_actions.get_object(action.tag);
new this.client_widget(this, this.element_id, action.params).start();
},
}
});
openerp.base.ViewManager = openerp.base.Widget.extend({
@ -285,13 +309,53 @@ 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)
.then(this.searchview.do_search);
}
}
},
on_mode_switch: function (view_type) {
this._super(view_type);
this.shortcut_check(this.views[view_type]);
},
shortcut_check : function(view) {
var self = this;
var grandparent = this.widget_parent && this.widget_parent.widget_parent;
// display shortcuts if on the first view for the action
var $shortcut_toggle = this.$element.find('.oe-shortcut-toggle');
if (!(grandparent instanceof openerp.base.WebClient) ||
!(view.view_type === this.views_src[0].view_type
&& view.view_id === this.views_src[0].view_id)) {
$shortcut_toggle.hide();
return;
}
$shortcut_toggle.removeClass('oe-shortcut-remove').show();
if (_(this.session.shortcuts).detect(function (shortcut) {
return shortcut.res_id === self.session.active_id; })) {
$shortcut_toggle.addClass("oe-shortcut-remove");
}
this.shortcut_add_remove();
},
shortcut_add_remove: function() {
var self = this;
var $shortcut_toggle = this.$element.find('.oe-shortcut-toggle');
$shortcut_toggle.click(function() {
if ($shortcut_toggle.hasClass("oe-shortcut-remove")) {
$(self.session.shortcuts.binding).trigger('remove-current');
$shortcut_toggle.removeClass("oe-shortcut-remove");
} else {
$(self.session.shortcuts.binding).trigger('add', {
'user_id': self.session.uid,
'res_id': self.session.active_id,
'resource': 'ir.ui.menu',
'name': self.action.name
});
$shortcut_toggle.addClass("oe-shortcut-remove");
}
});
}
});

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>
@ -359,7 +356,14 @@
</div>
</div>
<div class="oe-shortcuts"> </div>
</t>
<ul t-name="Shortcuts">
<li t-foreach="shortcuts" t-as="shortcut"
t-att-data-id="shortcut.res_id"
t-att-data-shortcut-id="shortcut.id"
><t t-esc="shortcut.name"/></li>
</ul>
<t t-name="Menu">
<table align="center">
<tr>
@ -408,7 +412,8 @@
<table class="view-manager-main-table">
<tr>
<td class="view-manager-main-content">
<!-- TODO prefix id with the element_id of the controller t-attf-id="#{prefix}_localid" -->
<a class="oe-shortcut-toggle" title="Add / Remove Shortcut..."
href="javascript: void(0)"> </a>
<div class="oe_vm_switch">
<t t-if="views.length != 1" t-foreach="views" t-as="view">
<button type="button" t-att-data-view-type="view.view_type">
@ -775,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"
@ -1157,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

@ -0,0 +1,23 @@
# Translations template for PROJECT.
# Copyright (C) 2011 ORGANIZATION
# This file is distributed under the same license as the PROJECT project.
# FIRST AUTHOR <EMAIL@ADDRESS>, 2011.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: PROJECT VERSION\n"
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
"POT-Creation-Date: 2011-08-17 13:28+0200\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Generated-By: Babel 0.9.6\n"
#: addons/base_calendar/static/src/xml/base_calendar.xml:0
msgid "&nbsp;"
msgstr ""

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

@ -0,0 +1,47 @@
# Translations template for PROJECT.
# Copyright (C) 2011 ORGANIZATION
# This file is distributed under the same license as the PROJECT project.
# FIRST AUTHOR <EMAIL@ADDRESS>, 2011.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: PROJECT VERSION\n"
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
"POT-Creation-Date: 2011-08-17 13:28+0200\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Generated-By: Babel 0.9.6\n"
#: addons/base_dashboard/static/src/xml/base_dashboard.xml:0
msgid "Reset"
msgstr ""
#: addons/base_dashboard/static/src/xml/base_dashboard.xml:0
msgid "Undo"
msgstr ""
#: addons/base_dashboard/static/src/xml/base_dashboard.xml:0
msgid "Add Widget"
msgstr ""
#: addons/base_dashboard/static/src/xml/base_dashboard.xml:0
msgid "Change layout"
msgstr ""
#: addons/base_dashboard/static/src/xml/base_dashboard.xml:0
msgid "Choose dashboard layout"
msgstr ""
#: addons/base_dashboard/static/src/xml/base_dashboard.xml:0
msgid "progress:"
msgstr ""
#: addons/base_dashboard/static/src/xml/base_dashboard.xml:0
msgid "%"
msgstr ""

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

@ -0,0 +1,41 @@
# Translations template for PROJECT.
# Copyright (C) 2011 ORGANIZATION
# This file is distributed under the same license as the PROJECT project.
# FIRST AUTHOR <EMAIL@ADDRESS>, 2011.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: PROJECT VERSION\n"
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
"POT-Creation-Date: 2011-08-17 13:28+0200\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Generated-By: Babel 0.9.6\n"
#: addons/base_default_home/static/src/xml/base_default_home.xml:0
msgid "Welcome to OpenERP"
msgstr ""
#: addons/base_default_home/static/src/xml/base_default_home.xml:0
msgid ""
"Don't forget to bookmark your application address to come back\n"
" later:"
msgstr ""
#: addons/base_default_home/static/src/xml/base_default_home.xml:0
msgid "URL:"
msgstr ""
#: addons/base_default_home/static/src/xml/base_default_home.xml:0
msgid "login:"
msgstr ""
#: addons/base_default_home/static/src/xml/base_default_home.xml:0
msgid "Install"
msgstr ""

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

@ -0,0 +1,19 @@
# Translations template for PROJECT.
# Copyright (C) 2011 ORGANIZATION
# This file is distributed under the same license as the PROJECT project.
# FIRST AUTHOR <EMAIL@ADDRESS>, 2011.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: PROJECT VERSION\n"
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
"POT-Creation-Date: 2011-08-17 13:28+0200\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Generated-By: Babel 0.9.6\n"

View File

@ -0,0 +1,19 @@
# Translations template for PROJECT.
# Copyright (C) 2011 ORGANIZATION
# This file is distributed under the same license as the PROJECT project.
# FIRST AUTHOR <EMAIL@ADDRESS>, 2011.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: PROJECT VERSION\n"
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
"POT-Creation-Date: 2011-08-17 13:28+0200\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Generated-By: Babel 0.9.6\n"

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

@ -0,0 +1,19 @@
# Translations template for PROJECT.
# Copyright (C) 2011 ORGANIZATION
# This file is distributed under the same license as the PROJECT project.
# FIRST AUTHOR <EMAIL@ADDRESS>, 2011.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: PROJECT VERSION\n"
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
"POT-Creation-Date: 2011-08-17 13:28+0200\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Generated-By: Babel 0.9.6\n"

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

@ -0,0 +1,19 @@
# Translations template for PROJECT.
# Copyright (C) 2011 ORGANIZATION
# This file is distributed under the same license as the PROJECT project.
# FIRST AUTHOR <EMAIL@ADDRESS>, 2011.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: PROJECT VERSION\n"
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
"POT-Creation-Date: 2011-08-17 13:28+0200\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Generated-By: Babel 0.9.6\n"

View File

@ -0,0 +1,19 @@
# Translations template for PROJECT.
# Copyright (C) 2011 ORGANIZATION
# This file is distributed under the same license as the PROJECT project.
# FIRST AUTHOR <EMAIL@ADDRESS>, 2011.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: PROJECT VERSION\n"
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
"POT-Creation-Date: 2011-08-17 13:28+0200\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Generated-By: Babel 0.9.6\n"

View File

@ -0,0 +1,71 @@
# Translations template for PROJECT.
# Copyright (C) 2011 ORGANIZATION
# This file is distributed under the same license as the PROJECT project.
# FIRST AUTHOR <EMAIL@ADDRESS>, 2011.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: PROJECT VERSION\n"
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
"POT-Creation-Date: 2011-08-17 13:28+0200\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Generated-By: Babel 0.9.6\n"
#: addons/web_mobile/static/src/xml/web_mobile.xml:0
msgid "OpenERP"
msgstr ""
#: addons/web_mobile/static/src/xml/web_mobile.xml:0
msgid "Home"
msgstr ""
#: addons/web_mobile/static/src/xml/web_mobile.xml:0
msgid "Database:"
msgstr ""
#: addons/web_mobile/static/src/xml/web_mobile.xml:0
msgid "Choose Database..."
msgstr ""
#: addons/web_mobile/static/src/xml/web_mobile.xml:0
msgid "Login:"
msgstr ""
#: addons/web_mobile/static/src/xml/web_mobile.xml:0
msgid "Password:"
msgstr ""
#: addons/web_mobile/static/src/xml/web_mobile.xml:0
msgid "Login"
msgstr ""
#: addons/web_mobile/static/src/xml/web_mobile.xml:0
msgid ":"
msgstr ""
#: addons/web_mobile/static/src/xml/web_mobile.xml:0
msgid "Shortcuts"
msgstr ""
#: addons/web_mobile/static/src/xml/web_mobile.xml:0
msgid "Menu"
msgstr ""
#: addons/web_mobile/static/src/xml/web_mobile.xml:0
msgid "Options"
msgstr ""
#: addons/web_mobile/static/src/xml/web_mobile.xml:0
msgid "Logout"
msgstr ""
#: addons/web_mobile/static/src/xml/web_mobile.xml:0
msgid "Preferences"
msgstr ""

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>

8
babel.cfg Normal file
View File

@ -0,0 +1,8 @@
[extractors]
qweb = npybabel:extract_qweb
xmljs = npybabel:extract_xmljs
[javascript: static/src/js/**.js]
[qweb: static/src/xml/**.xml]
[xmljs: static/src/xml/**.xml]

53
gen_translations.sh Executable file
View File

@ -0,0 +1,53 @@
#!/bin/sh
usage() {
cat << EOF
usage: $0 -a
usage: $0 DIR OUTPUT_FILE
OPTIONS:
-a recreate the .pot file for all addons
-h print this message
EOF
exit 0
}
do_all=
while getopts "a" opt
do
case "$opt" in
a)
do_all=true;;
h)
usage;;
\?)
usage;;
esac
done
shift $((OPTIND-1))
if [ -n "$do_all" ]
then
echo "Extracting all the translations"
executable=$0
extract_module() {
$executable addons/$1 addons/$1/po/$1.pot
}
extract_module base
extract_module base_calendar
extract_module base_dashboard
extract_module base_default_home
extract_module base_diagram
extract_module base_gantt
extract_module base_graph
extract_module base_hello
extract_module web_chat
extract_module web_mobile
elif [ -n "$2" ]
then
./npybabel.py extract -F babel.cfg -o $2 -k _t --no-default-keywords $1
else
usage
fi

65
npybabel.py Executable file
View File

@ -0,0 +1,65 @@
#!/usr/bin/python
# EASY-INSTALL-ENTRY-SCRIPT: 'Babel==0.9.6','console_scripts','pybabel'
__requires__ = 'Babel==0.9.6'
import sys
from pkg_resources import load_entry_point
import re
import json
import xml.etree.ElementTree as elt
if __name__ == '__main__':
sys.exit(
load_entry_point('Babel==0.9.6', 'console_scripts', 'pybabel')()
)
XMLJS_EXPR = re.compile(r"""(?:\_t *\( *((?:"(?:[^"\\]|\\.)*")|(?:'(?:[^'\\]|\\.)*')) *\))""")
def extract_xmljs(fileobj, keywords, comment_tags, options):
content = fileobj.read()
found = XMLJS_EXPR.finditer(content)
result = []
index = 0
line_nbr = 0
for f in found:
mes = f.group(1)
mes = json.loads(mes)
while index < f.start():
if content[index] == "\n":
line_nbr += 1
index += 1
result.append((line_nbr, None, mes, ""))
return result
def extract_qweb(fileobj, keywords, comment_tags, options):
"""Extract messages from XXX files.
:param fileobj: the file-like object the messages should be extracted
from
:param keywords: a list of keywords (i.e. function names) that should
be recognized as translation functions
:param comment_tags: a list of translator tags to search for and
include in the results
:param options: a dictionary of additional options (optional)
:return: an iterator over ``(lineno, funcname, message, comments)``
tuples
:rtype: ``iterator``
"""
result = []
def handle_text(str):
str = (str or "").strip()
if not str:
return
result.append((0, None, str, ""))
def iter_elements(current_element):
for el in current_element:
if "t-js" not in el.attrib and \
not ("t-jquery" in el.attrib and "t-operation" not in el.attrib) and \
not ("t-trad" in el.attrib and el.attrib["t-trad"].strip() == "off"):
handle_text(el.text)
iter_elements(el)
handle_text(el.tail)
tree = elt.parse(fileobj)
iter_elements(tree.getroot())
return result

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,40 +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 = self.httpsession.setdefault(kw.pop('session_id', None), 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

245
setup.py Executable file → Normal file
View File

@ -1,174 +1,89 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
##############################################################################
#
# OpenERP, Open Source Management Solution
# Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>).
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
# setup from TinERP
# taken from straw http://www.nongnu.org/straw/index.html
# taken from gnomolicious http://www.nongnu.org/gnomolicious/
# adapted by Nicolas Évrard <nicoe@altern.org>
#
# doc/migrate is not included since about 6.1-dev
# doc/tests is not included
# python25-compat/*py should be in the openerp (and imported appropriately)
import sys
import os
from os.path import join, isfile
import glob
import re
import sys
from setuptools import setup
from setuptools import setup, find_packages
name = 'openerp-web-proto'
version = '6.0.1'
description = "Web Client of OpenERP, the Enterprise Management Software"
long_description = "OpenERP Web is the web client of the OpenERP, a free enterprise management software"
author = "OpenERP S.A."
author_email = "info@openerp.com"
support_email = 'support@openerp.com'
url = "http://www.openerp.com/"
download_url = ''
license = "OEPL"
# Backports os.walk with followlinks from python 2.6.
# Needed to add all addons files to data_files for Windows packaging.
def walk_followlinks(top, topdown=True, onerror=None, followlinks=False):
from os.path import join, isdir, islink
from os import listdir, error
try:
names = listdir(top)
except error, err:
if onerror is not None:
onerror(err)
return
dirs, nondirs = [], []
for name in names:
if isdir(join(top, name)):
dirs.append(name)
else:
nondirs.append(name)
if topdown:
yield top, dirs, nondirs
for name in dirs:
path = join(top, name)
if followlinks or not islink(path):
for x in walk_followlinks(path, topdown, onerror, followlinks):
yield x
if not topdown:
yield top, dirs, nondirs
if sys.version_info < (2, 6):
os.walk = walk_followlinks
py2exe_keywords = {}
py2exe_data_files = []
if os.name == 'nt':
version_dash_incompatible = False
if 'bdist_rpm' in sys.argv:
version_dash_incompatible = True
try:
import py2exe
py2exe_keywords['console'] = [
{ "script": "openerp-server",
"icon_resources": [(1, join("pixmaps","openerp-icon.ico"))],
}]
py2exe_keywords['options'] = {
"py2exe": {
"skip_archive": 1,
"optimize": 2,
"dist_dir": 'dist',
"packages": [
"lxml", "lxml.builder", "lxml._elementpath", "lxml.etree",
"lxml.objectify", "decimal", "xml", "xml", "xml.dom", "xml.xpath",
"encodings", "dateutil", "pychart", "PIL", "pyparsing",
"pydot", "asyncore","asynchat", "reportlab", "vobject",
"HTMLParser", "select", "mako", "poplib",
"imaplib", "smtplib", "email", "yaml", "DAV",
"uuid", "commands", "openerp",
],
"excludes" : ["Tkconstants","Tkinter","tcl"],
}
}
# TODO is it still necessary now that we don't use the library.zip file?
def data_files():
'''For Windows, we consider all the addons as data files.
It seems also that package_data below isn't honored by py2exe.'''
files = []
os.chdir('openerp')
for (dp, dn, names) in os.walk('addons'):
files.append((join('openerp',dp), map(lambda x: join('openerp', dp, x), names)))
os.chdir('..')
files.append(('openerp', [join('openerp', 'import_xml.rng'),]))
from py2exe_utils import opts
version_dash_incompatible = True
except ImportError:
opts = {}
if version_dash_incompatible:
version = version.split('-')[0]
# copy pytz/timzeone
# TODO check if we have to also copy dateutil's timezone data.
import pytz
# Make sure the layout of pytz hasn't changed
assert (pytz.__file__.endswith('__init__.pyc') or
pytz.__file__.endswith('__init__.py')), pytz.__file__
pytz_dir = os.path.dirname(pytz.__file__)
FILE_PATTERNS = \
r'.+\.(py|cfg|po|pot|mo|txt|rst|gif|png|jpg|ico|mako|html|js|css|htc|swf)$'
def find_data_files(source, patterns=FILE_PATTERNS):
file_matcher = re.compile(patterns, re.I)
out = []
for base, _, files in os.walk(source):
cur_files = []
for f in files:
if file_matcher.match(f):
cur_files.append(os.path.join(base, f))
if cur_files:
out.append(
(base, cur_files))
saved_dir = os.getcwd()
os.chdir(pytz_dir)
for dp, dn, names in os.walk('zoneinfo'):
files.append((join('pytz',dp), map(lambda x: join(pytz_dir, dp, x), names)))
os.chdir(saved_dir)
return out
return files
py2exe_data_files = data_files()
execfile(join('openerp', 'release.py'))
setup(name = name,
version = version,
description = description,
long_description = long_desc,
url = url,
author = author,
author_email = author_email,
classifiers = filter(None, classifiers.split("\n")),
license = license,
data_files = [
(join('man', 'man1'), ['man/openerp-server.1']),
(join('man', 'man5'), ['man/openerp_serverrc.5']),
('doc', filter(isfile, glob.glob('doc/*'))),
] + py2exe_data_files,
scripts = ['openerp-server'],
packages = find_packages(),
include_package_data = True,
package_data = {
'': ['*.yml', '*.xml', '*.po', '*.pot', '*.csv'],
},
dependency_links = ['http://download.gna.org/pychart/'],
install_requires = [
# We require the same version as caldav for lxml.
'lxml==2.1.5',
'mako',
'python-dateutil',
'psycopg2',
# TODO the pychart package we include in openerp corresponds to PyChart 1.37.
# It seems there is a single difference, which is a spurious print in generate_docs.py.
# It is probably safe to move to PyChart 1.39 (the latest one).
# (Let setup.py choose the latest one, and we should check we can remove pychart from
# our tree.)
'pychart',
'pydot',
'pytz',
'reportlab',
'caldav',
'pyyaml',
'pywebdav',
'feedparser',
'simplejson >= 2.0',
],
extras_require = {
'SSL' : ['pyopenssl'],
},
**py2exe_keywords
setup(
name=name,
version=version,
description=description,
long_description=long_description,
author=author,
author_email=author_email,
url=url,
download_url=download_url,
license=license,
install_requires=[
"CherryPy >= 3.1.2",
"Babel >= 0.9.6",
"simplejson >= 2.0.9",
"python-dateutil >= 1.4.1",
"pytz",
],
tests_require=[
'unittest2',
'mock',
],
test_suite = 'unittest2.collector',
zip_safe=False,
packages=[
'addons',
'addons.base',
'addons.base.controllers',
'addons.base_calendar',
'addons.base_hello',
'openerpweb',
],
classifiers=[
'Development Status :: 6 - Production/Stable',
'Operating System :: OS Independent',
'Programming Language :: Python',
'Environment :: Web Environment',
'Topic :: Office/Business :: Financial',
],
scripts=['scripts/openerp-web'],
data_files=(find_data_files('addons')
+ opts.pop('data_files', [])
),
**opts
)