[MERGE] Merge with trunk upto revision no 733.

bzr revid: ysa@tinyerp.com-20110805101414-12wfpgz69la5qetr
This commit is contained in:
Yogesh (OpenERP)
2011-08-05 15:44:14 +05:30
39 changed files with 2499 additions and 1250 deletions
+1 -1
View File
@@ -5,7 +5,7 @@
'active': True,
'js' : [
"static/lib/datejs/date-en-US.js",
"static/lib/jquery/jquery-1.5.2.js",
"static/lib/jquery/jquery-1.6.2.js",
"static/lib/jquery.form/jquery.form.js",
"static/lib/jquery.validate/jquery.validate.js",
"static/lib/jquery.ba-bbq/jquery.ba-bbq.js",
+54 -40
View File
@@ -1,19 +1,23 @@
# -*- coding: utf-8 -*-
import base64, glob, os, re
import base64
import csv
import glob
import operator
import os
import re
import simplejson
import textwrap
import xmlrpclib
from xml.etree import ElementTree
from cStringIO import StringIO
import operator
import simplejson
import cherrypy
import openerpweb
import openerpweb.ast
import openerpweb.nonliterals
import cherrypy
import xmlrpclib
import csv
# Should move to openerpweb.Xml2Json
class Xml2Json:
@@ -86,6 +90,27 @@ def concat_files(file_list):
files_concat = "".join(files_content)
return files_concat
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]-->
</head>
<body id="oe" class="openerp"></body>
</html>
""")
class WebClient(openerpweb.Controller):
_cp_path = "/base/webclient"
@@ -114,41 +139,22 @@ class WebClient(openerpweb.Controller):
return concat
@openerpweb.httprequest
def home(self, req):
template ="""<!DOCTYPE html>
<html style="height: 100%%">
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>OpenERP</title>
%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"/>
%s
<!--[if lte IE 7]>
<link rel="stylesheet" href="/base/static/src/css/base-ie7.css" type="text/css"/>
<![endif]-->
</head>
<body id="oe" class="openerp"></body>
</html>
""".replace('\n'+' '*8,'\n')
def home(self, req, s_action=None):
# script tags
jslist = ['/base/webclient/js']
if 1: # debug == 1
jslist = manifest_glob(['base'], 'js')
js = "\n ".join(['<script type="text/javascript" src="%s"></script>'%i for i in jslist])
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
csslist = manifest_glob(['base'], 'css')
css = "\n ".join(['<link rel="stylesheet" href="%s">'%i for i in csslist])
r = template % (js, css)
css = "\n ".join(['<link rel="stylesheet" href="%s">'%i for i in csslist])
r = home_template % {
'javascript': js,
'css': css
}
return r
class Database(openerpweb.Controller):
@@ -172,9 +178,13 @@ class Database(openerpweb.Controller):
def create(self, req, fields):
params = dict(map(operator.itemgetter('name', 'value'), fields))
create_attrs = operator.itemgetter(
'super_admin_pwd', 'db_name', 'demo_data', 'db_lang', 'create_admin_pwd')(
params)
create_attrs = (
params['super_admin_pwd'],
params['db_name'],
bool(params.get('demo_data')),
params['db_lang'],
params['create_admin_pwd']
)
try:
return req.session.proxy("db").create(*create_attrs)
@@ -364,6 +374,11 @@ class Session(openerpweb.Controller):
return None
return saved_actions["actions"].get(key)
@openerpweb.jsonrequest
def check(self, req):
req.session.assert_valid()
return None
def eval_context_and_domain(session, context, domain=None):
e_context = session.eval_context(context)
# should we give the evaluated context as an evaluation context to the domain?
@@ -379,22 +394,21 @@ def load_actions_from_ir_values(req, key, key2, models, meta, context):
for id, name, action in actions]
def clean_action(action, session):
action.setdefault('flags', {})
if action['type'] != 'ir.actions.act_window':
return action
# values come from the server, we can just eval them
if isinstance(action.get('context', None), basestring):
if isinstance(action.get('context'), basestring):
action['context'] = eval(
action['context'],
session.evaluation_context()) or {}
if isinstance(action.get('domain', None), basestring):
if isinstance(action.get('domain'), basestring):
action['domain'] = eval(
action['domain'],
session.evaluation_context(
action.get('context', {}))) or []
if 'flags' not in action:
# Set empty flags dictionary for web client.
action['flags'] = dict()
return fix_view_modes(action)
def generate_views(action):
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -19,7 +19,7 @@ var QWeb2 = {
if (context.template) {
prefix += " - template['" + context.template + "']";
}
throw prefix + ": " + message;
throw new Error(prefix + ": " + message);
},
trim: function(s, mode) {
switch (mode) {
+67 -23
View File
@@ -1,4 +1,4 @@
// Underscore.js 1.1.5
// Underscore.js 1.1.7
// (c) 2011 Jeremy Ashkenas, DocumentCloud Inc.
// Underscore is freely distributable under the MIT license.
// Portions of Underscore are inspired or borrowed from Prototype,
@@ -55,25 +55,26 @@
module.exports = _;
_._ = _;
} else {
root._ = _;
// Exported as a string, for Closure Compiler "advanced" mode.
root['_'] = _;
}
// Current version.
_.VERSION = '1.1.5';
_.VERSION = '1.1.7';
// Collection Functions
// --------------------
// The cornerstone, an `each` implementation, aka `forEach`.
// Handles objects implementing `forEach`, arrays, and raw objects.
// Handles objects with the built-in `forEach`, arrays, and raw objects.
// Delegates to **ECMAScript 5**'s native `forEach` if available.
var each = _.each = _.forEach = function(obj, iterator, context) {
if (obj == null) return;
if (nativeForEach && obj.forEach === nativeForEach) {
obj.forEach(iterator, context);
} else if (_.isNumber(obj.length)) {
} else if (obj.length === +obj.length) {
for (var i = 0, l = obj.length; i < l; i++) {
if (iterator.call(context, obj[i], i, obj) === breaker) return;
if (i in obj && iterator.call(context, obj[i], i, obj) === breaker) return;
}
} else {
for (var key in obj) {
@@ -106,7 +107,7 @@
return initial ? obj.reduce(iterator, memo) : obj.reduce(iterator);
}
each(obj, function(value, index, list) {
if (!initial && index === 0) {
if (!initial) {
memo = value;
initial = true;
} else {
@@ -168,7 +169,6 @@
// Delegates to **ECMAScript 5**'s native `every` if available.
// Aliased as `all`.
_.every = _.all = function(obj, iterator, context) {
iterator = iterator || _.identity;
var result = true;
if (obj == null) return result;
if (nativeEvery && obj.every === nativeEvery) return obj.every(iterator, context);
@@ -187,9 +187,9 @@
if (obj == null) return result;
if (nativeSome && obj.some === nativeSome) return obj.some(iterator, context);
each(obj, function(value, index, list) {
if (result = iterator.call(context, value, index, list)) return breaker;
if (result |= iterator.call(context, value, index, list)) return breaker;
});
return result;
return !!result;
};
// Determine if a given value is included in the array or object using `===`.
@@ -208,7 +208,7 @@
_.invoke = function(obj, method) {
var args = slice.call(arguments, 2);
return _.map(obj, function(value) {
return (method ? value[method] : value).apply(value, args);
return (method.call ? method || value : value[method]).apply(value, args);
});
};
@@ -252,10 +252,20 @@
}), 'value');
};
// Groups the object's values by a criterion produced by an iterator
_.groupBy = function(obj, iterator) {
var result = {};
each(obj, function(value, index) {
var key = iterator(value, index);
(result[key] || (result[key] = [])).push(value);
});
return result;
};
// Use a comparator function to figure out at what index an object should
// be inserted so as to maintain order. Uses binary search.
_.sortedIndex = function(array, obj, iterator) {
iterator = iterator || _.identity;
iterator || (iterator = _.identity);
var low = 0, high = array.length;
while (low < high) {
var mid = (low + high) >> 1;
@@ -268,7 +278,7 @@
_.toArray = function(iterable) {
if (!iterable) return [];
if (iterable.toArray) return iterable.toArray();
if (_.isArray(iterable)) return iterable;
if (_.isArray(iterable)) return slice.call(iterable);
if (_.isArguments(iterable)) return slice.call(iterable);
return _.values(iterable);
};
@@ -317,8 +327,7 @@
// Return a version of the array that does not contain the specified value(s).
_.without = function(array) {
var values = slice.call(arguments, 1);
return _.filter(array, function(value){ return !_.include(values, value); });
return _.difference(array, slice.call(arguments, 1));
};
// Produce a duplicate-free version of the array. If the array has already
@@ -331,9 +340,15 @@
}, []);
};
// Produce an array that contains the union: each distinct element from all of
// the passed-in arrays.
_.union = function() {
return _.uniq(_.flatten(arguments));
};
// Produce an array that contains every item shared between all the
// passed-in arrays.
_.intersect = function(array) {
// passed-in arrays. (Aliased as "intersect" for back-compat.)
_.intersection = _.intersect = function(array) {
var rest = slice.call(arguments, 1);
return _.filter(_.uniq(array), function(item) {
return _.every(rest, function(other) {
@@ -342,6 +357,12 @@
});
};
// Take the difference between one array and another.
// Only the elements present in just the first array will remain.
_.difference = function(array, other) {
return _.filter(array, function(value){ return !_.include(other, value); });
};
// Zip together multiple lists into a single array -- elements that share
// an index go together.
_.zip = function() {
@@ -408,8 +429,9 @@
// Create a function bound to a given object (assigning `this`, and arguments,
// optionally). Binding with arguments is also known as `curry`.
// Delegates to **ECMAScript 5**'s native `Function.bind` if available.
// We check for `func.bind` first, to fail fast when `func` is undefined.
_.bind = function(func, obj) {
if (nativeBind && func.bind === nativeBind) return func.bind.apply(func, slice.call(arguments, 1));
if (func.bind === nativeBind && nativeBind) return nativeBind.apply(func, slice.call(arguments, 1));
var args = slice.call(arguments, 2);
return function() {
return func.apply(obj, args.concat(slice.call(arguments)));
@@ -428,7 +450,7 @@
// Memoize an expensive function by storing its results.
_.memoize = function(func, hasher) {
var memo = {};
hasher = hasher || _.identity;
hasher || (hasher = _.identity);
return function() {
var key = hasher.apply(this, arguments);
return hasOwnProperty.call(memo, key) ? memo[key] : (memo[key] = func.apply(this, arguments));
@@ -502,13 +524,21 @@
var funcs = slice.call(arguments);
return function() {
var args = slice.call(arguments);
for (var i=funcs.length-1; i >= 0; i--) {
for (var i = funcs.length - 1; i >= 0; i--) {
args = [funcs[i].apply(this, args)];
}
return args[0];
};
};
// Returns a function that will only be executed after being called N times.
_.after = function(times, func) {
return function() {
if (--times < 1) { return func.apply(this, arguments); }
};
};
// Object Functions
// ----------------
@@ -529,13 +559,19 @@
// Return a sorted list of the function names available on the object.
// Aliased as `methods`
_.functions = _.methods = function(obj) {
return _.filter(_.keys(obj), function(key){ return _.isFunction(obj[key]); }).sort();
var names = [];
for (var key in obj) {
if (_.isFunction(obj[key])) names.push(key);
}
return names.sort();
};
// Extend a given object with all the properties in passed-in object(s).
_.extend = function(obj) {
each(slice.call(arguments, 1), function(source) {
for (var prop in source) obj[prop] = source[prop];
for (var prop in source) {
if (source[prop] !== void 0) obj[prop] = source[prop];
}
});
return obj;
};
@@ -543,7 +579,9 @@
// Fill in a given object with default properties.
_.defaults = function(obj) {
each(slice.call(arguments, 1), function(source) {
for (var prop in source) if (obj[prop] == null) obj[prop] = source[prop];
for (var prop in source) {
if (obj[prop] == null) obj[prop] = source[prop];
}
});
return obj;
};
@@ -577,6 +615,7 @@
if (b._chain) b = b._wrapped;
// One of them implements an isEqual()?
if (a.isEqual) return a.isEqual(b);
if (b.isEqual) return b.isEqual(a);
// Check dates' integer values.
if (_.isDate(a) && _.isDate(b)) return a.getTime() === b.getTime();
// Both are NaN?
@@ -618,6 +657,11 @@
return toString.call(obj) === '[object Array]';
};
// Is a given variable an object?
_.isObject = function(obj) {
return obj === Object(obj);
};
// Is a given variable an arguments object?
_.isArguments = function(obj) {
return !!(obj && hasOwnProperty.call(obj, 'callee'));
+8 -7
View File
@@ -194,25 +194,25 @@ ul.db_options li {
}
table.db_option_table input.required {
background-color: #D2D2FF;
background-color: #D2D2FF !important;
}
.db_option_table input[type="text"], .db_option_table input[type="password"], .db_option_table select {
width: 300px;
width: 300px;
}
.option_string {
font-weight: bold;
color: #555;
width: 100%;
font-weight: bold;
color: #555;
width: 100%;
text-align: center;
padding: 10px 0;
font-size: large;
}
label.error {
float: none;
color: red;
float: none;
color: red;
padding-left: .5em;
vertical-align: top;
}
@@ -506,6 +506,7 @@ label.error {
}
/* Main Application */
.openerp .oe-main-content,
.openerp .oe-application {
padding: 0;
height: 100%;
+64 -6
View File
@@ -161,6 +161,8 @@ openerp.base.Session = openerp.base.Widget.extend( /** @lends openerp.base.Sessi
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();
@@ -171,12 +173,18 @@ openerp.base.Session = openerp.base.Widget.extend( /** @lends openerp.base.Sessi
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() {
this.uid = this.get_cookie('uid');
this.session_id = this.get_cookie('session_id');
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() {});
},
/**
@@ -858,7 +866,7 @@ openerp.base.Menu = openerp.base.Widget.extend({
init: function(parent, element_id, secondary_menu_id) {
this._super(parent, element_id);
this.secondary_menu_id = secondary_menu_id;
this.$secondary_menu = $("#" + secondary_menu_id);
this.$secondary_menu = $("#" + secondary_menu_id).hide();
this.menu = false;
},
start: function() {
@@ -917,7 +925,7 @@ openerp.base.Menu = openerp.base.Widget.extend({
this.on_menu_action_loaded);
}
$('.active', this.$element.add(this.$secondary_menu)).removeClass('active');
$('.active', this.$element.add(this.$secondary_menu.show())).removeClass('active');
$parent.addClass('active');
$menu.addClass('active');
$menu.parent('h4').addClass('active');
@@ -988,14 +996,64 @@ openerp.base.WebClient = openerp.base.Widget.extend({
// if using saved actions, load the action and give it to action manager
var parameters = jQuery.deparam(jQuery.param.querystring());
if(parameters["s_action"] != undefined) {
var key = parseInt(parameters["s_action"]);
if (parameters["s_action"] != undefined) {
var key = parseInt(parameters["s_action"], 10);
var self = this;
this.rpc("/base/session/get_session_action", {key:key}, function(action) {
self.action_manager.do_action(action);
});
} else if (openerp._modules_loaded) { // TODO: find better option than this
this.load_url_state()
} else {
this.session.on_modules_loaded.add({
callback: $.proxy(this, 'load_url_state'),
unique: true,
position: 'last'
})
}
},
/**
* Loads state from URL if any, or checks if there is a home action and
* loads that, assuming we're at the index
*/
load_url_state: function () {
var self = this;
// TODO: add actual loading if there is url state to unpack, test on window.location.hash
// not logged in
if (!this.session.uid) { return; }
var ds = new openerp.base.DataSetSearch(this, 'res.users');
ds.read_ids([this.session.uid], ['action_id'], function (users) {
var home_action = users[0].action_id;
if (!home_action) {
self.default_home();
return;
}
self.execute_home_action(home_action[0], ds);
})
},
default_home: function () { },
/**
* Bundles the execution of the home action
*
* @param {Number} action action id
* @param {openerp.base.DataSet} dataset action executor
*/
execute_home_action: function (action, dataset) {
var self = this;
this.rpc('/base/action/load', {
action_id: action,
context: dataset.get_context()
}, function (meh) {
var action = meh.result;
action.context = _.extend(action.context || {}, {
active_id: false,
active_ids: [false],
active_model: dataset.model
});
self.action_manager.do_action(action);
});
},
on_menu_action: function(action) {
this.action_manager.do_action(action);
},
+10 -2
View File
@@ -318,13 +318,13 @@ openerp.base.DataSet = openerp.base.Widget.extend( /** @lends openerp.base.Data
context: this.get_context()
}, callback, error_callback);
},
write: function (id, data, callback) {
write: function (id, data, callback, error_callback) {
return this.rpc('/base/dataset/save', {
model: this.model,
id: id,
data: data,
context: this.get_context()
}, callback);
}, callback, error_callback);
},
unlink: function(ids, callback, error_callback) {
var self = this;
@@ -409,6 +409,14 @@ openerp.base.DataSetStatic = openerp.base.DataSet.extend({
}
});
openerp.base.DataSetSearch = openerp.base.DataSet.extend({
/**
* @constructs
*
* @param {Object} parent
* @param {String} model
* @param {Object} context
* @param {Array} domain
*/
init: function(parent, model, context, domain) {
this._super(parent, model, context);
this.domain = domain || [];
+9 -1
View File
@@ -546,7 +546,7 @@ openerp.base.form.compute_domain = function(expr, fields) {
this.log("Unsupported operator in modifiers :", op);
}
}
return _.all(stack);
return _.all(stack, _.identity);
};
openerp.base.form.Widget = openerp.base.Widget.extend({
@@ -788,6 +788,14 @@ openerp.base.form.WidgetLabel = openerp.base.form.Widget.extend({
}
// Actual label widgets should not have a false and have type label
return QWeb.render(this.template, {widget: this});
},
start: function() {
this._super();
var self = this;
this.$element.find("label").dblclick(function() {
var widget = self['for'] || self;
console.log(widget.element_id , widget);
});
}
});
@@ -213,6 +213,9 @@ openerp.base.list.editable = function (openerp) {
save_row: function (edit_next) {
var self = this;
this.edition_form.do_save(function (result) {
if (result.created && !self.edition_index) {
self.edition_index = self.dataset.index;
}
self.cancel_pending_edition().then(function () {
$(self).trigger('saved', [self.dataset]);
if (!edit_next) {
+56 -62
View File
@@ -4,6 +4,7 @@
openerp.base.views = function(openerp) {
openerp.base.client_actions = new openerp.base.Registry();
openerp.base.ActionManager = openerp.base.Widget.extend({
// process all kind of actions
init: function(parent, element_id) {
@@ -14,24 +15,7 @@ openerp.base.ActionManager = openerp.base.Widget.extend({
// Will use parent to find it when implementation will be done.
this.session.action_manager = this;
},
/**
* Process an action
* Supported actions: act_window
*/
action_window: function() {
},
action_window_close: function() {
},
action_server: function() {
},
action_url: function() {
},
action_report: function() {
},
action_client: function() {
},
do_action: function(action, on_closed) {
var self = this;
action.flags = _.extend({
sidebar : action.target != 'new',
search_view : action.target != 'new',
@@ -41,54 +25,64 @@ openerp.base.ActionManager = openerp.base.Widget.extend({
pager : action.target != 'new'
}, action.flags || {});
// instantiate the right controllers by understanding the action
switch (action.type) {
case 'ir.actions.act_window':
if (!action.target && this.current_dialog) {
action.flags.new_window = true;
if (!(action.type in this)) {
console.log("Action manager can't handle action of type " + action.type, action);
return;
}
this[action.type](action, on_closed);
},
'ir.actions.act_window': function (action, on_closed) {
if (!action.target && this.current_dialog) {
action.flags.new_window = true;
}
if (action.target == 'new') {
var dialog = this.current_dialog = new openerp.base.ActionDialog(this, {
title: action.name,
width: '50%'
});
if (on_closed) {
dialog.close_callback = on_closed;
}
dialog.start(false);
var viewmanager = dialog.viewmanager = new openerp.base.ViewManagerAction(this, dialog.element_id, action);
viewmanager.start();
dialog.open();
} else if (action.flags.new_window) {
action.flags.new_window = false;
this.rpc("/base/session/save_session_action", { the_action : action}, function(key) {
var url = window.location.protocol + "//" + window.location.host +
window.location.pathname + "?" + jQuery.param({ s_action : "" + key });
window.open(url);
if (on_closed) {
on_closed();
}
if (action.target == 'new') {
var dialog = this.current_dialog = new openerp.base.ActionDialog(this, { title: action.name, width: '90%' });
if (on_closed) {
dialog.close_callback = on_closed;
}
dialog.start(false);
var viewmanager = dialog.viewmanager = new openerp.base.ViewManagerAction(this, dialog.element_id, action);
viewmanager.start();
dialog.open();
} else if (action.flags.new_window) {
action.flags.new_window = false;
this.rpc("/base/session/save_session_action", { the_action : action}, function(key) {
var url = window.location.protocol + "//" + window.location.host +
window.location.pathname + "?" + jQuery.param({ s_action : "" + key });
window.open(url);
if (on_closed) {
on_closed();
}
});
} else {
if (this.viewmanager) {
this.viewmanager.stop();
}
this.viewmanager = new openerp.base.ViewManagerAction(this, this.element_id, action);
this.viewmanager.start();
}
break;
case 'ir.actions.act_window_close':
this.close_dialog();
break;
case 'ir.actions.server':
this.rpc('/base/action/run', {
action_id: action.id,
context: {active_id: 66, active_ids: [66], active_model: 'ir.ui.menu'}
}).then(function (action) {
self.do_action(action, on_closed)
});
break;
default:
console.log("Action manager can't handle action of type " + action.type, action);
});
} else {
if (this.viewmanager) {
this.viewmanager.stop();
}
this.viewmanager = new openerp.base.ViewManagerAction(this, this.element_id, action);
this.viewmanager.start();
}
},
close_dialog: function() {
'ir.actions.act_window_close': function (action, on_closed) {
this.close_dialog();
},
'ir.actions.server': function (action, on_closed) {
var self = this;
this.rpc('/base/action/run', {
action_id: action.id,
context: {active_id: 66, active_ids: [66], active_model: 'ir.ui.menu'}
}).then(function (action) {
self.do_action(action, on_closed)
});
},
'ir.actions.client': function (action) {
var Handler = openerp.base.client_actions.get_object(action.tag);
new Handler(this, this.element_id, action.params).start();
},
close_dialog: function () {
if (this.current_dialog) {
this.current_dialog.stop();
this.current_dialog = null;
+2 -3
View File
@@ -89,7 +89,7 @@
</tr>
<tr>
<td><label for="demo_data">Load Demonstration data:</label></td>
<td><input type="checkbox" name="demo_data" checked='checked'/></td>
<td><input type="checkbox" name="demo_data"/></td>
</tr>
<tr>
<td><label for="db_lang">Default language:</label></td>
@@ -652,8 +652,7 @@
<t t-name="WidgetLabel">
<label t-att-for="widget.element_id + '_field'"
t-att-class="'oe_form_label' + (widget.help ? '_help' : '')"
t-att-title="widget.help"
t-att-ondblclick="'console.log(\'' + widget.element_id + '\', openerp.screen.' + widget.element_id + ')'">
t-att-title="widget.help">
<t t-esc="widget.string"/>
<span t-if="widget.help">?</span>
<t t-if="widget.string and widget.node.tag != 'label'">:</t>
+38 -28
View File
@@ -21,6 +21,9 @@ openerp.base_calendar.CalendarView = openerp.base.View.extend({
start: function() {
this.rpc("/base_calendar/calendarview/load", {"model": this.model, "view_id": this.view_id, 'toolbar': true}, this.on_loaded);
},
stop: function() {
scheduler.clearAll();
},
on_loaded: function(data) {
this.calendar_fields = {};
this.ids = this.dataset.ids;
@@ -64,41 +67,41 @@ openerp.base_calendar.CalendarView = openerp.base.View.extend({
this.sidebar.add_toolbar(data.fields_view.toolbar);
this.set_common_sidebar_sections(this.sidebar);
this.sidebar.do_unfold();
this.sidebar.do_fold.add_last(this.resize_scheduler);
this.sidebar.do_unfold.add_last(this.resize_scheduler);
this.sidebar.do_toggle.add_last(this.resize_scheduler);
this.sidebar.do_fold.add_last(this.refresh_scheduler);
this.sidebar.do_unfold.add_last(this.refresh_scheduler);
this.sidebar.do_toggle.add_last(this.refresh_scheduler);
}
this.init_scheduler();
this.load_scheduler();
this.has_been_loaded.resolve();
if (this.dataset.ids.length) {
this.dataset.read_ids(this.dataset.ids, _.keys(this.fields), this.on_events_loaded);
}
},
init_scheduler: function() {
var self = this;
scheduler.clearAll();
scheduler.config.api_date = "%Y-%m-%d %H:%M:%S";
//scheduler.config.details_on_dblclick = true;
//scheduler.config.details_on_create = true;
scheduler.keys.edit_cancel = 27;
if (this.fields[this.date_start]['type'] == 'time') {
scheduler.config.xml_date = "%H:%M:%S";
} else {
scheduler.config.xml_date = "%Y-%m-%d %H:%M:%S";
scheduler.config.xml_date = "%Y-%m-%d %H:%i";
}
this.mode = this.mode || 'month';
scheduler.config.api_date = "%Y-%m-%d %H:%i";
scheduler.config.multi_day = true; //Multi day events are not rendered in daily and weekly views
scheduler.config.start_on_monday = true;
scheduler.config.scroll_hour = 8;
scheduler.config.drag_resize = scheduler.config.drag_create = !!this.date_stop;
// Initialize Sceduler
this.mode = this.mode || 'month';
scheduler.init('openerp_scheduler', null, this.mode);
scheduler.detachAllEvents();
scheduler.attachEvent('onEventAdded', this.do_create_event);
scheduler.attachEvent('onEventDeleted', this.do_delete_event);
scheduler.attachEvent('onEventChanged', this.do_save_event);
scheduler.renderCalendar({
this.mini_calendar = scheduler.renderCalendar({
container: this.sidebar.navigator.element_id,
navigation: true,
date: scheduler._date,
@@ -107,9 +110,12 @@ openerp.base_calendar.CalendarView = openerp.base.View.extend({
}
});
},
resize_scheduler: function() {
refresh_scheduler: function() {
scheduler.setCurrentView(scheduler._date);
},
refresh_minical: function() {
scheduler.updateCalendar(this.mini_calendar);
},
load_scheduler: function() {
var self = this;
this.dataset.read_slice([], 0, false, function(events) {
@@ -119,14 +125,14 @@ openerp.base_calendar.CalendarView = openerp.base.View.extend({
'/base_calendar/static/lib/dhtmlxScheduler/sources/locale_' + self.session.locale_code + '.js',
'/base_calendar/static/lib/dhtmlxScheduler/sources/locale_recurring_' + self.session.locale_code + '.js'
]).wait(function() {
self.schedule_events(events);
self.on_events_loaded(events);
});
} else {
self.schedule_events(events);
self.on_events_loaded(events);
}
});
},
schedule_events: function(events) {
on_events_loaded: function(events) {
var self = this;
scheduler.clearAll();
@@ -163,9 +169,9 @@ openerp.base_calendar.CalendarView = openerp.base.View.extend({
}
res_events.push(this.convert_event(evt));
}
scheduler.parse(res_events, 'json');
this.resize_scheduler();
this.refresh_scheduler();
this.refresh_minical();
this.sidebar.responsible.on_events_loaded(sidebar_items);
},
convert_event: function(event) {
@@ -254,21 +260,27 @@ openerp.base_calendar.CalendarView = openerp.base.View.extend({
var id = parseInt(r.result, 10);
self.dataset.ids.push(id);
scheduler.changeEventId(event_id, id);
self.refresh_minical();
}, function(r, event) {
// TODO: open form view
self.notification.warn(self.name, "Could not create event");
event.preventDefault();
});
},
do_save_event: function(event_id, event_obj) {
var self = this,
data = this.get_event_data(event_obj);
this.dataset.write(event_id, data);
this.dataset.write(parseInt(event_id, 10), data, function() {
self.refresh_minical();
});
},
do_delete_event: function(event_id, event_obj) {
var self = this;
this.dataset.unlink(event_id, function(r) {
});
// dhtmlx sends this event even when it does not exist in openerp.
// Eg: use cancel in dhtmlx new event dialog
if (_.indexOf(this.dataset.ids, event_id) > -1) {
this.dataset.unlink(parseInt(event_id, 10, function() {
self.refresh_minical();
}));
}
},
get_event_data: function(event_obj) {
var data = {
@@ -302,9 +314,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(_.keys(self.fields), 0, self.limit, function(events) {
self.schedule_events(events);
});
self.dataset.read_slice(_.keys(self.fields), 0, self.limit, self.on_events_loaded);
});
},
do_show: function () {
@@ -1,15 +1,15 @@
<template>
<t t-name="CalendarView">
<h3 class="title"><t t-esc="fields_view.arch.attrs.string"/></h3>
<div id="openerp_scheduler" class="dhx_cal_container" style="height: 1000px;">
<div id="openerp_scheduler" class="dhx_cal_container" style="height: 600px;">
<div class="dhx_cal_navline">
<div class="dhx_cal_prev_button"/>
<div class="dhx_cal_next_button"/>
<div class="dhx_cal_today_button"/>
<div class="dhx_cal_date"/>
<div class="dhx_cal_tab" name="day_tab" style="right:204px;"/>
<div class="dhx_cal_tab" name="week_tab" style="right:140px;"/>
<div class="dhx_cal_tab" name="month_tab" style="right:76px;"/>
<div class="dhx_cal_prev_button">&amp;nbsp;</div>
<div class="dhx_cal_next_button">&amp;nbsp;</div>
<div class="dhx_cal_today_button" t-opentag="true"></div>
<div class="dhx_cal_date" t-opentag="true"></div>
<div class="dhx_cal_tab" name="day_tab" style="right:204px;" t-opentag="true"></div>
<div class="dhx_cal_tab" name="week_tab" style="right:140px;" t-opentag="true"></div>
<div class="dhx_cal_tab" name="month_tab" style="right:76px;" t-opentag="true"></div>
</div>
<div class="dhx_cal_header">
</div>
+1
View File
@@ -1 +1,2 @@
#!/usr/bin/env python
import controllers
+11
View File
@@ -0,0 +1,11 @@
# -*- coding: utf-8 -*-
import openerpweb
class Widgets(openerpweb.openerpweb.Controller):
_cp_path = '/base_dashboard/widgets'
@openerpweb.httprequest
def content(self, request, widget_id):
return request.session.model('res.widget').read(
[widget_id], ['content'], request.session.eval_context(request.context)
)[0]['content']
@@ -19,6 +19,7 @@
font-weight: bold;
}
.openerp a.oe-dashboard-action-rename {
float: left;
padding-right: 4px;
position: relative;
top: 1px;
@@ -46,10 +47,6 @@
float: right;
}
.openerp .oe-dashboard-action .oe-dashboard-action-content {
/*padding: 0.4em;*/
}
.openerp .oe-dashboard .ui-sortable-placeholder {
border: 1px dotted black;
visibility: visible !important;
@@ -131,6 +128,110 @@
right: 0px;
}
.openerp .oe-dashboard-config-overview .oe-config-progress {
border: 1px inset #d9d9d9;
background-color: #f2f2f2;
padding: 0.5em;
-webkit-border-radius: 0.5em;
-moz-border-radius: 0.5em;
border-radius: 0.5em;
}
.openerp .oe-dashboard-config-overview .oe-config-progress-title {
font-size: 1.1em;
font-weight: bold;
text-transform: uppercase;
margin: 0 0 0.5em 0;
}
.openerp .oe-dashboard-config-overview dt {
font-weight: bold;
text-transform: uppercase;
border-top: 1px solid #eee;
padding-top: 0.5em;
}
.openerp .oe-dashboard-config-overview dt:first-child {
border-top: none;
}
.openerp .oe-dashboard-config-overview dd {
margin-left: 1em;
padding-bottom: 0.5em;
}
.openerp .oe-dashboard-config-overview ul {
list-style: none;
padding: 0;
margin: 0;
}
.openerp .oe-dashboard-config-overview li {
cursor: pointer;
position: relative;
text-indent: 20px;
}
.openerp .oe-dashboard-config-overview li:hover {
cursor: pointer;
background-color: #f7f7f7;
}
.openerp .oe-dashboard-config-overview li.oe-done {
cursor: default;
color: #999999;
text-decoration: line-through;
}
.openerp .oe-dashboard-layout_2-1 .index_0 .oe-dashboard-config-overview ul,
.openerp .oe-dashboard-layout_1-2 .index_1 .oe-dashboard-config-overview ul {
-moz-column-count: 2;
-webkit-column-count: 2;
column-count: 2;
}
.openerp .oe-dashboard-config-overview li span.ui-icon {
position: absolute;
top: 0;
left: 0;
}
.openerp .oe-dashboard-home-tile {
text-align: center;
margin: 10px;
-webkit-border-radius: 10px;
-moz-border-radius: 10px;
border-radius: 10px;
-webkit-box-shadow: 3px 3px 5px 3px #DADDDD;
-moz-box-shadow: 3px 3px 5px 3px #DADDDD;
box-shadow: 3px 3px 5px 3px #DADDDD;
}
.openerp .oe-dashboard-home-tile span {
display: block;
padding: 0 0 15px;
font-weight: bold;
text-transform: uppercase;
color: #555;
white-space: nowrap;
}
.openerp .oe-dashboard-home-tile-icon {
height: 100px;
}
.openerp .oe-dashboard-home-tile-icon img {
display: block;
margin: 0 auto;
}
.openerp .oe-dashboard-home-tile-icon img.hover {
display: none;
}
.openerp .oe-dashboard-home-tile:hover {
background-color: #fafafa;
-webkit-box-shadow: 3px 3px 5px 3px #979797;
-moz-box-shadow: 3px 3px 5px 3px #979797;
box-shadow: 3px 3px 5px 3px #979797;
}
.openerp .oe-dashboard-home-tile:hover img {
display: none;
}
.openerp .oe-dashboard-home-tile:hover img.hover {
display: block;
}
.openerp .oe-dashboard-home-tile:hover span {
color: black;
}
.openerp .oe-dashboard-action .view-manager-main-content {
padding: 2px;
}
+159 -20
View File
@@ -64,7 +64,6 @@ openerp.base.form.DashBoard = openerp.base.form.Widget.extend({
type : 'ir.actions.act_window',
limit : 80,
auto_search : true,
domain : [['type', '=', 'ir.actions.act_window']],
flags : {
sidebar : false,
views_switcher : false,
@@ -74,22 +73,24 @@ openerp.base.form.DashBoard = openerp.base.form.Widget.extend({
// TODO: create a Dialog controller which optionally takes an action
// Should set width & height automatically and take buttons & views callback
var dialog_id = _.uniqueId('act_window_dialog');
var $dialog = $('<div id=' + dialog_id + '>').dialog({
modal : true,
title : 'Actions',
width : 800,
height : 600,
buttons : {
Cancel : function() {
$(this).dialog('destroy');
},
Add : function() {
self.do_add_widget(action_manager);
$(this).dialog('destroy');
}
}
});
new openerp.base.ViewManagerAction(this, dialog_id, action).start();
var action_manager = new openerp.base.ActionManager(this, dialog_id);
$('<div id=' + dialog_id + '>').dialog({
modal : true,
title : 'Actions',
width : 800,
height : 600,
buttons : {
Cancel : function() {
$(this).dialog('destroy');
},
Add : function() {
self.do_add_widget(action_manager);
$(this).dialog('destroy');
}
}
});
action_manager.start();
action_manager.do_action(action);
// TODO: should bind ListView#select_record in order to catch record clicking
},
do_add_widget : function(action_manager) {
@@ -148,7 +149,7 @@ openerp.base.form.DashBoard = openerp.base.form.Widget.extend({
modal: true,
title: 'Edit Layout',
width: 'auto',
height: 'auto',
height: 'auto'
}).html(QWeb.render('DashBoard.layouts', qdict));
$dialog.find('li').click(function() {
var layout = $(this).attr('data-layout');
@@ -227,8 +228,9 @@ openerp.base.form.DashBoard = openerp.base.form.Widget.extend({
action_buttons : false,
pager: false
};
new openerp.base.ViewManagerAction(this,
this.view.element_id + '_action_' + action.id, action).start();
new openerp.base.ActionManager(
this, this.view.element_id + '_action_' + action.id)
.do_action(action);
},
render: function() {
// We should start with three columns available
@@ -273,4 +275,141 @@ openerp.base.form.DashBoardLegacy = openerp.base.form.DashBoard.extend({
openerp.base.form.widgets.add('hpaned', 'openerp.base.form.DashBoardLegacy');
openerp.base.form.widgets.add('vpaned', 'openerp.base.form.DashBoardLegacy');
openerp.base.form.widgets.add('board', 'openerp.base.form.DashBoard');
openerp.base.client_actions.add(
'board.config.overview', 'openerp.base_dashboard.ConfigOverview'
);
if (!openerp.base_dashboard) {
openerp.base_dashboard = {};
}
openerp.base_dashboard.ConfigOverview = openerp.base.View.extend({
init: function (parent, element_id) {
this._super(parent, element_id);
this.dataset = new openerp.base.DataSetSearch(
this, 'ir.actions.todo');
this.dataset.domain = [['type', '=', 'manual']];
},
start: function () {
$.when(this.dataset.read_slice(['state', 'action_id', 'category_id']),
this.dataset.call('progress'))
.then(this.on_records_loaded);
},
on_records_loaded: function (read_response, progress_response) {
var records = read_response[0].records,
progress = progress_response[0];
var grouped_todos = _(records).chain()
.map(function (record) {
return {
id: record.id,
name: record.action_id[1],
done: record.state !== 'open',
to_do: record.state === 'open',
category: record['category_id'][1] || "Uncategorized"
}
})
.groupBy(function (record) {return record.category})
.value();
this.$element.html(QWeb.render('ConfigOverview', {
completion: 100 * progress.done / progress.total,
groups: grouped_todos
}));
var $progress = this.$element.find('div.oe-config-progress-bar');
$progress.progressbar({value: $progress.data('completion')});
var self = this;
this.$element.find('div.oe-dashboard-config-overview ul')
.delegate('input', 'click', function (e) {
// switch todo status
e.stopImmediatePropagation();
var new_state = this.checked ? 'done' : 'open',
todo_id = parseInt($(this).val(), 10);
self.dataset.write(todo_id, {state: new_state}, function () {
self.start();
});
})
.delegate('li:not(.oe-done)', 'click', function () {
self.execute_action({
type: 'object',
name: 'action_launch'
}, self.dataset,
self.session.action_manager,
$(this).data('id'), function () {
// after action popup closed, refresh configuration
// thingie
self.start();
});
});
}
});
openerp.base.client_actions.add(
'board.home.applications', 'openerp.base_dashboard.ApplicationTiles');
openerp.base_dashboard.ApplicationTiles = openerp.base.View.extend({
init: function (parent, element_id) {
this._super(parent, element_id);
this.dataset = new openerp.base.DataSetSearch(
this, 'ir.ui.menu', null, [['parent_id', '=', false]]);
},
start: function () {
var self = this;
this.dataset.read_slice(
['name', 'web_icon_data', 'web_icon_hover_data'],
null, null, function (applications) {
// Create a matrix of 3*x applications
var rows = [];
while (applications.length) {
rows.push(applications.splice(0, 3));
}
self.$element
.append(QWeb.render(
'ApplicationTiles', {rows: rows}))
.find('.oe-dashboard-home-tile')
.click(function () {
var $this = $(this);
$this.closest('.openerp')
.find('.menu a[data-menu=' + $this.data('menuid') + ']')
.click();});
});
}
});
openerp.base.client_actions.add(
'board.home.widgets', 'openerp.base_dashboard.Widgets');
openerp.base_dashboard.Widgets = openerp.base.View.extend({
init: function (parent, element_id) {
this._super(parent, element_id);
this.user_widgets = new openerp.base.DataSetSearch(
this, 'res.widget.user', null,
['|', ['user_id', '=', false],
['user_id', '=', parseInt(this.session.uid, 10)]]);
this.widgets = new openerp.base.DataSetSearch(this, 'res.widget');
},
start: function () {
this.user_widgets.read_slice(['widget_id', 'user_id'], null, null,
this.on_widgets_list_loaded);
},
on_widgets_list_loaded: function (user_widgets) {
var self = this;
var widget_user = {};
_(user_widgets).each(function (widget) {
widget['widget_id'] = widget['widget_id'][0];
widget_user[widget['widget_id']] = {
removable: widget['user_id'] !== false,
user_widget_id: widget['id']
};
});
this.widgets.read_ids(_(user_widgets).pluck('widget_id'), ['title'], function (widgets) {
_(widgets).each(function (widget) {
_.extend(widget, widget_user[widget['id']]);
});
var url = _.sprintf(
'/base_dashboard/widgets/content?session_id=%s&widget_id=',
self.session.session_id);
self.$element.html(QWeb.render('HomeWidgets', {
widgets: widgets,
url: url
}));
})
}
});
};
@@ -64,4 +64,54 @@
</board>
</form>
</t>
<div t-name="ConfigOverview" class="oe-dashboard-config-overview">
<div class="oe-config-progress">
<h6 class="oe-config-progress-title">
progress: <t t-esc="Math.round(completion)"/>%
</h6>
<div class="oe-config-progress-bar" t-att-data-completion="completion"/>
</div>
<dl>
<t t-foreach="groups" t-as="category">
<dt><t t-esc="category"/></dt>
<dd><ul>
<li t-foreach="category_value" t-as="todo"
t-att-class="todo.done ? 'oe-done' : undefined"
t-att-data-id="todo.id"
t-att-title="!todo.done ? 'Execute task \'' + todo.name + '\'' : undefined">
<input type="checkbox" t-att-value="todo.id"
t-att-title="!todo.done ? 'Mark this task as done' : undefined"
t-att-checked="todo.done ? 'checked' : undefined"/>
<t t-esc="todo.name"/>
</li>
</ul></dd>
</t>
</dl>
</div>
<div t-name="ApplicationTiles" class="oe-dashboard-home-tiles">
<table width="100%">
<tr t-foreach="rows" t-as="row">
<td t-foreach="row" t-as="application" width="33.3%">
<div class="oe-dashboard-home-tile"
t-att-data-menuid="application.id">
<div class="oe-dashboard-home-tile-icon">
<img t-if="application.web_icon_data"
t-att-src="'data:image/png;base64,' + application.web_icon_data"
/><img t-if="application.web_icon_hover_data" class="hover"
t-att-src="'data:image/png;base64,' + application.web_icon_hover_data"/>
</div>
<span><t t-esc="application.name"/></span>
</div>
</td>
</tr>
</table>
</div>
<div t-name="HomeWidgets" class="oe-dashboard-home-widgets">
<div class="oe-dashboard-home-widgets-widget"
t-foreach="widgets" t-as="widget">
<h3><t t-esc="widget.title"/></h3>
<iframe width="100%" frameborder="0" t-att-src="url + widget.id"/>
</div>
</div>
</template>
+8
View File
@@ -0,0 +1,8 @@
{
"name" : "OpenERP Web installer home",
"version" : "2.0",
"depends" : ['base'],
'active': True,
'js': ['static/src/js/home.js'],
'css': ['static/src/css/home.css']
}
@@ -0,0 +1,45 @@
.oe-static-home {
text-align: center;
}
.oe-static-home-banner {
display: inline-block;
margin: 0.5em 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 p {
}
.oe-static-home-banner address {
font-style: normal;
padding-left: 2em;
}
.oe-static-home-tiles {
text-align: left;
}
.oe-static-home-tiles td {
vertical-align: top;
}
.oe-static-home-tile {
margin: 0.5em;
padding: 0 1em;
}
.oe-static-home-tile-logo {
margin-right: 0.5em;
}
.oe-static-home-tile-text h2 {
margin-top: 0;
margin-bottom: 0.2em;
}
.oe-static-home-tile-text p {
margin: 0.5em 0;
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 9.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.0 KiB

@@ -0,0 +1,101 @@
openerp.base_default_home = function (openerp) {
QWeb.add_template('/base_default_home/static/src/xml/base_default_home.xml');
var old_home = openerp.base.WebClient.prototype.default_home;
openerp.base_default_home = {
applications: [
[
{
module: 'crm', name: 'CRM',
help: "Acquire leads, follow opportunities, manage prospects and phone calls, \u2026"
}, {
module: 'sale', name: 'Sales',
help: "Do quotations, follow sales orders, invoice and control deliveries"
}, {
module: 'account_voucher', name: 'Invoicing',
help: "Send invoice, track payments and reminders"
}, {
module: 'project', name: 'Projects',
help: "Manage projects, track tasks, invoice task works, follow issues, \u2026"
}
], [
{
module: 'purchase', name: 'Purchase',
help: "Do purchase orders, control invoices and reception, follow your suppliers, \u2026"
}, {
module: 'stock', name: 'Warehouse',
help: "Track your stocks, schedule product moves, manage incoming and outgoing shipments, \u2026"
}, {
module: 'hr', name: 'Human Resources',
help: "Manage employees and their contracts, follow laves, recruit people, \u2026"
}, {
module: 'point_of_sale', name: 'Point of Sales',
help: "Manage shop sales, use touch-screen POS"
}
], [
{
module: 'profile_tools', name: 'Extra Tools',
help: "Track ideas, manage lunch, create surveys, share data"
}, {
module: 'mrp', name: 'Manufacturing',
help: "Manage your manufacturing, control your supply chain, personalize master data, \u2026"
}, {
module: 'marketing', name: 'Marketing',
help: "Manage campaigns, follow activities, automate emails, \u2026"
}, {
module: 'knowledge', name: 'Knowledge',
help: "Track your documents, browse your files, \u2026"
}
]
]
};
_.extend(openerp.base.WebClient.prototype, {
default_home: function () {
var self = this;
var Installer = new openerp.base.DataSet(
this, 'base.setup.installer');
Installer.call('already_installed', [], function (installed_modules) {
if (!_(installed_modules).isEmpty()) {
return old_home.call(self);
}
self.$element.find('.oe-application').html(
QWeb.render('StaticHome', {
url: window.location.protocol + '//' + window.location.host + window.location.pathname,
session: self.session,
rows: openerp.base_default_home.applications
})).delegate('.oe-static-home-tile-text button', 'click', function () {
self.install_module($(this).val());
})
}, function (err, event) {
event.preventDefault();
return old_home.call(self);
});
},
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');
$.blockUI({
message: '<img src="/base_default_home/static/src/img/throbber.gif">'
});
Modules.read_slice(['id'], null, null, function (records) {
if (!(records.length === 1)) { return; }
Modules.call('state_update',
[_.pluck(records, 'id'), 'to install', ['uninstalled']],
function () {
Upgrade.call('upgrade_module', [[]], function () {
$.unblockUI();
// TODO: less brutal reloading
window.location.reload(true);
});
}
)
});
}
});
};
@@ -0,0 +1,42 @@
<template>
<div t-name="StaticHome" class="oe-static-home">
<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>
</div>
<div class="oe-static-home-tiles">
<table width="100%">
<tr t-foreach="rows" t-as="row">
<td t-foreach="row" t-as="application" width="25%">
<table class="oe-static-home-tile">
<tr>
<td>
<div class="oe-static-home-tile-logo">
<img t-att-src="'/base_default_home/static/src/img/' + application.module + '.png'"/>
</div>
</td>
<td>
<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>
</div>
</td>
</tr>
</table>
</td>
</tr>
</table>
</div>
</div>
</template>
+1 -1
View File
@@ -6,7 +6,7 @@
<link rel="stylesheet" href="/web_mobile/static/lib/jquery_mobile/css/jquery.mobile-1.0a4.1.css" />
<script type="text/javascript" src="/base/static/lib/LABjs/LAB.js"></script>
<script type="text/javascript" src="/base/static/lib/jquery/jquery-1.5.2.js"></script>
<script type="text/javascript" src="/base/static/lib/jquery/jquery-1.6.2.js"></script>
<script type="text/javascript" src="/base/static/lib/jquery.ui/js/jquery-ui-1.8.9.custom.min.js"></script>
<script type="text/javascript" src="/web_mobile/static/lib/jquery_mobile/js/jquery.mobile-1.0a4.1.js"></script>
+9 -4
View File
@@ -107,15 +107,20 @@ class OpenERPSession(object):
if uid: self.get_context()
return uid
def execute(self, model, func, *l, **d):
def assert_valid(self):
"""
Ensures this session is valid (logged into the openerp server)
"""
if not (self._db and self._uid and self._password):
raise OpenERPUnboundException()
def execute(self, model, func, *l, **d):
self.assert_valid()
r = self.proxy('object').execute(self._db, self._uid, self._password, model, func, *l, **d)
return r
def exec_workflow(self, model, id, signal):
if not (self._db and self._uid and self._password):
raise OpenERPUnboundException()
self.assert_valid()
r = self.proxy('object').exec_workflow(self._db, self._uid, self._password, model, signal, id)
return r
@@ -366,7 +371,7 @@ class HttpRequest(object):
self.context = kw.get('context', {})
host = cherrypy.config['openerp.server.host']
port = cherrypy.config['openerp.server.port']
self.session = self.httpsession.setdefault(kw.get('session_id'), OpenERPSession(host, 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)