[MERGE]
bzr revid: nicolas.vanhoren@openerp.com-20110519115807-9wliqklt0qme0ern
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
import base64
|
||||
import glob, os
|
||||
import pprint
|
||||
from xml.etree import ElementTree
|
||||
@@ -361,24 +362,6 @@ class DataSet(openerpweb.Controller):
|
||||
@openerpweb.jsonrequest
|
||||
def read(self, request, model, ids, fields=False):
|
||||
return self.do_search_read(request, model, ids, fields)
|
||||
def search_read(self, request, model, ids, fields=False):
|
||||
""" Performs a read()
|
||||
|
||||
:param request: a JSON-RPC request object
|
||||
:type request: openerpweb.JsonRequest
|
||||
:param str model: the name of the model to search on
|
||||
:param ids: the ids of the records
|
||||
:type ids: [?]
|
||||
:param fields: a list of the fields to return in the result records
|
||||
:type fields: [str]
|
||||
:returns: a list of result records
|
||||
:rtype: list
|
||||
"""
|
||||
Model = request.session.model(model)
|
||||
|
||||
reads = Model.read(ids, fields or False, request.context)
|
||||
reads.sort(key=lambda obj: ids.index(obj['id']))
|
||||
return reads
|
||||
|
||||
@openerpweb.jsonrequest
|
||||
def get(self, request, model, ids, fields=False):
|
||||
@@ -403,7 +386,7 @@ class DataSet(openerpweb.Controller):
|
||||
:rtype: list
|
||||
"""
|
||||
Model = request.session.model(model)
|
||||
records = Model.read(ids, fields)
|
||||
records = Model.read(ids, fields, request.context)
|
||||
|
||||
record_map = dict((record['id'], record) for record in records)
|
||||
|
||||
@@ -572,6 +555,48 @@ class FormView(View):
|
||||
fields_view = self.fields_view_get(req, model, view_id, 'form', toolbar=toolbar)
|
||||
return {'fields_view': fields_view}
|
||||
|
||||
@openerpweb.httprequest
|
||||
def image(self, request, session_id, model, id, field, **kw):
|
||||
cherrypy.response.headers['Content-Type'] = 'image/png'
|
||||
Model = request.session.model(model)
|
||||
try:
|
||||
if not id:
|
||||
res = Model.default_get([field], request.context).get(field, '')
|
||||
else:
|
||||
res = Model.read([id], [field], request.context)[0].get(field, '')
|
||||
return base64.decodestring(res)
|
||||
except:
|
||||
return self.placeholder()
|
||||
def placeholder(self):
|
||||
return open(os.path.join(openerpweb.path_addons, 'base', 'static', 'src', 'img', 'placeholder.png'), 'rb').read()
|
||||
|
||||
@openerpweb.httprequest
|
||||
def upload(self, request, session_id, callback, ufile=None):
|
||||
cherrypy.response.timeout = 500
|
||||
headers = {}
|
||||
for key, val in cherrypy.request.headers.iteritems():
|
||||
headers[key.lower()] = val
|
||||
size = int(headers.get('content-length', 0))
|
||||
# TODO: might be usefull to have a configuration flag for max-lenght file uploads
|
||||
try:
|
||||
out = """<script language="javascript" type="text/javascript">
|
||||
var win = window.top.window,
|
||||
callback = win[%s];
|
||||
if (typeof(callback) === 'function') {
|
||||
callback.apply(this, %s);
|
||||
} else {
|
||||
win.jQuery('#oe_notification', win.document).notify('create', {
|
||||
title: "Ajax File Upload",
|
||||
text: "Could not find callback"
|
||||
});
|
||||
}
|
||||
</script>"""
|
||||
data = ufile.file.read()
|
||||
args = [size, ufile.filename, ufile.headers.getheader('Content-Type'), base64.encodestring(data)]
|
||||
except Exception as e:
|
||||
args = [False, e.message]
|
||||
return out % (simplejson.dumps(callback), simplejson.dumps(args))
|
||||
|
||||
class ListView(View):
|
||||
_cp_path = "/base/listview"
|
||||
|
||||
|
||||
Executable
+480
@@ -0,0 +1,480 @@
|
||||
/*
|
||||
http://www.JSON.org/json2.js
|
||||
2011-02-23
|
||||
|
||||
Public Domain.
|
||||
|
||||
NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.
|
||||
|
||||
See http://www.JSON.org/js.html
|
||||
|
||||
|
||||
This code should be minified before deployment.
|
||||
See http://javascript.crockford.com/jsmin.html
|
||||
|
||||
USE YOUR OWN COPY. IT IS EXTREMELY UNWISE TO LOAD CODE FROM SERVERS YOU DO
|
||||
NOT CONTROL.
|
||||
|
||||
|
||||
This file creates a global JSON object containing two methods: stringify
|
||||
and parse.
|
||||
|
||||
JSON.stringify(value, replacer, space)
|
||||
value any JavaScript value, usually an object or array.
|
||||
|
||||
replacer an optional parameter that determines how object
|
||||
values are stringified for objects. It can be a
|
||||
function or an array of strings.
|
||||
|
||||
space an optional parameter that specifies the indentation
|
||||
of nested structures. If it is omitted, the text will
|
||||
be packed without extra whitespace. If it is a number,
|
||||
it will specify the number of spaces to indent at each
|
||||
level. If it is a string (such as '\t' or ' '),
|
||||
it contains the characters used to indent at each level.
|
||||
|
||||
This method produces a JSON text from a JavaScript value.
|
||||
|
||||
When an object value is found, if the object contains a toJSON
|
||||
method, its toJSON method will be called and the result will be
|
||||
stringified. A toJSON method does not serialize: it returns the
|
||||
value represented by the name/value pair that should be serialized,
|
||||
or undefined if nothing should be serialized. The toJSON method
|
||||
will be passed the key associated with the value, and this will be
|
||||
bound to the value
|
||||
|
||||
For example, this would serialize Dates as ISO strings.
|
||||
|
||||
Date.prototype.toJSON = function (key) {
|
||||
function f(n) {
|
||||
// Format integers to have at least two digits.
|
||||
return n < 10 ? '0' + n : n;
|
||||
}
|
||||
|
||||
return this.getUTCFullYear() + '-' +
|
||||
f(this.getUTCMonth() + 1) + '-' +
|
||||
f(this.getUTCDate()) + 'T' +
|
||||
f(this.getUTCHours()) + ':' +
|
||||
f(this.getUTCMinutes()) + ':' +
|
||||
f(this.getUTCSeconds()) + 'Z';
|
||||
};
|
||||
|
||||
You can provide an optional replacer method. It will be passed the
|
||||
key and value of each member, with this bound to the containing
|
||||
object. The value that is returned from your method will be
|
||||
serialized. If your method returns undefined, then the member will
|
||||
be excluded from the serialization.
|
||||
|
||||
If the replacer parameter is an array of strings, then it will be
|
||||
used to select the members to be serialized. It filters the results
|
||||
such that only members with keys listed in the replacer array are
|
||||
stringified.
|
||||
|
||||
Values that do not have JSON representations, such as undefined or
|
||||
functions, will not be serialized. Such values in objects will be
|
||||
dropped; in arrays they will be replaced with null. You can use
|
||||
a replacer function to replace those with JSON values.
|
||||
JSON.stringify(undefined) returns undefined.
|
||||
|
||||
The optional space parameter produces a stringification of the
|
||||
value that is filled with line breaks and indentation to make it
|
||||
easier to read.
|
||||
|
||||
If the space parameter is a non-empty string, then that string will
|
||||
be used for indentation. If the space parameter is a number, then
|
||||
the indentation will be that many spaces.
|
||||
|
||||
Example:
|
||||
|
||||
text = JSON.stringify(['e', {pluribus: 'unum'}]);
|
||||
// text is '["e",{"pluribus":"unum"}]'
|
||||
|
||||
|
||||
text = JSON.stringify(['e', {pluribus: 'unum'}], null, '\t');
|
||||
// text is '[\n\t"e",\n\t{\n\t\t"pluribus": "unum"\n\t}\n]'
|
||||
|
||||
text = JSON.stringify([new Date()], function (key, value) {
|
||||
return this[key] instanceof Date ?
|
||||
'Date(' + this[key] + ')' : value;
|
||||
});
|
||||
// text is '["Date(---current time---)"]'
|
||||
|
||||
|
||||
JSON.parse(text, reviver)
|
||||
This method parses a JSON text to produce an object or array.
|
||||
It can throw a SyntaxError exception.
|
||||
|
||||
The optional reviver parameter is a function that can filter and
|
||||
transform the results. It receives each of the keys and values,
|
||||
and its return value is used instead of the original value.
|
||||
If it returns what it received, then the structure is not modified.
|
||||
If it returns undefined then the member is deleted.
|
||||
|
||||
Example:
|
||||
|
||||
// Parse the text. Values that look like ISO date strings will
|
||||
// be converted to Date objects.
|
||||
|
||||
myData = JSON.parse(text, function (key, value) {
|
||||
var a;
|
||||
if (typeof value === 'string') {
|
||||
a =
|
||||
/^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}(?:\.\d*)?)Z$/.exec(value);
|
||||
if (a) {
|
||||
return new Date(Date.UTC(+a[1], +a[2] - 1, +a[3], +a[4],
|
||||
+a[5], +a[6]));
|
||||
}
|
||||
}
|
||||
return value;
|
||||
});
|
||||
|
||||
myData = JSON.parse('["Date(09/09/2001)"]', function (key, value) {
|
||||
var d;
|
||||
if (typeof value === 'string' &&
|
||||
value.slice(0, 5) === 'Date(' &&
|
||||
value.slice(-1) === ')') {
|
||||
d = new Date(value.slice(5, -1));
|
||||
if (d) {
|
||||
return d;
|
||||
}
|
||||
}
|
||||
return value;
|
||||
});
|
||||
|
||||
|
||||
This is a reference implementation. You are free to copy, modify, or
|
||||
redistribute.
|
||||
*/
|
||||
|
||||
/*jslint evil: true, strict: false, regexp: false */
|
||||
|
||||
/*members "", "\b", "\t", "\n", "\f", "\r", "\"", JSON, "\\", apply,
|
||||
call, charCodeAt, getUTCDate, getUTCFullYear, getUTCHours,
|
||||
getUTCMinutes, getUTCMonth, getUTCSeconds, hasOwnProperty, join,
|
||||
lastIndex, length, parse, prototype, push, replace, slice, stringify,
|
||||
test, toJSON, toString, valueOf
|
||||
*/
|
||||
|
||||
|
||||
// Create a JSON object only if one does not already exist. We create the
|
||||
// methods in a closure to avoid creating global variables.
|
||||
|
||||
var JSON;
|
||||
if (!JSON) {
|
||||
JSON = {};
|
||||
}
|
||||
|
||||
(function () {
|
||||
"use strict";
|
||||
|
||||
function f(n) {
|
||||
// Format integers to have at least two digits.
|
||||
return n < 10 ? '0' + n : n;
|
||||
}
|
||||
|
||||
if (typeof Date.prototype.toJSON !== 'function') {
|
||||
|
||||
Date.prototype.toJSON = function (key) {
|
||||
|
||||
return isFinite(this.valueOf()) ?
|
||||
this.getUTCFullYear() + '-' +
|
||||
f(this.getUTCMonth() + 1) + '-' +
|
||||
f(this.getUTCDate()) + 'T' +
|
||||
f(this.getUTCHours()) + ':' +
|
||||
f(this.getUTCMinutes()) + ':' +
|
||||
f(this.getUTCSeconds()) + 'Z' : null;
|
||||
};
|
||||
|
||||
String.prototype.toJSON =
|
||||
Number.prototype.toJSON =
|
||||
Boolean.prototype.toJSON = function (key) {
|
||||
return this.valueOf();
|
||||
};
|
||||
}
|
||||
|
||||
var cx = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
|
||||
escapable = /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
|
||||
gap,
|
||||
indent,
|
||||
meta = { // table of character substitutions
|
||||
'\b': '\\b',
|
||||
'\t': '\\t',
|
||||
'\n': '\\n',
|
||||
'\f': '\\f',
|
||||
'\r': '\\r',
|
||||
'"' : '\\"',
|
||||
'\\': '\\\\'
|
||||
},
|
||||
rep;
|
||||
|
||||
|
||||
function quote(string) {
|
||||
|
||||
// If the string contains no control characters, no quote characters, and no
|
||||
// backslash characters, then we can safely slap some quotes around it.
|
||||
// Otherwise we must also replace the offending characters with safe escape
|
||||
// sequences.
|
||||
|
||||
escapable.lastIndex = 0;
|
||||
return escapable.test(string) ? '"' + string.replace(escapable, function (a) {
|
||||
var c = meta[a];
|
||||
return typeof c === 'string' ? c :
|
||||
'\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
|
||||
}) + '"' : '"' + string + '"';
|
||||
}
|
||||
|
||||
|
||||
function str(key, holder) {
|
||||
|
||||
// Produce a string from holder[key].
|
||||
|
||||
var i, // The loop counter.
|
||||
k, // The member key.
|
||||
v, // The member value.
|
||||
length,
|
||||
mind = gap,
|
||||
partial,
|
||||
value = holder[key];
|
||||
|
||||
// If the value has a toJSON method, call it to obtain a replacement value.
|
||||
|
||||
if (value && typeof value === 'object' &&
|
||||
typeof value.toJSON === 'function') {
|
||||
value = value.toJSON(key);
|
||||
}
|
||||
|
||||
// If we were called with a replacer function, then call the replacer to
|
||||
// obtain a replacement value.
|
||||
|
||||
if (typeof rep === 'function') {
|
||||
value = rep.call(holder, key, value);
|
||||
}
|
||||
|
||||
// What happens next depends on the value's type.
|
||||
|
||||
switch (typeof value) {
|
||||
case 'string':
|
||||
return quote(value);
|
||||
|
||||
case 'number':
|
||||
|
||||
// JSON numbers must be finite. Encode non-finite numbers as null.
|
||||
|
||||
return isFinite(value) ? String(value) : 'null';
|
||||
|
||||
case 'boolean':
|
||||
case 'null':
|
||||
|
||||
// If the value is a boolean or null, convert it to a string. Note:
|
||||
// typeof null does not produce 'null'. The case is included here in
|
||||
// the remote chance that this gets fixed someday.
|
||||
|
||||
return String(value);
|
||||
|
||||
// If the type is 'object', we might be dealing with an object or an array or
|
||||
// null.
|
||||
|
||||
case 'object':
|
||||
|
||||
// Due to a specification blunder in ECMAScript, typeof null is 'object',
|
||||
// so watch out for that case.
|
||||
|
||||
if (!value) {
|
||||
return 'null';
|
||||
}
|
||||
|
||||
// Make an array to hold the partial results of stringifying this object value.
|
||||
|
||||
gap += indent;
|
||||
partial = [];
|
||||
|
||||
// Is the value an array?
|
||||
|
||||
if (Object.prototype.toString.apply(value) === '[object Array]') {
|
||||
|
||||
// The value is an array. Stringify every element. Use null as a placeholder
|
||||
// for non-JSON values.
|
||||
|
||||
length = value.length;
|
||||
for (i = 0; i < length; i += 1) {
|
||||
partial[i] = str(i, value) || 'null';
|
||||
}
|
||||
|
||||
// Join all of the elements together, separated with commas, and wrap them in
|
||||
// brackets.
|
||||
|
||||
v = partial.length === 0 ? '[]' : gap ?
|
||||
'[\n' + gap + partial.join(',\n' + gap) + '\n' + mind + ']' :
|
||||
'[' + partial.join(',') + ']';
|
||||
gap = mind;
|
||||
return v;
|
||||
}
|
||||
|
||||
// If the replacer is an array, use it to select the members to be stringified.
|
||||
|
||||
if (rep && typeof rep === 'object') {
|
||||
length = rep.length;
|
||||
for (i = 0; i < length; i += 1) {
|
||||
if (typeof rep[i] === 'string') {
|
||||
k = rep[i];
|
||||
v = str(k, value);
|
||||
if (v) {
|
||||
partial.push(quote(k) + (gap ? ': ' : ':') + v);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
||||
// Otherwise, iterate through all of the keys in the object.
|
||||
|
||||
for (k in value) {
|
||||
if (Object.prototype.hasOwnProperty.call(value, k)) {
|
||||
v = str(k, value);
|
||||
if (v) {
|
||||
partial.push(quote(k) + (gap ? ': ' : ':') + v);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Join all of the member texts together, separated with commas,
|
||||
// and wrap them in braces.
|
||||
|
||||
v = partial.length === 0 ? '{}' : gap ?
|
||||
'{\n' + gap + partial.join(',\n' + gap) + '\n' + mind + '}' :
|
||||
'{' + partial.join(',') + '}';
|
||||
gap = mind;
|
||||
return v;
|
||||
}
|
||||
}
|
||||
|
||||
// If the JSON object does not yet have a stringify method, give it one.
|
||||
|
||||
if (typeof JSON.stringify !== 'function') {
|
||||
JSON.stringify = function (value, replacer, space) {
|
||||
|
||||
// The stringify method takes a value and an optional replacer, and an optional
|
||||
// space parameter, and returns a JSON text. The replacer can be a function
|
||||
// that can replace values, or an array of strings that will select the keys.
|
||||
// A default replacer method can be provided. Use of the space parameter can
|
||||
// produce text that is more easily readable.
|
||||
|
||||
var i;
|
||||
gap = '';
|
||||
indent = '';
|
||||
|
||||
// If the space parameter is a number, make an indent string containing that
|
||||
// many spaces.
|
||||
|
||||
if (typeof space === 'number') {
|
||||
for (i = 0; i < space; i += 1) {
|
||||
indent += ' ';
|
||||
}
|
||||
|
||||
// If the space parameter is a string, it will be used as the indent string.
|
||||
|
||||
} else if (typeof space === 'string') {
|
||||
indent = space;
|
||||
}
|
||||
|
||||
// If there is a replacer, it must be a function or an array.
|
||||
// Otherwise, throw an error.
|
||||
|
||||
rep = replacer;
|
||||
if (replacer && typeof replacer !== 'function' &&
|
||||
(typeof replacer !== 'object' ||
|
||||
typeof replacer.length !== 'number')) {
|
||||
throw new Error('JSON.stringify');
|
||||
}
|
||||
|
||||
// Make a fake root object containing our value under the key of ''.
|
||||
// Return the result of stringifying the value.
|
||||
|
||||
return str('', {'': value});
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
// If the JSON object does not yet have a parse method, give it one.
|
||||
|
||||
if (typeof JSON.parse !== 'function') {
|
||||
JSON.parse = function (text, reviver) {
|
||||
|
||||
// The parse method takes a text and an optional reviver function, and returns
|
||||
// a JavaScript value if the text is a valid JSON text.
|
||||
|
||||
var j;
|
||||
|
||||
function walk(holder, key) {
|
||||
|
||||
// The walk method is used to recursively walk the resulting structure so
|
||||
// that modifications can be made.
|
||||
|
||||
var k, v, value = holder[key];
|
||||
if (value && typeof value === 'object') {
|
||||
for (k in value) {
|
||||
if (Object.prototype.hasOwnProperty.call(value, k)) {
|
||||
v = walk(value, k);
|
||||
if (v !== undefined) {
|
||||
value[k] = v;
|
||||
} else {
|
||||
delete value[k];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return reviver.call(holder, key, value);
|
||||
}
|
||||
|
||||
|
||||
// Parsing happens in four stages. In the first stage, we replace certain
|
||||
// Unicode characters with escape sequences. JavaScript handles many characters
|
||||
// incorrectly, either silently deleting them, or treating them as line endings.
|
||||
|
||||
text = String(text);
|
||||
cx.lastIndex = 0;
|
||||
if (cx.test(text)) {
|
||||
text = text.replace(cx, function (a) {
|
||||
return '\\u' +
|
||||
('0000' + a.charCodeAt(0).toString(16)).slice(-4);
|
||||
});
|
||||
}
|
||||
|
||||
// In the second stage, we run the text against regular expressions that look
|
||||
// for non-JSON patterns. We are especially concerned with '()' and 'new'
|
||||
// because they can cause invocation, and '=' because it can cause mutation.
|
||||
// But just to be safe, we want to reject all unexpected forms.
|
||||
|
||||
// We split the second stage into 4 regexp operations in order to work around
|
||||
// crippling inefficiencies in IE's and Safari's regexp engines. First we
|
||||
// replace the JSON backslash pairs with '@' (a non-JSON character). Second, we
|
||||
// replace all simple value tokens with ']' characters. Third, we delete all
|
||||
// open brackets that follow a colon or comma or that begin the text. Finally,
|
||||
// we look to see that the remaining characters are only whitespace or ']' or
|
||||
// ',' or ':' or '{' or '}'. If that is so, then the text is safe for eval.
|
||||
|
||||
if (/^[\],:{}\s]*$/
|
||||
.test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@')
|
||||
.replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']')
|
||||
.replace(/(?:^|:|,)(?:\s*\[)+/g, ''))) {
|
||||
|
||||
// In the third stage we use the eval function to compile the text into a
|
||||
// JavaScript structure. The '{' operator is subject to a syntactic ambiguity
|
||||
// in JavaScript: it can begin a block or an object literal. We wrap the text
|
||||
// in parens to eliminate the ambiguity.
|
||||
|
||||
j = eval('(' + text + ')');
|
||||
|
||||
// In the optional fourth stage, we recursively walk the new structure, passing
|
||||
// each name/value pair to a reviver function for possible transformation.
|
||||
|
||||
return typeof reviver === 'function' ?
|
||||
walk({'': j}, '') : j;
|
||||
}
|
||||
|
||||
// If the text is not JSON parseable, then a SyntaxError is thrown.
|
||||
|
||||
throw new SyntaxError('JSON.parse');
|
||||
};
|
||||
}
|
||||
}());
|
||||
@@ -1,4 +1,5 @@
|
||||
// TODO: trim support
|
||||
// TODO: line number -> https://bugzilla.mozilla.org/show_bug.cgi?id=618650
|
||||
var QWeb2 = {
|
||||
expressions_cache: {},
|
||||
reserved_words: 'true,false,NaN,null,undefined,debugger,in,instanceof,new,function,return,this,typeof,eval,Math,RegExp,Array,Object'.split(','),
|
||||
@@ -295,8 +296,7 @@ QWeb2.Engine = (function() {
|
||||
compile : function(node) {
|
||||
var e = new QWeb2.Element(this, node);
|
||||
var template = node.getAttribute(this.prefix + '-name');
|
||||
return "(function(dict) {\n" +
|
||||
" /* 'this' refers to Qweb2.Engine instance */\n" +
|
||||
return " /* 'this' refers to Qweb2.Engine instance */\n" +
|
||||
" var context = { engine : this, template : " + (this.tools.js_escape(template)) + " };\n" +
|
||||
" dict = dict || {};\n" +
|
||||
" dict['__template__'] = '" + template + "';\n" +
|
||||
@@ -306,8 +306,7 @@ QWeb2.Engine = (function() {
|
||||
" /* END OF TEMPLATE */ } catch(error) {\n" +
|
||||
" context.engine.tools.exception('Runtime Error: ' + error, context);\n" +
|
||||
" }\n" +
|
||||
" return r.join('');\n" +
|
||||
"});";
|
||||
" return r.join('');";
|
||||
},
|
||||
render : function(template, dict) {
|
||||
if (this.debug && window['console'] !== undefined) {
|
||||
@@ -332,12 +331,16 @@ QWeb2.Engine = (function() {
|
||||
}
|
||||
var code = this.compile(this.templates[template]), tcompiled;
|
||||
try {
|
||||
// tcompiled = new Function(code); TODO: Check if could use this in order to avoid eval
|
||||
tcompiled = eval(code);
|
||||
tcompiled = new Function(['dict'], code);
|
||||
} catch (error) {
|
||||
console.log(code);
|
||||
if (this.debug && window.console) {
|
||||
console.log(code);
|
||||
}
|
||||
this.tools.exception("Error evaluating template: " + error, { template: name });
|
||||
}
|
||||
if (!tcompiled) {
|
||||
this.tools.exception("Error evaluating template: (IE?)" + error, { template: name });
|
||||
}
|
||||
this.compiled_templates[template] = tcompiled;
|
||||
return this.render(template, dict);
|
||||
} else {
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
<script type="text/javascript" src="/base/static/lib/jquery.superfish/js/superfish.js"></script>
|
||||
<script type="text/javascript" src="/base/static/lib/jquery.ba-bbq/jquery.ba-bbq.js"></script>
|
||||
<script type="text/javascript" src="/base/static/lib/datejs/date-en-US.js"></script>
|
||||
<script type="text/javascript" src="/base/static/lib/json/json2.js"></script>
|
||||
<script type="text/javascript" src="/base/static/src/js/base.js"></script>
|
||||
<script type="text/javascript" src="/base/static/src/js/dates.js"></script>
|
||||
<script type="text/javascript" src="/base/static/src/js/chrome.js"></script>
|
||||
@@ -35,6 +36,9 @@
|
||||
<link rel="stylesheet" type="text/css" href="/base/static/lib/jquery.superfish/css/superfish.css" media="screen">
|
||||
|
||||
<link rel="stylesheet" href="/base/static/src/css/base.css" type="text/css"/>
|
||||
<!--[if lte IE 7]>
|
||||
<link rel="stylesheet" href="/base/static/src/css/base-ie7.css" type="text/css"/>
|
||||
<![endif]-->
|
||||
|
||||
<script type="text/javascript">
|
||||
$(function() {
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
|
||||
.openerp .menu span {
|
||||
min-width: 0px;
|
||||
}
|
||||
@@ -95,57 +95,40 @@ body.openerp {
|
||||
|
||||
.openerp .menu {
|
||||
height: 34px;
|
||||
position: relative;
|
||||
white-space: nowrap;
|
||||
background: url(../img/menu-bg.png) repeat-x;
|
||||
}
|
||||
.openerp .menu ul {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
list-style: none;
|
||||
overflow: hidden;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
right: 0;
|
||||
text-align: center;
|
||||
}
|
||||
.openerp .menu li {
|
||||
display: -moz-inline-stack;
|
||||
display: inline; /*IE7 */
|
||||
display: inline-block;
|
||||
margin: 6px 1px;
|
||||
text-align: center;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
.openerp .menu a {
|
||||
display: block;
|
||||
float: left;
|
||||
padding: 0 0 0 3px;
|
||||
background: url(../img/menu-item.png) no-repeat;
|
||||
color: #eee;
|
||||
text-shadow: #222 0 1px 0;
|
||||
text-decoration: none;
|
||||
|
||||
text-align: center;
|
||||
text-transform: uppercase;
|
||||
margin: 2px 1px;
|
||||
height: 23px;
|
||||
}
|
||||
.openerp .menu span {
|
||||
display: block;
|
||||
float: left;
|
||||
min-width: 60px;
|
||||
height: 23px;
|
||||
padding: 0 9px 0 6px;
|
||||
background: url(../img/menu-item.png) 100% 0 no-repeat;
|
||||
line-height: 22px;
|
||||
line-height: 23px;
|
||||
font-weight: bold;
|
||||
font-size: 85%;
|
||||
}
|
||||
.openerp .menu ul li a:hover,
|
||||
.openerp .menu li a:focus,
|
||||
.openerp .menu ul li a.active {
|
||||
.openerp .menu a:hover,
|
||||
.openerp .menu a:focus,
|
||||
.openerp .menu a.active {
|
||||
background-position: 0 -23px;
|
||||
color: #fff;
|
||||
}
|
||||
.openerp .menu ul li a:hover span,
|
||||
.openerp .menu ul li a:focus span,
|
||||
.openerp .menu ul li a.active span {
|
||||
.openerp .menu a:hover span,
|
||||
.openerp .menu a:focus span,
|
||||
.openerp .menu a.active span {
|
||||
background-position: 100% -23px;
|
||||
}
|
||||
/* Secondary Menu */
|
||||
@@ -156,6 +139,7 @@ body.openerp {
|
||||
border-bottom: 1px solid #5A5858;
|
||||
background: #5A5858;
|
||||
vertical-align: top;
|
||||
height: 100%;
|
||||
}
|
||||
.openerp .secondary_menu .menu_content {
|
||||
padding: 0;
|
||||
@@ -637,6 +621,27 @@ body.openerp {
|
||||
-moz-background-origin: content-box;
|
||||
-webkit-background-origin: content-box;
|
||||
}
|
||||
/* http://www.quirksmode.org/dom/inputfile.html
|
||||
* http://stackoverflow.com/questions/2855589/replace-input-type-file-by-an-image
|
||||
*/
|
||||
.openerp button.oe-binary-file-set {
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
}
|
||||
.openerp input.oe-binary-file {
|
||||
z-index: 2;
|
||||
line-height: 0;
|
||||
font-size: 50px;
|
||||
position: absolute;
|
||||
/* Should be adjusted for all browsers */
|
||||
top: -2px;
|
||||
left: -700px;
|
||||
opacity: 0;
|
||||
filter: alpha(opacity = 0);
|
||||
-ms-filter: "alpha(opacity=0)";
|
||||
margin: 0;
|
||||
padding:0;
|
||||
}
|
||||
|
||||
/* Widgets */
|
||||
.openerp .separator {
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 1.3 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 673 B |
@@ -44,8 +44,11 @@
|
||||
// The dummy class constructor
|
||||
function Class() {
|
||||
// All construction is actually done in the init method
|
||||
if ( !initializing && this.init )
|
||||
this.init.apply(this, arguments);
|
||||
if ( !initializing && this.init ) {
|
||||
var ret = this.init.apply(this, arguments);
|
||||
if (ret) { return ret; }
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
// Populate our constructed prototype object
|
||||
|
||||
@@ -296,6 +296,9 @@ openerp.base.Session = openerp.base.BasicController.extend( /** @lends openerp.b
|
||||
// Construct a JSON-RPC2 request, method is currently unused
|
||||
params.session_id = this.session_id;
|
||||
params.context = typeof(params.context) != "undefined" ? params.context : this.context;
|
||||
if (!params.context.bin_size) {
|
||||
params.context.bin_size = true;
|
||||
}
|
||||
|
||||
// Use a default error handler unless defined
|
||||
error_callback = typeof(error_callback) != "undefined" ? error_callback : this.on_rpc_error;
|
||||
|
||||
@@ -242,7 +242,6 @@ openerp.base.DataSet = openerp.base.Controller.extend( /** @lends openerp.base.
|
||||
ids: ids,
|
||||
args: args
|
||||
}, callback);
|
||||
|
||||
},
|
||||
name_search: function (search_str, callback) {
|
||||
search_str = search_str || '';
|
||||
@@ -352,7 +351,7 @@ openerp.base.DataSetMany2Many = openerp.base.DataSetStatic.extend({
|
||||
|
||||
unlink: function(ids) {
|
||||
// just do nothing
|
||||
},
|
||||
}
|
||||
});
|
||||
|
||||
};
|
||||
|
||||
@@ -71,6 +71,9 @@ openerp.base.FormView = openerp.base.View.extend( /** @lends openerp.base.FormV
|
||||
} else {
|
||||
this.dataset.read_index(_.keys(this.fields_view.fields), this.on_record_loaded);
|
||||
}
|
||||
if (this.view_manager && this.view_manager.sidebar) {
|
||||
this.view_manager.sidebar.refresh(true);
|
||||
}
|
||||
},
|
||||
do_hide: function () {
|
||||
this.$element.hide();
|
||||
@@ -321,7 +324,7 @@ openerp.base.form.compute_domain = function(expr, fields) {
|
||||
var ex = expr[i];
|
||||
if (ex.length == 1) {
|
||||
var top = stack.pop();
|
||||
switch (ex[0]) {
|
||||
switch (ex) {
|
||||
case '|':
|
||||
stack.push(stack.pop() || top);
|
||||
continue;
|
||||
@@ -332,7 +335,7 @@ openerp.base.form.compute_domain = function(expr, fields) {
|
||||
stack.push(!top);
|
||||
continue;
|
||||
default:
|
||||
throw new Error('Unknown domain operator ' + ex[0]);
|
||||
throw new Error('Unknown domain operator ' + ex);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -362,17 +365,17 @@ openerp.base.form.compute_domain = function(expr, fields) {
|
||||
stack.push(field >= val);
|
||||
break;
|
||||
case 'in':
|
||||
stack.push(_.indexOf(val, field) > -1);
|
||||
stack.push(_(val).contains(field));
|
||||
break;
|
||||
case 'not in':
|
||||
stack.push(_.indexOf(val, field) == -1);
|
||||
stack.push(!_(val).contains(field));
|
||||
break;
|
||||
default:
|
||||
this.log("Unsupported operator in attrs :", op);
|
||||
}
|
||||
}
|
||||
return _.indexOf(stack, false) == -1;
|
||||
}
|
||||
return _.all(stack);
|
||||
};
|
||||
|
||||
openerp.base.form.Widget = openerp.base.Controller.extend({
|
||||
init: function(view, node) {
|
||||
@@ -891,7 +894,7 @@ openerp.base.form.FieldMany2OneDatasSet = openerp.base.DataSetStatic.extend({
|
||||
},
|
||||
write: function (id, data, callback) {
|
||||
this._super(id, data, callback);
|
||||
},
|
||||
}
|
||||
});
|
||||
|
||||
openerp.base.form.FieldMany2OneViewManager = openerp.base.ViewManager.extend({
|
||||
@@ -1188,10 +1191,58 @@ openerp.base.form.FieldImage = openerp.base.form.Field.extend({
|
||||
init: function(view, node) {
|
||||
this._super(view, node);
|
||||
this.template = "FieldImage";
|
||||
this.iframe = this.element_id + '_iframe';
|
||||
},
|
||||
start: function() {
|
||||
this._super.apply(this, arguments);
|
||||
this.$element.find('input.oe-binary-file').change(this.on_file_change);
|
||||
this.$element.find('button.oe-binary-file-clear').click(this.on_clear);
|
||||
},
|
||||
set_value_from_ui: function() {
|
||||
},
|
||||
set_image_maxwidth: function() {
|
||||
this.$element.find('img.oe-binary-image').css('max-width', this.$element.width());
|
||||
},
|
||||
on_file_change: function() {
|
||||
this.set_image_maxwidth();
|
||||
// TODO: on modern browsers, we could directly read the file locally on client ready to be used on image cropper
|
||||
// http://www.html5rocks.com/tutorials/file/dndfiles/
|
||||
// http://deepliquid.com/projects/Jcrop/demos.php?demo=handler
|
||||
window[this.iframe] = this.on_file_uploaded;
|
||||
this.$element.find('form.oe-binary-form input[name=session_id]').val(this.session.session_id);
|
||||
this.$element.find('form.oe-binary-form').submit();
|
||||
this.toggle_progress();
|
||||
},
|
||||
toggle_progress: function() {
|
||||
this.$element.find('div.oe-binary-progress, div.oe-binary').toggle();
|
||||
},
|
||||
on_file_uploaded: function(size, name, content_type, img) {
|
||||
delete(window[this.iframe]);
|
||||
if (size === false) {
|
||||
this.notification.warn("File Upload", "There was a problem while uploading your file");
|
||||
// TODO: use openerp web exception handler
|
||||
console.log("Error while uploading file : ", name);
|
||||
} else {
|
||||
this.value = img;
|
||||
this.$element.find('img.oe-binary-image').attr('src', 'data:' + (content_type || 'image/png') + ';base64,' + img);
|
||||
this.on_ui_change();
|
||||
}
|
||||
this.toggle_progress();
|
||||
},
|
||||
on_clear: function() {
|
||||
if (this.value !== false) {
|
||||
this.value = false;
|
||||
this.$element.find('img.oe-binary-image').attr('src', '/base/static/src/img/placeholder.png');
|
||||
this.on_ui_change();
|
||||
}
|
||||
return false;
|
||||
},
|
||||
set_value: function(value) {
|
||||
this._super.apply(this, arguments);
|
||||
this.$element.find('img').show().attr('src', 'data:image/png;base64,' + this.value);
|
||||
this.set_image_maxwidth();
|
||||
var url = '/base/formview/image?session_id=' + this.session.session_id + '&model=' +
|
||||
this.view.dataset.model +'&id=' + (this.view.datarecord.id || '') + '&field=' + this.name + '&t=' + (new Date().getTime())
|
||||
this.$element.find('img.oe-binary-image').attr('src', url);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -251,6 +251,9 @@ openerp.base.ListView = openerp.base.View.extend( /** @lends openerp.base.ListVi
|
||||
this.do_reload();
|
||||
this.hidden = false;
|
||||
}
|
||||
if (this.view_manager && this.view_manager.sidebar) {
|
||||
this.view_manager.sidebar.refresh(true);
|
||||
}
|
||||
},
|
||||
do_hide: function () {
|
||||
this.$element.hide();
|
||||
|
||||
@@ -90,7 +90,7 @@ openerp.base.m2o = function(openerp){
|
||||
return true;
|
||||
}
|
||||
ui.item.value = self.element.data("autocomplete").term.length ? self.element.val() + '[' + ui.item.orig_val.substring(self.element.data("autocomplete").term.length) + ']' : this.lastSearch;
|
||||
},
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
@@ -111,4 +111,4 @@ openerp.base.m2o = function(openerp){
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,7 +24,8 @@ openerp.base.ActionManager = openerp.base.Controller.extend({
|
||||
sidebar : true,
|
||||
search_view : true,
|
||||
new_window : false,
|
||||
toolbar : true,
|
||||
views_switcher : true,
|
||||
action_buttons : true,
|
||||
pager : true
|
||||
}, action.flags || {});
|
||||
// instantiate the right controllers by understanding the action
|
||||
@@ -46,6 +47,7 @@ openerp.base.ActionManager = openerp.base.Controller.extend({
|
||||
viewmanager.start();
|
||||
this.dialog_stack.push(viewmanager);
|
||||
} 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 });
|
||||
@@ -79,6 +81,7 @@ openerp.base.ViewManager = openerp.base.Controller.extend({
|
||||
this.active_view = null;
|
||||
this.views_src = views;
|
||||
this.views = {};
|
||||
this.flags = this.flags || {};
|
||||
},
|
||||
/**
|
||||
* @returns {jQuery.Deferred} initial view loading promise
|
||||
@@ -93,6 +96,9 @@ openerp.base.ViewManager = openerp.base.Controller.extend({
|
||||
_.each(this.views_src, function(view) {
|
||||
self.views[view[1]] = { view_id: view[0], controller: null };
|
||||
});
|
||||
if (this.flags.views_switcher === false) {
|
||||
this.$element.find('.oe_vm_switch').hide();
|
||||
}
|
||||
// switch to the first one in sequence
|
||||
return this.on_mode_switch(this.views_src[0][1]);
|
||||
},
|
||||
@@ -116,7 +122,7 @@ openerp.base.ViewManager = openerp.base.Controller.extend({
|
||||
this.views[view_type].controller = controller;
|
||||
}
|
||||
|
||||
if(this.searchview) {
|
||||
if (this.searchview) {
|
||||
if (view.controller.searchable === false) {
|
||||
this.searchview.hide();
|
||||
} else {
|
||||
@@ -152,6 +158,9 @@ openerp.base.ViewManager = openerp.base.Controller.extend({
|
||||
this.searchview.stop();
|
||||
}
|
||||
this.searchview = new openerp.base.SearchView(this, this.session, this.element_id + "_search", this.dataset, view_id, search_defaults);
|
||||
if (this.flags.search_view === false) {
|
||||
this.searchview.hide();
|
||||
}
|
||||
this.searchview.on_search.add(function(domains, contexts, groupbys) {
|
||||
self.views[self.active_view].controller.do_search.call(
|
||||
self, domains.concat(self.domains()),
|
||||
@@ -201,7 +210,12 @@ openerp.base.ViewManagerAction = openerp.base.ViewManager.extend({
|
||||
}
|
||||
this._super(session, element_id, dataset, action.views);
|
||||
this.action = action;
|
||||
if (action.flags.sidebar) {
|
||||
this.flags = this.action.flags || {};
|
||||
if (action.res_model == 'board.board' && action.views.length == 1 && action.views) {
|
||||
// Not elegant but allows to avoid flickering of SearchView#do_hide
|
||||
this.flags.search_view = this.flags.pager = this.flags.action_buttons = false;
|
||||
}
|
||||
if (this.flags.sidebar) {
|
||||
this.sidebar = new openerp.base.Sidebar(null, this);
|
||||
}
|
||||
},
|
||||
@@ -281,17 +295,31 @@ openerp.base.Sidebar = openerp.base.BaseWidget.extend({
|
||||
var section = {elements:toolbar[type[0]], label:type[1]};
|
||||
self.sections.push(section);
|
||||
});
|
||||
this.refresh();
|
||||
this.refresh(true);
|
||||
},
|
||||
refresh: function() {
|
||||
this.$element.html(QWeb.render("ViewManager.sidebar.internal", _.extend({_:_}, this)));
|
||||
refresh: function(new_view) {
|
||||
var view = this.view_manager.active_view;
|
||||
the_condition = this.sections.length > 0 && _.detect(this.sections,
|
||||
function(x) {return x.elements.length > 0;}) != undefined
|
||||
&& (!new_view || view != 'list');
|
||||
if (!the_condition) {
|
||||
this.$element.addClass('closed-sidebar');
|
||||
this.$element.removeClass('open-sidebar');
|
||||
} else {
|
||||
this.$element.addClass('open-sidebar');
|
||||
this.$element.removeClass('closed-sidebar');
|
||||
}
|
||||
|
||||
this.$element.html(QWeb.render("ViewManager.sidebar.internal",this));
|
||||
|
||||
var self = this;
|
||||
this.$element.find(".toggle-sidebar").click(function(e) {
|
||||
self.$element.toggleClass('open-sidebar closed-sidebar');
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
});
|
||||
this.$element.find("a").click(function(e) {
|
||||
|
||||
this.$element.find("a.oe_sidebar_action_a").click(function(e) {
|
||||
var $this = jQuery(this);
|
||||
var i = $this.attr("data-i");
|
||||
var j = $this.attr("data-j");
|
||||
@@ -306,7 +334,7 @@ openerp.base.Sidebar = openerp.base.BaseWidget.extend({
|
||||
},
|
||||
start: function() {
|
||||
this._super();
|
||||
this.refresh();
|
||||
this.refresh(false);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -28,8 +28,10 @@
|
||||
<tr>
|
||||
<td valign="top" id="oe_secondary_menu" class="secondary_menu">
|
||||
</td>
|
||||
<td valign="top" width="100%" height="100%">
|
||||
<div id="oe_app" class="oe-application"></div>
|
||||
<td valign="top" >
|
||||
<div id="oe_app" class="oe-application">
|
||||
<div style="width:100%;">&nbsp;</div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
@@ -85,13 +87,17 @@
|
||||
</div>
|
||||
</t>
|
||||
<t t-name="Menu">
|
||||
<ul>
|
||||
<li t-foreach="data.children" t-as="menu">
|
||||
<a href="#" t-att-data-menu="menu.id">
|
||||
<span><t t-esc="menu.name"/></span>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
<table align="center">
|
||||
<tr>
|
||||
<t t-foreach="data.children" t-as="menu">
|
||||
<td>
|
||||
<a href="#" t-att-data-menu="menu.id">
|
||||
<span><t t-esc="menu.name"/></span>
|
||||
</a>
|
||||
</td>
|
||||
</t>
|
||||
</tr>
|
||||
</table>
|
||||
</t>
|
||||
<t t-name="Menu.secondary">
|
||||
<div style="display: none" class="menu_accordion" t-att-data-menu-parent="menu.id">
|
||||
@@ -130,7 +136,7 @@
|
||||
<td class="view-manager-main-content">
|
||||
<!-- TODO prefix id with the element_id of the controller t-attf-id="#{prefix}_localid" -->
|
||||
<div class="oe_vm_switch">
|
||||
<t t-foreach="views" t-as="view">
|
||||
<t t-if="views.length != 1" t-foreach="views" t-as="view">
|
||||
<button type="button" t-att-data-view-type="view[1]">
|
||||
<t t-esc="view[1]"/>
|
||||
</button>
|
||||
@@ -153,27 +159,31 @@
|
||||
<tr t-if="options.selectable">
|
||||
<th t-if="actions_span" t-att-colspan="actions_span"
|
||||
class="oe-actions">
|
||||
<button type="button" id="oe-list-add"
|
||||
t-if="options.addable">
|
||||
<t t-esc="options.addable"/>
|
||||
</button>
|
||||
<button type="button" id="oe-list-delete"
|
||||
t-if="options.deletable">
|
||||
Delete
|
||||
</button>
|
||||
<t t-if="view_manager.action.flags.action_buttons !== false">
|
||||
<button type="button" id="oe-list-add"
|
||||
t-if="options.addable">
|
||||
<t t-esc="options.addable"/>
|
||||
</button>
|
||||
<button type="button" id="oe-list-delete"
|
||||
t-if="options.deletable">
|
||||
Delete
|
||||
</button>
|
||||
</t>
|
||||
</th>
|
||||
<th t-att-colspan="columns_count - actions_span"
|
||||
class="oe-list-pager">
|
||||
<button type="button" data-pager-action="first">First</button>
|
||||
<button type="button" data-pager-action="previous"
|
||||
><<</button>
|
||||
<t t-if="view_manager.action.flags.pager !== false">
|
||||
<button type="button" data-pager-action="first">First</button>
|
||||
<button type="button" data-pager-action="previous"
|
||||
><<</button>
|
||||
|
||||
<span class="oe-pager-first">1</span>
|
||||
to <span class="oe-pager-last">1</span>
|
||||
of <span class="oe-pager-total">1</span>
|
||||
<span class="oe-pager-first">1</span>
|
||||
to <span class="oe-pager-last">1</span>
|
||||
of <span class="oe-pager-total">1</span>
|
||||
|
||||
<button type="button" data-pager-action="next">>></button>
|
||||
<button type="button" data-pager-action="last">Last</button>
|
||||
<button type="button" data-pager-action="next">>></button>
|
||||
<button type="button" data-pager-action="last">Last</button>
|
||||
</t>
|
||||
</th>
|
||||
</tr>
|
||||
<tr t-if="options.header">
|
||||
@@ -229,13 +239,13 @@
|
||||
<t t-name="FormView">
|
||||
<h2 class="oe_view_title"><t t-esc="view.fields_view.arch.attrs.string"/></h2>
|
||||
<div class="oe_form_header" t-att-id="view.element_id + '_header'">
|
||||
<div class="oe_form_buttons">
|
||||
<div class="oe_form_buttons" t-if="view.view_manager.action.flags.action_buttons !== false">
|
||||
<!--<button type="button" class="oe_form_button_save">Save</button>-->
|
||||
<button type="button" class="oe_form_button_save_edit">Save & Edit</button>
|
||||
<!--<button type="button" class="oe_form_button_cancel">Cancel</button>-->
|
||||
<button type="button" class="oe_form_button_new">New</button>
|
||||
</div>
|
||||
<div class="oe_form_pager">
|
||||
<div class="oe_form_pager" t-if="view.view_manager.action.flags.pager !== false">
|
||||
<button type="button" data-pager-action="first">First</button>
|
||||
<button type="button" data-pager-action="previous"><<</button>
|
||||
|
||||
@@ -311,7 +321,7 @@
|
||||
<t t-call="FieldChar"/>
|
||||
</td>
|
||||
<td width="16">
|
||||
<button class="button" title="Send an e-mail with your default e-mail client">
|
||||
<button type="button" class="button" title="Send an e-mail with your default e-mail client">
|
||||
<img src="/base/static/src/img/icons/terp-mail-message-new.png"/>
|
||||
</button>
|
||||
</td>
|
||||
@@ -377,13 +387,46 @@
|
||||
</div>
|
||||
</t>
|
||||
<t t-name="FieldImage">
|
||||
<img align="left" border="1" style="display: none"
|
||||
t-att-id="widget.element_id + '_field'"
|
||||
t-att-name="widget.name"
|
||||
t-att-class="'field_' + widget.type"
|
||||
t-att-width="widget.node.attrs.img_width || widget.node.attrs.width"
|
||||
t-att-height="widget.node.attrs.img_height || widget.node.attrs.height"
|
||||
/>
|
||||
<table cellpadding="0" cellspacing="0" border="0">
|
||||
<tr>
|
||||
<td align="center">
|
||||
<img src="/base/static/src/img/placeholder.png" class="oe-binary-image" border="1"
|
||||
t-att-id="widget.element_id + '_field'"
|
||||
t-att-name="widget.name"
|
||||
t-att-class="'field_' + widget.type"
|
||||
t-att-width="widget.node.attrs.img_width || widget.node.attrs.width"
|
||||
t-att-height="widget.node.attrs.img_height || widget.node.attrs.height"
|
||||
/>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center" valign="bottom" height="25">
|
||||
<div class="oe-binary">
|
||||
<!-- TODO: input@type=file inside a button won't work in firefox. Use links instead -->
|
||||
<button class="button oe-binary-file-set" type="button" title="Set Image">
|
||||
<img src="/base/static/src/img/icons/STOCK_DIRECTORY.png"/>
|
||||
<form class="oe-binary-form" t-att-target="widget.iframe"
|
||||
method="post" enctype="multipart/form-data" action="/base/formview/upload">
|
||||
<input type="hidden" name="session_id" value=""/>
|
||||
<input type="hidden" name="callback" t-att-value="widget.iframe"/>
|
||||
<input type="file" class="oe-binary-file" name="ufile"/>
|
||||
</form>
|
||||
</button>
|
||||
<button class="button oe-binary-file-save" type="button" title="Save As">
|
||||
<img src="/base/static/src/img/icons/gtk-save.png"/>
|
||||
</button>
|
||||
<button class="button oe-binary-file-clear" type="button" title="Clear">
|
||||
<img src="/base/static/src/img/icons/STOCK_MISSING_IMAGE.png"/>
|
||||
</button>
|
||||
</div>
|
||||
<div class="oe-binary-progress" style="display: none">
|
||||
<img src="/base/static/src/img/throbber.gif" width="16" height="16"/>
|
||||
<b>Uploading ...</b>
|
||||
</div>
|
||||
<iframe t-att-id="widget.iframe" t-att-name="widget.iframe" style="display: none"> </iframe>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</t>
|
||||
<t t-name="WidgetButton">
|
||||
<button type="button"
|
||||
@@ -398,7 +441,7 @@
|
||||
<h2 class="oe_view_title"><t t-esc="view.attrs['string']"/></h2>
|
||||
<form>
|
||||
<t t-call="SearchView.render_lines"/>
|
||||
<div class="oe_search-view-buttons" style="text-align:right;">
|
||||
<div class="oe_search-view-buttons" style="text-align: right;">
|
||||
<input type="submit" value="Search"/>
|
||||
<input type="reset" value="Clear"/>
|
||||
</div>
|
||||
@@ -547,37 +590,31 @@
|
||||
<input t-att-id="element_id"/>
|
||||
</t>
|
||||
<t t-name="ViewManager.sidebar">
|
||||
<div t-att-id="element_id" class="sidebar-main-div open-sidebar">
|
||||
<div t-att-id="element_id" class="sidebar-main-div closed-sidebar">
|
||||
|
||||
</div>
|
||||
</t>
|
||||
<t t-name="ViewManager.sidebar.internal">
|
||||
<t t-js="d">
|
||||
d.the_condition = d.sections.length > 0 && d._.detect(d.sections, function(x) {
|
||||
return x.elements.length > 0;
|
||||
}) != undefined
|
||||
</t>
|
||||
<t t-if="the_condition">
|
||||
<a class="toggle-sidebar"></a>
|
||||
<div t-att-id="element_id" class="sidebar-sub-div">
|
||||
<div class="sidebar-displaying-div">
|
||||
<t t-set="i" t-value="1-1"/> <!-- al do stupid things -->
|
||||
<t t-foreach="sections" t-as="section">
|
||||
<t t-if="section.elements.length > 0">
|
||||
<h2><t t-esc="section.label"/></h2>
|
||||
<ul>
|
||||
<t t-set="j" t-value="1-1"/>
|
||||
<t t-foreach="section.elements" t-as="element">
|
||||
<li><a t-att-data-i="i" t-att-data-j="j" href="#"><t t-esc="element.name"/></a></li>
|
||||
<t t-set="j" t-value="j+1"/>
|
||||
</t>
|
||||
</ul>
|
||||
<a class="toggle-sidebar"></a>
|
||||
<div t-att-id="element_id" class="sidebar-sub-div">
|
||||
<div class="sidebar-displaying-div">
|
||||
<t t-set="i" t-value="1-1"/> <!-- al do stupid things -->
|
||||
<t t-foreach="sections" t-as="section">
|
||||
<t t-if="section.elements.length > 0">
|
||||
<h2><t t-esc="section.label"/></h2>
|
||||
<ul>
|
||||
<t t-set="j" t-value="1-1"/>
|
||||
<t t-foreach="section.elements" t-as="element">
|
||||
<li><a class="oe_sidebar_action_a" t-att-data-i="i" t-att-data-j="j" href="#">
|
||||
<t t-esc="element.name"/></a></li>
|
||||
<t t-set="j" t-value="j+1"/>
|
||||
</t>
|
||||
<t t-set="i" t-value="i+1"/>
|
||||
</ul>
|
||||
</t>
|
||||
</div>
|
||||
<t t-set="i" t-value="i+1"/>
|
||||
</t>
|
||||
</div>
|
||||
</t>
|
||||
</div>
|
||||
</t>
|
||||
<t t-name="DialogWarning">
|
||||
<div id="dialog-message" t-att-title="title">
|
||||
|
||||
@@ -3,9 +3,8 @@
|
||||
"version": "2.0",
|
||||
"depends": ['base'],
|
||||
"js": [
|
||||
'static/lib/jquery.dashboard/js/jquery.dashboard.js',
|
||||
'static/src/js/dashboard.js'
|
||||
],
|
||||
"css": ['static/lib/jquery.dashboard/css/dashboardui.css'],
|
||||
"css": ['static/src/css/dashboard.css'],
|
||||
'active': True
|
||||
}
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
content 4 content 4 content 4 content 4 content 4 content 4 content 4 content 4 content 4 content 4 content 4
|
||||
@@ -1,261 +0,0 @@
|
||||
.ui-icon {
|
||||
cursor:default;
|
||||
}
|
||||
.widgetheader {
|
||||
cursor:move;
|
||||
}
|
||||
|
||||
#layout-dialog .selected {
|
||||
background: no-repeat scroll 0px -51px transparent;
|
||||
}
|
||||
#layout-dialog .layoutchoice {
|
||||
width: 82px;
|
||||
height: 51px;
|
||||
float:left;
|
||||
list-style-type:none;
|
||||
margin:5px;
|
||||
padding:0;
|
||||
}
|
||||
.selectedcolumn {
|
||||
border: 3px dashed #aaaaaa;
|
||||
}
|
||||
.emptycolumn {
|
||||
font-size:20px;
|
||||
font-weight:bold;
|
||||
color: #aaaaaa;
|
||||
padding: 5px 5px 5px 5px;
|
||||
}
|
||||
|
||||
.dashboard {
|
||||
margin-top: 5px;
|
||||
}
|
||||
.right {
|
||||
float:right;
|
||||
}
|
||||
.widgetheader {
|
||||
padding:2px 2px 5px 5px;
|
||||
}
|
||||
.ui-icon {
|
||||
float:left;
|
||||
}
|
||||
.widgetcontent {
|
||||
padding:2px 2px 5px 5px;
|
||||
}
|
||||
.widget {
|
||||
margin-bottom:10px;
|
||||
}
|
||||
.column {
|
||||
float:left;
|
||||
margin:0 1% -1.5em;
|
||||
padding:0;
|
||||
width:47.5%;
|
||||
}
|
||||
|
||||
.layout-a .column {
|
||||
width:98%;
|
||||
}
|
||||
.layout-a .column.second, .layout-a .column.third {
|
||||
display:none;
|
||||
}
|
||||
.layout-aa .column {
|
||||
width:47.5%;
|
||||
}
|
||||
.layout-aa .third {
|
||||
display:none;
|
||||
}
|
||||
.layout-ba .column {
|
||||
width:68%;
|
||||
}
|
||||
.layout-ba .first {
|
||||
width:27%;
|
||||
}
|
||||
.layout-ba .third {
|
||||
display:none;
|
||||
}
|
||||
.layout-ab .column {
|
||||
width:27%;
|
||||
}
|
||||
.layout-ab .first {
|
||||
width:68%;
|
||||
}
|
||||
.layout-ab .third {
|
||||
display:none;
|
||||
}
|
||||
.layout-aaa .column {
|
||||
width:30.9%;
|
||||
}
|
||||
|
||||
/*body {
|
||||
margin:0;
|
||||
color:#333333;
|
||||
font:12px/1.4 arial,FreeSans,Helvetica,sans-serif;
|
||||
}*/
|
||||
|
||||
.headerlink {
|
||||
color:#ffffff;
|
||||
}
|
||||
|
||||
.headerlinks {
|
||||
text-align:right;
|
||||
margin-right:20px;
|
||||
line-height:24px;
|
||||
text-decoration:underline;
|
||||
font-weight:bold;
|
||||
}
|
||||
|
||||
.headerbox {
|
||||
height:148px;
|
||||
}
|
||||
|
||||
.ui-widget-overlay {
|
||||
opacity:0.5;
|
||||
}
|
||||
|
||||
/*.loading {
|
||||
padding: 50px;
|
||||
text-align: center;
|
||||
background-image:loading.gif;
|
||||
}*/
|
||||
|
||||
|
||||
#layout-dialog ul {
|
||||
margin:0;
|
||||
padding:0;
|
||||
}
|
||||
|
||||
#layout-dialog ul li a, #layout-dialog ul li a:link, #layout-dialog ul li a:visited {
|
||||
border:1px solid #BBBBBB;
|
||||
display:block;
|
||||
float:left;
|
||||
margin:0 1em 1em 0;
|
||||
outline:medium none;
|
||||
padding:0.35em;
|
||||
width:auto;
|
||||
}
|
||||
|
||||
.hidden {
|
||||
display:none;
|
||||
}
|
||||
|
||||
.controls {
|
||||
border:1px solid #BBBBBB;
|
||||
float:none;
|
||||
margin:0;
|
||||
padding:4px 0;
|
||||
}
|
||||
|
||||
.controls {
|
||||
width:100px;
|
||||
background:none repeat scroll 0 0 #dddddd;
|
||||
border:1px solid #6A8EB3;
|
||||
color:#000000;
|
||||
margin-top:-1px;
|
||||
padding:4px 0;
|
||||
position:absolute;
|
||||
right:0;
|
||||
z-index:2003;
|
||||
}
|
||||
|
||||
.controls li {
|
||||
float:none;
|
||||
margin:0;
|
||||
padding:0;
|
||||
list-style-type:none;
|
||||
margin:0 0 0 0.2em;
|
||||
width:auto;
|
||||
position:static;
|
||||
}
|
||||
|
||||
.controls li a {
|
||||
color:#000000;
|
||||
font-weight:normal;
|
||||
float:none;
|
||||
margin:0;
|
||||
text-decoration:none;
|
||||
width:auto;
|
||||
padding-left:5px;
|
||||
}
|
||||
|
||||
.hiddenmenu {
|
||||
position:relative;
|
||||
}
|
||||
|
||||
.dialog .categories {
|
||||
list-style:none outside none;
|
||||
height: 414px;
|
||||
}
|
||||
|
||||
.dialog .categories li.selected button {
|
||||
color:#FFFFFF;
|
||||
font-weight:800;
|
||||
}
|
||||
.dialog .categories li button {
|
||||
background:none repeat scroll 0 0 transparent;
|
||||
border:medium none;
|
||||
color:#666666;
|
||||
font-family:"segoe ui",helvetica,arial,sans-serif;
|
||||
font-size:0.8em;
|
||||
padding:0.4em 1.2em;
|
||||
text-align:left;
|
||||
width:100%;
|
||||
}
|
||||
ul.categories button {
|
||||
cursor:pointer;
|
||||
}
|
||||
|
||||
.widgetitem {
|
||||
border:2px none white;
|
||||
float:left;
|
||||
font-size:0.77em;
|
||||
height:142px;
|
||||
margin:0;
|
||||
overflow:hidden;
|
||||
padding:0 20px 0 142px;
|
||||
width:152px;
|
||||
}
|
||||
|
||||
ol.widgets {
|
||||
float:left;
|
||||
list-style:none outside none;
|
||||
margin:-10px;
|
||||
padding:0;
|
||||
width:auto;
|
||||
}
|
||||
|
||||
.dialog .panel-body {
|
||||
overflow:auto;
|
||||
padding:10px;
|
||||
}
|
||||
|
||||
.dialog .categories {
|
||||
background:none repeat scroll 0 0 #FFFFFF;
|
||||
border-right:1px solid #F0F0F0;
|
||||
float:left;
|
||||
height:100%;
|
||||
list-style:none outside none;
|
||||
margin:0 1.17em 0 0;
|
||||
padding:10px 0 0;
|
||||
width:25%;
|
||||
}
|
||||
|
||||
.dialog .categories li.selected {
|
||||
background:none repeat scroll 0 0 #6699CC;
|
||||
color:#FFFFFF;
|
||||
}
|
||||
|
||||
.widgetitem .add-button {
|
||||
float:left;
|
||||
margin:81px 0 0 -131px;
|
||||
width:auto;
|
||||
}
|
||||
|
||||
.widgetitem h3 {
|
||||
margin:11px 0 0;
|
||||
padding:0;
|
||||
}
|
||||
|
||||
.widgetitem img {
|
||||
border:1px solid #999999;
|
||||
float:left;
|
||||
margin:10px 0 0 -132px;
|
||||
}
|
||||
@@ -1,936 +0,0 @@
|
||||
/*
|
||||
* dashboard 1.0
|
||||
* http://www.gxdeveloperweb.com/dashboard/
|
||||
*
|
||||
* Copyright (c) 2010 Mark Machielsen
|
||||
*
|
||||
* Dual licensed under the MIT and GPL licenses (same as jQuery):
|
||||
* http://www.opensource.org/licenses/mit-license.php
|
||||
* http://www.gnu.org/licenses/gpl.html
|
||||
*
|
||||
*/
|
||||
|
||||
(function($) { // Create closure.
|
||||
|
||||
// Constructor for dashboard object.
|
||||
$.fn.dashboard = function(options) {
|
||||
// Public properties of dashboard.
|
||||
var dashboard = {};
|
||||
var loading;
|
||||
var widgetDirectoryUrl;
|
||||
dashboard.layout;
|
||||
dashboard.element = this;
|
||||
dashboard.id = this.attr("id");
|
||||
dashboard.widgets = {};
|
||||
dashboard.widgetsToAdd = {};
|
||||
dashboard.widgetCategories = {};
|
||||
dashboard.initialized = false;
|
||||
|
||||
// Public methods
|
||||
dashboard.serialize = function() {
|
||||
dashboard.log('entering serialize function',1);
|
||||
var r = '{"layout": "' + dashboard.layout.id + '", "data" : [';
|
||||
// add al widgets in the right order
|
||||
var i=0;
|
||||
if ($('.' + opts.columnClass).length == 0) dashboard.log(opts.columnClass + ' class not found',5);
|
||||
$('.' + opts.columnClass).each(function() {
|
||||
$(this).children().each(function() {
|
||||
if ($(this).hasClass(opts.widgetClass)) {
|
||||
if (i > 0) { r+= ','; }
|
||||
r+= (dashboard.getWidget($(this).attr("id"))).serialize();
|
||||
i++;
|
||||
}
|
||||
});
|
||||
});
|
||||
r+= ']}';
|
||||
return r;
|
||||
}
|
||||
|
||||
dashboard.log = function(msg, level) {
|
||||
if (level >= opts.debuglevel && typeof console != 'undefined') {
|
||||
var l = '';
|
||||
if (level == 1) l = 'INFO';
|
||||
if (level == 2) l = 'EVENT';
|
||||
if (level == 3) l = 'WARNING';
|
||||
if (level == 5) l = 'ERROR';
|
||||
console.log(l + ' - ' + msg);
|
||||
}
|
||||
}
|
||||
|
||||
dashboard.setLayout = function(layout) {
|
||||
if (layout != null) {
|
||||
dashboard.log('entering setLayout function with layout ' + layout.id,1);
|
||||
} else {
|
||||
dashboard.log('entering setLayout function with layout null',1);
|
||||
}
|
||||
dashboard.layout = layout;
|
||||
|
||||
loading.remove();
|
||||
if (dashboard.layout != null) {
|
||||
if (typeof opts.layoutClass != 'undefined') {
|
||||
this.element.find('.' + opts.layoutClass).addClass(dashboard.layout.classname);
|
||||
} else {
|
||||
this.element.html(dashboard.layout.html);
|
||||
}
|
||||
}
|
||||
|
||||
// make the columns sortable, see http://jqueryui.com/demos/sortable/ for explaination
|
||||
$('.' + opts.columnClass).sortable({
|
||||
connectWith: $('.' + opts.columnClass),
|
||||
opacity: opts.opacity,
|
||||
handle: '.' + opts.widgetHeaderClass,
|
||||
over: function(event, ui) {
|
||||
$(this).addClass("selectedcolumn");
|
||||
},
|
||||
out: function(event, ui) {
|
||||
$(this).removeClass("selectedcolumn");
|
||||
},
|
||||
receive: function(event, ui) {
|
||||
// update the column attribute for the widget
|
||||
var w = dashboard.getWidget(ui.item.attr("id"));
|
||||
w.column = getColumnIdentifier($(this).attr("class"));
|
||||
|
||||
dashboard.log('dashboardStateChange event thrown for widget ' + w.id,2);
|
||||
dashboard.element.trigger("dashboardStateChange",{"stateChange":"widgetMoved","widget":w});
|
||||
|
||||
dashboard.log('widgetDropped event thrown for widget ' + w.id,2);
|
||||
w.element.trigger("widgetDropped",{"widget":w});
|
||||
},
|
||||
deactivate: function(event, ui) {
|
||||
// This event is called for each column
|
||||
dashboard.log('Widget is dropped: check if the column is now empty.',1);
|
||||
var childLength = $(this).children().length;
|
||||
if (childLength == 0) {
|
||||
dashboard.log('adding the empty text to the column',1);
|
||||
$(this).html('<div class="emptycolumn">' + opts.emptyColumnHtml + '</div>');
|
||||
} else {
|
||||
if (childLength == 2) {
|
||||
// remove the empty column HTML
|
||||
$(this).find('.emptycolumn').remove();
|
||||
}
|
||||
}
|
||||
},
|
||||
start: function(event, ui) {
|
||||
ui.item.find('.' + opts.widgetTitleClass).addClass('noclick');
|
||||
},
|
||||
stop: function(event, ui) {
|
||||
//sorting changed (within one list)
|
||||
setTimeout(function(){
|
||||
ui.item.find('.' + opts.widgetTitleClass).removeClass('noclick');
|
||||
}, 300);
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
fixSortableColumns();
|
||||
|
||||
// trigger the dashboardLayoutLoaded event
|
||||
dashboard.log('dashboardLayoutLoaded event thrown',2);
|
||||
dashboard.element.trigger("dashboardLayoutLoaded");
|
||||
}
|
||||
|
||||
// This is a workaround for the following problem: when I drag a widget from column2 to column1, sometimes the widget is
|
||||
// moved to column3, which is not visible
|
||||
function fixSortableColumns() {
|
||||
dashboard.log('entering fixSortableColumns function',1);
|
||||
$('.nonsortablecolumn').removeClass('nonsortablecolumn').addClass(opts.columnClass);
|
||||
$('.' + opts.columnClass).filter(function() {return $(this).css("display") == 'none'}).addClass('nonsortablecolumn').removeClass(opts.columnClass);
|
||||
}
|
||||
|
||||
function getColumnIdentifier(classes) {
|
||||
dashboard.log('entering getColumnIdentifier function',1);
|
||||
var r;
|
||||
var s = classes.split(" ");
|
||||
for (var i = 0;i < s.length;i++) {
|
||||
if (s[i].indexOf(opts.columnPrefix) === 0) { r = s[i] };
|
||||
};
|
||||
return r.replace(opts.columnPrefix,'');
|
||||
}
|
||||
|
||||
dashboard.loadLayout = function() {
|
||||
dashboard.log('entering loadLayout function',1);
|
||||
if (typeof opts.json_data.url != 'undefined' && opts.json_data.url.length > 0) {
|
||||
// ajax option
|
||||
dashboard.log('Getting JSON feed : ' + opts.json_data.url,1);
|
||||
$.getJSON(opts.json_data.url, function(json) {
|
||||
if (json == null) {
|
||||
alert('Unable to get json. If you are using chrome: there is an issue with loading json with local files. It works on a server :-)',5);
|
||||
return;
|
||||
}
|
||||
// set the layout
|
||||
var currentLayout = (typeof dashboard.layout != 'undefined') ? dashboard.layout : getLayout(json.layout);
|
||||
dashboard.setLayout(currentLayout);
|
||||
dashboard.loadWidgets(json.data);
|
||||
});
|
||||
} else {
|
||||
// set the layout
|
||||
var currentLayout = (typeof dashboard.layout != 'undefined') ? dashboard.layout : getLayout(opts.json_data.layout);
|
||||
dashboard.setLayout(currentLayout);
|
||||
dashboard.loadWidgets(opts.json_data.data);
|
||||
}
|
||||
};
|
||||
|
||||
dashboard.addWidget = function(obj, column) {
|
||||
dashboard.log('entering addWidget function',1);
|
||||
// add the widget to the column
|
||||
var wid = obj.id;
|
||||
|
||||
// check if the widget is already registered and available in the dom
|
||||
if (typeof dashboard.widgets[wid] != 'undefined' && $('#' + wid).length > 0) {
|
||||
var wi = $('#' + wid);
|
||||
column = dashboard.widgets[wid].column;
|
||||
|
||||
// add it to the column
|
||||
wi.appendTo(column);
|
||||
|
||||
} else {
|
||||
// build the widget
|
||||
dashboard.log('Applying template : ' + opts.widgetTemplate,1);
|
||||
if ($('#' + opts.widgetTemplate).length == 0) dashboard.log('Template "' + opts.widgetTemplate + ' not found',5);
|
||||
var widgetStr = tmpl($('#' + opts.widgetTemplate).html(), obj);
|
||||
var wi = $(widgetStr);
|
||||
|
||||
// add it to the column
|
||||
wi.appendTo(column);
|
||||
|
||||
if(column.find('.emptycolumn').length)
|
||||
column.find('.emptycolumn').remove();
|
||||
|
||||
dashboard.widgets[wid] = widget({
|
||||
id: wid,
|
||||
element: wi,
|
||||
column: obj.column,
|
||||
url: (typeof obj.url != 'undefined' ? obj.url : null),
|
||||
editurl: obj.editurl,
|
||||
title: obj.title,
|
||||
open: obj.open,
|
||||
metadata: obj.metadata
|
||||
});
|
||||
}
|
||||
|
||||
dashboard.log('widgetAdded event thrown for widget ' + wid,2);
|
||||
dashboard.widgets[wid].element.trigger("widgetAdded", {"widget":dashboard.widgets[wid]});
|
||||
|
||||
if (dashboard.initialized) {
|
||||
dashboard.log('dashboardStateChange event thrown for widget ' + wid,2);
|
||||
dashboard.element.trigger("dashboardStateChange",{"stateChange":"widgetAdded","widget":wi});
|
||||
}
|
||||
}
|
||||
|
||||
dashboard.loadWidgets = function(data) {
|
||||
dashboard.log('entering loadWidgets function',1);
|
||||
dashboard.element.find('.' + opts.columnClass).empty();
|
||||
|
||||
|
||||
// This is for the manual feed
|
||||
$(data).each(function() {
|
||||
var column = this.column;
|
||||
dashboard.addWidget(this, dashboard.element.find('.' + opts.columnPrefix + column));
|
||||
}); // end loop for widgets
|
||||
|
||||
// check if there are widgets in the temp dashboard which needs to be moved
|
||||
// this is not the correct place, but otherwise we are too late
|
||||
|
||||
// check if there are still widgets in the temp
|
||||
$('#tempdashboard').find('.' + opts.widgetClass).each(function() {
|
||||
// append it to the first column
|
||||
var firstCol = dashboard.element.find('.' + opts.columnClass + ':first');
|
||||
$(this).appendTo(firstCol);
|
||||
|
||||
// set the new column
|
||||
dashboard.getWidget($(this).attr("id")).column = firstCol.attr("id");
|
||||
});
|
||||
$('#tempdashboard').remove();
|
||||
|
||||
// add the text to the empty columns
|
||||
$('.' + opts.columnClass).each(function() {
|
||||
if ($(this).children().length == 0) {
|
||||
$(this).html('<div class="emptycolumn">' + opts.emptyColumnHtml + '</div>');
|
||||
}
|
||||
});
|
||||
|
||||
dashboard.initialized = true;
|
||||
};
|
||||
|
||||
dashboard.init = function() {
|
||||
dashboard.log('entering init function',1);
|
||||
// load the widgets as fast as we can. After that add the binding
|
||||
dashboard.loadLayout();
|
||||
}
|
||||
|
||||
dashboard.getWidget = function(id) {
|
||||
dashboard.log('entering getWidget function',1);
|
||||
var wi = dashboard.widgets[id];
|
||||
if (typeof wi != 'undefined') {
|
||||
return wi;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Merge in the caller's options with the defaults.
|
||||
var opts = $.extend({}, $.fn.dashboard.defaults, options);
|
||||
var addOpts = $.extend({}, $.fn.dashboard.defaults.addWidgetSettings, options.addWidgetSettings);
|
||||
var layoutOpts = $.extend({}, $.fn.dashboard.defaults.editLayoutSettings, options.editLayoutSettings);
|
||||
|
||||
// Execution 'forks' here and restarts in init(). Tell the user we're busy with a loading.
|
||||
var loading = $(opts.loadingHtml).appendTo(dashboard.element);
|
||||
|
||||
/**
|
||||
* widget object
|
||||
* Private sub-class of dashboard
|
||||
* Constructor starts
|
||||
*/
|
||||
function widget(widget) {
|
||||
|
||||
dashboard.log('entering widget constructor',1);
|
||||
// Merge default options with the options defined for this widget.
|
||||
widget = $.extend({}, $.fn.dashboard.widget.defaults, widget);
|
||||
|
||||
// public functions
|
||||
widget.openContent = function() {
|
||||
// hide the open link, show the close link
|
||||
widget.element.find('.widgetOpen').hide();
|
||||
widget.element.find('.widgetClose').show();
|
||||
|
||||
dashboard.log('entering openContent function',1);
|
||||
widget.open = true;
|
||||
if (!widget.loaded) {
|
||||
// load the content in the widget if the state == open
|
||||
if (this.url != '' && this.url != null && typeof this.url != 'undefined') {
|
||||
// add the loading
|
||||
$(opts.loadingHtml).appendTo(widget.element.find('.' + opts.widgetContentClass));
|
||||
|
||||
dashboard.log('widgetShow event thrown for widget ' + widget.id,2);
|
||||
widget.element.trigger("widgetShow", {"widget":widget});
|
||||
|
||||
widget.element.find('.' + opts.widgetContentClass).load(this.url, function(response, status, xhr) {
|
||||
if (status == "error") {
|
||||
widget.element.find('.' + opts.widgetContentClass).html(opts.widgetNotFoundHtml);
|
||||
}
|
||||
widget.loaded = true;
|
||||
dashboard.log('widgetLoaded event thrown for widget ' + widget.id,2);
|
||||
widget.element.trigger("widgetLoaded", {"widget":widget});
|
||||
});
|
||||
} else {
|
||||
dashboard.log('widgetShow event thrown for widget ' + widget.id,2);
|
||||
widget.element.trigger("widgetShow", {"widget":widget});
|
||||
|
||||
dashboard.log('widgetLoaded event thrown',2);
|
||||
widget.element.trigger("widgetLoaded", {"widget":widget});
|
||||
}
|
||||
} else {
|
||||
dashboard.log('widgetShow event thrown for widget ' + widget.id,2);
|
||||
widget.element.trigger("widgetShow", {"widget":widget});
|
||||
}
|
||||
if (dashboard.initialized) {
|
||||
dashboard.log('dashboardStateChange event thrown for widget ' + widget.id,2);
|
||||
dashboard.element.trigger("dashboardStateChange",{"stateChange":"widgetOpened","widget":widget});
|
||||
}
|
||||
};
|
||||
widget.refreshContent = function() {
|
||||
dashboard.log('entering refreshContent function',1);
|
||||
widget.loaded = false;
|
||||
if (widget.open) {
|
||||
widget.openContent();
|
||||
}
|
||||
}
|
||||
widget.setTitle = function(newTitle){
|
||||
dashboard.log('entering setTitle function',1);
|
||||
widget.title=newTitle;
|
||||
widget.element.find('.' + opts.widgetTitleClass).html(newTitle);
|
||||
if (dashboard.initialized) {
|
||||
dashboard.log('dashboardStateChange event thrown for widget ' + widget.id,2);
|
||||
dashboard.element.trigger("dashboardStateChange",{"stateChange":"titleChanged","widget":widget});
|
||||
}
|
||||
}
|
||||
widget.closeContent = function() {
|
||||
dashboard.log('entering closeContent function',1);
|
||||
widget.open = false;
|
||||
|
||||
dashboard.log('widgetHide event thrown for widget ' + widget.id,2);
|
||||
widget.element.trigger("widgetHide", {"widget":widget});
|
||||
|
||||
// show the open link, hide the close link
|
||||
widget.element.find('.widgetOpen').show();
|
||||
widget.element.find('.widgetClose').hide();
|
||||
|
||||
dashboard.log('dashboardStateChange event thrown for widget ' + widget.id,2);
|
||||
dashboard.element.trigger("dashboardStateChange",{"stateChange":"widgetClosed","widget":widget});
|
||||
};
|
||||
widget.addMetadataValue = function(name, value) {
|
||||
dashboard.log('entering addMetadataValue function',1);
|
||||
if (typeof widget.metadata == 'undefined') {
|
||||
widget.metadata = {};
|
||||
}
|
||||
widget.metadata[name] = value;
|
||||
dashboard.log('dashboardStateChange event thrown for widget ' + widget.id,2);
|
||||
dashboard.element.trigger("dashboardStateChange",{"stateChange":"metadataChanged","widget":widget});
|
||||
};
|
||||
widget.openMenu = function() {
|
||||
dashboard.log('entering openMenu function',1);
|
||||
widget.element.find('.' + opts.menuClass).show();
|
||||
};
|
||||
widget.closeMenu = function() {
|
||||
dashboard.log('entering closeMenu function',1);
|
||||
widget.element.find('.' + opts.menuClass).hide();
|
||||
};
|
||||
widget.remove = function() {
|
||||
dashboard.log('entering remove function',1);
|
||||
widget.element.remove();
|
||||
dashboard.log('widgetDeleted event thrown for widget ' + widget.id,2);
|
||||
widget.element.trigger('widgetDeleted', {"widget":widget});
|
||||
|
||||
dashboard.log('dashboardStateChange event thrown for widget ' + widget.id,2);
|
||||
dashboard.element.trigger("dashboardStateChange",{"stateChange":"widgetRemoved","widget":widget});
|
||||
};
|
||||
widget.serialize = function() {
|
||||
dashboard.log('entering serialize function',1);
|
||||
var r = '{"title" : "' + widget.title + '", "id" : "' + widget.id + '", "column" : "' + widget.column + '","editurl" : "' + widget.editurl + '","open" : ' + widget.open + ',"url" : "' + widget.url + '"';
|
||||
|
||||
if (typeof widget.metadata != 'undefined') {
|
||||
r+= ',"metadata":{'
|
||||
var obj = widget.metadata;
|
||||
var i=0;
|
||||
for(var item in obj) {
|
||||
if (i > 0) { r+= ',' };
|
||||
|
||||
// FIXME: support for more than string, eg numbers subobjects
|
||||
r+= '"' + item + '":"' + obj[item] + '"';
|
||||
i++;
|
||||
}
|
||||
r+= '}'
|
||||
|
||||
}
|
||||
|
||||
r += '}';
|
||||
return r;
|
||||
};
|
||||
widget.openFullscreen = function() {
|
||||
dashboard.log('entering openFullscreen function',1);
|
||||
widget.fullscreen = true;
|
||||
|
||||
// create a clone
|
||||
var clone = widget.element.clone();
|
||||
|
||||
// move the dashboard
|
||||
var temp = $('<div style="display:none" id="tempdashboard_' + dashboard.id + '"></div>');
|
||||
temp.appendTo($("body"));
|
||||
dashboard.element.children().appendTo(temp);
|
||||
|
||||
// add the clone to the dashboard
|
||||
var fs = $('<ul id="fullscreen_' + dashboard.id + '"></ul>');
|
||||
fs.appendTo(dashboard.element);
|
||||
clone.appendTo(fs);
|
||||
|
||||
};
|
||||
widget.closeFullscreen = function() {
|
||||
dashboard.log('entering closeFullscreen function',1);
|
||||
widget.fullscreen = false;
|
||||
|
||||
// remove the fullscreen
|
||||
$('#fullscreen_' + dashboard.id).remove();
|
||||
|
||||
// move the content from the tempdashboard back
|
||||
$('#tempdashboard_' + dashboard.id).children().appendTo(dashboard.element);
|
||||
$('#tempdashboard_' + dashboard.id).remove();
|
||||
|
||||
};
|
||||
widget.openSettings = function() {
|
||||
dashboard.log('entering openSettings function',1);
|
||||
widget.element.find('.' + opts.widgetContentClass).load(widget.editurl);
|
||||
};
|
||||
|
||||
// called when widget is initialized
|
||||
if (widget.open) {
|
||||
widget.openContent();
|
||||
}
|
||||
|
||||
widget.initialized = true;
|
||||
|
||||
dashboard.log('widgetInitialized event thrown',2);
|
||||
widget.element.trigger("widgetInitialized", {"widget":widget});
|
||||
|
||||
return widget;
|
||||
};
|
||||
|
||||
|
||||
// FIXME: can this be done easier??
|
||||
function getLayout(id) {
|
||||
dashboard.log('entering getLayout function',1);
|
||||
var r = null;
|
||||
var first = null;
|
||||
if (typeof opts.layouts != 'undefined') {
|
||||
|
||||
$.each(opts.layouts,function(i, item) {
|
||||
if (i == 0) { first = item; }
|
||||
if (item.id == id) {
|
||||
r = item;
|
||||
}
|
||||
});
|
||||
}
|
||||
if (r == null) { r = first }
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
$('#' + dashboard.id + ' .menutrigger').live('click', function() {
|
||||
dashboard.log('widgetOpenMenu event thrown for widget ' + widget.id,2);
|
||||
var wi = dashboard.getWidget($(this).closest('.' + opts.widgetClass).attr("id"));
|
||||
|
||||
wi.element.trigger('widgetOpenMenu', {"widget":wi});
|
||||
return false;
|
||||
});
|
||||
|
||||
// add event handlers to the menu
|
||||
$('#' + dashboard.id + ' .' + opts.widgetFullScreenClass).live('click',function(e) {
|
||||
// close the menu
|
||||
dashboard.log('widgetCloseMenu event thrown for widget ' + widget.id,2);
|
||||
var wi = dashboard.getWidget($(this).closest('.' + opts.widgetClass).attr("id"));
|
||||
wi.element.trigger('widgetCloseMenu', {"widget":wi});
|
||||
|
||||
if (wi.fullscreen) {
|
||||
dashboard.log('widgetCloseFullScreen event thrown for widget ' + wi.id,2);
|
||||
wi.element.trigger('widgetCloseFullScreen', {"widget":wi});
|
||||
} else {
|
||||
dashboard.log('widgetOpenFullScreen event thrown for widget ' + wi.id,2);
|
||||
wi.element.trigger('widgetOpenFullScreen', {"widget":wi});
|
||||
}
|
||||
return false;
|
||||
});
|
||||
|
||||
$('#' + dashboard.id + ' .controls li').live('click',function(e) {
|
||||
// close the menu
|
||||
dashboard.log('widgetCloseMenu event thrown for widget ' + widget.id,2);
|
||||
|
||||
var wi = dashboard.getWidget($(this).closest('.' + opts.widgetClass).attr("id"));
|
||||
wi.element.trigger('widgetCloseMenu', {"widget":wi});
|
||||
|
||||
// use the class on the li to determine what action to trigger
|
||||
dashboard.log($(this).attr('class') + ' event thrown for widget ' + widget.id,2);
|
||||
|
||||
var wi = dashboard.getWidget($(this).closest('.' + opts.widgetClass).attr("id"));
|
||||
wi.element.trigger($(this).attr('class'), {"widget":wi});
|
||||
return false;
|
||||
});
|
||||
|
||||
// add the menu events (by default triggers are connected in dashboard_jsonfeed)
|
||||
$('#' + dashboard.id + ' .' + opts.widgetClass).live('widgetCloseMenu',function(e,o) {
|
||||
dashboard.log("Closing menu " + $(this).attr("id"),1);
|
||||
o.widget.closeMenu();
|
||||
});
|
||||
|
||||
$('#' + dashboard.id + ' .' + opts.widgetClass).live('widgetOpenMenu',function(e,o) {
|
||||
dashboard.log("Opening menu " + $(this).attr("id"),1);
|
||||
o.widget.openMenu();
|
||||
});
|
||||
|
||||
$('#' + dashboard.id + ' .' + opts.widgetClass).live('widgetDelete',function(e,o) {
|
||||
if (confirm(opts.deleteConfirmMessage)) {
|
||||
dashboard.log("Removing widget " + $(this).attr("id"),1);
|
||||
o.widget.remove();
|
||||
}
|
||||
});
|
||||
|
||||
$('#' + dashboard.id + ' .' + opts.widgetClass).live('widgetRefresh',function(e,o) {
|
||||
o.widget.refreshContent();
|
||||
});
|
||||
|
||||
$('#' + dashboard.id + ' .' + opts.widgetClass).live('widgetSetTitle',function(event, o) {
|
||||
o.widget.setTitle(o.title);
|
||||
});
|
||||
|
||||
$('#' + dashboard.id + ' .' + opts.widgetClass).live('widgetClose',function(e,o) {
|
||||
dashboard.log("Closing widget " + $(this).attr("id"),1);
|
||||
o.widget.closeContent();
|
||||
});
|
||||
|
||||
$('#' + dashboard.id + ' .' + opts.widgetClass).live('widgetOpen',function(e,o) {
|
||||
dashboard.log("Opening widget " + $(this).attr("id"),1);
|
||||
o.widget.openContent();
|
||||
});
|
||||
|
||||
$('#' + dashboard.id + ' .' + opts.widgetClass).live('widgetShow',function() {
|
||||
$(this).find('.' + opts.widgetContentClass).show();
|
||||
});
|
||||
|
||||
$('#' + dashboard.id + ' .' + opts.widgetClass).live('widgetHide',function() {
|
||||
$(this).find('.' + opts.widgetContentClass).hide();
|
||||
});
|
||||
|
||||
$('#' + dashboard.id + ' .' + opts.widgetClass).live('widgetAddMetadataValue',function(e,o) {
|
||||
dashboard.log("Changing metadata for widget " + $(this).attr("id") + ", metadata name: " + o.name + ", value: " + o.value, 1);
|
||||
o.widget.addMetadataValue(o.name, o.value);
|
||||
});
|
||||
|
||||
// Define a toggle event when clicking at the header
|
||||
$('#' + dashboard.id + ' .' + opts.widgetTitleClass).live('click',function(e) {
|
||||
dashboard.log("Click on the header detected for widget " + $(this).attr("id"),1);
|
||||
if (!$(this).hasClass('noclick')) {
|
||||
var wi = dashboard.getWidget($(this).closest('.' + opts.widgetClass).attr("id"));
|
||||
if (wi.open) {
|
||||
dashboard.log('widgetClose event thrown for widget ' + wi,2);
|
||||
wi.element.trigger('widgetClose', {"widget":wi});
|
||||
} else {
|
||||
dashboard.log('widgetOpen event thrown for widget ' + wi,2);
|
||||
wi.element.trigger('widgetOpen', {"widget":wi});
|
||||
}
|
||||
}
|
||||
return false;
|
||||
});
|
||||
|
||||
$('#' + dashboard.id + ' .' + opts.widgetHeaderClass).live('mouseover',function () {
|
||||
$(this).find('.' + opts.iconsClass).removeClass("hidden");
|
||||
});
|
||||
|
||||
$('#' + dashboard.id + ' .' + opts.widgetHeaderClass).live('mouseout', function () {
|
||||
$(this).find('.' + opts.iconsClass).addClass("hidden");
|
||||
});
|
||||
|
||||
$('body').click(function() {
|
||||
$('.' + opts.menuClass).hide();
|
||||
});
|
||||
|
||||
$('#' + dashboard.id + ' .' + opts.widgetClass).live('widgetOpenFullScreen',function(e,o) {
|
||||
o.widget.openFullscreen();
|
||||
});
|
||||
|
||||
$('.' + opts.widgetClass).live('widgetCloseFullScreen',function(e,o) {
|
||||
o.widget.closeFullscreen();
|
||||
});
|
||||
|
||||
$('#' + dashboard.id + ' .' + opts.widgetClass).live('widgetEdit',function(e,o) {
|
||||
o.widget.openSettings();
|
||||
});
|
||||
|
||||
if ($('#' + addOpts.dialogId).length == 0) dashboard.log('Unable to find ' + addOpts.dialogId,5);
|
||||
$('#' + addOpts.dialogId).dialog({
|
||||
autoOpen: false,
|
||||
height: 414,
|
||||
width: 550,
|
||||
modal: true,
|
||||
buttons: {
|
||||
Cancel: function() {
|
||||
$(this).dialog('close');
|
||||
}
|
||||
},
|
||||
close: function() {
|
||||
//close
|
||||
}
|
||||
});
|
||||
|
||||
if ($('#' + layoutOpts.dialogId).length == 0) dashboard.log('Unable to find ' + layoutOpts.dialogId,5);
|
||||
$('#' + layoutOpts.dialogId).dialog({
|
||||
autoOpen: false,
|
||||
height: 300,
|
||||
width: 600,
|
||||
modal: true
|
||||
});
|
||||
|
||||
$('.' + layoutOpts.openDialogClass).live('click', function(){
|
||||
dashboard.log('dashboardOpenLayoutDialog event thrown',2);
|
||||
dashboard.element.trigger("dashboardOpenLayoutDialog");
|
||||
return false;
|
||||
});
|
||||
|
||||
dashboard.element.live('dashboardOpenLayoutDialog', function(){
|
||||
dashboard.log('Opening dialog ' + layoutOpts.dialogId,1);
|
||||
$('#' + layoutOpts.dialogId).dialog('open');
|
||||
|
||||
// add the layout images
|
||||
var h = $('#' + layoutOpts.dialogId).find('.' + layoutOpts.layoutClass);
|
||||
h.empty();
|
||||
if (h.children().length == 0) {
|
||||
dashboard.log('Number of layouts : ' + opts.layouts.length,1);
|
||||
$.each(opts.layouts,function(i, item) {
|
||||
dashboard.log('Applying template : ' + layoutOpts.layoutTemplate,1);
|
||||
if ($('#' + layoutOpts.layoutTemplate).length == 0) dashboard.log('Template "' + layoutOpts.layoutTemplate + ' not found',5);
|
||||
h.append(tmpl($('#' + layoutOpts.layoutTemplate).html(), item));
|
||||
});
|
||||
}
|
||||
|
||||
// set the selected class for the selected layout
|
||||
$('.' + layoutOpts.selectLayoutClass).removeClass(layoutOpts.selectedLayoutClass);
|
||||
$('#' + dashboard.layout.id).addClass(layoutOpts.selectedLayoutClass);
|
||||
|
||||
bindSelectLayout();
|
||||
});
|
||||
|
||||
|
||||
dashboard.element.live('dashboardStateChange', function(){
|
||||
if (typeof opts.stateChangeUrl != 'undefined' && opts.stateChangeUrl != null && opts.stateChangeUrl != '') {
|
||||
$.ajax({type: 'POST',
|
||||
url: opts.stateChangeUrl,
|
||||
data: { dashboard: dashboard.element.attr("id"), settings: dashboard.serialize() },
|
||||
success: function(data){
|
||||
if (data == "NOK" || data.indexOf('<response>NOK</response>') != -1){
|
||||
dashboard.log('dashboardSaveFailed event thrown',2);
|
||||
dashboard.element.trigger("dashboardSaveFailed");
|
||||
} else {
|
||||
dashboard.log('dashboardSuccessfulSaved event thrown',2);
|
||||
dashboard.element.trigger("dashboardSuccessfulSaved");
|
||||
}
|
||||
},
|
||||
error: function(XMLHttpRequest, textStatus, errorThrown){
|
||||
dashboard.log('dashboardSaveFailed event thrown',2);
|
||||
dashboard.element.trigger("dashboardSaveFailed");
|
||||
},
|
||||
dataType: "text"
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
dashboard.element.live('dashboardCloseLayoutDialog', function(){
|
||||
// close the dialog
|
||||
$('#' + layoutOpts.dialogId).dialog('close');
|
||||
});
|
||||
|
||||
// FIXME: why doesn't the live construct work in this case
|
||||
function bindSelectLayout() {
|
||||
if ($('.' + layoutOpts.selectLayoutClass).length == 0) dashboard.log('Unable to find ' + layoutOpts.selectLayoutClass,5);
|
||||
$('.' + layoutOpts.selectLayoutClass).bind('click', function(e){
|
||||
var currentLayout = dashboard.layout;
|
||||
|
||||
dashboard.log('dashboardCloseLayoutDialog event thrown',2);
|
||||
dashboard.element.trigger('dashboardCloseLayoutDialog');
|
||||
|
||||
// Now set the new layout
|
||||
var newLayout = getLayout($(this).attr("id"));
|
||||
dashboard.layout = newLayout;
|
||||
|
||||
// remove the class of the old layout
|
||||
if (typeof opts.layoutClass != 'undefined') {
|
||||
dashboard.element.find('.' + opts.layoutClass).removeClass(currentLayout.classname).addClass(newLayout.classname);
|
||||
|
||||
fixSortableColumns();
|
||||
|
||||
// check if there are widgets in hidden columns, move them to the first column
|
||||
if ($('.' + opts.columnClass).length == 0) dashboard.log('Unable to find ' + opts.columnClass,5);
|
||||
dashboard.element.find('.' + opts.columnClass).each(function() {
|
||||
if ($(this).css("display") == "none") {
|
||||
// move the widgets to the first column
|
||||
$(this).children().appendTo(dashboard.element.find('.' + opts.columnClass + ':first'));
|
||||
}
|
||||
|
||||
$('.emptycolumn').remove();
|
||||
// add the text to the empty columns
|
||||
$('.' + opts.columnClass).each(function() {
|
||||
if ($(this).children().length == 0) {
|
||||
$(this).html('<div class="emptycolumn">' + opts.emptyColumnHtml + '</div>');
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
});
|
||||
|
||||
} else {
|
||||
// set the new layout, but first move the dashboard to a temp
|
||||
var temp = $('<div style="display:none" id="tempdashboard"></div>');
|
||||
temp.appendTo($("body"));
|
||||
|
||||
dashboard.element.children().appendTo(temp);
|
||||
|
||||
// reload the dashboard
|
||||
dashboard.init();
|
||||
}
|
||||
|
||||
// throw an event upon changing the layout.
|
||||
dashboard.log('dashboardChangeLayout event thrown',2);
|
||||
dashboard.element.trigger('dashboardLayoutChanged');
|
||||
|
||||
});
|
||||
return false;
|
||||
}
|
||||
|
||||
$('.' + addOpts.selectCategoryClass).live('click', function(){
|
||||
dashboard.log('addWidgetDialogSelectCategory event thrown',2);
|
||||
dashboard.element.trigger('addWidgetDialogSelectCategory', {"category":$(this)});
|
||||
return false;
|
||||
});
|
||||
|
||||
dashboard.element.live('addWidgetDialogSelectCategory', function(e, obj){
|
||||
// remove the category selection
|
||||
$('.' + addOpts.selectCategoryClass).removeClass(addOpts.selectedCategoryClass);
|
||||
|
||||
// empty the widgets div
|
||||
$('#' + addOpts.dialogId).find('.' + addOpts.widgetClass).empty();
|
||||
|
||||
// select the category
|
||||
$(obj.category).addClass(addOpts.selectedCategoryClass);
|
||||
|
||||
// get the widgets
|
||||
url = dashboard.widgetCategories[$(obj.category).attr("id")];
|
||||
|
||||
dashboard.log('Getting JSON feed : ' + url,1);
|
||||
$.getJSON(url, {"cache":true}, function(json) {
|
||||
// load the widgets from the category
|
||||
if (json.data == 0) dashboard.log('Empty data returned',3);
|
||||
$.each(json.data, function(i,item){
|
||||
dashboard.widgetsToAdd[item.id] = item;
|
||||
|
||||
dashboard.log('Applying template : ' + addOpts.widgetTemplate,1);
|
||||
if ($('#' + addOpts.widgetTemplate).length == 0) dashboard.log('Template "' + addOpts.widgetTemplate + ' not found',5);
|
||||
var html = tmpl($('#' + addOpts.widgetTemplate).html(), item);
|
||||
$('#' + addOpts.dialogId).find('.' + addOpts.widgetClass).append(html);
|
||||
});
|
||||
});
|
||||
|
||||
dashboard.log('addWidgetDialogWidgetsLoaded event thrown',2);
|
||||
dashboard.element.trigger('addWidgetDialogWidgetsLoaded');
|
||||
});
|
||||
|
||||
|
||||
$('.' + addOpts.addWidgetClass).live('click', function(){
|
||||
var widget = dashboard.widgetsToAdd[$(this).attr("id").replace('addwidget','')];
|
||||
dashboard.log('dashboardAddWidget event thrown',2);
|
||||
dashboard.element.trigger('dashboardAddWidget', {"widget":widget});
|
||||
|
||||
dashboard.log('dashboardCloseWidgetDialog event thrown',2);
|
||||
dashboard.element.trigger('dashboardCloseWidgetDialog');
|
||||
return false;
|
||||
});
|
||||
|
||||
$('.' + addOpts.openDialogClass).live('click', function(){
|
||||
dashboard.log('dashboardOpenWidgetDialog event thrown',2);
|
||||
dashboard.element.trigger('dashboardOpenWidgetDialog');
|
||||
return false;
|
||||
});
|
||||
|
||||
dashboard.element.live('dashboardCloseWidgetDialog', function(){
|
||||
// close the dialog
|
||||
$('#' + addOpts.dialogId).dialog('close');
|
||||
});
|
||||
|
||||
dashboard.element.live('dashboardOpenWidgetDialog', function(){
|
||||
|
||||
//remove existing categories/widgets from the DOM, to prevent duplications
|
||||
$('#' + addOpts.dialogId).find('.' + addOpts.categoryClass).empty();
|
||||
$('#' + addOpts.dialogId).find('.' + addOpts.widgetClass).empty();
|
||||
|
||||
dashboard.log('Opening dialog ' + addOpts.dialogId,1);
|
||||
$('#' + addOpts.dialogId).dialog('open');
|
||||
|
||||
dashboard.log('Getting JSON feed : ' + addOpts.widgetDirectoryUrl,1);
|
||||
$.getJSON(addOpts.widgetDirectoryUrl, function(json) {
|
||||
if (json.category == 0) dashboard.log('Empty data returned',3);
|
||||
$.each(json.category, function(i,item){
|
||||
// Add the categories to the dashboard
|
||||
dashboard.widgetCategories[item.id] = item.url;
|
||||
|
||||
dashboard.log('Applying template : ' + addOpts.categoryTemplate,1);
|
||||
if ($('#' + addOpts.categoryTemplate).length == 0) dashboard.log('Template "' + addOpts.categoryTemplate + ' not found',5);
|
||||
var html = tmpl($('#' + addOpts.categoryTemplate).html(),item);
|
||||
$('#' + addOpts.dialogId).find('.' + addOpts.categoryClass).append(html);
|
||||
});
|
||||
dashboard.log('addWidgetDialogCategoriesLoaded event thrown',2);
|
||||
dashboard.element.trigger('addWidgetDialogCategoriesLoaded');
|
||||
|
||||
dashboard.log('addWidgetDialogSelectCategory event thrown',2);
|
||||
dashboard.element.trigger('addWidgetDialogSelectCategory', {"category":$('#' + addOpts.dialogId).find('.' + addOpts.categoryClass + '>li:first')});
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
return dashboard;
|
||||
};
|
||||
|
||||
|
||||
// Public static properties of dashboard. Default settings.
|
||||
$.fn.dashboard.defaults = {
|
||||
debuglevel:3,
|
||||
json_data: {},
|
||||
loadingHtml: '<div class="loading"><img alt="Loading, please wait" src="../themes/default/loading.gif" /><p>Loading...</p></div>',
|
||||
emptyColumnHtml: 'Drag your widgets here',
|
||||
widgetTemplate: 'widgettemplate',
|
||||
columnPrefix: 'column-',
|
||||
opacity:"0.2",
|
||||
deleteConfirmMessage: "Are you sure you want to delete this widget?",
|
||||
widgetNotFoundHtml: "The content of this widget is not available anymore. You may remove this widget.",
|
||||
columnClass: 'column',
|
||||
widgetClass: 'widget',
|
||||
menuClass: 'controls',
|
||||
widgetContentClass: 'widgetcontent',
|
||||
widgetTitleClass: 'widgettitle',
|
||||
widgetHeaderClass: 'widgetheader',
|
||||
widgetFullScreenClass: 'widgetopenfullscreen',
|
||||
iconsClass: 'icons',
|
||||
stateChangeUrl: '',
|
||||
|
||||
addWidgetSettings: {
|
||||
openDialogClass: 'openaddwidgetdialog',
|
||||
addWidgetClass: 'addwidget',
|
||||
selectCategoryClass: 'selectcategory',
|
||||
selectedCategoryClass: 'selected',
|
||||
categoryClass: 'categories',
|
||||
widgetClass: 'widgets',
|
||||
|
||||
dialogId: 'addwidgetdialog',
|
||||
|
||||
categoryTemplate: 'categorytemplate',
|
||||
widgetTemplate: 'addwidgettemplate'
|
||||
},
|
||||
editLayoutSettings: {
|
||||
dialogId: 'editLayout',
|
||||
layoutClass: 'layoutselection',
|
||||
selectLayoutClass: 'layoutchoice',
|
||||
selectedLayoutClass: 'selected',
|
||||
openDialogClass: 'editlayout',
|
||||
layoutTemplate: 'selectlayouttemplate'
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
// Default widget settings.
|
||||
$.fn.dashboard.widget = {
|
||||
defaults: {
|
||||
open: true,
|
||||
fullscreen: false,
|
||||
loaded: false,
|
||||
url: '',
|
||||
metadata: {}
|
||||
}
|
||||
};
|
||||
|
||||
})(jQuery); // end of closure
|
||||
|
||||
|
||||
// Simple JavaScript Templating
|
||||
// John Resig - http://ejohn.org/ - MIT Licensed
|
||||
(function(){
|
||||
var cache = {};
|
||||
|
||||
this.tmpl = function tmpl(str, data){
|
||||
// Figure out if we're getting a template, or if we need to
|
||||
// load the template - and be sure to cache the result.
|
||||
|
||||
var fn = !/\W/.test(str) ?
|
||||
cache[str] = cache[str] ||
|
||||
tmpl(document.getElementById(str).innerHTML) :
|
||||
|
||||
// Generate a reusable function that will serve as a template
|
||||
// generator (and which will be cached).
|
||||
new Function("obj",
|
||||
"var p=[],print=function(){p.push.apply(p,arguments);};" +
|
||||
|
||||
// Introduce the data as local variables using with(){}
|
||||
"with(obj){p.push('" +
|
||||
|
||||
// Convert the template into pure JavaScript
|
||||
str
|
||||
.replace(/[\r\t\n]/g, " ")
|
||||
.split("<%").join("\t")
|
||||
.replace(/((^|%>)[^\t]*)'/g, "$1\r")
|
||||
.replace(/\t=(.*?)%>/g, "',$1,'")
|
||||
.split("\t").join("');")
|
||||
.split("%>").join("p.push('")
|
||||
.split("\r").join("\\'")
|
||||
+ "');}return p.join('');");
|
||||
|
||||
// Provide some basic currying to the user
|
||||
return data ? fn( data ) : fn;
|
||||
};
|
||||
})();
|
||||
@@ -0,0 +1,36 @@
|
||||
.column {
|
||||
float: left;
|
||||
padding-bottom: 100px;
|
||||
}
|
||||
|
||||
.portlet {
|
||||
margin: 0 1em 1em 0;
|
||||
}
|
||||
|
||||
.portlet-header {
|
||||
margin: 0.3em;
|
||||
padding-bottom: 4px;
|
||||
padding-left: 0.2em;
|
||||
}
|
||||
|
||||
.portlet-header:hover {
|
||||
cursor: move;
|
||||
}
|
||||
|
||||
.portlet-header .ui-icon {
|
||||
float: right;
|
||||
}
|
||||
|
||||
.portlet-content {
|
||||
padding: 0.4em;
|
||||
}
|
||||
|
||||
.ui-sortable-placeholder {
|
||||
border: 1px dotted black;
|
||||
visibility: visible !important;
|
||||
height: 50px !important;
|
||||
}
|
||||
|
||||
.ui-sortable-placeholder * {
|
||||
visibility: hidden;
|
||||
}
|
||||
@@ -1,85 +0,0 @@
|
||||
<script type="text/html" id="categorytemplate">
|
||||
<li id="<%= id %>" class="selectcategory"><button><%= title %> (<%= amount %>)</button></li>
|
||||
</script>
|
||||
|
||||
|
||||
<script type="text/html" id="widgettemplate">
|
||||
<div class="ui-widget ui-corner-all ui-widget-content widget" id="<%= id %>" title="<%= title %>">
|
||||
<div class="ui-widget-header ui-corner-all widgetheader">
|
||||
<span class="widgettitle"><%= title %></span>
|
||||
<span class="right icons hidden">
|
||||
<span class="ui-icon ui-icon-newwin widgetopenfullscreen"></span>
|
||||
<span class="ui-icon ui-icon-arrowthickstop-1-s menutrigger"></span>
|
||||
<span class="hiddenmenu">
|
||||
<ul style="top: 13px;" class="hidden controls ui-widget-header">
|
||||
<li class="widgetClose">
|
||||
<span class="ui-icon ui-icon-minus"></span>
|
||||
<a class="minimization" href="#">Minimize</a>
|
||||
</li>
|
||||
<li class="widgetOpen">
|
||||
<span class="ui-icon ui-icon-extlink"></span>
|
||||
<a class="minimization" href="#">Maximize</a>
|
||||
</li>
|
||||
<li class="widgetDelete">
|
||||
<span class="ui-icon ui-icon-close"></span>
|
||||
<a class="delete" href="#">Delete</a>
|
||||
</li>
|
||||
<!-- This could be implemented -->
|
||||
<!--
|
||||
<li class="widgetEdit">
|
||||
<span class="ui-icon ui-icon-tag"></span>
|
||||
<a class="no_target" href="#">Edit</a>
|
||||
</li>
|
||||
-->
|
||||
<li class="widgetRefresh">
|
||||
<span class="ui-icon ui-icon-arrowrefresh-1-w"></span>
|
||||
<a class="no_target" href="#">Refresh</a>
|
||||
</li>
|
||||
</ul>
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
<div class="widgetcontent">
|
||||
</div>
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script type="text/html" id="selectlayouttemplate">
|
||||
<li class="layoutchoice" id="<%= id %>" style="background-image: url('<%= image %>')"></li>
|
||||
</script>
|
||||
|
||||
<script type="text/html" id="addwidgettemplate">
|
||||
|
||||
<li class="widgetitem">
|
||||
<img src="<%= image %>" alt="" height="60" width="120">
|
||||
<div class="add-button">
|
||||
<input class="macro-button-add addwidget" id="addwidget<%= id %>" value="Add it Now" type="button"><br>
|
||||
<input class="macro-hidden-uri" value="<%= url %>" type="hidden">
|
||||
</div>
|
||||
<!-- // .add-button -->
|
||||
<h3><a href=""><%= title %></a></h3>
|
||||
|
||||
<p>By <%= creator %></p>
|
||||
<p><%= description %></p>
|
||||
</li>
|
||||
|
||||
</script>
|
||||
|
||||
<div class="dialog" id="addwidgetdialog" title="Widget Directory">
|
||||
<ul class="categories">
|
||||
</ul>
|
||||
|
||||
<div class="panel-body">
|
||||
<ol id="category-all" class="widgets">
|
||||
</ol>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="dialog" id="editLayout" title="Edit layout">
|
||||
<div class="panel-body" id="layout-dialog">
|
||||
<p><strong>Choose dashboard layout</strong></p>
|
||||
<ul class="layoutselection">
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
@@ -10,39 +10,70 @@ openerp.base.form.Board = openerp.base.form.Widget.extend({
|
||||
},
|
||||
start: function() {
|
||||
this._super.apply(this, arguments);
|
||||
this.$element.html(QWeb.render(this.template));
|
||||
},
|
||||
|
||||
render: function() {
|
||||
var self = this;
|
||||
jQuery('body').append(
|
||||
jQuery('<div>', {'id': 'dashboard_template'}).load('/base_dashboard/static/src/dashboard_template.html',self.on_loaded).hide()
|
||||
)
|
||||
},
|
||||
|
||||
on_loaded: function() {
|
||||
|
||||
this.$element.html(QWeb.render(this.template));
|
||||
var $dashboard = this.$element.find('#dashboard');
|
||||
var children = this.node.children;
|
||||
var board = jQuery('#dashboard').dashboard({
|
||||
layoutClass:'layout'
|
||||
});
|
||||
board.init();
|
||||
for(var ch = 0; ch < children.length; ch++) {
|
||||
var ch_widgets = children[ch].children;
|
||||
for(var chld = 0; chld < ch_widgets.length; chld++) {
|
||||
var widget_type = ch_widgets[chld].tag;
|
||||
var child_index = widget_type == 'action' ? chld : ch;
|
||||
var widget = new (openerp.base.form.widgets.get_object(widget_type)) (this.view, ch_widgets[chld], board, child_index);
|
||||
widget.start();
|
||||
|
||||
for(var ch=0; ch < children.length; ch++) {
|
||||
var node = children[ch];
|
||||
|
||||
var widget;
|
||||
if(node.tag.indexOf('child') >= 0) {
|
||||
widget = new (openerp.base.form.widgets.get_object('child')) (this.view, node, $dashboard);
|
||||
} else {
|
||||
//Vpaned
|
||||
widget = new (openerp.base.form.widgets.get_object(node.tag)) (this.view, node, $dashboard);
|
||||
}
|
||||
|
||||
widget.start();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
jQuery('.column').css('width', 100/children.length+'%');
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
openerp.base.form.Dashbar = openerp.base.form.Widget.extend({
|
||||
init: function(view, node, dashboard) {
|
||||
this._super(view, node, dashboard);
|
||||
this.dashboard = dashboard;
|
||||
this.template = 'Portlet'
|
||||
},
|
||||
start: function() {
|
||||
var $dashboard = this.dashboard;
|
||||
var children = this.node.children;
|
||||
$dashboard.append(QWeb.render(this.template, {widget: this, 'children': children}))
|
||||
|
||||
for(var chld=0; chld < children.length;chld++) {
|
||||
var child = children[chld];
|
||||
var widget = new (openerp.base.form.widgets.get_object(child.tag)) (this.view, child);
|
||||
widget.start()
|
||||
}
|
||||
$( ".column" ).sortable({
|
||||
connectWith: ".column",
|
||||
scroll: false
|
||||
});
|
||||
|
||||
$( ".portlet" ).addClass( "ui-widget ui-widget-content ui-helper-clearfix ui-corner-all" )
|
||||
.find( ".portlet-header" )
|
||||
.addClass( "ui-widget-header ui-corner-all" )
|
||||
.end()
|
||||
.find( ".portlet-content" );
|
||||
|
||||
$( ".portlet-header .ui-icon" ).click(function() {
|
||||
$( this ).toggleClass( "ui-icon-minusthick" ).toggleClass( "ui-icon-plusthick" );
|
||||
$( this ).parents( ".portlet:first" ).find( ".portlet-content" ).toggle();
|
||||
});
|
||||
|
||||
$( ".column" ).disableSelection();
|
||||
}
|
||||
})
|
||||
|
||||
openerp.base.form.Action = openerp.base.form.Widget.extend({
|
||||
init: function(view, node, board, child_index) {
|
||||
this._super(view, node, board, child_index);
|
||||
this.board = board;
|
||||
this.child_index = child_index;
|
||||
init: function(view, node) {
|
||||
this._super(view, node);
|
||||
},
|
||||
start: function() {
|
||||
this._super.apply(this, arguments);
|
||||
@@ -54,26 +85,17 @@ openerp.base.form.Action = openerp.base.form.Widget.extend({
|
||||
|
||||
on_load_action: function(result) {
|
||||
var action = result.action;
|
||||
|
||||
action.search_view = false;
|
||||
action.no_sidebar = true;
|
||||
action.search_view_id = false;
|
||||
|
||||
action.flags = {
|
||||
search_view : false,
|
||||
sidebar : false,
|
||||
views_switcher : false,
|
||||
action_buttons : false
|
||||
}
|
||||
var node_attrs = this.node.attrs;
|
||||
var get_column = ['first', 'second', 'third'];
|
||||
var board_element = this.board.element.find('[id=column-'+get_column[this.child_index]+']');
|
||||
|
||||
this.board.addWidget({
|
||||
'id': node_attrs.name,
|
||||
'title': node_attrs.string,
|
||||
}, board_element);
|
||||
|
||||
var content_id = node_attrs.name+'-widgetcontent';
|
||||
this.board.getWidget(node_attrs.name).element.find('.widgetcontent').attr('id',content_id)
|
||||
|
||||
action_manager = new openerp.base.ActionManager(this.session, content_id);
|
||||
var content_id = 'portlet-content-'+node_attrs.name;
|
||||
var action_manager = new openerp.base.ActionManager(this.session, content_id);
|
||||
action_manager.start();
|
||||
this.board.getWidget(node_attrs.name).url = action_manager.do_action(action);
|
||||
action_manager.do_action(action);
|
||||
}
|
||||
})
|
||||
|
||||
@@ -99,6 +121,7 @@ openerp.base.form.Vpaned = openerp.base.form.Widget.extend({
|
||||
})
|
||||
|
||||
openerp.base.form.widgets.add('hpaned', 'openerp.base.form.Board');
|
||||
openerp.base.form.widgets.add('child', 'openerp.base.form.Dashbar');
|
||||
openerp.base.form.widgets.add('vpaned', 'openerp.base.form.Vpaned');
|
||||
openerp.base.form.widgets.add('action', 'openerp.base.form.Action');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,12 +1,17 @@
|
||||
<template>
|
||||
<t t-name="Board">
|
||||
<div id="dashboard" class="dashboard">
|
||||
<!-- this HTML covers all layouts. The 5 different layouts are handled by setting another layout classname -->
|
||||
<div class="layout">
|
||||
<div id="column-first" class="column first column-first"></div>
|
||||
<div id="column-second" class="column second column-second"></div>
|
||||
<div id="column-third" class="column third column-third"></div>
|
||||
</div>
|
||||
<div id="dashboard" class="demo">
|
||||
</div>
|
||||
</t>
|
||||
<t t-name="Portlet">
|
||||
<div t-att-id="widget.node.tag" class="column">
|
||||
<div class="portlet" t-foreach="children" t-as="child" t-att-id="child.attrs.name">
|
||||
<div class="portlet-header">
|
||||
<t t-esc="child.attrs.string"/>
|
||||
<span class="ui-icon ui-icon-minusthick"></span>
|
||||
</div>
|
||||
<div class="portlet-content" t-att-id="'portlet-content-'+child.attrs.name"></div>
|
||||
</div>
|
||||
</div>
|
||||
</t>
|
||||
</template>
|
||||
@@ -3,8 +3,8 @@
|
||||
"version": "2.0",
|
||||
"depends": ['base'],
|
||||
"js": [
|
||||
'static/lib/dhtmlxGantt/codebase/dhtmlxcommon.js',
|
||||
'static/lib/dhtmlxGantt/codebase/dhtmlxgantt.js',
|
||||
'static/lib/dhtmlxGantt/sources/dhtmlxcommon.js',
|
||||
'static/lib/dhtmlxGantt/sources/dhtmlxgantt.js',
|
||||
'static/src/js/gantt.js'
|
||||
],
|
||||
"css": ['static/lib/dhtmlxGantt/codebase/dhtmlxgantt.css'],
|
||||
|
||||
@@ -1,184 +1,11 @@
|
||||
import glob, os
|
||||
from xml.etree import ElementTree
|
||||
import math
|
||||
import simplejson
|
||||
import openerpweb
|
||||
import time
|
||||
import datetime
|
||||
from base.controllers.main import Xml2Json
|
||||
|
||||
from base.controllers.main import View
|
||||
|
||||
COLOR_PALETTE = ['#f57900', '#cc0000', '#d400a8', '#75507b', '#3465a4', '#73d216', '#c17d11', '#edd400',
|
||||
'#fcaf3e', '#ef2929', '#ff00c9', '#ad7fa8', '#729fcf', '#8ae234', '#e9b96e', '#fce94f',
|
||||
'#ff8e00', '#ff0000', '#b0008c', '#9000ff', '#0078ff', '#00ff00', '#e6ff00', '#ffff00',
|
||||
'#905000', '#9b0000', '#840067', '#510090', '#0000c9', '#009b00', '#9abe00', '#ffc900', ]
|
||||
|
||||
_colorline = ['#%02x%02x%02x' % (25 + ((r + 10) % 11) * 23, 5 + ((g + 1) % 11) * 20, 25 + ((b + 4) % 11) * 23) for r in range(11) for g in range(11) for b in range(11) ]
|
||||
|
||||
def choice_colors(n):
|
||||
if n > len(COLOR_PALETTE):
|
||||
return _colorline[0:-1:len(_colorline) / (n + 1)]
|
||||
elif n:
|
||||
return COLOR_PALETTE[:n]
|
||||
return []
|
||||
|
||||
class GanttView(openerpweb.Controller):
|
||||
class GanttView(View):
|
||||
_cp_path = "/base_gantt/ganttview"
|
||||
|
||||
date_start = None
|
||||
date_delay = None
|
||||
date_stop = None
|
||||
color_field = None
|
||||
|
||||
day_length = 8
|
||||
fields = {}
|
||||
events = []
|
||||
calendar_fields = {}
|
||||
ids = []
|
||||
model = ''
|
||||
domain = []
|
||||
context = {}
|
||||
event_res = []
|
||||
colors = {}
|
||||
color_values = []
|
||||
|
||||
|
||||
@openerpweb.jsonrequest
|
||||
def load(self, req, model, view_id):
|
||||
m = req.session.model(model)
|
||||
r = m.fields_view_get(view_id, 'gantt')
|
||||
r["arch"] = Xml2Json.convert_to_structure(r["arch"])
|
||||
return {'fields_view':r}
|
||||
|
||||
@openerpweb.jsonrequest
|
||||
def get_events(self, req, **kw):
|
||||
fields_view = self.fields_view_get(req, model, view_id, 'gantt')
|
||||
return {'fields_view':fields_view}
|
||||
|
||||
self.model = kw['model']
|
||||
self.fields = kw['fields']
|
||||
self.day_length = kw['day_length']
|
||||
self.calendar_fields = kw['calendar_fields']
|
||||
self.color_field = kw.get('color_field') or self.color_field or None
|
||||
self.fields[self.color_field] = ""
|
||||
self.colors = kw.get('colors') or {}
|
||||
self.text = self.calendar_fields['text']['name']
|
||||
|
||||
self.date_start = self.calendar_fields['date_start']['name']
|
||||
self.fields[self.date_start] = ""
|
||||
|
||||
if self.calendar_fields.get('date_stop'):
|
||||
self.date_stop = self.calendar_fields['date_stop']['name']
|
||||
self.fields[self.date_stop] = ""
|
||||
if self.calendar_fields.get('date_delay'):
|
||||
self.date_delay = self.calendar_fields['date_delay']['name']
|
||||
self.fields[self.date_delay] = ""
|
||||
if self.calendar_fields.get('parent'):
|
||||
self.parent = self.calendar_fields['parent']['name']
|
||||
self.fields[self.parent] = ""
|
||||
|
||||
model = req.session.model(self.model)
|
||||
event_ids = model.search([])
|
||||
|
||||
return self.create_event(event_ids, model)
|
||||
|
||||
def create_event(self, event_ids, model):
|
||||
|
||||
self.events = model.read(event_ids, self.fields.keys())
|
||||
result = []
|
||||
for evt in self.events:
|
||||
|
||||
event_res = {}
|
||||
key = evt[self.color_field]
|
||||
name = key
|
||||
value = key
|
||||
if isinstance(key, list): # M2O, XMLRPC returns List instead of Tuple
|
||||
name = key[0]
|
||||
value = key[-1]
|
||||
evt[self.color_field] = key = key[-1]
|
||||
if isinstance(key, tuple): # M2O
|
||||
value, name = key
|
||||
|
||||
self.colors[key] = (name, value, None)
|
||||
|
||||
st_date = evt.get(self.date_start)
|
||||
if st_date:
|
||||
self.set_format(st_date)
|
||||
if self.date_delay:
|
||||
duration = evt.get(self.date_delay)
|
||||
else:
|
||||
en_date = evt.get(self.date_stop)
|
||||
|
||||
duration = (time.mktime(time.strptime(en_date, self.format))-\
|
||||
time.mktime(time.strptime(st_date, self.format)))/ (60 * 60)
|
||||
|
||||
if duration > self.day_length :
|
||||
d = math.floor(duration / 24)
|
||||
h = duration % 24
|
||||
duration = d * self.day_length + h
|
||||
|
||||
event_res = {}
|
||||
event_res['start_date'] = st_date
|
||||
event_res['duration'] = duration
|
||||
event_res['text'] = evt.get(self.text)
|
||||
event_res['id'] = evt['id']
|
||||
event_res['parent'] = evt.get(self.parent)
|
||||
result.append(event_res)
|
||||
|
||||
colors = choice_colors(len(self.colors))
|
||||
for i, (key, value) in enumerate(self.colors.items()):
|
||||
self.colors[key] = [value[0], value[1], colors[i]]
|
||||
|
||||
return {'result': result,'sidebar': self.colors}
|
||||
|
||||
def set_format(self, st_date):
|
||||
if len(st_date) == 10 :
|
||||
self.format = "%Y-%m-%d"
|
||||
else :
|
||||
self.format = "%Y-%m-%d %H:%M:%S"
|
||||
return
|
||||
|
||||
def check_format(self, date):
|
||||
if self.format == "%Y-%m-%d %H:%M:%S":
|
||||
date = date + " 00:00:00"
|
||||
return date
|
||||
|
||||
@openerpweb.jsonrequest
|
||||
def on_event_resize(self, req, **kw):
|
||||
if self.date_delay:
|
||||
key = self.date_delay
|
||||
value = kw['duration']
|
||||
else:
|
||||
key = self.date_stop
|
||||
value = self.check_format(kw['end_date'])
|
||||
try:
|
||||
model = req.session.model(self.model)
|
||||
res = model.write(kw['id'], {key : value})
|
||||
except Exception, e:
|
||||
print "eeeeeeeeeeeeeeeeeeeeeeeeeee",e
|
||||
return True
|
||||
|
||||
@openerpweb.jsonrequest
|
||||
def on_event_drag(self, req, **kw):
|
||||
start_date = self.check_format(kw['start_date'])
|
||||
if self.date_delay:
|
||||
key = self.date_delay
|
||||
value = kw['duration']
|
||||
else:
|
||||
key = self.date_stop
|
||||
value = self.check_format(kw['end_date'])
|
||||
try:
|
||||
model = req.session.model(self.model)
|
||||
res = model.write(kw['id'], {self.date_start : start_date, key : value})
|
||||
except Exception, e:
|
||||
print "eeeeeeeeeeeeeeeeeeeeeeeeeee",e
|
||||
return True
|
||||
|
||||
@openerpweb.jsonrequest
|
||||
def reload_gantt(self, req, **kw):
|
||||
|
||||
model = req.session.model(kw['model'])
|
||||
if (kw['domain']):
|
||||
domain = (kw['color_field'],'in', kw['domain'])
|
||||
event_ids = model.search([domain])
|
||||
else:
|
||||
event_ids = model.search([])
|
||||
return self.create_event(event_ids, model)
|
||||
|
||||
@@ -173,8 +173,9 @@ GanttProjectInfo.prototype.getTaskByIdInTree = function(parentTask, id)
|
||||
* @type: public
|
||||
* @topic: 0
|
||||
*/
|
||||
function GanttTaskInfo(id, name, est, duration, percentCompleted, predecessorTaskId)
|
||||
function GanttTaskInfo(id, name, est, duration, percentCompleted, predecessorTaskId, color)
|
||||
{
|
||||
this.color = color || "white";
|
||||
this.Id = id;
|
||||
this.Name = name;
|
||||
this.EST = est;
|
||||
@@ -348,7 +349,7 @@ GanttProject.prototype.create = function()
|
||||
* @type: public
|
||||
* @topic: 0
|
||||
*/
|
||||
function GanttChart()
|
||||
function GanttChart(day_length)
|
||||
{
|
||||
this.Error = new GanttError();
|
||||
this.dhtmlXMLSenderObject = new dhtmlXMLSenderObject(this);
|
||||
@@ -356,7 +357,7 @@ function GanttChart()
|
||||
//settings
|
||||
this.heightTaskItem = 12;
|
||||
this.dayInPixels = 24;
|
||||
this.hoursInDay = 8;
|
||||
this.hoursInDay = day_length;
|
||||
this._showTreePanel = true;
|
||||
this._showTooltip = true;
|
||||
this.isShowDescTask = false;
|
||||
@@ -4869,11 +4870,13 @@ GanttTask.prototype.createTaskItem = function()
|
||||
cellTblTask.height = this.Chart.heightTaskItem + "px";
|
||||
cellTblTask.width = this.TaskInfo.PercentCompleted + "%";
|
||||
cellTblTask.style.lineHeight = "1px";
|
||||
cellTblTask.style.backgroundColor = self.TaskInfo.color;
|
||||
|
||||
var imgPr = document.createElement("img");
|
||||
imgPr.style.width = (this.TaskInfo.PercentCompleted * this.TaskInfo.Duration * this.Chart.hourInPixelsWork) / 100 + "px";
|
||||
imgPr.style.height = this.Chart.heightTaskItem + "px";
|
||||
cellTblTask.appendChild(imgPr);
|
||||
imgPr.src = this.Chart.imgs + "progress_filled.png";
|
||||
//imgPr.src = this.Chart.imgs + "progress_filled.png";
|
||||
}
|
||||
|
||||
if (this.TaskInfo.PercentCompleted != 100)
|
||||
@@ -4943,9 +4946,9 @@ GanttTask.prototype.createTaskItem = function()
|
||||
}
|
||||
|
||||
var taskClick = function() {
|
||||
self.Chart.callEvent("onTaskClick", [self]);
|
||||
self.Chart.callEvent("onTaskDblClick", [self]);
|
||||
};
|
||||
this.addEvent(divMove, 'click', taskClick, false);
|
||||
this.addEvent(divMove, 'dblclick', taskClick, false);
|
||||
|
||||
if (this.Chart.isEditable)
|
||||
{
|
||||
|
||||
@@ -7,7 +7,8 @@ QWeb.add_template('/base_gantt/static/src/xml/base_gantt.xml');
|
||||
openerp.base.views.add('gantt', 'openerp.base_gantt.GanttView');
|
||||
openerp.base_gantt.GanttView = openerp.base.Controller.extend({
|
||||
|
||||
init: function(view_manager, session, element_id, dataset, view_id) {
|
||||
init: function(view_manager, session, element_id, dataset, view_id) {
|
||||
|
||||
this._super(session, element_id);
|
||||
this.view_manager = view_manager;
|
||||
this.dataset = dataset;
|
||||
@@ -16,207 +17,326 @@ openerp.base_gantt.GanttView = openerp.base.Controller.extend({
|
||||
this.fields_views = {};
|
||||
this.widgets = {};
|
||||
this.widgets_counter = 0;
|
||||
this.fields = {};
|
||||
this.datarecord = {};
|
||||
this.fields = this.dataset.fields ? this.dataset.fields: {};
|
||||
this.ids = this.dataset.ids;
|
||||
this.name = "";
|
||||
this.date_start = "";
|
||||
this.date_delay = "";
|
||||
this.date_stop = "";
|
||||
this.color_field = "";
|
||||
this.day_lenth = 8;
|
||||
this.colors = [];
|
||||
this.color_values = [];
|
||||
this.calendar_fields = {};
|
||||
this.info_fields = [];
|
||||
this.domain = this.dataset._domain ? this.dataset._domain: [];
|
||||
this.context = {};
|
||||
},
|
||||
do_show: function () {
|
||||
// TODO: re-trigger search
|
||||
this.$element.show();
|
||||
},
|
||||
do_hide: function () {
|
||||
this.$element.hide();
|
||||
},
|
||||
|
||||
start: function() {
|
||||
this.rpc("/base_gantt/ganttview/load", {"model": this.model, "view_id": this.view_id}, this.on_loaded);
|
||||
this.rpc("/base_gantt/ganttview/load",
|
||||
{"model": this.model, "view_id": this.view_id}, this.on_loaded);
|
||||
},
|
||||
|
||||
on_loaded: function(data) {
|
||||
this.fields_view = data.fields_view;
|
||||
|
||||
var self = this;
|
||||
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;
|
||||
|
||||
this.date_start = this.fields_view.arch.attrs.date_start;
|
||||
this.date_delay = this.fields_view.arch.attrs.date_delay;
|
||||
this.date_stop = this.fields_view.arch.attrs.date_stop;
|
||||
this.color_field = this.fields_view.arch.attrs.color;
|
||||
|
||||
this.color_field = this.fields_view.arch.attrs.color;
|
||||
this.day_length = this.fields_view.arch.attrs.day_length || 8;
|
||||
this.colors = this.fields_view.arch.attrs.colors;
|
||||
this.fields = this.fields_view.fields;
|
||||
|
||||
this.text = this.fields_view.arch.children[0].children[0].attrs.name;
|
||||
this.parent = this.fields_view.arch.children[0].attrs.link;
|
||||
|
||||
this.calendar_fields['parent'] = {'name': this.parent};
|
||||
this.calendar_fields['date_start'] = {'name': this.date_start};
|
||||
this.calendar_fields['text'] = {'name': this.text};
|
||||
if(this.date_delay)
|
||||
this.calendar_fields['date_delay'] = {'name': this.date_delay};
|
||||
if(this.date_stop)
|
||||
this.calendar_fields['date_stop'] = {'name': this.date_stop};
|
||||
this.format = "yyyy-MM-dd";
|
||||
|
||||
self.create_gantt();
|
||||
self.get_events();
|
||||
|
||||
this.calendar_fields['day_length'] = this.day_length;
|
||||
this.rpc('/base_gantt/ganttview/get_events',
|
||||
{'model': this.model,
|
||||
'fields': this.fields,
|
||||
'color_field': this.color_field,
|
||||
'day_length': this.day_length,
|
||||
'calendar_fields': this.calendar_fields,
|
||||
'colors': this.colors,
|
||||
'info_fields': this.info_fields
|
||||
},
|
||||
function(res) {
|
||||
self.create_gantt();
|
||||
self.load_event(res);
|
||||
})
|
||||
this.$element.html(QWeb.render("GanttView", {"view": this, "fields_view": this.fields_view}));
|
||||
|
||||
},
|
||||
convert_date_format: function(date) {
|
||||
date=date+"";
|
||||
if(typeof (date)!="string"||date.length===0){
|
||||
return null;
|
||||
}
|
||||
var iso=date.split("-");
|
||||
if(iso.length===0){
|
||||
return null;
|
||||
}
|
||||
var day = iso[2];
|
||||
var iso_hours = day.split(' ');
|
||||
|
||||
if (iso_hours.length > 1) {
|
||||
day = iso_hours[0];
|
||||
var iso_date_hours = iso_hours[1].split(':')
|
||||
var new_date = new Date(iso[0], iso[1] - 1, day);
|
||||
new_date.setHours(iso_date_hours[0]);
|
||||
new_date.setMinutes(iso_date_hours[1]);
|
||||
new_date.setSeconds(iso_date_hours[2]);
|
||||
}
|
||||
else {
|
||||
var new_date = new Date(iso[0], iso[1] - 1, day);
|
||||
}
|
||||
new_date.setFullYear(iso[0]);
|
||||
new_date.setMonth(iso[1]-1);
|
||||
new_date.setDate(day);
|
||||
return new_date;
|
||||
},
|
||||
|
||||
create_gantt: function() {
|
||||
ganttChartControl = new GanttChart();
|
||||
|
||||
ganttChartControl = new GanttChart(this.day_length);
|
||||
ganttChartControl.setImagePath("/base_gantt/static/lib/dhtmlxGantt/codebase/imgs/");
|
||||
ganttChartControl.setEditable(true);
|
||||
ganttChartControl.showTreePanel(true);
|
||||
ganttChartControl.showContextMenu(true);
|
||||
ganttChartControl.showDescTask(true,'d,s-f');
|
||||
ganttChartControl.showDescProject(true,'n,d');
|
||||
},
|
||||
load_event: function(res) {
|
||||
var self = this
|
||||
var result = res.result;
|
||||
var sidebar = res.sidebar;
|
||||
var project_id = new Array();
|
||||
var project = new Array();
|
||||
var j = -1;
|
||||
var self = this;
|
||||
for (i in result) {
|
||||
|
||||
var parent_id = result[i]['parent'][0];
|
||||
var parent_name = result[i]['parent'][1];
|
||||
|
||||
if (jQuery.inArray(parent_id, project_id) == -1){
|
||||
if (parent_id == undefined){
|
||||
parent_name = "";
|
||||
}
|
||||
j = j + 1;
|
||||
project[j] = new GanttProjectInfo(parent_id, parent_name, new Date(2011, 1, 1));
|
||||
project_id[j] = parent_id;
|
||||
}
|
||||
|
||||
var id = result[i]['id'];
|
||||
var text = result[i]['text'];
|
||||
var start_date = this.convert_date_format(result[i]['start_date']);
|
||||
var duration = result[i]['duration'];
|
||||
|
||||
var task = new GanttTaskInfo(id, text, start_date, duration, 100, "");
|
||||
|
||||
k = project_id.indexOf(parent_id);
|
||||
project[k].addTask(task);
|
||||
|
||||
}
|
||||
for (i in project_id){
|
||||
ganttChartControl.addProject(project[i]);
|
||||
}
|
||||
ganttChartControl.create("GanttDiv");
|
||||
ganttChartControl.attachEvent("onTaskEndResize", function(task) {self.on_task_end_resize(task);})
|
||||
ganttChartControl.attachEvent("onTaskEndDrag", function(task) {self.on_task_end_drag(task);})
|
||||
|
||||
//Create Sidebar
|
||||
if (jQuery('#cal-sidebar-option').length == 0){
|
||||
jQuery('#gantt-sidebar').append(
|
||||
jQuery('<table>',{'width':'100%','cellspacing': 0, 'cellpadding': 0, 'id':'cal-sidebar-option'})
|
||||
)
|
||||
for(s in sidebar) {
|
||||
jQuery('#cal-sidebar-option').append(
|
||||
jQuery('<tr>').append(
|
||||
jQuery('<td>').append(
|
||||
jQuery('<div>')
|
||||
.append(
|
||||
jQuery('<input>',
|
||||
{
|
||||
'type': 'checkbox',
|
||||
'id':sidebar[s][0],
|
||||
'value':sidebar[s][0]
|
||||
}).bind('click',function(){
|
||||
self.reload_gantt(self.color_field,self.model)
|
||||
}),
|
||||
sidebar[s][1]
|
||||
)
|
||||
.css('background-color',sidebar[s][sidebar[s].length-1])
|
||||
)
|
||||
)
|
||||
)
|
||||
},
|
||||
|
||||
get_events: function() {
|
||||
|
||||
var self = this;
|
||||
this.dataset.read_ids(this.dataset.ids, {}, function(result) {
|
||||
self.load_event(result);
|
||||
});
|
||||
|
||||
},
|
||||
|
||||
load_event: function(events) {
|
||||
|
||||
var self = this;
|
||||
|
||||
var result = events;
|
||||
var project = {};
|
||||
var project_smalldate = {};
|
||||
var proj_id = [];
|
||||
var proj_id_text = [];
|
||||
|
||||
COLOR_PALETTE = ['#ccccff', '#cc99ff', '#75507b', '#3465a4', '#73d216', '#c17d11', '#edd400',
|
||||
'#fcaf3e', '#ef2929', '#ff00c9', '#ad7fa8', '#729fcf', '#8ae234', '#e9b96e', '#fce94f',
|
||||
'#ff8e00', '#ff0000', '#b0008c', '#9000ff', '#0078ff', '#00ff00', '#e6ff00', '#ffff00',
|
||||
'#905000', '#9b0000', '#840067', '#510090', '#0000c9', '#009b00', '#9abe00', '#ffc900']
|
||||
|
||||
//Smallest date of child is parent start date
|
||||
for (i in result){
|
||||
var res = result[i];
|
||||
|
||||
if (res[this.date_start] != false){
|
||||
|
||||
var parent_id = res[this.parent][0] || res[this.parent];
|
||||
var parent_name = res[this.parent][1];
|
||||
var start_date = this.convert_str_date(res[this.date_start]);
|
||||
|
||||
if (project_smalldate[parent_id] == undefined){
|
||||
project_smalldate[parent_id] = start_date;
|
||||
proj_id.push(parent_id);
|
||||
|
||||
if (parent_name != undefined){
|
||||
proj_id_text.push(res[this.parent]);
|
||||
}
|
||||
}
|
||||
else{
|
||||
if (start_date < project_smalldate[parent_id]){
|
||||
project_smalldate[parent_id] = start_date;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
//get parent text
|
||||
if (parent_name == undefined){
|
||||
|
||||
var ajax = {
|
||||
url: '/base/dataset/call',
|
||||
async: false
|
||||
};
|
||||
|
||||
this.rpc(ajax, {
|
||||
model: this.dataset.model,
|
||||
method: "name_get",
|
||||
ids: proj_id,
|
||||
args: ""
|
||||
}, function(response) {
|
||||
proj_id_text = response.result;
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
//create parents
|
||||
for (i in proj_id){
|
||||
|
||||
var id = proj_id_text[i][0];
|
||||
var text = proj_id_text[i][1];
|
||||
|
||||
project[id] = new GanttProjectInfo(id, text, project_smalldate[id]);
|
||||
}
|
||||
|
||||
//create childs
|
||||
var k = 0;
|
||||
var color_box = {};
|
||||
for (i in result) {
|
||||
|
||||
var res = result[i];
|
||||
if (res[this.date_start] != false){
|
||||
|
||||
var parent_id = res[this.parent][0] || res[this.parent];
|
||||
var id = res['id'];
|
||||
var text = res[this.text];
|
||||
|
||||
var start_date = this.convert_str_date(res[this.date_start]);
|
||||
|
||||
var color = res[this.color_field][0] || res[this.color_field];
|
||||
if (color_box[color] == undefined){
|
||||
color_box[color] = COLOR_PALETTE[k];
|
||||
k = k + 1;
|
||||
}
|
||||
|
||||
if (this.date_stop != undefined){
|
||||
if (res[this.date_stop] != false){
|
||||
var stop_date = this.convert_str_date(res[this.date_stop]);
|
||||
var duration= self.hours_between(start_date, stop_date);
|
||||
}
|
||||
else{
|
||||
var duration = 0;
|
||||
}
|
||||
}
|
||||
else{
|
||||
var duration = res[this.date_delay];
|
||||
}
|
||||
if (duration == false)
|
||||
duration = 0
|
||||
task = new GanttTaskInfo(id, text, start_date, duration, 100, "", color_box[color]);
|
||||
project[parent_id].addTask(task);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
//Add parent
|
||||
for (i in proj_id){
|
||||
ganttChartControl.addProject(project[proj_id[i]]);
|
||||
}
|
||||
|
||||
ganttChartControl.create("GanttDiv");
|
||||
ganttChartControl.attachEvent("onTaskStartDrag", function(task) {self.on_drag_start(task);});
|
||||
ganttChartControl.attachEvent("onTaskEndResize", function(task) {self.on_resize_drag_end(task, "resize");});
|
||||
ganttChartControl.attachEvent("onTaskEndDrag", function(task) {self.on_resize_drag_end(task, "drag");});
|
||||
ganttChartControl.attachEvent("onTaskDblClick", function(task) {self.open_popup(task);});
|
||||
|
||||
},
|
||||
reload_gantt: function(color_field, model) {
|
||||
var domain = [];
|
||||
|
||||
hours_between: function(date1, date2) {
|
||||
|
||||
var ONE_DAY = 1000 * 60 * 60 * 24;
|
||||
var date1_ms = date1.getTime();
|
||||
var date2_ms = date2.getTime();
|
||||
var difference_ms = Math.abs(date1_ms - date2_ms);
|
||||
|
||||
d = Math.round(difference_ms / ONE_DAY);
|
||||
h = Math.round((difference_ms % ONE_DAY)/(1000 * 60 * 60));
|
||||
|
||||
return (d * this.day_length) + h;
|
||||
|
||||
},
|
||||
|
||||
open_popup : function(task) {
|
||||
var event_id = task.getId();
|
||||
if (event_id) {
|
||||
event_id = parseInt(event_id, 10);
|
||||
var dataset_event_index = jQuery.inArray(event_id, this.ids);
|
||||
} else {
|
||||
var dataset_event_index = null;
|
||||
}
|
||||
this.dataset.index = dataset_event_index;
|
||||
var element_id = _.uniqueId("act_window_dialog");
|
||||
var dialog = jQuery('<div>',
|
||||
{'id': element_id
|
||||
}).dialog({
|
||||
title: 'Gantt Chart',
|
||||
modal: true,
|
||||
minWidth: 800,
|
||||
position: 'top'
|
||||
});
|
||||
var event_form = new openerp.base.FormView(this.view_manager, this.session, element_id, this.dataset, false);
|
||||
event_form.start();
|
||||
},
|
||||
|
||||
on_drag_start : function(task){
|
||||
st_date = task.getEST();
|
||||
if(st_date.getHours()){
|
||||
self.hh = st_date.getHours();
|
||||
self.mm = st_date.getMinutes();
|
||||
}
|
||||
},
|
||||
|
||||
on_resize_drag_end : function(task, evt){
|
||||
|
||||
var event_id = task.getId();
|
||||
var data = {};
|
||||
|
||||
if (evt == "drag"){
|
||||
full_date = task.getEST().set({hour: self.hh, minute : self.mm, second:0});
|
||||
data[this.date_start] = this.convert_date_str(full_date);
|
||||
}
|
||||
if (this.date_stop != undefined){
|
||||
tm = (task.getDuration() % this.day_length);
|
||||
stp = task.getFinishDate().add(tm).hour();
|
||||
data[this.date_stop] = this.convert_date_str(stp);
|
||||
}else{
|
||||
data[this.date_delay] = task.getDuration();
|
||||
}
|
||||
this.dataset.write(event_id, data, function(result) {});
|
||||
|
||||
},
|
||||
|
||||
do_show: function () {
|
||||
this.$element.show();
|
||||
},
|
||||
|
||||
do_hide: function () {
|
||||
this.$element.hide();
|
||||
},
|
||||
|
||||
convert_str_date: function (str){
|
||||
if (str.length == 19){
|
||||
this.format = "yyyy-MM-dd HH:mm:ss";
|
||||
return openerp.base.parse_datetime(str);
|
||||
} else if (str.length == 10){
|
||||
this.format = "yyyy-MM-dd";
|
||||
return openerp.base.parse_date(str);
|
||||
} else if (str.length == 8){
|
||||
this.format = "HH:mm:ss";
|
||||
return openerp.base.parse_time(str);
|
||||
}
|
||||
throw "Unrecognized date/time format";
|
||||
},
|
||||
|
||||
convert_date_str: function(full_date) {
|
||||
if (this.format == "yyyy-MM-dd HH:mm:ss"){
|
||||
return openerp.base.format_datetime(full_date);
|
||||
} else if (this.format == "yyyy-MM-dd"){
|
||||
return openerp.base.format_date(full_date);
|
||||
} else if (this.format == "HH:mm:ss"){
|
||||
return openerp.base.format_time(full_date);
|
||||
}
|
||||
throw "Unrecognized date/time format";
|
||||
},
|
||||
|
||||
reload_gantt: function(domain) {
|
||||
var self = this;
|
||||
jQuery('input[type=checkbox]:checked','#cal-sidebar-option').each(function() {
|
||||
domain.push(parseInt(jQuery(this).attr('id')))
|
||||
var ajax = {
|
||||
url: '/base/dataset/search_read',
|
||||
async: false
|
||||
};
|
||||
this.rpc(ajax, {
|
||||
model: this.dataset.model,
|
||||
domain: self.dataset.domain,
|
||||
context :self.dataset.context
|
||||
}, function(response) {
|
||||
ganttChartControl.clearAll();
|
||||
jQuery("#GanttDiv").children().remove();
|
||||
self.load_event(response);
|
||||
});
|
||||
},
|
||||
|
||||
do_search: function (domains, contexts, groupbys) {
|
||||
|
||||
var self = this;
|
||||
|
||||
return this.rpc('/base/session/eval_domain_and_context', {
|
||||
domains: domains,
|
||||
contexts: contexts,
|
||||
group_by_seq: groupbys
|
||||
}, function (results) {
|
||||
self.dataset.context = results.context;
|
||||
self.dataset.domain = results.domain;
|
||||
return self.reload_gantt(self.dataset.domain);
|
||||
});
|
||||
this.rpc('/base_gantt/ganttview/reload_gantt',{
|
||||
'domain':domain,
|
||||
'color_field':color_field,
|
||||
'model': model
|
||||
},function(res) {
|
||||
ganttChartControl.clearAll();
|
||||
jQuery("#GanttDiv").children().remove();
|
||||
self.load_event(res);
|
||||
});
|
||||
},
|
||||
reverse_convert_date_format: function(date) {
|
||||
return date.getFullYear()+"-"+(date.getMonth()+1)+"-"+date.getDate();
|
||||
},
|
||||
|
||||
on_task_end_resize : function(task) {
|
||||
this.rpc('/base_gantt/ganttview/on_event_resize',
|
||||
{'id' : task.getId(),
|
||||
'end_date' : this.reverse_convert_date_format(task.getFinishDate()),
|
||||
'duration' : task.getDuration()
|
||||
},
|
||||
function(result) {
|
||||
})
|
||||
},
|
||||
on_task_end_drag : function(task) {
|
||||
this.rpc('/base_gantt/ganttview/on_event_drag',
|
||||
{'id' : task.getId(),
|
||||
'start_date' : this.reverse_convert_date_format(task.getEST()),
|
||||
'end_date' : this.reverse_convert_date_format(task.getFinishDate()),
|
||||
'duration' : task.getDuration()
|
||||
},
|
||||
function(result) {
|
||||
})
|
||||
}
|
||||
|
||||
});
|
||||
@@ -224,5 +344,4 @@ openerp.base_gantt.GanttView = openerp.base.Controller.extend({
|
||||
// here you may tweak globals object, if any, and play with on_* or do_* callbacks on them
|
||||
|
||||
};
|
||||
|
||||
// vim:et fdc=0 fdl=0:
|
||||
|
||||
@@ -3,12 +3,9 @@
|
||||
<h3 class="title"><t t-esc="view.fields_view.arch.attrs.string"/></h3>
|
||||
<table class="gantt-view" width="100%" height="100%" cellspacing="0" cellpadding="0">
|
||||
<tr>
|
||||
<td style="width:85%">
|
||||
<td>
|
||||
<div style="width:100%;height:300px;position:relative" id="GanttDiv"/>
|
||||
</td>
|
||||
<td valign = "top">
|
||||
<div id="gantt-sidebar"/>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</t>
|
||||
|
||||
@@ -422,6 +422,8 @@ class HttpRequest(object):
|
||||
self.applicationsession = applicationsession
|
||||
self.httpsession_id = "cookieid"
|
||||
self.httpsession = cherrypy.session
|
||||
self.context = kw.get('context', {})
|
||||
self.session = self.httpsession.setdefault(kw.get('session_id', None), OpenERPSession())
|
||||
self.result = ""
|
||||
print "GET/POST --> %s.%s %s %r" % (controller.__class__.__name__, f.__name__, request, kw)
|
||||
r = f(controller, self, **kw)
|
||||
|
||||
Reference in New Issue
Block a user