[MERGE]Merge with trunk upto revision no 970.

bzr revid: kch@tinyerp.com-20110908103919-0elkj4hdhhgpvx6o
This commit is contained in:
Kunal Chavda (OpenERP)
2011-09-08 16:09:19 +05:30
36 changed files with 277 additions and 231 deletions
+6 -4
View File
@@ -1,9 +1,8 @@
.PHONY: all release clean
.PHONY: all doc release clean
HOST = 127.0.0.1
PORT = 8080
all: run
run:
@@ -24,6 +23,9 @@ clean:
@rm -rf dist
@rm -rf *.egg-info
cloc:
cloc openerpweb/*.py addons/*/controllers/*.py addons/*/static/src/*.js addons/*/static/src/js/*.js addons/*/static/src/css/*.css addons/*/static/src/xml/*.xml
doc:
make -C doc html
cloc:
cloc addons/*/common/*.py addons/*/controllers/*.py addons/*/static/src/*.js addons/*/static/src/js/*.js addons/*/static/src/css/*.css addons/*/static/src/xml/*.xml
+4 -37
View File
@@ -1,42 +1,9 @@
Coding style
------------
Javascript
http://javascript.crockford.com/code.html with the following amendements:
- Line Length should be 160 (132?), dont split at 80, rationale in 2011 we all use 16/9 screens
http://google-styleguide.googlecode.com/svn/trunk/javascriptguide.xml ?
Modules Conventions
-------------------
addons/<modulename>/controllers/ python controller
addons/<modulename>/controllers/main.py main python controller is there is only one (or should it be <modulename>.py ?)
addons/<modulename>/static/ static directory (directly served by the web server)
addons/<modulename>/static/<external_library>/ directory containing an external javascrip library respect the directory structure of upstream is this directory
addons/<modulename>/static/openerp/ module specfic static files
addons/<modulename>/static/openerp/js/ module specific javscript files
addons/<modulename>/static/openerp/css/ module specific css files
addons/<modulename>/static/openerp/img/ module specific images files
addons/<modulename>/static/openerp/ other files
addons/<modulename>/__openerp__.py module manifest referencing js and css files
Dependecies
OpenERP Web
-----------
Depends on
install "CherryPy>=3.1.2" "-d cherrypy"
install "simplejson>=2.0.9" "-d simplejson"
To build the documentation use:
Maybe soon on
$ make doc
#install "Babel>=0.9.4" "-d babel"
#install "pytz>=2009j" "-d pytz"
then look at doc/build/html/index.html
Probably not anymore on:
#install "Mako>=0.2.4" "-d mako"
#install "formencode>=1.2.2" "-d formencode"
#install "pyparsing>=1.5.2" "-f pyparsing.py"
#install "xlwt>=0.7" "-d xlwt"
+14 -15
View File
@@ -4,6 +4,7 @@ from __future__ import with_statement
import functools
import logging
import os
import pprint
import sys
import traceback
import uuid
@@ -26,6 +27,8 @@ import backendrpc as backend
__all__ = ['Root', 'jsonrequest', 'httprequest', 'Controller',
'WebRequest', 'JsonRequest', 'HttpRequest']
_logger = logging.getLogger(__name__)
#-----------------------------------------------------------
# Globals (wont move into a pool)
#-----------------------------------------------------------
@@ -159,8 +162,8 @@ class JsonRequest(WebRequest):
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)
if _logger.isEnabledFor(logging.DEBUG):
_logger.debug("--> %s.%s\n%s", controller.__class__.__name__, method.__name__, pprint.pformat(self.jsonrequest))
response['id'] = self.jsonrequest.get('id')
response["result"] = method(controller, self, **self.params)
except backend.OpenERPUnboundException:
@@ -184,7 +187,7 @@ class JsonRequest(WebRequest):
}
}
except Exception:
logging.getLogger('openerp.JSONRequest.dispatch').exception\
logging.getLogger(__name__ + '.JSONRequest.dispatch').exception\
("An error occured while handling a json request")
error = {
'code': 300,
@@ -197,10 +200,8 @@ class JsonRequest(WebRequest):
if error:
response["error"] = error
if self.debug or 1:
print "<--", response
print
if _logger.isEnabledFor(logging.DEBUG):
_logger.debug("<--\n%s", pprint.pformat(response))
content = simplejson.dumps(response, cls=nonliterals.NonLiteralEncoder)
return werkzeug.wrappers.Response(
content, headers=[('Content-Type', 'application/json'),
@@ -237,15 +238,13 @@ class HttpRequest(WebRequest):
akw[key] = value
else:
akw[key] = type(value)
if self.debug or 1:
print "%s --> %s.%s %r" % (self.httprequest.method, controller.__class__.__name__, method.__name__, akw)
_logger.debug("%s --> %s.%s %r", self.httprequest.method, controller.__class__.__name__, method.__name__, akw)
r = method(controller, self, **self.params)
if self.debug or 1:
if isinstance(r, werkzeug.wrappers.BaseResponse):
print '<--', r
_logger.debug('<-- %s', r)
else:
print "<--", 'size:', len(r)
print
_logger.debug("<-- size: %s", len(r))
return r
def make_response(self, data, headers=None, cookies=None):
@@ -317,7 +316,7 @@ class Root(object):
by the server, will be filtered by this pattern
"""
def __init__(self, options):
self.root = werkzeug.urls.Href('/web/webclient/home')
self.root = werkzeug.urls.Href('/web/webclient/home?debug')
self.config = options
self.session_cookie = 'sessionid'
@@ -391,7 +390,7 @@ class Root(object):
manifest_path = os.path.join(addons_path, module, '__openerp__.py')
if os.path.isfile(manifest_path):
manifest = ast.literal_eval(open(manifest_path).read())
print "Loading", module
_logger.info("Loading %s", module)
m = __import__(module)
addons_module[module] = m
addons_manifest[module] = manifest
@@ -424,6 +423,6 @@ class Root(object):
meth = rest[0]
m = getattr(c, meth)
if getattr(m, 'exposed', False):
print "Dispatching to", ps, c, meth, m
_logger.debug("Dispatching to %s %s %s", ps, c, meth)
return m
return None
+82 -49
View File
@@ -11,6 +11,7 @@ import simplejson
import textwrap
import xmlrpclib
import time
import zlib
import webrelease
from xml.etree import ElementTree
from cStringIO import StringIO
@@ -23,8 +24,6 @@ openerpweb.nonliterals = web.common.nonliterals
from babel.messages.pofile import read_po
_REPORT_POLLER_DELAY = 0.05
# Should move to openerpweb.Xml2Json
class Xml2Json:
# xml2json-direct
@@ -104,7 +103,6 @@ home_template = textwrap.dedent("""<!DOCTYPE html>
%(javascript)s
<script type="text/javascript">
$(function() {
QWeb = new QWeb2.Engine();
var c = new openerp.init();
var wc = new c.web.WebClient("oe");
wc.start();
@@ -144,13 +142,13 @@ class WebClient(openerpweb.Controller):
# script tags
jslist = ['/web/webclient/js']
if req.debug:
jslist = manifest_glob(req.config.addons_path, ['web'], 'js')
jslist = [i + '?debug=' + str(time.time()) for i in manifest_glob(req.config.addons_path, ['web'], 'js')]
js = "\n ".join(['<script type="text/javascript" src="%s"></script>'%i for i in jslist])
# css tags
csslist = ['/web/webclient/css']
if req.debug:
csslist = manifest_glob(req.config.addons_path, ['web'], 'css')
csslist = [i + '?debug=' + str(time.time()) for i in manifest_glob(req.config.addons_path, ['web'], 'css')]
css = "\n ".join(['<link rel="stylesheet" href="%s">'%i for i in csslist])
r = home_template % {
'javascript': js,
@@ -453,8 +451,6 @@ def load_actions_from_ir_values(req, key, key2, models, meta):
def clean_action(req, action):
action.setdefault('flags', {})
if action['type'] != 'ir.actions.act_window':
return action
context = req.session.eval_context(req.context)
eval_ctx = req.session.evaluation_context(context)
@@ -466,7 +462,9 @@ def clean_action(req, action):
if isinstance(action.get('domain'), basestring):
action['domain'] = eval( action['domain'], eval_ctx ) or []
return fix_view_modes(action)
if action['type'] == 'ir.actions.act_window':
return fix_view_modes(action)
return action
# I think generate_views,fix_view_modes should go into js ActionManager
def generate_views(action):
@@ -764,6 +762,8 @@ class View(openerpweb.Controller):
fvg = Model.fields_view_get(view_id, view_type, context, toolbar, submenu)
# todo fme?: check that we should pass the evaluated context here
self.process_view(req.session, fvg, context, transform)
if toolbar and transform:
self.process_toolbar(req, fvg['toolbar'])
return fvg
def process_view(self, session, fvg, context, transform):
@@ -795,6 +795,22 @@ class View(openerpweb.Controller):
if field.get('context'):
field["context"] = self.parse_context(field["context"], session)
def process_toolbar(self, req, toolbar):
"""
The toolbar is a mapping of section_key: [action_descriptor]
We need to clean all those actions in order to ensure correct
round-tripping
"""
for actions in toolbar.itervalues():
for action in actions:
if 'context' in action:
action['context'] = self.parse_context(
action['context'], req.session)
if 'domain' in action:
action['domain'] = self.parse_domain(
action['domain'], req.session)
@openerpweb.jsonrequest
def add_custom(self, req, view_id, arch):
CustomView = req.session.model('ir.ui.view.custom')
@@ -884,22 +900,13 @@ class View(openerpweb.Controller):
if context_string:
elem.set(el, self.parse_context(context_string, session))
class FormView(View):
_cp_path = "/web/formview"
@openerpweb.jsonrequest
def load(self, req, model, view_id, toolbar=False):
fields_view = self.fields_view_get(req, model, view_id, 'form', toolbar=toolbar)
return {'fields_view': fields_view}
def load(self, req, model, view_id, view_type, toolbar=False):
return self.fields_view_get(req, model, view_id, view_type, toolbar=toolbar)
class ListView(View):
_cp_path = "/web/listview"
@openerpweb.jsonrequest
def load(self, req, model, view_id, toolbar=False):
fields_view = self.fields_view_get(req, model, view_id, 'tree', toolbar=toolbar)
return {'fields_view': fields_view}
def process_colors(self, view, row, context):
colors = view['arch']['attrs'].get('colors')
@@ -918,6 +925,15 @@ class ListView(View):
return color[0]
return 'maroon'
class TreeView(View):
_cp_path = "/web/treeview"
@openerpweb.jsonrequest
def action(self, req, model, id):
return load_actions_from_ir_values(
req,'action', 'tree_but_open',[(model, id)],
False)
class SearchView(View):
_cp_path = "/web/searchview"
@@ -1062,8 +1078,11 @@ class Action(openerpweb.Controller):
context = req.session.eval_context(req.context)
action_type = Actions.read([action_id], ['type'], context)
if action_type:
action = req.session.model(action_type[0]['type']).read([action_id], False,
context)
ctx = {}
if action_type[0]['type'] == 'ir.actions.report.xml':
ctx.update({'bin_size': True})
ctx.update(context)
action = req.session.model(action_type[0]['type']).read([action_id], False, ctx)
if action:
value = clean_action(req, action[0])
return {'result': value}
@@ -1073,19 +1092,6 @@ class Action(openerpweb.Controller):
return clean_action(req, req.session.model('ir.actions.server').run(
[action_id], req.session.eval_context(req.context)))
class TreeView(View):
_cp_path = "/web/treeview"
@openerpweb.jsonrequest
def load(self, req, model, view_id, toolbar=False):
return self.fields_view_get(req, model, view_id, 'tree', toolbar=toolbar)
@openerpweb.jsonrequest
def action(self, req, model, id):
return load_actions_from_ir_values(
req,'action', 'tree_but_open',[(model, id)],
False)
class Export(View):
_cp_path = "/web/export"
@@ -1336,29 +1342,56 @@ class ExcelExport(Export):
fp.close()
return data
class Reports(View):
_cp_path = "/web/report"
POLLING_DELAY = 0.25
TYPES_MAPPING = {
'doc': 'application/vnd.ms-word',
'html': 'text/html',
'odt': 'application/vnd.oasis.opendocument.text',
'pdf': 'application/pdf',
'sxw': 'application/vnd.sun.xml.writer',
'xls': 'application/vnd.ms-excel',
}
@openerpweb.httprequest
def index(self, req, action, token):
action = simplejson.loads(action)
@openerpweb.jsonrequest
def get_report(self, req, action):
report_srv = req.session.proxy("report")
context = req.session.eval_context(openerpweb.nonliterals.CompoundContext(req.context, \
action["context"]))
context = req.session.eval_context(
openerpweb.nonliterals.CompoundContext(
req.context or {}, action[ "context"]))
args = [req.session._db, req.session._uid, req.session._password, action["report_name"], context["active_ids"], {"id": context["active_id"], "model": context["active_model"], "report_type": action["report_type"]}, context]
report_id = report_srv.report(*args)
report = None
report_data = {"id": context["active_id"], "model": context["active_model"]}
if 'report_type' in action:
report_data['report_type'] = action['report_type']
report_id = report_srv.report(
req.session._db, req.session._uid, req.session._password,
action["report_name"], context["active_ids"],
report_data, context)
report_struct = None
while True:
args2 = [req.session._db, req.session._uid, req.session._password, report_id]
report = report_srv.report_get(*args2)
if report["state"]:
report_struct = report_srv.report_get(
req.session._db, req.session._uid, req.session._password, report_id)
if report_struct["state"]:
break
time.sleep(_REPORT_POLLER_DELAY)
time.sleep(self.POLLING_DELAY)
report = base64.b64decode(report_struct['result'])
if report_struct.get('code') == 'zlib':
report = zlib.decompress(report)
report_mimetype = self.TYPES_MAPPING.get(
report_struct['format'], 'octet-stream')
return req.make_response(report,
headers=[
('Content-Disposition', 'attachment; filename="%s.%s"' % (action['report_name'], report_struct['format'])),
('Content-Type', report_mimetype),
('Content-Length', len(report))],
cookies={'fileToken': int(token)})
#TODO: ok now we've got the report, and so what?
return False
class Import(View):
_cp_path = "/web/import"
@@ -1534,4 +1567,4 @@ class Import(View):
d+= ('%s: %s' % (str(key),str(val)))
msg = 'Error trying to import this record:%s. ErrorMessage:%s %s' % (d,res[2],res[3])
error = {'message':str(msg), 'title':'ImportationError'}
return simplejson.dumps({'error':error})
return simplejson.dumps({'error':error})
+4 -2
View File
@@ -201,7 +201,7 @@ QWeb2.Engine = (function() {
this.templates = {};
this.compiled_templates = {};
this.extend_templates = {};
this.dict = {};
this.default_dict = {};
this.tools = QWeb2.tools;
this.jQuery = window.jQuery;
this.reserved_words = QWeb2.RESERVED_WORDS.slice(0);
@@ -323,10 +323,12 @@ QWeb2.Engine = (function() {
" return r.join('');";
},
render : function(template, dict) {
var ndict = QWeb2.tools.extend({}, this.default_dict);
QWeb2.tools.extend(ndict, dict);
if (this.debug && window['console'] !== undefined) {
console.time("QWeb render template " + template);
}
var r = this._render(template, dict);
var r = this._render(template, ndict);
if (this.debug && window['console'] !== undefined) {
console.timeEnd("QWeb render template " + template);
}
+2 -1
View File
@@ -838,7 +838,8 @@ label.error {
.openerp label.oe_label_help {
cursor: help;
}
.openerp .oe_form_field label.oe_label, .openerp .oe_form_field label.oe_label_help {
.openerp label.oe_label,
.openerp label.oe_label_help {
text-align: right;
margin: 3px 0 0 10px;
}
+1
View File
@@ -3,6 +3,7 @@
*---------------------------------------------------------*/
openerp.web.chrome = function(openerp) {
var QWeb = openerp.web.qweb;
openerp.web.Notification = openerp.web.Widget.extend({
init: function(parent, element_id) {
+4 -3
View File
@@ -3,6 +3,7 @@
*--------------------------------------------------------*/
openerp.web.core = function(openerp) {
openerp.web.qweb = new QWeb2.Engine();
/**
* John Resig Class with factory improvement
*/
@@ -374,7 +375,7 @@ openerp.web.Session = openerp.web.CallbackEnabled.extend( /** @lends openerp.web
jsonrpc: "2.0",
method: "call",
params: params,
id:null
id: _.uniqueId('browser-client-')
}).then(function () {deferred.resolve.apply(deferred, arguments);},
function(error) {deferred.reject(error, $.Event());});
return deferred.fail(function() {
@@ -868,7 +869,7 @@ openerp.web.Widget = openerp.web.SessionAware.extend({
* @param {Object} additional Additional context arguments to pass to the template.
*/
render: function (additional) {
return QWeb.render(this.template, _.extend({widget: this}, additional || {}));
return openerp.web.qweb.render(this.template, _.extend({widget: this}, additional || {}));
},
/**
* Method called after rendering. Mostly used to bind actions, perform asynchronous
@@ -946,7 +947,7 @@ openerp.web.Widget = openerp.web.SessionAware.extend({
*/
openerp.web.OldWidget = openerp.web.Widget.extend({
render: function (additional) {
return QWeb.render(this.template, _.extend(_.extend({}, this), additional || {}));
return openerp.web.qweb.render(this.template, _.extend(_.extend({}, this), additional || {}));
}
});
+1
View File
@@ -1,4 +1,5 @@
openerp.web.data_export = function(openerp) {
var QWeb = openerp.web.qweb;
openerp.web.DataExport = openerp.web.Dialog.extend({
template: 'ExportTreeView',
dialog_title: 'Export Data',
+54 -15
View File
@@ -1,6 +1,7 @@
openerp.web.form = function (openerp) {
var _t = openerp.web._t;
var QWeb = openerp.web.qweb;
openerp.web.views.add('form', 'openerp.web.FormView');
openerp.web.FormView = openerp.web.View.extend( /** @lends openerp.web.FormView# */{
@@ -46,12 +47,17 @@ openerp.web.FormView = openerp.web.View.extend( /** @lends openerp.web.FormView#
if (this.embedded_view) {
var def = $.Deferred().then(this.on_loaded);
var self = this;
setTimeout(function() {def.resolve({fields_view: self.embedded_view});}, 0);
setTimeout(function() {def.resolve(self.embedded_view);}, 0);
return def.promise();
} else {
var context = new openerp.web.CompoundContext(this.dataset.get_context());
return this.rpc("/web/formview/load", {"model": this.model, "view_id": this.view_id,
toolbar: this.options.sidebar, context: context}, this.on_loaded);
return this.rpc("/web/view/load", {
"model": this.model,
"view_id": this.view_id,
"view_type": "form",
toolbar: this.options.sidebar,
context: context
}, this.on_loaded);
}
},
stop: function() {
@@ -65,7 +71,7 @@ openerp.web.FormView = openerp.web.View.extend( /** @lends openerp.web.FormView#
},
on_loaded: function(data) {
var self = this;
this.fields_view = data.fields_view;
this.fields_view = data;
var frame = new (this.registry.get_object('frame'))(this, this.fields_view.arch);
this.$element.html(QWeb.render(this.template, { 'frame': frame, 'view': this }));
@@ -94,7 +100,7 @@ openerp.web.FormView = openerp.web.View.extend( /** @lends openerp.web.FormView#
this.sidebar.start();
this.sidebar.do_unfold();
this.sidebar.attachments = new openerp.web.form.SidebarAttachments(this.sidebar, this.sidebar.add_section('attachments', "Attachments"), this);
this.sidebar.add_toolbar(data.fields_view.toolbar);
this.sidebar.add_toolbar(this.fields_view.toolbar);
this.set_common_sidebar_sections(this.sidebar);
}
this.has_been_loaded.resolve();
@@ -450,6 +456,34 @@ openerp.web.FormView = openerp.web.View.extend( /** @lends openerp.web.FormView#
return id ? [id] : [];
}
});
openerp.web.FormDialog = openerp.web.Dialog.extend({
init: function(parent, options, view_id, dataset) {
this._super(parent, options);
this.dataset = dataset;
this.view_id = view_id;
return this;
},
start: function() {
this._super();
this.form = new openerp.web.FormView(this, this.element_id, this.dataset, this.view_id, {
sidebar: false,
pager: false
});
this.form.start();
this.form.on_created.add_last(this.on_form_dialog_saved);
this.form.on_saved.add_last(this.on_form_dialog_saved);
return this;
},
load_id: function(id) {
var self = this;
return this.dataset.read_ids([id], _.keys(this.form.fields_view.fields), function(records) {
self.form.on_record_loaded(records[0]);
});
},
on_form_dialog_saved: function() {
this.close();
}
});
/** @namespace */
openerp.web.form = {};
@@ -1217,11 +1251,16 @@ openerp.web.form.FieldTextXml = openerp.web.form.Field.extend({
openerp.web.form.FieldSelection = openerp.web.form.Field.extend({
init: function(view, node) {
var self = this;
this._super(view, node);
this.template = "FieldSelection";
this.field_index = _.map(this.field.selection, function(x, index) {
return {"ikey": "" + index, "ekey": x[0], "label": x[1]};
this.values = this.field.selection;
_.each(this.values, function(v, i) {
if (v[0] === false && v[1] === '') {
self.values.splice(i, 1);
}
});
this.values.unshift([false, '']);
},
start: function() {
// Flag indicating whether we're in an event chain containing a change
@@ -1251,13 +1290,14 @@ openerp.web.form.FieldSelection = openerp.web.form.Field.extend({
value = value === null ? false : value;
value = value instanceof Array ? value[0] : value;
this._super(value);
var option = _.detect(this.field_index, function(x) {return x.ekey === value;});
this.$element.find('select').val(option === undefined ? '' : option.ikey);
var index = 0;
for (var i = 0, ii = this.values.length; i < ii; i++) {
if (this.values[i][0] === value) index = i;
}
this.$element.find('select')[0].selectedIndex = index;
},
set_value_from_ui: function() {
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.value = this.values[this.$element.find('select')[0].selectedIndex][0];
this._super();
},
update_dom: function() {
@@ -1265,9 +1305,8 @@ openerp.web.form.FieldSelection = openerp.web.form.Field.extend({
this.$element.find('select').attr('disabled', this.readonly);
},
validate: function() {
var ikey = this.$element.find('select').val();
var option = _.detect(this.field_index, function(x) {return x.ikey === ikey;});
this.invalid = this.required && (option === undefined || option.ekey === false);
var value = this.values[this.$element.find('select')[0].selectedIndex];
this.invalid = !(value && !(this.required && value[0] === false));
},
focus: function() {
this.$element.find('select').focus();
+2 -2
View File
@@ -74,7 +74,7 @@ openerp.web.list_editable = function (openerp) {
},
on_loaded: function (data, grouped) {
// tree/@editable takes priority on everything else if present.
this.options.editable = data.fields_view.arch.attrs.editable || this.options.editable;
this.options.editable = data.arch.attrs.editable || this.options.editable;
return this._super(data, grouped);
}
});
@@ -183,7 +183,7 @@ openerp.web.list_editable = function (openerp) {
template: 'ListView.row.form',
registry: openerp.web.list.form.widgets
});
$.when(self.edition_form.on_loaded({fields_view: self.get_form_fields_view()})).then(function () {
$.when(self.edition_form.on_loaded(self.get_form_fields_view())).then(function () {
// put in $.when just in case FormView.on_loaded becomes asynchronous
$new_row.find('td')
.addClass('oe-field-cell')
+5 -3
View File
@@ -1,4 +1,5 @@
openerp.web.list = function (openerp) {
var QWeb = openerp.web.qweb;
openerp.web.views.add('list', 'openerp.web.ListView');
openerp.web.ListView = openerp.web.View.extend( /** @lends openerp.web.ListView# */ {
defaults: {
@@ -147,7 +148,7 @@ openerp.web.ListView = openerp.web.View.extend( /** @lends openerp.web.ListView#
*/
on_loaded: function(data, grouped) {
var self = this;
this.fields_view = data.fields_view;
this.fields_view = data;
//this.log(this.fields_view);
this.name = "" + this.fields_view.arch.attrs.string;
@@ -218,7 +219,7 @@ openerp.web.ListView = openerp.web.View.extend( /** @lends openerp.web.ListView#
if (!this.sidebar && this.options.sidebar && this.options.sidebar_id) {
this.sidebar = new openerp.web.Sidebar(this, this.options.sidebar_id);
this.sidebar.start();
this.sidebar.add_toolbar(data.fields_view.toolbar);
this.sidebar.add_toolbar(this.fields_view.toolbar);
this.set_common_sidebar_sections(this.sidebar);
}
},
@@ -368,11 +369,12 @@ openerp.web.ListView = openerp.web.View.extend( /** @lends openerp.web.ListView#
self.on_loaded(field_view_get, grouped);
};
if (this.embedded_view) {
return $.Deferred().then(callback).resolve({fields_view: this.embedded_view});
return $.Deferred().then(callback).resolve(this.embedded_view);
} else {
return this.rpc('/web/listview/load', {
model: this.model,
view_id: this.view_id,
view_type: "tree",
context: this.dataset.get_context(context),
toolbar: this.options.sidebar
}, callback);
+1
View File
@@ -1,4 +1,5 @@
openerp.web.search = function(openerp) {
var QWeb = openerp.web.qweb;
openerp.web.SearchView = openerp.web.Widget.extend({
init: function(parent, element_id, dataset, view_id, defaults) {
+2
View File
@@ -3,6 +3,7 @@
*---------------------------------------------------------*/
openerp.web.view_tree = function(openerp) {
var QWeb = openerp.web.qweb;
openerp.web.views.add('tree', 'openerp.web.TreeView');
/**
@@ -31,6 +32,7 @@ openerp.web.TreeView = openerp.web.View.extend({
return this.rpc("/web/treeview/load", {
model: this.model,
view_id: this.view_id,
view_type: "tree",
toolbar: this.view_manager ? !!this.view_manager.sidebar : false
}, this.on_loaded);
},
+11 -7
View File
@@ -5,6 +5,7 @@
openerp.web.views = function(openerp) {
var _t = openerp.web._t;
var QWeb = openerp.web.qweb;
/**
* Registry for all the client actions key: tag value: widget
@@ -125,11 +126,11 @@ openerp.web.ActionManager = openerp.web.Widget.extend({
(this.client_widget = new ClientWidget(this, action.params)).appendTo(this);
},
ir_actions_report_xml: function(action) {
this.rpc('/web/report/get_report', {
action: action,
context: {}
}).then(function(result) {
debugger;
$.blockUI();
this.session.get_file({
url: '/web/report',
data: {action: JSON.stringify(action)},
complete: $.unblockUI
});
}
});
@@ -443,7 +444,10 @@ openerp.web.Sidebar = openerp.web.Widget.extend({
if (item.action) {
var ids = self.widget_parent.get_selected_ids();
if (ids.length == 0) {
//TODO niv: maybe show a warning?
$("<div />").text(_t("You must choose at least one record.")).dialog({
title: _t("Warning"),
modal: true
});
return false;
}
var additional_context = {
@@ -453,7 +457,7 @@ openerp.web.Sidebar = openerp.web.Widget.extend({
};
self.rpc("/web/action/load", {
action_id: item.action.id,
context: _.extend({"bin_size": true}, additional_context)
context: additional_context
}, function(result) {
result.result.context = _.extend(result.result.context || {},
additional_context);
+4 -5
View File
@@ -799,10 +799,8 @@
t-att-id="widget.element_id + '_field'"
t-att-class="'field_' + widget.type"
style="width: 100%">
<t t-foreach="widget.field_index" t-as="options">
<option t-att-value="options.ikey">
<t t-esc="options.label"/>
</option>
<t t-foreach="widget.values" t-as="option">
<option><t t-esc="option[1]"/></option>
</t>
</select>
</t>
@@ -1113,7 +1111,8 @@
<div t-att-id="element_id">
<select class="searchview_extended_prop_field">
<t t-foreach="attrs.fields" t-as="field">
<option t-att="{'selected': field === attrs.selected ? 'selected' : null}"
<option t-if="typeof field.store === 'undefined' || field.store || field.fnct_search"
t-att="{'selected': field === attrs.selected ? 'selected' : null}"
t-att-value="field.name">
<t t-esc="field.string"/>
</option>
-1
View File
@@ -1,2 +1 @@
#!/usr/bin/python
import controllers
@@ -1 +0,0 @@
import main
-11
View File
@@ -1,11 +0,0 @@
import web.common as openerpweb
from web.controllers.main import View
class CalendarView(View):
_cp_path = "/web_calendar/calendarview"
@openerpweb.jsonrequest
def load(self, req, model, view_id, toolbar=False):
fields_view = self.fields_view_get(req, model, view_id, 'calendar', toolbar=toolbar)
return {'fields_view': fields_view}
@@ -3,6 +3,7 @@
*---------------------------------------------------------*/
openerp.web_calendar = function(openerp) {
var QWeb = openerp.web.qweb;
QWeb.add_template('/web_calendar/static/src/xml/web_calendar.xml');
openerp.web.views.add('calendar', 'openerp.web_calendar.CalendarView');
openerp.web_calendar.CalendarView = openerp.web.View.extend({
@@ -29,18 +30,18 @@ openerp.web_calendar.CalendarView = openerp.web.View.extend({
this.color_map = {};
},
start: function() {
this.rpc("/web_calendar/calendarview/load", {"model": this.model, "view_id": this.view_id, 'toolbar': true}, this.on_loaded);
this.rpc("/web/view/load", {"model": this.model, "view_id": this.view_id, "view_type":"calendar", 'toolbar': true}, this.on_loaded);
},
stop: function() {
scheduler.clearAll();
},
on_loaded: function(data) {
this.fields_view = data;
this.calendar_fields = {};
this.ids = this.dataset.ids;
this.color_values = [];
this.info_fields = [];
this.fields_view = data.fields_view;
this.name = this.fields_view.name || this.fields_view.arch.attrs.string;
this.view_id = this.fields_view.view_id;
@@ -79,7 +80,7 @@ openerp.web_calendar.CalendarView = openerp.web.View.extend({
this.sidebar.start();
this.sidebar.navigator = new openerp.web_calendar.SidebarNavigator(this.sidebar, this.sidebar.add_section('navigator', "Navigator"), this);
this.sidebar.responsible = new openerp.web_calendar.SidebarResponsible(this.sidebar, this.sidebar.add_section('responsible', "Responsible"), this);
this.sidebar.add_toolbar(data.fields_view.toolbar);
this.sidebar.add_toolbar(this.fields_view.toolbar);
this.set_common_sidebar_sections(this.sidebar);
this.sidebar.do_unfold();
this.sidebar.do_fold.add_last(this.refresh_scheduler);
+4 -1
View File
@@ -3,6 +3,9 @@ import time
import simplejson
import web.common as openerpweb
import logging
_logger = logging.getLogger(__name__)
#----------------------------------------------------------
# OpenERP Web ajaxim Controllers
@@ -195,7 +198,7 @@ class PollServer(openerpweb.Controller):
"""
mq = req.applicationsession.setdefault("web_chat", PollServerMessageQueue())
print "======== chat status ========",kw
_logger.debug("======== chat status ======== %s", kw)
# mq.write()
return {"action": ""}
@@ -1,5 +1,5 @@
openerp.web_dashboard = function(openerp) {
var QWeb = openerp.web.qweb;
QWeb.add_template('/web_dashboard/static/src/xml/web_dashboard.xml');
openerp.web.form.DashBoard = openerp.web.form.Widget.extend({
@@ -1,4 +1,5 @@
openerp.web_default_home = function (openerp) {
var QWeb = openerp.web.qweb;
QWeb.add_template('/web_default_home/static/src/xml/web_default_home.xml');
openerp.web_default_home = {
@@ -3,6 +3,7 @@
*---------------------------------------------------------*/
openerp.web_diagram = function (openerp) {
var QWeb = openerp.web.qweb;
QWeb.add_template('/web_diagram/static/src/xml/base_diagram.xml');
openerp.web.views.add('diagram', 'openerp.web.DiagramView');
openerp.web.DiagramView = openerp.web.View.extend({
-1
View File
@@ -1,2 +1 @@
#!/usr/bin/python
import controllers
-1
View File
@@ -1 +0,0 @@
import main
-11
View File
@@ -1,11 +0,0 @@
import web.common as openerpweb
from web.controllers.main import View
class GanttView(View):
_cp_path = "/web_gantt/ganttview"
@openerpweb.jsonrequest
def load(self, req, model, view_id):
fields_view = self.fields_view_get(req, model, view_id, 'gantt')
return {'fields_view':fields_view}
+3 -3
View File
@@ -2,6 +2,7 @@
* OpenERP web_gantt
*---------------------------------------------------------*/
openerp.web_gantt = function (openerp) {
var QWeb = openerp.web.qweb;
QWeb.add_template('/web_gantt/static/src/xml/web_gantt.xml');
openerp.web.views.add('gantt', 'openerp.web_gantt.GanttView');
openerp.web_gantt.GanttView = openerp.web.View.extend({
@@ -31,14 +32,13 @@ init: function(parent, element_id, dataset, view_id) {
},
start: function() {
this.rpc("/web_gantt/ganttview/load",
{"model": this.model, "view_id": this.view_id}, this.on_loaded);
this.rpc("/web/view/load", {"model": this.model, "view_id": this.view_id, "view_type": "gantt"}, this.on_loaded);
},
on_loaded: function(data) {
var self = this;
this.fields_view = data.fields_view;
this.fields_view = data;
this.name = this.fields_view.arch.attrs.string;
this.view_id = this.fields_view.view_id;
+1
View File
@@ -12,6 +12,7 @@ var COLOR_PALETTE = [
'#ad7fa8', '#729fcf', '#8ae234', '#e9b96e', '#fce94f', '#f57900',
'#cc0000', '#d400a8'];
var QWeb = openerp.web.qweb;
QWeb.add_template('/web_graph/static/src/xml/web_graph.xml');
openerp.web.views.add('graph', 'openerp.web_graph.GraphView');
openerp.web_graph.GraphView = openerp.web.View.extend({
-1
View File
@@ -1 +0,0 @@
import controllers
@@ -1 +0,0 @@
import main
-11
View File
@@ -1,11 +0,0 @@
import web.common as openerpweb
from web.controllers.main import View
class KanbanView(View):
_cp_path = "/web_kanban/kanbanview"
@openerpweb.jsonrequest
def load(self, req, model, view_id):
fields_view = self.fields_view_get(req, model, view_id, 'kanban')
return {'fields_view': fields_view}
+47 -35
View File
@@ -1,5 +1,6 @@
openerp.web_kanban = function (openerp) {
var QWeb = openerp.web.qweb;
QWeb.add_template('/web_kanban/static/src/xml/web_kanban.xml');
openerp.web.views.add('kanban', 'openerp.web_kanban.KanbanView');
openerp.web_kanban.KanbanView = openerp.web.View.extend({
@@ -17,14 +18,16 @@ openerp.web_kanban.KanbanView = openerp.web.View.extend({
this.all_display_data = false;
this.groups = [];
this.qweb = new QWeb2.Engine();
if (this.options.action_views_ids.form) {
this.form_dialog = new openerp.web.FormDialog(this, {}, this.options.action_views_ids.form, dataset).start();
}
},
start: function() {
return this.rpc("/web_kanban/kanbanview/load",
{"model": this.model, "view_id": this.view_id}, this.on_loaded);
return this.rpc("/web/view/load", {"model": this.model, "view_id": this.view_id, "view_type": "kanban"}, this.on_loaded);
},
on_loaded: function(data) {
var self = this;
this.fields_view = data.fields_view;
this.fields_view = data;
this.add_qweb_template();
if (this.qweb.has_template('kanban-box')) {
self.dataset.read_slice(_.keys(self.fields_view.fields), {
@@ -42,13 +45,27 @@ openerp.web_kanban.KanbanView = openerp.web.View.extend({
var child = this.fields_view.arch.children[i];
if (child.tag === "templates") {
this.transform_qweb_template(child);
this.qweb.add_template(openerp.web.json_node_to_xml(child, true));
this.qweb.add_template(openerp.web.json_node_to_xml(child));
break;
}
}
},
do_get_kanban_color: function(variable) {
return 'oe_kanban_color_1';
var number_of_color_schemes = 2,
index = 0;
switch (typeof(variable)) {
case 'string':
for (var i=0, ii=variable.length; i<ii; i++) {
index += variable.charCodeAt(i);
}
break;
case 'number':
index = Math.round(variable);
break;
default:
return '';
}
return 'oe_kanban_color_' + ((index % number_of_color_schemes) + 1);
},
transform_qweb_template: function(node) {
switch (node.tag) {
@@ -143,25 +160,20 @@ openerp.web_kanban.KanbanView = openerp.web.View.extend({
}
},
on_confirm_click: function (dataset, button_attrs, index, record_id) {
if (button_attrs.type == 'edit') {
this.do_edit_record(dataset, index);
this.on_execute_button_click(dataset, button_attrs, record_id);
},
do_add_record: function() {
this.dataset.index = null;
this.do_switch_view('form');
},
do_edit_record: function(record_id) {
if (this.form_dialog) {
this.form_dialog.load_id(record_id);
this.form_dialog.open();
} else {
this.on_execute_button_click(dataset, button_attrs, record_id);
this.notification.warn("Kanban", "No form view defined for this object");
}
},
do_add_record: function () {
this.do_edit_record(this.dataset, null);
},
do_edit_record: function (dataset, index) {
var self = this;
_.extend(this.dataset, {
domain: dataset.domain,
context: dataset.get_context()
}).read_slice([], {}, function () {
self.dataset.index = index;
self.do_switch_view('form');
});
},
do_delete: function (id) {
var self = this;
return $.when(this.dataset.unlink([id])).then(function () {
@@ -297,24 +309,24 @@ openerp.web_kanban.KanbanView = openerp.web.View.extend({
self.all_display_data.splice(index, 1);
}
});
this.$element.find('.oe_kanban_action').click(function() {
var record_id = $(this).closest(".oe_kanban_record").attr("id");
if (record_id) {
record_id = parseInt(record_id.split("_")[1])
if (record_id) {
if ($(this).data("type") == "delete") {
self.do_delete(record_id);
} else {
var button_attrs = $(this).data()
self.on_button_click(button_attrs, record_id);
}
}
}
});
this.$element.find('.oe_kanban_action').click(this.on_action_clicked);
this.$element.find('.oe_kanban_record').click(function() {
$(this).find('.oe_kanban_box_show_onclick').removeClass('oe_kanban_box_show_onclick');
});
},
on_action_clicked: function(evt) {
var $action = $(evt.currentTarget),
record_id = parseInt($action.closest(".oe_kanban_record").attr("id").split('_')[1]),
type = $action.data('type');
if (type == 'delete') {
this.do_delete(record_id);
} else if (type == 'edit') {
this.do_edit_record(record_id);
} else {
var button_attrs = $(this).data();
this.on_button_click(button_attrs, record_id);
}
},
do_transform_record: function(record) {
var self = this,
new_record = {};
+2 -2
View File
@@ -338,10 +338,10 @@ replace ``addons`` by the directory in which your own addon lives.
Python
++++++
.. autoclass:: base.common.backendrpc.OpenERPSession
.. autoclass:: web.common.backendrpc.OpenERPSession
:members:
.. autoclass:: base.common.backendrpc.OpenERPModel
.. autoclass:: web.common.backendrpc.OpenERPModel
:members:
* Addons lifecycle (loading, execution, events, ...)
+4 -4
View File
@@ -391,14 +391,14 @@ Python
These classes should be moved to other sections of the doc as needed,
probably.
.. automodule:: base.common.dispatch
.. automodule:: web.common.dispatch
:members:
:undoc-members:
See also: :class:`~base.common.backendrpc.OpenERPSession`,
:class:`~base.common.backendrpc.OpenERPModel`
See also: :class:`~web.common.backendrpc.OpenERPSession`,
:class:`~web.common.backendrpc.OpenERPModel`
.. automodule:: base.controllers.main
.. automodule:: web.controllers.main
:members:
:undoc-members:
+12
View File
@@ -3,6 +3,8 @@ import optparse
import os
import sys
import tempfile
import logging
import logging.config
import werkzeug.serving
@@ -31,6 +33,10 @@ optparser.add_option('--no-serve-static', dest='serve_static',
optparser.add_option('--reloader', dest='reloader',
default=False, action='store_true',
help="Reload application when python files change")
optparser.add_option("--log-level", dest="log_level",
default='debug', help="Log level", metavar="LOG_LEVEL")
optparser.add_option("--log-config", dest="log_config",
default='', help="Log config file", metavar="LOG_CONFIG")
import web.common.dispatch
@@ -38,6 +44,12 @@ if __name__ == "__main__":
(options, args) = optparser.parse_args(sys.argv[1:])
os.environ["TZ"] = "UTC"
if not options.log_config:
logging.basicConfig(level=getattr(logging, options.log_level.upper()))
else:
logging.config.fileConfig(options.log_config)
app = web.common.dispatch.Root(options)
werkzeug.serving.run_simple(