[MERGE]resove conflict and merge with main branch.

bzr revid: vme@tinyerp.com-20111122061753-5uxqy3mxw0eedthn
This commit is contained in:
Vidhin Mehta (OpenERP) 2011-11-22 11:47:53 +05:30
commit 67e7ba0d00
49 changed files with 1374 additions and 482 deletions

View File

@ -403,7 +403,7 @@ class Root(object):
request.parameter_storage_class = werkzeug.datastructures.ImmutableDict
if request.path == '/':
params = urllib.urlencode(dict(request.args, debug=''))
params = urllib.urlencode(request.args)
return werkzeug.utils.redirect(self.root + '?' + params, 301)(
environ, start_response)
elif request.path == '/mobile':

View File

@ -338,7 +338,8 @@ class Session(openerpweb.Controller):
"session_id": req.session_id,
"uid": req.session._uid,
"context": ctx,
"db": req.session._db
"db": req.session._db,
"login": req.session._login
}
@openerpweb.jsonrequest
@ -347,7 +348,8 @@ class Session(openerpweb.Controller):
return {
"uid": req.session._uid,
"context": req.session.get_context() if req.session._uid else False,
"db": req.session._db
"db": req.session._db,
"login": req.session._login
}
@openerpweb.jsonrequest

View File

@ -1,5 +1,5 @@
--- jquery.tipTip_old.js 2011-11-14 14:05:53.000000000 +0100
+++ jquery.tipTip.js 2011-11-14 14:41:34.000000000 +0100
--- jquery.tipTip_old.js 2011-11-14 21:40:55.000000000 +0100
+++ jquery.tipTip.js 2011-11-15 10:09:35.000000000 +0100
@@ -31,7 +31,7 @@
fadeIn: 200,
fadeOut: 200,
@ -32,3 +32,21 @@
tiptip_content.html(org_title);
tiptip_holder.hide().removeAttr("class").css("margin","0");
tiptip_arrow.removeAttr("style");
@@ -176,8 +173,15 @@
tiptip_arrow.css({"margin-left": arrow_left+"px", "margin-top": arrow_top+"px"});
tiptip_holder.css({"margin-left": marg_left+"px", "margin-top": marg_top+"px"}).attr("class","tip"+t_class);
- if (timeout){ clearTimeout(timeout); }
- timeout = setTimeout(function(){ tiptip_holder.stop(true,true).fadeIn(opts.fadeIn); }, opts.delay);
+ if (timeout) {
+ clearTimeout(timeout);
+ }
+ timeout = setTimeout(function() {
+ tiptip_holder.stop(true,true);
+ if ($.contains(document.documentElement, org_elem[0])) {
+ tiptip_holder.fadeIn(opts.fadeIn);
+ }
+ }, opts.delay);
}
function deactive_tiptip(){

View File

@ -174,7 +174,12 @@
tiptip_holder.css({"margin-left": marg_left+"px", "margin-top": marg_top+"px"}).attr("class","tip"+t_class);
if (timeout){ clearTimeout(timeout); }
timeout = setTimeout(function(){ tiptip_holder.stop(true,true).fadeIn(opts.fadeIn); }, opts.delay);
timeout = setTimeout(function() {
tiptip_holder.stop(true,true);
if ($.contains(document.documentElement, org_elem[0])) {
tiptip_holder.fadeIn(opts.fadeIn);
}
}, opts.delay);
}
function deactive_tiptip(){

View File

@ -4,7 +4,7 @@
// TODO: t-set + t-value + children node == scoped variable ?
var QWeb2 = {
expressions_cache: {},
RESERVED_WORDS: 'true,false,NaN,null,undefined,debugger,in,instanceof,new,function,return,this,typeof,eval,Math,RegExp,Array,Object,Date'.split(','),
RESERVED_WORDS: 'true,false,NaN,null,undefined,debugger,console,in,instanceof,new,function,return,this,typeof,eval,Math,RegExp,Array,Object,Date'.split(','),
ACTIONS_PRECEDENCE: 'foreach,if,call,set,esc,escf,raw,rawf,js,debug,log'.split(','),
WORD_REPLACEMENT: {
'and': '&&',

View File

@ -0,0 +1,30 @@
// Underscore.js 1.2.2
// (c) 2011 Jeremy Ashkenas, DocumentCloud Inc.
// Underscore is freely distributable under the MIT license.
// Portions of Underscore are inspired or borrowed from Prototype,
// Oliver Steele's Functional, and John Resig's Micro-Templating.
// For all details and documentation:
// http://documentcloud.github.com/underscore
(function(){function r(a,c,d){if(a===c)return a!==0||1/a==1/c;if(a==null||c==null)return a===c;if(a._chain)a=a._wrapped;if(c._chain)c=c._wrapped;if(b.isFunction(a.isEqual))return a.isEqual(c);if(b.isFunction(c.isEqual))return c.isEqual(a);var e=l.call(a);if(e!=l.call(c))return false;switch(e){case "[object String]":return String(a)==String(c);case "[object Number]":return a=+a,c=+c,a!=a?c!=c:a==0?1/a==1/c:a==c;case "[object Date]":case "[object Boolean]":return+a==+c;case "[object RegExp]":return a.source==
c.source&&a.global==c.global&&a.multiline==c.multiline&&a.ignoreCase==c.ignoreCase}if(typeof a!="object"||typeof c!="object")return false;for(var f=d.length;f--;)if(d[f]==a)return true;d.push(a);var f=0,g=true;if(e=="[object Array]"){if(f=a.length,g=f==c.length)for(;f--;)if(!(g=f in a==f in c&&r(a[f],c[f],d)))break}else{if("constructor"in a!="constructor"in c||a.constructor!=c.constructor)return false;for(var h in a)if(m.call(a,h)&&(f++,!(g=m.call(c,h)&&r(a[h],c[h],d))))break;if(g){for(h in c)if(m.call(c,
h)&&!f--)break;g=!f}}d.pop();return g}var s=this,F=s._,o={},k=Array.prototype,p=Object.prototype,i=k.slice,G=k.unshift,l=p.toString,m=p.hasOwnProperty,v=k.forEach,w=k.map,x=k.reduce,y=k.reduceRight,z=k.filter,A=k.every,B=k.some,q=k.indexOf,C=k.lastIndexOf,p=Array.isArray,H=Object.keys,t=Function.prototype.bind,b=function(a){return new n(a)};if(typeof exports!=="undefined"){if(typeof module!=="undefined"&&module.exports)exports=module.exports=b;exports._=b}else typeof define==="function"&&define.amd?
define("underscore",function(){return b}):s._=b;b.VERSION="1.2.2";var j=b.each=b.forEach=function(a,c,b){if(a!=null)if(v&&a.forEach===v)a.forEach(c,b);else if(a.length===+a.length)for(var e=0,f=a.length;e<f;e++){if(e in a&&c.call(b,a[e],e,a)===o)break}else for(e in a)if(m.call(a,e)&&c.call(b,a[e],e,a)===o)break};b.map=function(a,c,b){var e=[];if(a==null)return e;if(w&&a.map===w)return a.map(c,b);j(a,function(a,g,h){e[e.length]=c.call(b,a,g,h)});return e};b.reduce=b.foldl=b.inject=function(a,c,d,e){var f=
d!==void 0;a==null&&(a=[]);if(x&&a.reduce===x)return e&&(c=b.bind(c,e)),f?a.reduce(c,d):a.reduce(c);j(a,function(a,b,i){f?d=c.call(e,d,a,b,i):(d=a,f=true)});if(!f)throw new TypeError("Reduce of empty array with no initial value");return d};b.reduceRight=b.foldr=function(a,c,d,e){a==null&&(a=[]);if(y&&a.reduceRight===y)return e&&(c=b.bind(c,e)),d!==void 0?a.reduceRight(c,d):a.reduceRight(c);a=(b.isArray(a)?a.slice():b.toArray(a)).reverse();return b.reduce(a,c,d,e)};b.find=b.detect=function(a,c,b){var e;
D(a,function(a,g,h){if(c.call(b,a,g,h))return e=a,true});return e};b.filter=b.select=function(a,c,b){var e=[];if(a==null)return e;if(z&&a.filter===z)return a.filter(c,b);j(a,function(a,g,h){c.call(b,a,g,h)&&(e[e.length]=a)});return e};b.reject=function(a,c,b){var e=[];if(a==null)return e;j(a,function(a,g,h){c.call(b,a,g,h)||(e[e.length]=a)});return e};b.every=b.all=function(a,c,b){var e=true;if(a==null)return e;if(A&&a.every===A)return a.every(c,b);j(a,function(a,g,h){if(!(e=e&&c.call(b,a,g,h)))return o});
return e};var D=b.some=b.any=function(a,c,d){var c=c||b.identity,e=false;if(a==null)return e;if(B&&a.some===B)return a.some(c,d);j(a,function(a,b,h){if(e||(e=c.call(d,a,b,h)))return o});return!!e};b.include=b.contains=function(a,c){var b=false;if(a==null)return b;return q&&a.indexOf===q?a.indexOf(c)!=-1:b=D(a,function(a){return a===c})};b.invoke=function(a,c){var d=i.call(arguments,2);return b.map(a,function(a){return(c.call?c||a:a[c]).apply(a,d)})};b.pluck=function(a,c){return b.map(a,function(a){return a[c]})};
b.max=function(a,c,d){if(!c&&b.isArray(a))return Math.max.apply(Math,a);if(!c&&b.isEmpty(a))return-Infinity;var e={computed:-Infinity};j(a,function(a,b,h){b=c?c.call(d,a,b,h):a;b>=e.computed&&(e={value:a,computed:b})});return e.value};b.min=function(a,c,d){if(!c&&b.isArray(a))return Math.min.apply(Math,a);if(!c&&b.isEmpty(a))return Infinity;var e={computed:Infinity};j(a,function(a,b,h){b=c?c.call(d,a,b,h):a;b<e.computed&&(e={value:a,computed:b})});return e.value};b.shuffle=function(a){var c=[],b;
j(a,function(a,f){f==0?c[0]=a:(b=Math.floor(Math.random()*(f+1)),c[f]=c[b],c[b]=a)});return c};b.sortBy=function(a,c,d){return b.pluck(b.map(a,function(a,b,g){return{value:a,criteria:c.call(d,a,b,g)}}).sort(function(a,c){var b=a.criteria,d=c.criteria;return b<d?-1:b>d?1:0}),"value")};b.groupBy=function(a,c){var d={},e=b.isFunction(c)?c:function(a){return a[c]};j(a,function(a,c){var b=e(a,c);(d[b]||(d[b]=[])).push(a)});return d};b.sortedIndex=function(a,c,d){d||(d=b.identity);for(var e=0,f=a.length;e<
f;){var g=e+f>>1;d(a[g])<d(c)?e=g+1:f=g}return e};b.toArray=function(a){return!a?[]:a.toArray?a.toArray():b.isArray(a)?i.call(a):b.isArguments(a)?i.call(a):b.values(a)};b.size=function(a){return b.toArray(a).length};b.first=b.head=function(a,b,d){return b!=null&&!d?i.call(a,0,b):a[0]};b.initial=function(a,b,d){return i.call(a,0,a.length-(b==null||d?1:b))};b.last=function(a,b,d){return b!=null&&!d?i.call(a,Math.max(a.length-b,0)):a[a.length-1]};b.rest=b.tail=function(a,b,d){return i.call(a,b==null||
d?1:b)};b.compact=function(a){return b.filter(a,function(a){return!!a})};b.flatten=function(a,c){return b.reduce(a,function(a,e){if(b.isArray(e))return a.concat(c?e:b.flatten(e));a[a.length]=e;return a},[])};b.without=function(a){return b.difference(a,i.call(arguments,1))};b.uniq=b.unique=function(a,c,d){var d=d?b.map(a,d):a,e=[];b.reduce(d,function(d,g,h){if(0==h||(c===true?b.last(d)!=g:!b.include(d,g)))d[d.length]=g,e[e.length]=a[h];return d},[]);return e};b.union=function(){return b.uniq(b.flatten(arguments,
true))};b.intersection=b.intersect=function(a){var c=i.call(arguments,1);return b.filter(b.uniq(a),function(a){return b.every(c,function(c){return b.indexOf(c,a)>=0})})};b.difference=function(a,c){return b.filter(a,function(a){return!b.include(c,a)})};b.zip=function(){for(var a=i.call(arguments),c=b.max(b.pluck(a,"length")),d=Array(c),e=0;e<c;e++)d[e]=b.pluck(a,""+e);return d};b.indexOf=function(a,c,d){if(a==null)return-1;var e;if(d)return d=b.sortedIndex(a,c),a[d]===c?d:-1;if(q&&a.indexOf===q)return a.indexOf(c);
for(d=0,e=a.length;d<e;d++)if(a[d]===c)return d;return-1};b.lastIndexOf=function(a,b){if(a==null)return-1;if(C&&a.lastIndexOf===C)return a.lastIndexOf(b);for(var d=a.length;d--;)if(a[d]===b)return d;return-1};b.range=function(a,b,d){arguments.length<=1&&(b=a||0,a=0);for(var d=arguments[2]||1,e=Math.max(Math.ceil((b-a)/d),0),f=0,g=Array(e);f<e;)g[f++]=a,a+=d;return g};var E=function(){};b.bind=function(a,c){var d,e;if(a.bind===t&&t)return t.apply(a,i.call(arguments,1));if(!b.isFunction(a))throw new TypeError;
e=i.call(arguments,2);return d=function(){if(!(this instanceof d))return a.apply(c,e.concat(i.call(arguments)));E.prototype=a.prototype;var b=new E,g=a.apply(b,e.concat(i.call(arguments)));return Object(g)===g?g:b}};b.bindAll=function(a){var c=i.call(arguments,1);c.length==0&&(c=b.functions(a));j(c,function(c){a[c]=b.bind(a[c],a)});return a};b.memoize=function(a,c){var d={};c||(c=b.identity);return function(){var b=c.apply(this,arguments);return m.call(d,b)?d[b]:d[b]=a.apply(this,arguments)}};b.delay=
function(a,b){var d=i.call(arguments,2);return setTimeout(function(){return a.apply(a,d)},b)};b.defer=function(a){return b.delay.apply(b,[a,1].concat(i.call(arguments,1)))};b.throttle=function(a,c){var d,e,f,g,h,i=b.debounce(function(){h=g=false},c);return function(){d=this;e=arguments;var b;f||(f=setTimeout(function(){f=null;h&&a.apply(d,e);i()},c));g?h=true:a.apply(d,e);i();g=true}};b.debounce=function(a,b){var d;return function(){var e=this,f=arguments;clearTimeout(d);d=setTimeout(function(){d=
null;a.apply(e,f)},b)}};b.once=function(a){var b=false,d;return function(){if(b)return d;b=true;return d=a.apply(this,arguments)}};b.wrap=function(a,b){return function(){var d=[a].concat(i.call(arguments));return b.apply(this,d)}};b.compose=function(){var a=i.call(arguments);return function(){for(var b=i.call(arguments),d=a.length-1;d>=0;d--)b=[a[d].apply(this,b)];return b[0]}};b.after=function(a,b){return a<=0?b():function(){if(--a<1)return b.apply(this,arguments)}};b.keys=H||function(a){if(a!==
Object(a))throw new TypeError("Invalid object");var b=[],d;for(d in a)m.call(a,d)&&(b[b.length]=d);return b};b.values=function(a){return b.map(a,b.identity)};b.functions=b.methods=function(a){var c=[],d;for(d in a)b.isFunction(a[d])&&c.push(d);return c.sort()};b.extend=function(a){j(i.call(arguments,1),function(b){for(var d in b)b[d]!==void 0&&(a[d]=b[d])});return a};b.defaults=function(a){j(i.call(arguments,1),function(b){for(var d in b)a[d]==null&&(a[d]=b[d])});return a};b.clone=function(a){return!b.isObject(a)?
a:b.isArray(a)?a.slice():b.extend({},a)};b.tap=function(a,b){b(a);return a};b.isEqual=function(a,b){return r(a,b,[])};b.isEmpty=function(a){if(b.isArray(a)||b.isString(a))return a.length===0;for(var c in a)if(m.call(a,c))return false;return true};b.isElement=function(a){return!!(a&&a.nodeType==1)};b.isArray=p||function(a){return l.call(a)=="[object Array]"};b.isObject=function(a){return a===Object(a)};b.isArguments=l.call(arguments)=="[object Arguments]"?function(a){return l.call(a)=="[object Arguments]"}:
function(a){return!(!a||!m.call(a,"callee"))};b.isFunction=function(a){return l.call(a)=="[object Function]"};b.isString=function(a){return l.call(a)=="[object String]"};b.isNumber=function(a){return l.call(a)=="[object Number]"};b.isNaN=function(a){return a!==a};b.isBoolean=function(a){return a===true||a===false||l.call(a)=="[object Boolean]"};b.isDate=function(a){return l.call(a)=="[object Date]"};b.isRegExp=function(a){return l.call(a)=="[object RegExp]"};b.isNull=function(a){return a===null};
b.isUndefined=function(a){return a===void 0};b.noConflict=function(){s._=F;return this};b.identity=function(a){return a};b.times=function(a,b,d){for(var e=0;e<a;e++)b.call(d,e)};b.escape=function(a){return(""+a).replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;").replace(/'/g,"&#x27;").replace(/\//g,"&#x2F;")};b.mixin=function(a){j(b.functions(a),function(c){I(c,b[c]=a[c])})};var J=0;b.uniqueId=function(a){var b=J++;return a?a+b:b};b.templateSettings={evaluate:/<%([\s\S]+?)%>/g,
interpolate:/<%=([\s\S]+?)%>/g,escape:/<%-([\s\S]+?)%>/g};b.template=function(a,c){var d=b.templateSettings,d="var __p=[],print=function(){__p.push.apply(__p,arguments);};with(obj||{}){__p.push('"+a.replace(/\\/g,"\\\\").replace(/'/g,"\\'").replace(d.escape,function(a,b){return"',_.escape("+b.replace(/\\'/g,"'")+"),'"}).replace(d.interpolate,function(a,b){return"',"+b.replace(/\\'/g,"'")+",'"}).replace(d.evaluate||null,function(a,b){return"');"+b.replace(/\\'/g,"'").replace(/[\r\n\t]/g," ")+";__p.push('"}).replace(/\r/g,
"\\r").replace(/\n/g,"\\n").replace(/\t/g,"\\t")+"');}return __p.join('');",e=new Function("obj","_",d);return c?e(c,b):function(a){return e(a,b)}};var n=function(a){this._wrapped=a};b.prototype=n.prototype;var u=function(a,c){return c?b(a).chain():a},I=function(a,c){n.prototype[a]=function(){var a=i.call(arguments);G.call(a,this._wrapped);return u(c.apply(b,a),this._chain)}};b.mixin(b);j("pop,push,reverse,shift,sort,splice,unshift".split(","),function(a){var b=k[a];n.prototype[a]=function(){b.apply(this._wrapped,
arguments);return u(this._wrapped,this._chain)}});j(["concat","join","slice"],function(a){var b=k[a];n.prototype[a]=function(){return u(b.apply(this._wrapped,arguments),this._chain)}});n.prototype.chain=function(){this._chain=true;return this};n.prototype.value=function(){return this._wrapped}}).call(this);

View File

@ -1,4 +1,4 @@
// Underscore.js 1.1.7
// Underscore.js 1.2.2
// (c) 2011 Jeremy Ashkenas, DocumentCloud Inc.
// Underscore is freely distributable under the MIT license.
// Portions of Underscore are inspired or borrowed from Prototype,
@ -48,19 +48,26 @@
// Create a safe reference to the Underscore object for use below.
var _ = function(obj) { return new wrapper(obj); };
// Export the Underscore object for **CommonJS**, with backwards-compatibility
// for the old `require()` API. If we're not in CommonJS, add `_` to the
// global object.
if (typeof module !== 'undefined' && module.exports) {
module.exports = _;
_._ = _;
// Export the Underscore object for **Node.js** and **"CommonJS"**, with
// backwards-compatibility for the old `require()` API. If we're not in
// CommonJS, add `_` to the global object.
if (typeof exports !== 'undefined') {
if (typeof module !== 'undefined' && module.exports) {
exports = module.exports = _;
}
exports._ = _;
} else if (typeof define === 'function' && define.amd) {
// Register as a named module with AMD.
define('underscore', function() {
return _;
});
} else {
// Exported as a string, for Closure Compiler "advanced" mode.
root['_'] = _;
}
// Current version.
_.VERSION = '1.1.7';
_.VERSION = '1.2.2';
// Collection Functions
// --------------------
@ -187,7 +194,7 @@
if (obj == null) return result;
if (nativeSome && obj.some === nativeSome) return obj.some(iterator, context);
each(obj, function(value, index, list) {
if (result |= iterator.call(context, value, index, list)) return breaker;
if (result || (result = iterator.call(context, value, index, list))) return breaker;
});
return !!result;
};
@ -198,8 +205,8 @@
var found = false;
if (obj == null) return found;
if (nativeIndexOf && obj.indexOf === nativeIndexOf) return obj.indexOf(target) != -1;
any(obj, function(value) {
if (found = value === target) return true;
found = any(obj, function(value) {
return value === target;
});
return found;
};
@ -220,6 +227,7 @@
// Return the maximum element or (element-based computation).
_.max = function(obj, iterator, context) {
if (!iterator && _.isArray(obj)) return Math.max.apply(Math, obj);
if (!iterator && _.isEmpty(obj)) return -Infinity;
var result = {computed : -Infinity};
each(obj, function(value, index, list) {
var computed = iterator ? iterator.call(context, value, index, list) : value;
@ -231,6 +239,7 @@
// Return the minimum element (or element-based computation).
_.min = function(obj, iterator, context) {
if (!iterator && _.isArray(obj)) return Math.min.apply(Math, obj);
if (!iterator && _.isEmpty(obj)) return Infinity;
var result = {computed : Infinity};
each(obj, function(value, index, list) {
var computed = iterator ? iterator.call(context, value, index, list) : value;
@ -239,6 +248,21 @@
return result.value;
};
// Shuffle an array.
_.shuffle = function(obj) {
var shuffled = [], rand;
each(obj, function(value, index, list) {
if (index == 0) {
shuffled[0] = value;
} else {
rand = Math.floor(Math.random() * (index + 1));
shuffled[index] = shuffled[rand];
shuffled[rand] = value;
}
});
return shuffled;
};
// Sort the object's values by a criterion produced by an iterator.
_.sortBy = function(obj, iterator, context) {
return _.pluck(_.map(obj, function(value, index, list) {
@ -252,9 +276,11 @@
}), 'value');
};
// Groups the object's values by a criterion produced by an iterator
_.groupBy = function(obj, iterator) {
// Groups the object's values by a criterion. Pass either a string attribute
// to group by, or a function that returns the criterion.
_.groupBy = function(obj, val) {
var result = {};
var iterator = _.isFunction(val) ? val : function(obj) { return obj[val]; };
each(obj, function(value, index) {
var key = iterator(value, index);
(result[key] || (result[key] = [])).push(value);
@ -298,6 +324,24 @@
return (n != null) && !guard ? slice.call(array, 0, n) : array[0];
};
// Returns everything but the last entry of the array. Especcialy useful on
// the arguments object. Passing **n** will return all the values in
// the array, excluding the last N. The **guard** check allows it to work with
// `_.map`.
_.initial = function(array, n, guard) {
return slice.call(array, 0, array.length - ((n == null) || guard ? 1 : n));
};
// Get the last element of an array. Passing **n** will return the last N
// values in the array. The **guard** check allows it to work with `_.map`.
_.last = function(array, n, guard) {
if ((n != null) && !guard) {
return slice.call(array, Math.max(array.length - n, 0));
} else {
return array[array.length - 1];
}
};
// Returns everything but the first entry of the array. Aliased as `tail`.
// Especially useful on the arguments object. Passing an **index** will return
// the rest of the values in the array from that index onward. The **guard**
@ -306,20 +350,15 @@
return slice.call(array, (index == null) || guard ? 1 : index);
};
// Get the last element of an array.
_.last = function(array) {
return array[array.length - 1];
};
// Trim out all falsy values from an array.
_.compact = function(array) {
return _.filter(array, function(value){ return !!value; });
};
// Return a completely flattened version of an array.
_.flatten = function(array) {
_.flatten = function(array, shallow) {
return _.reduce(array, function(memo, value) {
if (_.isArray(value)) return memo.concat(_.flatten(value));
if (_.isArray(value)) return memo.concat(shallow ? value : _.flatten(value));
memo[memo.length] = value;
return memo;
}, []);
@ -333,17 +372,23 @@
// Produce a duplicate-free version of the array. If the array has already
// been sorted, you have the option of using a faster algorithm.
// Aliased as `unique`.
_.uniq = _.unique = function(array, isSorted) {
return _.reduce(array, function(memo, el, i) {
if (0 == i || (isSorted === true ? _.last(memo) != el : !_.include(memo, el))) memo[memo.length] = el;
_.uniq = _.unique = function(array, isSorted, iterator) {
var initial = iterator ? _.map(array, iterator) : array;
var result = [];
_.reduce(initial, function(memo, el, i) {
if (0 == i || (isSorted === true ? _.last(memo) != el : !_.include(memo, el))) {
memo[memo.length] = el;
result[result.length] = array[i];
}
return memo;
}, []);
return result;
};
// Produce an array that contains the union: each distinct element from all of
// the passed-in arrays.
_.union = function() {
return _.uniq(_.flatten(arguments));
return _.uniq(_.flatten(arguments, true));
};
// Produce an array that contains every item shared between all the
@ -391,7 +436,6 @@
return -1;
};
// Delegates to **ECMAScript 5**'s native `lastIndexOf` if available.
_.lastIndexOf = function(array, item) {
if (array == null) return -1;
@ -426,15 +470,25 @@
// Function (ahem) Functions
// ------------------
// Reusable constructor function for prototype setting.
var ctor = function(){};
// Create a function bound to a given object (assigning `this`, and arguments,
// optionally). Binding with arguments is also known as `curry`.
// Delegates to **ECMAScript 5**'s native `Function.bind` if available.
// We check for `func.bind` first, to fail fast when `func` is undefined.
_.bind = function(func, obj) {
_.bind = function bind(func, context) {
var bound, args;
if (func.bind === nativeBind && nativeBind) return nativeBind.apply(func, slice.call(arguments, 1));
var args = slice.call(arguments, 2);
return function() {
return func.apply(obj, args.concat(slice.call(arguments)));
if (!_.isFunction(func)) throw new TypeError;
args = slice.call(arguments, 2);
return bound = function() {
if (!(this instanceof bound)) return func.apply(context, args.concat(slice.call(arguments)));
ctor.prototype = func.prototype;
var self = new ctor;
var result = func.apply(self, args.concat(slice.call(arguments)));
if (Object(result) === result) return result;
return self;
};
};
@ -470,31 +524,43 @@
return _.delay.apply(_, [func, 1].concat(slice.call(arguments, 1)));
};
// Internal function used to implement `_.throttle` and `_.debounce`.
var limit = function(func, wait, debounce) {
var timeout;
return function() {
var context = this, args = arguments;
var throttler = function() {
timeout = null;
func.apply(context, args);
};
if (debounce) clearTimeout(timeout);
if (debounce || !timeout) timeout = setTimeout(throttler, wait);
};
};
// Returns a function, that, when invoked, will only be triggered at most once
// during a given window of time.
_.throttle = function(func, wait) {
return limit(func, wait, false);
var context, args, timeout, throttling, more;
var whenDone = _.debounce(function(){ more = throttling = false; }, wait);
return function() {
context = this; args = arguments;
var later = function() {
timeout = null;
if (more) func.apply(context, args);
whenDone();
};
if (!timeout) timeout = setTimeout(later, wait);
if (throttling) {
more = true;
} else {
func.apply(context, args);
}
whenDone();
throttling = true;
};
};
// Returns a function, that, as long as it continues to be invoked, will not
// be triggered. The function will be called after it stops being called for
// N milliseconds.
_.debounce = function(func, wait) {
return limit(func, wait, true);
var timeout;
return function() {
var context = this, args = arguments;
var later = function() {
timeout = null;
func.apply(context, args);
};
clearTimeout(timeout);
timeout = setTimeout(later, wait);
};
};
// Returns a function that will be executed at most one time, no matter how
@ -533,12 +599,12 @@
// Returns a function that will only be executed after being called N times.
_.after = function(times, func) {
if (times <= 0) return func();
return function() {
if (--times < 1) { return func.apply(this, arguments); }
};
};
// Object Functions
// ----------------
@ -588,6 +654,7 @@
// Create a (shallow-cloned) duplicate of an object.
_.clone = function(obj) {
if (!_.isObject(obj)) return obj;
return _.isArray(obj) ? obj.slice() : _.extend({}, obj);
};
@ -599,47 +666,103 @@
return obj;
};
// Perform a deep comparison to check if two objects are equal.
_.isEqual = function(a, b) {
// Check object identity.
if (a === b) return true;
// Different types?
var atype = typeof(a), btype = typeof(b);
if (atype != btype) return false;
// Basic equality test (watch out for coercions).
if (a == b) return true;
// One is falsy and the other truthy.
if ((!a && b) || (a && !b)) return false;
// Internal recursive comparison function.
function eq(a, b, stack) {
// Identical objects are equal. `0 === -0`, but they aren't identical.
// See the Harmony `egal` proposal: http://wiki.ecmascript.org/doku.php?id=harmony:egal.
if (a === b) return a !== 0 || 1 / a == 1 / b;
// A strict comparison is necessary because `null == undefined`.
if (a == null || b == null) return a === b;
// Unwrap any wrapped objects.
if (a._chain) a = a._wrapped;
if (b._chain) b = b._wrapped;
// One of them implements an isEqual()?
if (a.isEqual) return a.isEqual(b);
if (b.isEqual) return b.isEqual(a);
// Check dates' integer values.
if (_.isDate(a) && _.isDate(b)) return a.getTime() === b.getTime();
// Both are NaN?
if (_.isNaN(a) && _.isNaN(b)) return false;
// Compare regular expressions.
if (_.isRegExp(a) && _.isRegExp(b))
return a.source === b.source &&
a.global === b.global &&
a.ignoreCase === b.ignoreCase &&
a.multiline === b.multiline;
// If a is not an object by this point, we can't handle it.
if (atype !== 'object') return false;
// Check for different array lengths before comparing contents.
if (a.length && (a.length !== b.length)) return false;
// Nothing else worked, deep compare the contents.
var aKeys = _.keys(a), bKeys = _.keys(b);
// Different object sizes?
if (aKeys.length != bKeys.length) return false;
// Recursive comparison of contents.
for (var key in a) if (!(key in b) || !_.isEqual(a[key], b[key])) return false;
return true;
// Invoke a custom `isEqual` method if one is provided.
if (_.isFunction(a.isEqual)) return a.isEqual(b);
if (_.isFunction(b.isEqual)) return b.isEqual(a);
// Compare `[[Class]]` names.
var className = toString.call(a);
if (className != toString.call(b)) return false;
switch (className) {
// Strings, numbers, dates, and booleans are compared by value.
case '[object String]':
// Primitives and their corresponding object wrappers are equivalent; thus, `"5"` is
// equivalent to `new String("5")`.
return String(a) == String(b);
case '[object Number]':
a = +a;
b = +b;
// `NaN`s are equivalent, but non-reflexive. An `egal` comparison is performed for
// other numeric values.
return a != a ? b != b : (a == 0 ? 1 / a == 1 / b : a == b);
case '[object Date]':
case '[object Boolean]':
// Coerce dates and booleans to numeric primitive values. Dates are compared by their
// millisecond representations. Note that invalid dates with millisecond representations
// of `NaN` are not equivalent.
return +a == +b;
// RegExps are compared by their source patterns and flags.
case '[object RegExp]':
return a.source == b.source &&
a.global == b.global &&
a.multiline == b.multiline &&
a.ignoreCase == b.ignoreCase;
}
if (typeof a != 'object' || typeof b != 'object') return false;
// Assume equality for cyclic structures. The algorithm for detecting cyclic
// structures is adapted from ES 5.1 section 15.12.3, abstract operation `JO`.
var length = stack.length;
while (length--) {
// Linear search. Performance is inversely proportional to the number of
// unique nested structures.
if (stack[length] == a) return true;
}
// Add the first object to the stack of traversed objects.
stack.push(a);
var size = 0, result = true;
// Recursively compare objects and arrays.
if (className == '[object Array]') {
// Compare array lengths to determine if a deep comparison is necessary.
size = a.length;
result = size == b.length;
if (result) {
// Deep compare the contents, ignoring non-numeric properties.
while (size--) {
// Ensure commutative equality for sparse arrays.
if (!(result = size in a == size in b && eq(a[size], b[size], stack))) break;
}
}
} else {
// Objects with different constructors are not equivalent.
if ("constructor" in a != "constructor" in b || a.constructor != b.constructor) return false;
// Deep compare objects.
for (var key in a) {
if (hasOwnProperty.call(a, key)) {
// Count the expected number of properties.
size++;
// Deep compare each member.
if (!(result = hasOwnProperty.call(b, key) && eq(a[key], b[key], stack))) break;
}
}
// Ensure that both objects contain the same number of properties.
if (result) {
for (key in b) {
if (hasOwnProperty.call(b, key) && !(size--)) break;
}
result = !size;
}
}
// Remove the first object from the stack of traversed objects.
stack.pop();
return result;
}
// Perform a deep comparison to check if two objects are equal.
_.isEqual = function(a, b) {
return eq(a, b, []);
};
// Is a given array or object empty?
// Is a given array, string, or object empty?
// An "empty" object has no enumerable own-properties.
_.isEmpty = function(obj) {
if (_.isArray(obj) || _.isString(obj)) return obj.length === 0;
for (var key in obj) if (hasOwnProperty.call(obj, key)) return false;
@ -654,7 +777,7 @@
// Is a given value an array?
// Delegates to ECMA5's native Array.isArray
_.isArray = nativeIsArray || function(obj) {
return toString.call(obj) === '[object Array]';
return toString.call(obj) == '[object Array]';
};
// Is a given variable an object?
@ -663,44 +786,50 @@
};
// Is a given variable an arguments object?
_.isArguments = function(obj) {
return !!(obj && hasOwnProperty.call(obj, 'callee'));
};
if (toString.call(arguments) == '[object Arguments]') {
_.isArguments = function(obj) {
return toString.call(obj) == '[object Arguments]';
};
} else {
_.isArguments = function(obj) {
return !!(obj && hasOwnProperty.call(obj, 'callee'));
};
}
// Is a given value a function?
_.isFunction = function(obj) {
return !!(obj && obj.constructor && obj.call && obj.apply);
return toString.call(obj) == '[object Function]';
};
// Is a given value a string?
_.isString = function(obj) {
return !!(obj === '' || (obj && obj.charCodeAt && obj.substr));
return toString.call(obj) == '[object String]';
};
// Is a given value a number?
_.isNumber = function(obj) {
return !!(obj === 0 || (obj && obj.toExponential && obj.toFixed));
return toString.call(obj) == '[object Number]';
};
// Is the given value `NaN`? `NaN` happens to be the only value in JavaScript
// that does not equal itself.
// Is the given value `NaN`?
_.isNaN = function(obj) {
// `NaN` is the only value for which `===` is not reflexive.
return obj !== obj;
};
// Is a given value a boolean?
_.isBoolean = function(obj) {
return obj === true || obj === false;
return obj === true || obj === false || toString.call(obj) == '[object Boolean]';
};
// Is a given value a date?
_.isDate = function(obj) {
return !!(obj && obj.getTimezoneOffset && obj.setUTCFullYear);
return toString.call(obj) == '[object Date]';
};
// Is the given value a regular expression?
_.isRegExp = function(obj) {
return !!(obj && obj.test && obj.exec && (obj.ignoreCase || obj.ignoreCase === false));
return toString.call(obj) == '[object RegExp]';
};
// Is a given value equal to null?
@ -733,6 +862,11 @@
for (var i = 0; i < n; i++) iterator.call(context, i);
};
// Escape a string for HTML interpolation.
_.escape = function(string) {
return (''+string).replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;').replace(/'/g, '&#x27;').replace(/\//g,'&#x2F;');
};
// Add your own custom functions to the Underscore object, ensuring that
// they're correctly added to the OOP wrapper as well.
_.mixin = function(obj) {
@ -753,7 +887,8 @@
// following template settings to use alternative delimiters.
_.templateSettings = {
evaluate : /<%([\s\S]+?)%>/g,
interpolate : /<%=([\s\S]+?)%>/g
interpolate : /<%=([\s\S]+?)%>/g,
escape : /<%-([\s\S]+?)%>/g
};
// JavaScript micro-templating, similar to John Resig's implementation.
@ -765,19 +900,22 @@
'with(obj||{}){__p.push(\'' +
str.replace(/\\/g, '\\\\')
.replace(/'/g, "\\'")
.replace(c.escape, function(match, code) {
return "',_.escape(" + code.replace(/\\'/g, "'") + "),'";
})
.replace(c.interpolate, function(match, code) {
return "'," + code.replace(/\\'/g, "'") + ",'";
})
.replace(c.evaluate || null, function(match, code) {
return "');" + code.replace(/\\'/g, "'")
.replace(/[\r\n\t]/g, ' ') + "__p.push('";
.replace(/[\r\n\t]/g, ' ') + ";__p.push('";
})
.replace(/\r/g, '\\r')
.replace(/\n/g, '\\n')
.replace(/\t/g, '\\t')
+ "');}return __p.join('');";
var func = new Function('obj', tmpl);
return data ? func(data) : func;
var func = new Function('obj', '_', tmpl);
return data ? func(data, _) : function(data) { return func(data, _) };
};
// The OOP Wrapper
@ -836,4 +974,4 @@
return this._wrapped;
};
})();
}).call(this);

View File

@ -1,20 +1,14 @@
// Underscore.string
// (c) 2010 Esa-Matti Suuronen <esa-matti aet suuronen dot org>
// Underscore.strings is freely distributable under the terms of the MIT license.
// Documentation: https://github.com/edtsech/underscore.string
// Documentation: https://github.com/epeli/underscore.string
// Some code is borrowed from MooTools and Alexandru Marasteanu.
// Version 1.1.6
// Version 1.2.0
(function(root){
'use strict';
if (typeof _ != 'undefined') {
var _reverse = _().reverse,
_include = _.include;
}
// Defining helper functions.
var nativeTrim = String.prototype.trim;
@ -22,7 +16,7 @@
var parseNumber = function(source) { return source * 1 || 0; };
var strRepeat = function(i, m) {
for (var o = []; m > 0; o[--m] = i);
for (var o = []; m > 0; o[--m] = i) {}
return o.join('');
};
@ -174,6 +168,8 @@
var _s = {
VERSION: '1.2.0',
isBlank: sArgs(function(str){
return (/^\s*$/).test(str);
}),
@ -235,18 +231,10 @@
return arr.join('');
}),
includes: sArgs(function(str, needle){
include: sArgs(function(str, needle){
return str.indexOf(needle) !== -1;
}),
include: function(obj, needle) {
if (!_include || (/string|number/).test(typeof obj)) {
return this.includes(obj, needle);
} else {
return _include(obj, needle);
}
},
join: sArgs(function(sep) {
var args = slice(arguments);
return args.join(args.shift());
@ -256,13 +244,9 @@
return str.split("\n");
}),
reverse: function(obj){
if (!_reverse || (/string|number/).test(typeof obj)) {
return Array.prototype.reverse.apply(String(obj).split('')).join('');
} else {
return _reverse.call(_(obj));
}
},
reverse: sArgs(function(str){
return Array.prototype.reverse.apply(String(str).split('')).join('');
}),
splice: sArgs(function(str, i, howmany, substr){
var arr = str.split('');
@ -309,6 +293,10 @@
return _s.trim(str).replace(/([a-z\d])([A-Z]+)/g, '$1-$2').replace(/^([A-Z]+)/, '-$1').replace(/\_|\s+/g, '-').toLowerCase();
},
humanize: function(str){
return _s.capitalize(this.underscored(str).replace(/_id$/,'').replace(/_/g, ' '));
},
trim: sArgs(function(str, characters){
if (!characters && nativeTrim) {
return nativeTrim.call(str);
@ -333,6 +321,27 @@
return str.length > length ? str.slice(0,length) + truncateStr : str;
}),
/**
* _s.prune: a more elegant version of truncate
* prune extra chars, never leaving a half-chopped word.
* @author github.com/sergiokas
*/
prune: sArgs(function(str, length, pruneStr){
pruneStr = pruneStr || '...';
length = parseNumber(length);
var pruned = '';
// Check if we're in the middle of a word
if( str.substring(length-1, length+1).search(/^\w\w$/) === 0 )
pruned = _s.rtrim(str.slice(0,length).replace(/([\W][\w]*)$/,''));
else
pruned = _s.rtrim(str.slice(0,length));
pruned = pruned.replace(/\W+$/,'');
return (pruned.length+pruneStr.length>str.length) ? str : pruned + pruneStr;
}),
words: function(str, delimiter) {
return String(str).split(delimiter || " ");
},
@ -409,31 +418,51 @@
strLeftBack: sArgs(function(sourceStr, sep){
var pos = sourceStr.lastIndexOf(sep);
return (pos != -1) ? sourceStr.slice(0, pos) : sourceStr;
})
}),
exports: function() {
var result = {};
for (var prop in this) {
if (!this.hasOwnProperty(prop) || prop == 'include' || prop == 'contains' || prop == 'reverse') continue;
result[prop] = this[prop];
}
return result;
}
};
// Aliases
_s.strip = _s.trim;
_s.lstrip = _s.ltrim;
_s.rstrip = _s.rtrim;
_s.center = _s.lrpad;
_s.ljust = _s.lpad;
_s.rjust = _s.rpad;
_s.strip = _s.trim;
_s.lstrip = _s.ltrim;
_s.rstrip = _s.rtrim;
_s.center = _s.lrpad;
_s.ljust = _s.lpad;
_s.rjust = _s.rpad;
_s.contains = _s.include;
// CommonJS module is defined
if (typeof module !== 'undefined' && module.exports) {
// Export module
module.exports = _s;
if (typeof exports !== 'undefined') {
if (typeof module !== 'undefined' && module.exports) {
// Export module
module.exports = _s;
}
exports._s = _s;
// Integrate with Underscore.js
} else if (typeof root._ !== 'undefined') {
root._.mixin(_s);
// root._.mixin(_s);
root._.string = _s;
root._.str = root._.string;
// Or define it
} else {
root._ = _s;
root._ = {
string: _s,
str: _s
};
}
}(this || window));

View File

@ -0,0 +1,14 @@
(function(k){var o=String.prototype.trim,l=function(a,b){for(var c=[];b>0;c[--b]=a);return c.join("")},d=function(a){return function(){for(var b=Array.prototype.slice.call(arguments),c=0;c<b.length;c++)b[c]=b[c]==null?"":""+b[c];return a.apply(null,b)}},m=function(){function a(a){return Object.prototype.toString.call(a).slice(8,-1).toLowerCase()}var b=function(){b.cache.hasOwnProperty(arguments[0])||(b.cache[arguments[0]]=b.parse(arguments[0]));return b.format.call(null,b.cache[arguments[0]],arguments)};
b.format=function(b,n){var e=1,d=b.length,f="",j=[],h,i,g,k;for(h=0;h<d;h++)if(f=a(b[h]),f==="string")j.push(b[h]);else if(f==="array"){g=b[h];if(g[2]){f=n[e];for(i=0;i<g[2].length;i++){if(!f.hasOwnProperty(g[2][i]))throw m('[_.sprintf] property "%s" does not exist',g[2][i]);f=f[g[2][i]]}}else f=g[1]?n[g[1]]:n[e++];if(/[^s]/.test(g[8])&&a(f)!="number")throw m("[_.sprintf] expecting number but found %s",a(f));switch(g[8]){case "b":f=f.toString(2);break;case "c":f=String.fromCharCode(f);break;case "d":f=
parseInt(f,10);break;case "e":f=g[7]?f.toExponential(g[7]):f.toExponential();break;case "f":f=g[7]?parseFloat(f).toFixed(g[7]):parseFloat(f);break;case "o":f=f.toString(8);break;case "s":f=(f=String(f))&&g[7]?f.substring(0,g[7]):f;break;case "u":f=Math.abs(f);break;case "x":f=f.toString(16);break;case "X":f=f.toString(16).toUpperCase()}f=/[def]/.test(g[8])&&g[3]&&f>=0?"+"+f:f;i=g[4]?g[4]=="0"?"0":g[4].charAt(1):" ";k=g[6]-String(f).length;i=g[6]?l(i,k):"";j.push(g[5]?f+i:i+f)}return j.join("")};b.cache=
{};b.parse=function(a){for(var b=[],e=[],d=0;a;){if((b=/^[^\x25]+/.exec(a))!==null)e.push(b[0]);else if((b=/^\x25{2}/.exec(a))!==null)e.push("%");else if((b=/^\x25(?:([1-9]\d*)\$|\(([^\)]+)\))?(\+)?(0|'[^$])?(-)?(\d+)?(?:\.(\d+))?([b-fosuxX])/.exec(a))!==null){if(b[2]){d|=1;var f=[],j=b[2],h=[];if((h=/^([a-z_][a-z_\d]*)/i.exec(j))!==null)for(f.push(h[1]);(j=j.substring(h[0].length))!=="";)if((h=/^\.([a-z_][a-z_\d]*)/i.exec(j))!==null)f.push(h[1]);else if((h=/^\[(\d+)\]/.exec(j))!==null)f.push(h[1]);
else throw"[_.sprintf] huh?";else throw"[_.sprintf] huh?";b[2]=f}else d|=2;if(d===3)throw"[_.sprintf] mixing positional and named placeholders is not (yet) supported";e.push(b)}else throw"[_.sprintf] huh?";a=a.substring(b[0].length)}return e};return b}(),e={VERSION:"1.2.0",isBlank:d(function(a){return/^\s*$/.test(a)}),stripTags:d(function(a){return a.replace(/<\/?[^>]+>/ig,"")}),capitalize:d(function(a){return a.charAt(0).toUpperCase()+a.substring(1).toLowerCase()}),chop:d(function(a,b){for(var b=
b*1||0||a.length,c=[],e=0;e<a.length;)c.push(a.slice(e,e+b)),e+=b;return c}),clean:d(function(a){return e.strip(a.replace(/\s+/g," "))}),count:d(function(a,b){for(var c=0,e,d=0;d<a.length;)e=a.indexOf(b,d),e>=0&&c++,d=d+(e>=0?e:0)+b.length;return c}),chars:d(function(a){return a.split("")}),escapeHTML:d(function(a){return a.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;").replace(/'/g,"&apos;")}),unescapeHTML:d(function(a){return a.replace(/&lt;/g,"<").replace(/&gt;/g,
">").replace(/&quot;/g,'"').replace(/&apos;/g,"'").replace(/&amp;/g,"&")}),escapeRegExp:d(function(a){return a.replace(/([-.*+?^${}()|[\]\/\\])/g,"\\$1")}),insert:d(function(a,b,c){a=a.split("");a.splice(b*1||0,0,c);return a.join("")}),include:d(function(a,b){return a.indexOf(b)!==-1}),join:d(function(a){var b=Array.prototype.slice.call(arguments);return b.join(b.shift())}),lines:d(function(a){return a.split("\n")}),reverse:d(function(a){return Array.prototype.reverse.apply(String(a).split("")).join("")}),
splice:d(function(a,b,c,e){a=a.split("");a.splice(b*1||0,c*1||0,e);return a.join("")}),startsWith:d(function(a,b){return a.length>=b.length&&a.substring(0,b.length)===b}),endsWith:d(function(a,b){return a.length>=b.length&&a.substring(a.length-b.length)===b}),succ:d(function(a){var b=a.split("");b.splice(a.length-1,1,String.fromCharCode(a.charCodeAt(a.length-1)+1));return b.join("")}),titleize:d(function(a){for(var a=a.split(" "),b,c=0;c<a.length;c++)b=a[c].split(""),typeof b[0]!=="undefined"&&(b[0]=
b[0].toUpperCase()),c+1===a.length?a[c]=b.join(""):a[c]=b.join("")+" ";return a.join("")}),camelize:d(function(a){return e.trim(a).replace(/(\-|_|\s)+(.)?/g,function(a,c,e){return e?e.toUpperCase():""})}),underscored:function(a){return e.trim(a).replace(/([a-z\d])([A-Z]+)/g,"$1_$2").replace(/\-|\s+/g,"_").toLowerCase()},dasherize:function(a){return e.trim(a).replace(/([a-z\d])([A-Z]+)/g,"$1-$2").replace(/^([A-Z]+)/,"-$1").replace(/\_|\s+/g,"-").toLowerCase()},humanize:function(a){return e.capitalize(this.underscored(a).replace(/_id$/,
"").replace(/_/g," "))},trim:d(function(a,b){if(!b&&o)return o.call(a);b=b?e.escapeRegExp(b):"\\s";return a.replace(RegExp("^["+b+"]+|["+b+"]+$","g"),"")}),ltrim:d(function(a,b){b=b?e.escapeRegExp(b):"\\s";return a.replace(RegExp("^["+b+"]+","g"),"")}),rtrim:d(function(a,b){b=b?e.escapeRegExp(b):"\\s";return a.replace(RegExp("["+b+"]+$","g"),"")}),truncate:d(function(a,b,c){b=b*1||0;return a.length>b?a.slice(0,b)+(c||"..."):a}),prune:d(function(a,b,c){var c=c||"...",b=b*1||0,d="",d=a.substring(b-
1,b+1).search(/^\w\w$/)===0?e.rtrim(a.slice(0,b).replace(/([\W][\w]*)$/,"")):e.rtrim(a.slice(0,b)),d=d.replace(/\W+$/,"");return d.length+c.length>a.length?a:d+c}),words:function(a,b){return String(a).split(b||" ")},pad:d(function(a,b,c,e){var d="",d=0,b=b*1||0;c?c.length>1&&(c=c.charAt(0)):c=" ";switch(e){case "right":d=b-a.length;d=l(c,d);a+=d;break;case "both":d=b-a.length;d={left:l(c,Math.ceil(d/2)),right:l(c,Math.floor(d/2))};a=d.left+a+d.right;break;default:d=b-a.length,d=l(c,d),a=d+a}return a}),
lpad:function(a,b,c){return e.pad(a,b,c)},rpad:function(a,b,c){return e.pad(a,b,c,"right")},lrpad:function(a,b,c){return e.pad(a,b,c,"both")},sprintf:m,vsprintf:function(a,b){b.unshift(a);return m.apply(null,b)},toNumber:function(a,b){var c;c=(a*1||0).toFixed(b*1||0)*1||0;return!(c===0&&a!=="0"&&a!==0)?c:Number.NaN},strRight:d(function(a,b){var c=!b?-1:a.indexOf(b);return c!=-1?a.slice(c+b.length,a.length):a}),strRightBack:d(function(a,b){var c=!b?-1:a.lastIndexOf(b);return c!=-1?a.slice(c+b.length,
a.length):a}),strLeft:d(function(a,b){var c=!b?-1:a.indexOf(b);return c!=-1?a.slice(0,c):a}),strLeftBack:d(function(a,b){var c=a.lastIndexOf(b);return c!=-1?a.slice(0,c):a}),exports:function(){var a={},b;for(b in this)if(this.hasOwnProperty(b)&&!(b=="include"||b=="contains"||b=="reverse"))a[b]=this[b];return a}};e.strip=e.trim;e.lstrip=e.ltrim;e.rstrip=e.rtrim;e.center=e.lrpad;e.ljust=e.lpad;e.rjust=e.rpad;e.contains=e.include;if(typeof exports!=="undefined"){if(typeof module!=="undefined"&&module.exports)module.exports=
e;exports._s=e}else typeof k._!=="undefined"?(k._.string=e,k._.str=k._.string):k._={string:e,str:e}})(this||window);

View File

@ -809,33 +809,33 @@ label.error {
also on the first and last children of the first and last row
*/
.openerp .oe-listview table.oe-listview-content {
-webkit-border-radius: 7px;
-moz-border-radius: 7px;
border-radius: 7px;
-webkit-border-radius: 4px;
-moz-border-radius: 4px;
border-radius: 4px;
}
.openerp .oe-listview table.oe-listview-content thead tr:first-child th:first-child {
-webkit-border-top-left-radius: 7px;
-moz-border-radius-topleft: 7px;
border-top-left-radius: 7px;
-webkit-border-top-left-radius: 4px;
-moz-border-radius-topleft: 4px;
border-top-left-radius: 4px;
}
.openerp .oe-listview table.oe-listview-content thead tr:first-child th:last-child {
-webkit-border-top-right-radius: 7px;
-moz-border-radius-topright: 7px;
border-top-right-radius: 7px;
-webkit-border-top-right-radius: 4px;
-moz-border-radius-topright: 4px;
border-top-right-radius: 4px;
}
.openerp .oe-listview table.oe-listview-content tfoot tr:last-child th:first-child,
.openerp .oe-listview table.oe-listview-content tfoot tr:last-child td:first-child,
.openerp .oe-listview table.oe-listview-content tbody:last-child tr:last-child th:first-child {
-webkit-border-bottom-left-radius: 7px;
-moz-border-radius-bottomleft: 7px;
border-bottom-left-radius: 7px;
-webkit-border-bottom-left-radius: 4px;
-moz-border-radius-bottomleft: 4px;
border-bottom-left-radius: 4px;
}
.openerp .oe-listview table.oe-listview-content tfoot tr:last-child th:last-child,
.openerp .oe-listview table.oe-listview-content tfoot tr:last-child td:last-child,
.openerp .oe-listview table.oe-listview-content tbody:last-child tr:last-child td:last-child {
-webkit-border-bottom-right-radius: 7px;
-moz-border-radius-bottomright: 7px;
border-bottom-right-radius: 7px;
-webkit-border-bottom-right-radius: 4px;
-moz-border-radius-bottomright: 4px;
border-bottom-right-radius: 4px;
}
/* Notebook */
@ -967,20 +967,25 @@ label.error {
.openerp .oe_forms textarea {
resize:vertical;
}
.openerp .oe_forms input[type="text"], .openerp .oe_forms input[type="password"], .openerp .oe_forms select, .openerp .oe_forms .button {
.openerp .oe_forms input[type="text"], .openerp .oe_forms input[type="password"], .openerp .oe_forms select, .openerp .oe_forms .oe_button {
height: 22px;
}
.openerp .oe_forms input.field_datetime {
min-width: 11em;
}
.openerp .oe_forms.oe_frame .oe_datepicker_root {
width: 100%;
}
.openerp .oe_forms .button {
.openerp .oe_forms .oe_button {
color: #4c4c4c;
white-space: nowrap;
min-width: 100%;
width: 100%;
}
.openerp .oe_forms .button span {
@-moz-document url-prefix() {
/* Strange firefox behaviour on width: 100% + white-space: nowrap */
.openerp .oe_forms .oe_button {
width: auto;
}
}
.openerp .oe_forms .oe_button span {
position: relative;
vertical-align: top;
}
@ -989,13 +994,20 @@ label.error {
cursor: pointer;
right: 5px;
top: 3px;
z-index: 2;
}
.openerp .oe_datepicker_container {
position: absolute;
top: 0;
right: 0;
display: none;
}
.openerp .oe_datepicker_root {
position: relative;
display: inline-block;
}
.openerp .oe_datepicker_root input[type="text"] {
min-width: 160px;
.openerp .oe_forms.oe_frame .oe_datepicker_root {
width: 100%;
}
.openerp .oe_input_icon_disabled {
position: absolute;
@ -1003,7 +1015,7 @@ label.error {
opacity: 0.5;
filter:alpha(opacity=50);
right: 5px;
top: 5px;
top: 3px;
}
.openerp img.oe_field_translate {
margin-left: -21px;

View File

@ -158,7 +158,7 @@ openerp.web.CrashManager = openerp.web.CallbackEnabled.extend({
},
on_managed_error: function(error) {
$('<div>' + QWeb.render('DialogWarning', {error: error}) + '</div>').dialog({
title: "OpenERP " + _.capitalize(error.type),
title: "OpenERP " + _.str.capitalize(error.type),
buttons: {
Ok: function() {
$(this).dialog("close");
@ -168,7 +168,7 @@ openerp.web.CrashManager = openerp.web.CallbackEnabled.extend({
},
on_traceback: function(error) {
var dialog = new openerp.web.Dialog(this, {
title: "OpenERP " + _.capitalize(error.type),
title: "OpenERP " + _.str.capitalize(error.type),
autoOpen: true,
width: '90%',
height: '90%',
@ -184,7 +184,8 @@ openerp.web.CrashManager = openerp.web.CallbackEnabled.extend({
}
});
openerp.web.Loading = openerp.web.Widget.extend(/** @lends openerp.web.Loading# */{
openerp.web.Loading = openerp.web.Widget.extend(/** @lends openerp.web.Loading# */{
template: 'Loading',
/**
* @constructs openerp.web.Loading
* @extends openerp.web.Widget
@ -192,8 +193,8 @@ openerp.web.Loading = openerp.web.Widget.extend(/** @lends openerp.web.Loading#
* @param parent
* @param element_id
*/
init: function(parent, element_id) {
this._super(parent, element_id);
init: function(parent) {
this._super(parent);
this.count = 0;
this.blocked_ui = false;
this.session.on_rpc_request.add_first(this.on_rpc_event, 1);
@ -210,12 +211,13 @@ openerp.web.Loading = openerp.web.Widget.extend(/** @lends openerp.web.Loading#
}
this.count += increment;
if (this.count) {
if (this.count > 0) {
//this.$element.html(QWeb.render("Loading", {}));
this.$element.html("Loading ("+this.count+")");
this.$element.show();
this.widget_parent.$element.addClass('loading');
} else {
this.count = 0;
clearTimeout(this.long_running_timer);
// Don't unblock if blocked by somebody else
if (self.blocked_ui) {
@ -242,10 +244,8 @@ openerp.web.Database = openerp.web.Widget.extend(/** @lends openerp.web.Database
this.$option_id = $('#' + option_id);
},
start: function() {
this._super();
this.$element.html(QWeb.render("Database", this));
this.$element.closest(".openerp")
.removeClass("login-mode")
.addClass("database_block");
var self = this;
var fetch_db = this.rpc("/web/database/get_list", {}, function(result) {
@ -266,23 +266,30 @@ openerp.web.Database = openerp.web.Widget.extend(/** @lends openerp.web.Database
this.$element.find('#db-restore').click(this.do_restore);
this.$element.find('#db-change-password').click(this.do_change_password);
this.$element.find('#back-to-login').click(function() {
self.stop();
self.hide();
});
},
stop: function () {
this.hide();
this.$option_id.empty();
this.$element
.find('#db-create, #db-drop, #db-backup, #db-restore, #db-change-password, #back-to-login')
.unbind('click')
.end()
.closest(".openerp")
.addClass("login-mode")
.removeClass("database_block")
.end()
.empty();
this._super();
},
show: function () {
this.$element.closest(".openerp")
.removeClass("login-mode")
.addClass("database_block");
},
hide: function () {
this.$element.closest(".openerp")
.addClass("login-mode")
.removeClass("database_block")
},
/**
* Converts a .serializeArray() result into a dict. Does not bother folding
* multiple identical keys into an array, last key wins.
@ -368,6 +375,7 @@ openerp.web.Database = openerp.web.Widget.extend(/** @lends openerp.web.Database
}
self.db_list.push(self.to_object(fields)['db_name']);
self.db_list.sort();
self.widget_parent.set_db_list(self.db_list);
var form_obj = self.to_object(fields);
self.wait_for_newdb(result, {
password: form_obj['super_admin_pwd'],
@ -397,6 +405,7 @@ openerp.web.Database = openerp.web.Widget.extend(/** @lends openerp.web.Database
}
$db_list.find(':selected').remove();
self.db_list.splice(_.indexOf(self.db_list, db, true), 1);
self.widget_parent.set_db_list(self.db_list);
self.do_notify("Dropping database", "The database '" + db + "' has been dropped");
});
}
@ -529,16 +538,16 @@ openerp.web.Login = openerp.web.Widget.extend(/** @lends openerp.web.Login# */{
var self = this;
this.database = new openerp.web.Database(
this, "oe_database", "oe_db_options");
this.database.start();
this.$element.find('#oe-db-config').click(function() {
self.database.start();
self.database.show();
});
this.$element.find("form").submit(this.on_submit);
this.rpc("/web/database/get_list", {}, function(result) {
var tpl = openerp.web.qweb.render('Login_dblist', {db_list: result.db_list, selected_db: self.selected_db});
self.$element.find("input[name=db]").replaceWith(tpl)
self.set_db_list(result.db_list);
},
function(error, event) {
if (error.data.fault_code === 'AccessDenied') {
@ -547,6 +556,15 @@ openerp.web.Login = openerp.web.Widget.extend(/** @lends openerp.web.Login# */{
});
},
stop: function () {
this.database.stop();
this._super();
},
set_db_list: function (list) {
this.$element.find("[name=db]").replaceWith(
openerp.web.qweb.render('Login_dblist', {
db_list: list, selected_db: this.selected_db}))
},
on_login_invalid: function() {
this.$element.closest(".openerp").addClass("login-mode");
},
@ -966,7 +984,7 @@ openerp.web.WebClient = openerp.web.Widget.extend(/** @lends openerp.web.WebClie
this.$element.html(QWeb.render("Interface", params));
this.notification = new openerp.web.Notification(this);
this.loading = new openerp.web.Loading(this,"oe_loading");
this.loading = new openerp.web.Loading(this);
this.crashmanager = new openerp.web.CrashManager();
this.header = new openerp.web.Header(this);
@ -990,6 +1008,7 @@ openerp.web.WebClient = openerp.web.Widget.extend(/** @lends openerp.web.WebClie
start: function() {
this._super.apply(this, arguments);
this.notification.prependTo(this.$element);
this.loading.appendTo($('#oe_loading'));
this.header.appendTo($("#oe_header"));
this.session.start();
this.login.appendTo($('#oe_login'));

View File

@ -125,7 +125,11 @@ openerp.web.callback = function(obj, method) {
callback.callback_chain.splice(i, 1);
i -= 1;
}
r = c.callback.apply(c.self, c.args.concat(args));
var result = c.callback.apply(c.self, c.args.concat(args));
if (c.callback === method) {
// return the result of the original method
r = result;
}
// TODO special value to stop the chain
// openerp.web.callback_stop
}
@ -354,6 +358,7 @@ openerp.web.Connection = openerp.web.CallbackEnabled.extend( /** @lends openerp.
this.debug = (window.location.search.indexOf('?debug') !== -1);
this.session_id = false;
this.uid = false;
this.username = false;
this.user_context= {};
this.db = false;
this.module_list = [];
@ -484,10 +489,13 @@ openerp.web.Connection = openerp.web.CallbackEnabled.extend( /** @lends openerp.
var self = this;
var params = { db: db, login: login, password: password };
return this.rpc("/web/session/login", params, function(result) {
self.session_id = result.session_id;
self.uid = result.uid;
self.user_context = result.context;
self.db = result.db;
_.extend(self, {
session_id: result.session_id,
uid: result.uid,
user_context: result.context,
db: result.db,
username: result.login
});
self.session_save();
self.on_session_valid();
return true;
@ -501,9 +509,12 @@ openerp.web.Connection = openerp.web.CallbackEnabled.extend( /** @lends openerp.
var self = this;
this.session_id = this.get_cookie('session_id');
return this.rpc("/web/session/get_session_info", {}).then(function(result) {
self.uid = result.uid;
self.user_context = result.context;
self.db = result.db;
_.extend(self, {
uid: result.uid,
user_context: result.context,
db: result.db,
username: result.login
});
if (self.uid)
self.on_session_valid();
else
@ -716,7 +727,7 @@ openerp.web.Connection = openerp.web.CallbackEnabled.extend( /** @lends openerp.
if (parseInt(cookie_val, 10) !== token) { continue; }
// clear cookie
document.cookie = _.sprintf("%s=;expires=%s;path=/",
document.cookie = _.str.sprintf("%s=;expires=%s;path=/",
cookie_name, new Date().toGMTString());
if (options.success) { options.success(); }
complete();
@ -1055,7 +1066,7 @@ openerp.web.qweb.format_text_node = function(s) {
if (translation && translation.value === 'off') {
return s;
}
var ts = _.trim(s);
var ts = _.str.trim(s);
if (ts.length === 0) {
return s;
}

View File

@ -119,17 +119,18 @@ openerp.web.ContainerDataGroup = openerp.web.DataGroup.extend( /** @lends opener
aggregates[key] = value || 0;
});
var group_size = fixed_group[field_name + '_count'] || fixed_group.__count || 0;
var leaf_group = fixed_group.__context.group_by.length === 0;
return {
__context: fixed_group.__context,
__domain: fixed_group.__domain,
grouped_on: field_name,
// if terminal group (or no group) and group_by_no_leaf => use group.__count
length: fixed_group[field_name + '_count'] || fixed_group.__count,
length: group_size,
value: fixed_group[field_name],
openable: !(this.context['group_by_no_leaf']
&& fixed_group.__context.group_by.length === 0),
// A group is openable if it's not a leaf in group_by_no_leaf mode
openable: !(leaf_group && this.context['group_by_no_leaf']),
aggregates: aggregates
};
@ -315,7 +316,7 @@ openerp.web.DataSet = openerp.web.Widget.extend( /** @lends openerp.web.DataSet
def.reject();
} else {
fields = fields || false;
return this.read_ids([this.ids[this.index]], fields).then(function(records) {
this.read_ids([this.ids[this.index]], fields).then(function(records) {
def.resolve(records[0]);
}, function() {
def.reject.apply(def, arguments);

View File

@ -76,7 +76,13 @@ openerp.web.format_value = function (value, descriptor, value_if_empty) {
if (typeof value === 'number' && isNaN(value)) {
value = false;
}
//noinspection FallthroughInSwitchStatementJS
switch (value) {
case '':
if (descriptor.type === 'char') {
return '';
}
console.warn('Field', descriptor, 'had an empty string as value, treating as false...');
case false:
case Infinity:
case -Infinity:
@ -86,18 +92,18 @@ openerp.web.format_value = function (value, descriptor, value_if_empty) {
switch (descriptor.widget || descriptor.type) {
case 'integer':
return openerp.web.insert_thousand_seps(
_.sprintf('%d', value));
_.str.sprintf('%d', value));
case 'float':
var precision = descriptor.digits ? descriptor.digits[1] : 2;
var formatted = _.sprintf('%.' + precision + 'f', value).split('.');
var formatted = _.str.sprintf('%.' + precision + 'f', value).split('.');
formatted[0] = openerp.web.insert_thousand_seps(formatted[0]);
return formatted.join(l10n.decimal_point);
case 'float_time':
return _.sprintf("%02d:%02d",
return _.str.sprintf("%02d:%02d",
Math.floor(value),
Math.round((value % 1) * 60));
case 'progressbar':
return _.sprintf(
return _.str.sprintf(
'<progress value="%.2f" max="100.0">%.2f%%</progress>',
value, value);
case 'many2one':

View File

@ -41,7 +41,11 @@ openerp.web.SearchView = openerp.web.Widget.extend(/** @lends openerp.web.Search
if (this.headless) {
this.ready.resolve();
} else {
this.rpc("/web/searchview/load", {"model": this.model, "view_id":this.view_id}, this.on_loaded);
this.rpc("/web/searchview/load", {
model: this.model,
view_id: this.view_id,
context: this.dataset.get_context()
}, this.on_loaded);
}
return this.ready.promise();
},
@ -137,7 +141,7 @@ openerp.web.SearchView = openerp.web.Widget.extend(/** @lends openerp.web.Search
on_loaded: function(data) {
if (data.fields_view.type !== 'search' ||
data.fields_view.arch.tag !== 'search') {
throw new Error(_.sprintf(
throw new Error(_.str.sprintf(
"Got non-search view after asking for a search view: type %s, arch root %s",
data.fields_view.type, data.fields_view.arch.tag));
}
@ -425,7 +429,7 @@ openerp.web.search.Invalid = openerp.web.Class.extend( /** @lends openerp.web.se
this.message = message;
},
toString: function () {
return _.sprintf(
return _.str.sprintf(
_t("Incorrect value for field %(fieldname)s: [%(value)s] is %(message)s"),
{fieldname: this.field, value: this.value, message: this.message}
);

View File

@ -18,7 +18,7 @@ openerp.web.ViewEditor = openerp.web.Widget.extend({
init_view_editor: function() {
var self = this;
var action = {
name: _.sprintf("Manage Views (%s)", this.model),
name: _.str.sprintf("Manage Views (%s)", this.model),
context: this.session.user_context,
domain: [["model", "=", this.model]],
res_model: 'ir.ui.view',
@ -78,7 +78,7 @@ openerp.web.ViewEditor = openerp.web.Widget.extend({
var self = this;
this.create_view_dialog = new openerp.web.Dialog(this, {
modal: true,
title: _.sprintf("Create a view (%s)", self.model),
title: _.str.sprintf("Create a view (%s)", self.model),
width: 500,
height: 400,
buttons: {
@ -86,16 +86,16 @@ openerp.web.ViewEditor = openerp.web.Widget.extend({
var view_values = {};
var warn = false;
_.each(self.create_view_widget, function(widget) {
if (widget.invalid) {
if (widget.is_invalid) {
warn = true;
return false;
};
if (widget.dirty && !widget.invalid) {
if (widget.dirty && !widget.is_invalid) {
view_values[widget.name] = widget.get_value();
}
});
if (warn) {
self.on_valid_create_view();
self.on_valid_create_view(self.create_view_widget);
} else {
$.when(self.do_save_view(view_values)).then(function() {
self.create_view_dialog.close();
@ -112,15 +112,11 @@ openerp.web.ViewEditor = openerp.web.Widget.extend({
this.create_view_dialog.start().open();
var view_widget = [{'name': 'view_name', 'string':'View Name', 'type': 'char', 'required': true, 'value' : this.model + '.custom_' + Math.round(Math.random() * 1000)},
{'name': 'view_type', 'string': 'View Type', 'type': 'selection', 'required': true, 'value': 'Form', 'selection': [['',''],['tree', 'Tree'],['form', 'Form'],['graph', 'Graph'],['calendar', 'Calender']]},
{'name': 'proirity', 'string': 'Priority', 'type': 'char', 'required': true, 'value':'16'}];
{'name': 'proirity', 'string': 'Priority', 'type': 'float', 'required': true, 'value':'16'}];
this.create_view_dialog.$element.append('<table id="create_view" style="width:400px" class="oe_forms"></table>');
this.create_view_widget = [];
_.each(view_widget, function(widget) {
var type_widget = new (self.property.get_any([widget.type])) (self.create_view_dialog, widget.name);
if (widget.selection) {
type_widget.selection = widget.selection;
}
type_widget.required = widget.required;
var type_widget = new (self.property.get_any([widget.type])) (self.create_view_dialog, widget);
self.create_view_dialog.$element.find('table[id=create_view]').append('<tr><td width="100px" align="right">' + widget.string + ':</td>' + type_widget.render()+'</tr>');
var value = null;
if (widget.value) {
@ -147,7 +143,7 @@ openerp.web.ViewEditor = openerp.web.Widget.extend({
if (field_name) {
model_dataset.read_slice(['name','field_id'], {"domain": [['model','=',self.model]]}, function(records) {
if (records) {view_string = records[0].name;}
var arch = _.sprintf("<?xml version='1.0'?>\n<%s string='%s'>\n\t<field name='%s'/>\n</%s>", values.view_type, view_string, field_name, values.view_type);
var arch = _.str.sprintf("<?xml version='1.0'?>\n<%s string='%s'>\n\t<field name='%s'/>\n</%s>", values.view_type, view_string, field_name, values.view_type);
var vals = {'model': self.model, 'name': values.view_name, 'priority': values.priority, 'type': values.view_type, 'arch': arch};
self.dataset.create(vals, function(suc) {
def.resolve();
@ -157,25 +153,29 @@ openerp.web.ViewEditor = openerp.web.Widget.extend({
});
return def.promise();
},
on_valid_create_view: function() {
on_valid_create_view: function(widgets) {
var msg = "<ul>";
_.each(self.create_view_widget, function(widget) {
if (widget.invalid) {
_.each(widgets, function(widget) {
if (widget.is_invalid) {
msg += "<li>" + widget.name + "</li>";
}
});
msg += "</ul>";
self.do_warn("The following fields are invalid :", msg);
this.do_warn("The following fields are invalid :", msg);
},
add_node_name : function(node) {
if(node.tagName.toLowerCase() == "button" || node.tagName.toLowerCase() == "field"){
return (node.getAttribute('name'))?
_.sprintf( "<%s name='%s'>",node.tagName.toLowerCase(), node.getAttribute('name')):
_.sprintf( "<%s>",node.tagName.toLowerCase());
_.str.sprintf( "<%s name='%s'>",node.tagName.toLowerCase(), node.getAttribute('name')):
_.str.sprintf( "<%s>",node.tagName.toLowerCase());
}else if(node.tagName.toLowerCase() == "group"){
return (node.getAttribute('string'))?
_.str.sprintf( "<%s>",node.getAttribute('string')):
_.str.sprintf( "<%s>",node.tagName.toLowerCase());
}else{
return (node.getAttribute('string'))?
_.sprintf( "<%s string='%s'>",node.tagName.toLowerCase(), node.getAttribute('string')):
_.sprintf( "<%s>",node.tagName.toLowerCase());
_.str.sprintf( "<%s string='%s'>",node.tagName.toLowerCase(), node.getAttribute('string')):
_.str.sprintf( "<%s>",node.tagName.toLowerCase());
}
},
do_delete_view: function() {
@ -237,7 +237,7 @@ openerp.web.ViewEditor = openerp.web.Widget.extend({
'level': 0,
'id': this.xml_element_id +=1,
'att_list': [],
'name': _.sprintf("<view view_id = %s>", view_id),
'name': _.str.sprintf("<view view_id = %s>", view_id),
'child_id': []
};
var xml_arch = QWeb.load_xml(arch);
@ -249,7 +249,7 @@ openerp.web.ViewEditor = openerp.web.Widget.extend({
this.dataset.read_ids([parseInt(self.main_view_id)], ['arch', 'type'], function(arch) {
if (arch.length) {
var arch_object = self.parse_xml(arch[0].arch, self.main_view_id);
self.main_view_type = arch[0].type
self.main_view_type = arch[0].type == 'tree'? 'list': arch[0].type;
view_arch_list.push({"view_id": self.main_view_id, "arch": arch[0].arch});
self.dataset.read_slice([], {domain: [['inherit_id','=', parseInt(self.main_view_id)]]}, function(result) {
_.each(result, function(res) {
@ -295,7 +295,7 @@ openerp.web.ViewEditor = openerp.web.Widget.extend({
});
}else{
var temp = _.reject(xpath_arch_object[0].child_id[0].att_list, function(list) {
return _.include(list, "position")
return list instanceof Array? _.include(list, "position"): false
});
expr_to_list = [_.flatten(temp)];
}
@ -382,12 +382,12 @@ openerp.web.ViewEditor = openerp.web.Widget.extend({
this.one_object = one_object;
this.edit_xml_dialog = new openerp.web.Dialog(this, {
modal: true,
title: _.sprintf("View Editor %d - %s", self.main_view_id, self.model),
title: _.str.sprintf("View Editor %d - %s", self.main_view_id, self.model),
width: 750,
height: 500,
buttons: {
"Inherited View": function() {
//todo
//TODO
},
"Preview": function() {
var action = {
@ -439,7 +439,7 @@ openerp.web.ViewEditor = openerp.web.Widget.extend({
var view_id,view_xml_id;
var view_find = side;
//for view id found
//for view id finding
var min_level = this.one_object.clicked_tr_id;
if(($(side).find('a').text()).search("view_id") != -1){
view_id = parseInt(($(view_find).find('a').text()).replace(/[^0-9]+/g, ''));
@ -494,7 +494,7 @@ openerp.web.ViewEditor = openerp.web.Widget.extend({
_.each([tr,parent_tr],function(element){
property_to_check.push(
_.detect(_.keys(_CHILDREN),function(res){
return _.includes(element, res);
return _.str.include(element, res);
}));
});
self.on_add_node(property_to_check, fields);
@ -502,12 +502,17 @@ openerp.web.ViewEditor = openerp.web.Widget.extend({
},
do_node_edit: function(side){
var self = this;
var tr = $(side).find('a').text();
var result = self.get_object_by_id(this.one_object.clicked_tr_id,this.one_object['main_object'], []);
if (result.length && result[0] && result[0].att_list) {
var properties = _PROPERTIES[result[0].att_list[0]];
self.on_edit_node(properties);
}
/* var tr = $(side).find('a').text();
var tag = _.detect(_.keys(_PROPERTIES),function(res){
return _.includes(tr, res);
});
var properties = _PROPERTIES[tag];
self.on_edit_node(properties);
self.on_edit_node(properties);*/
},
do_node_down: function(cur_tr, img){
var self = this;
@ -663,18 +668,15 @@ openerp.web.ViewEditor = openerp.web.Widget.extend({
parent = $(arch1).parents();
} else if (move_direct == "update_node") {
_.each(update_values, function(val){
if(val[0] == "required"){
$(arch1).attr("required", "true");
}else{
$(arch1).attr(val[0],val[1]);
}
if (val[1]) $(arch1)[0].setAttribute(val[0], val[1]);
else $(arch1)[0].removeAttribute(val[0]);
});
var new_obj = self.create_View_Node(arch1);
new_obj.id = obj.id,new_obj.child_id = obj.child_id;
self.edit_xml_dialog.$element.find("tr[id='viewedit-"+self.one_object.clicked_tr_id+"']")
.find('a').text(new_obj.name);
self.edit_xml_dialog.$element.
find("tr[id='viewedit-"+this.one_object.clicked_tr_id+"']").
find('a').text(new_obj.name);
child_list.splice(index, 1, new_obj);
parent = $(arch1).parents();
@ -802,14 +804,23 @@ openerp.web.ViewEditor = openerp.web.Widget.extend({
height: 400,
buttons: {
"Update": function(){
var warn = false;
var update_values = [];
_.each(self.edit_widget, function(widget) {
if (widget.dirty && !widget.invalid) {
if (widget.is_invalid) {
warn = true;
return false;
};
if (widget.dirty && !widget.is_invalid) {
update_values.push([widget.name, widget.get_value()]);
}
});
self.do_save_update_arch("update_node", update_values);
self.edit_node_dialog.close();
if (warn) {
self.on_valid_create_view(self.edit_widget);
} else {
self.do_save_update_arch("update_node", update_values);
self.edit_node_dialog.close();
}
},
"Cancel": function(){
self.edit_node_dialog.close();
@ -817,24 +828,63 @@ openerp.web.ViewEditor = openerp.web.Widget.extend({
}
});
this.edit_node_dialog.start().open();
var widget = _.keys(self.property.map);
var _PROPERTIES_ATTRIBUTES = {
'name' : {'name':'name', 'string': 'Name', 'type': 'char'},
'string' : {'name':'string', 'string': 'String', 'type': 'char'},
'required' : {'name':'required', 'string': 'Required', 'type': 'boolean'},
'readonly' : {'name':'readonly', 'string': 'Readonly', 'type': 'boolean'},
'domain' : {'name':'domain', 'string': 'Domain', 'type': 'char'},
'context' : {'name':'context', 'string': 'Context', 'type': 'char'},
'limit' : {'name':'limit', 'string': 'Limit', 'type': 'float'},
'min_rows' : {'name':'min_rows', 'string': 'Minimum rows', 'type': 'float'},
'date_start' : {'name':'date_start', 'string': 'Start date', 'type': 'char'},
'date_delay' : {'name':'date_delay', 'string': 'Delay date', 'type': 'char'},
'day_length' : {'name':'day_length', 'string': 'Day length', 'type': 'char'},
'mode' : {'name':'mode', 'string': 'Mode', 'type': 'char'},
'align' : {'name':'align', 'string': 'Alignment ', 'type': 'selection', 'selection': [['', ''], ['0.0', 'Left'], ['0.5', 'Center'], ['1.0', 'Right']]},
'icon' : {'name':'icon', 'string': 'Icon', 'type': 'selection', 'selection': _ICONS},
'type' : {'name':'type', 'string': 'Type', 'type': 'selection', 'selection': [['', ''], ['action', 'Action'], ['object', 'Object'], ['workflow', 'Workflow'], ['server_action', 'Server Action']]},
'special' : {'name':'special', 'string': 'Special', 'type': 'selection', 'selection': [['',''],['save', 'Save Button'], ['cancel', 'Cancel Button'], ['open', 'Open Button']]},
'target' : {'name':'target', 'string': 'Target', 'type': 'selection', 'selection': [['', ''], ['new', 'New Window']]},
'confirm' : {'name':'confirm', 'string': 'Confirm', 'type': 'char'},
'style' : {'name':'style', 'string': 'Style', 'type': 'selection', 'selection':[["",""],["1", "1"],["1-1", "1-1"],["1-2", "1-2"],["2-1", "2-1"],["1-1-1", "1-1-1"]]},
'filename' : {'name':'filename', 'string': 'File Name', 'type': 'char'},
'width' : {'name':'width', 'string': 'Width', 'type': 'float'},
'height' : {'name':'height', 'string': 'Height', 'type': 'float'},
'attrs' : {'name':'attrs', 'string': 'Attrs', 'type': 'char'},
'col' : {'name':'col', 'string': 'col', 'type': 'float'},
'link' : {'name':'link', 'string': 'Link', 'type': 'char'},
'position' : {'name':'position', 'string': 'Position', 'type': 'selection', 'selection': [['',''],['after', 'After'],['before', 'Before'],['inside', 'Inside'],['replace', 'Replace']]},
'states' : {'name':'states', 'string': 'states', 'type': 'char'},
'eval' : {'name':'eval', 'string': 'Eval', 'type': 'char'},
'ref' : {'name':'ref', 'string': 'Ref', 'type': 'char'},
'on_change' : {'name':'on_change', 'string': 'On change', 'type': 'char'},
'nolabel' : {'name':'nolabel', 'string': 'No label', 'type': 'boolean'},
'completion' : {'name':'completion', 'string': 'Completion', 'type': 'boolean'},
'colspan' : {'name':'colspan', 'string': 'Colspan', 'type': 'float'},
'widget' : {'name':'widget', 'string': 'widget', 'type': 'selection'},
'colors' : {'name':'colors', 'string': 'Colors', 'type': 'char'},
'editable' : {'name':'editable', 'string': 'Editable', 'type': 'selection', 'selection': [["",""],["top","Top"],["bottom", "Bottom"]]},
'groups' : {'name':'groups', 'string': 'Groups', 'type': 'seleciton_multi'},
};
var arch_val = self.get_object_by_id(this.one_object.clicked_tr_id,this.one_object['main_object'], []);
this.edit_node_dialog.$element.append('<table id="rec_table" style="width:400px" class="oe_forms"></table>');
this.edit_widget = [];
_.each(properties, function(property) {
type_widget = false;
self.ready = $.when(self.on_groups(property)).then(function () {
if (_.include(widget, property)){
type_widget = new (self.property.get_any([property])) (self.edit_node_dialog, property);
} else {
type_widget = new openerp.web.ViewEditor.FieldChar (self.edit_node_dialog, property);
}
self.ready = $.when(self.on_groups(properties)).then(function () {
_PROPERTIES_ATTRIBUTES['groups']['selection'] = self.groups;
var values = _.keys( openerp.web.form.widgets.map);
values.push('');
values.sort();
_PROPERTIES_ATTRIBUTES['widget']['selection'] = values;
var widgets = _.filter(_PROPERTIES_ATTRIBUTES, function(property){ return _.include(properties, property.name)})
_.each(widgets, function(widget) {
var type_widget = new (self.property.get_any([widget.type])) (self.edit_node_dialog, widget);
var value = _.detect(arch_val[0]['att_list'],function(res) {
return _.include(res, property);
if (res instanceof Array) return _.include(res, widget.name);
else return false;
});
value = value instanceof Array ? value[1] : value;
if (property == 'groups') type_widget.selection = self.groups;
self.edit_node_dialog.$element.find('table[id=rec_table]').append('<tr><td align="right">' + property + ':</td>' + type_widget.render() + '</tr>');
self.edit_node_dialog.$element.find('table[id=rec_table]').append('<tr><td align="right">' + widget.string + ':</td>' + type_widget.render() + '</tr>');
type_widget.start();
type_widget.set_value(value);
self.edit_widget.push(type_widget);
@ -842,12 +892,12 @@ openerp.web.ViewEditor = openerp.web.Widget.extend({
});
},
//for getting groups
on_groups: function(property){
on_groups: function(properties){
var self = this,
def = $.Deferred();
if (property != 'groups') {
if (!_.include(properties, 'groups')) {
self.groups = false;
return false;
def.resolve();
}
var group_ids = [],
group_names = {},
@ -862,7 +912,7 @@ openerp.web.ViewEditor = openerp.web.Widget.extend({
group_names[key]=res.name;
group_ids.push(res.id);
});
model_data
model_data
.read_slice([],{domain:[['res_id', 'in', group_ids],['model','=','res.groups']]})
.done(function(model_grp) {
_.each(model_grp,function(res_group){
@ -879,9 +929,9 @@ openerp.web.ViewEditor = openerp.web.Widget.extend({
var positions = ['After','Before','Inside'];
var render_list = [];
var render_list =[{'name': 'node_type','selection': _.keys(_CHILDREN).sort(),
'value': 'field', 'string': 'Node Type'},
{'name': 'position','selection': positions, 'value': false, 'string': 'Position'},
{'name': 'field_value','selection': fields, 'value': false, 'string': ''}];
'value': 'field', 'string': 'Node Type','type': 'selection'},
{'name': 'position','selection': positions, 'value': false, 'string': 'Position','type': 'selection'},
{'name': 'field_value','selection': fields, 'value': false, 'string': '','type': 'selection'}];
this.add_widget = [];
this.add_node_dialog = new openerp.web.Dialog(this,{
modal: true,
@ -903,8 +953,8 @@ openerp.web.ViewEditor = openerp.web.Widget.extend({
}
if(check_add_node){
var tag = (values.node_type == "field")?
_.sprintf("<%s name='%s'> </%s>",values.node_type,values.field_value,values.node_type):
_.sprintf("<%s> </%s>",values.node_type,values.node_type);
_.str.sprintf("<%s name='%s'> </%s>",values.node_type,values.field_value,values.node_type):
_.str.sprintf("<%s> </%s>",values.node_type,values.node_type);
self.do_save_update_arch("add_node", [tag, values.position]);
}else{alert("Can't Update View");}
},
@ -917,8 +967,7 @@ openerp.web.ViewEditor = openerp.web.Widget.extend({
append('<table id="rec_table" style="width:400px" class="oe_forms"></table>');
var table_selector = self.add_node_dialog.$element.find('table[id=rec_table]');
_.each(render_list,function(node){
type_widget = new openerp.web.ViewEditor.FieldSelect (self.add_node_dialog, node.name);
type_widget.selection = node.selection;
type_widget = new (self.property.get_any([node.type])) (self.add_node_dialog, node);
table_selector.append('<tr><td align="right">' + node.string + ':</td>' + type_widget.render() + '</tr>');
type_widget.start();
type_widget.set_value(node.value);
@ -963,33 +1012,39 @@ openerp.web.ViewEditor = openerp.web.Widget.extend({
}
});
openerp.web.ViewEditor.Field = openerp.web.Class.extend({
init: function(view, name) {
init: function(view, widget) {
this.$element = view.$element;
this.dirty = false;
this.name = name;
this.required = false;
this.invalid = false;
this.name = widget.name;
this.selection = widget.selection || [];
this.required = widget.required || false;
this.string = widget.string || "";
this.type = widget.type;
this.is_invalid = false;
},
start: function () {
this.update_dom();
},
update_dom: function() {
this.$element.find("td[id="+ this.name+"]").toggleClass('invalid', this.invalid);
this.$element.find("td[id="+ this.name+"]").toggleClass('invalid', this.is_invalid);
this.$element.find("td[id="+ this.name+"]").toggleClass('required', this.required);
},
on_ui_change: function() {
var value = this.get_value();
value = value instanceof Array ? value[1] : value;
if (this.required && !value) {
this.invalid = true;
} else {
this.invalid = false;
}
this.validate();
this.dirty = true;
this.update_dom();
},
validate: function() {
this.is_invalid = false;
try {
var value = openerp.web.parse_value(this.get_value(), this, '');
this.is_invalid = this.required && value === '';
} catch(e) {
this.is_invalid = true;
}
},
render: function() {
return _.sprintf("<td id = %s>%s</td>", this.name, QWeb.render(this.template, {widget: this}))
return _.str.sprintf("<td id = %s>%s</td>", this.name, QWeb.render(this.template, {widget: this}))
},
});
openerp.web.ViewEditor.FieldBoolean = openerp.web.ViewEditor.Field.extend({
@ -1000,7 +1055,6 @@ openerp.web.ViewEditor.FieldBoolean = openerp.web.ViewEditor.Field.extend({
this.$element.find("input[id="+ self.name+"]").change(function() {
self.on_ui_change();
});
},
set_value: function(value) {
if (value) {
@ -1008,7 +1062,8 @@ openerp.web.ViewEditor.FieldBoolean = openerp.web.ViewEditor.Field.extend({
}
},
get_value: function() {
return this.$element.find("input[id=" + this.name + "]").is(':checked') || null;
var value = this.$element.find("input[id=" + this.name + "]").is(':checked')
return value? "1" : null;
}
});
openerp.web.ViewEditor.FieldChar = openerp.web.ViewEditor.Field.extend({
@ -1029,10 +1084,6 @@ openerp.web.ViewEditor.FieldChar = openerp.web.ViewEditor.Field.extend({
});
openerp.web.ViewEditor.FieldSelect = openerp.web.ViewEditor.Field.extend({
template : "vieweditor_selection",
init: function(view, name) {
this._super(view, name);
this.selection = false;
},
start: function () {
var self = this;
this._super();
@ -1058,53 +1109,7 @@ openerp.web.ViewEditor.FieldSelect = openerp.web.ViewEditor.Field.extend({
return this.$element.find("select[id=" + this.name + "]").val();
}
});
openerp.web.ViewEditor.WidgetProperty = openerp.web.ViewEditor.FieldSelect.extend({
init: function(view, name) {
this._super(view, name);
this.registry = openerp.web.form.widgets;
var values = _.keys(this.registry.map);
values.push('');
values.sort();
this.selection = values;
},
});
openerp.web.ViewEditor.IconProperty = openerp.web.ViewEditor.FieldSelect.extend({
init: function(view, name) {
this._super(view, name);
this.selection = _ICONS;
},
});
openerp.web.ViewEditor.ButtonTargetProperty = openerp.web.ViewEditor.FieldSelect.extend({
init: function(view, name) {
this._super(view, name);
this.selection = [['', ''], ['new', 'New Window']];
},
});
openerp.web.ViewEditor.ButtonTypeProperty = openerp.web.ViewEditor.FieldSelect.extend({
init: function(view, name) {
this._super(view, name);
this.selection = [['', ''], ['action', 'Action'], ['object', 'Object'], ['workflow', 'Workflow'], ['server_action', 'Server Action']];
},
});
openerp.web.ViewEditor.AlignProperty = openerp.web.ViewEditor.FieldSelect.extend({
init: function(view, name) {
this._super(view, name);
this.selection = [['', ''], ['0.0', 'Left'], ['0.5', 'Center'], ['1.0', 'Right']];
},
});
openerp.web.ViewEditor.ButtonSpecialProperty = openerp.web.ViewEditor.FieldSelect.extend({
init: function(view, name) {
this._super(view, name);
this.selection = [['',''],['save', 'Save Button'], ['cancel', 'Cancel Button'], ['open', 'Open Button']];
},
});
openerp.web.ViewEditor.PositionProperty = openerp.web.ViewEditor.FieldSelect.extend({
init: function(view, name) {
this._super(view, name);
this.selection = [['',''],['after', 'After'],['before', 'Before'],['inside', 'Inside'],['replace', 'Replace']];
},
});
openerp.web.ViewEditor.GroupsProperty = openerp.web.ViewEditor.FieldSelect.extend({
openerp.web.ViewEditor.FieldSelectMulti = openerp.web.ViewEditor.FieldSelect.extend({
start: function () {
this._super();
this.$element.find("select[id=" + this.name + "]").css('height', '100px').attr("multiple",true);
@ -1120,9 +1125,13 @@ openerp.web.ViewEditor.GroupsProperty = openerp.web.ViewEditor.FieldSelect.exten
});
}
});
openerp.web.ViewEditor.FieldFloat = openerp.web.ViewEditor.FieldChar.extend({
});
var _PROPERTIES = {
'field' : ['name', 'string', 'required', 'readonly', 'domain', 'context', 'nolabel', 'completion',
'colspan', 'widget', 'eval', 'ref', 'on_change', 'groups', 'attrs'],
'colspan', 'widget', 'eval', 'ref', 'on_change', 'attrs', 'groups'],
'form' : ['string', 'col', 'link'],
'notebook' : ['colspan', 'position', 'groups'],
'page' : ['string', 'states', 'attrs', 'groups'],
@ -1130,7 +1139,7 @@ var _PROPERTIES = {
'image' : ['filename', 'width', 'height', 'groups'],
'separator' : ['string', 'colspan', 'groups'],
'label': ['string', 'align', 'colspan', 'groups'],
'button': ['name', 'string', 'icon', 'type', 'states', 'readonly', 'special', 'target', 'confirm', 'context', 'attrs', 'groups','colspan'],
'button': ['name', 'string', 'icon', 'type', 'states', 'readonly', 'special', 'target', 'confirm', 'context', 'attrs', 'colspan', 'groups'],
'newline' : [],
'board': ['style'],
'column' : [],
@ -1156,7 +1165,7 @@ var _CHILDREN = {
'newline': [],
'separator': [],
};
var icons = ['','STOCK_ABOUT', 'STOCK_ADD', 'STOCK_APPLY', 'STOCK_BOLD',
var _ICONS = ['','STOCK_ABOUT', 'STOCK_ADD', 'STOCK_APPLY', 'STOCK_BOLD',
'STOCK_CANCEL', 'STOCK_CDROM', 'STOCK_CLEAR', 'STOCK_CLOSE', 'STOCK_COLOR_PICKER',
'STOCK_CONNECT', 'STOCK_CONVERT', 'STOCK_COPY', 'STOCK_CUT', 'STOCK_DELETE',
'STOCK_DIALOG_AUTHENTICATION', 'STOCK_DIALOG_ERROR', 'STOCK_DIALOG_INFO',
@ -1184,19 +1193,10 @@ var icons = ['','STOCK_ABOUT', 'STOCK_ADD', 'STOCK_APPLY', 'STOCK_BOLD',
'terp-project', 'terp-report', 'terp-stock', 'terp-calendar', 'terp-graph'
];
openerp.web.ViewEditor.property_widget = new openerp.web.Registry({
'required' : 'openerp.web.ViewEditor.FieldBoolean',
'readonly' : 'openerp.web.ViewEditor.FieldBoolean',
'nolabel' : 'openerp.web.ViewEditor.FieldBoolean',
'completion' : 'openerp.web.ViewEditor.FieldBoolean',
'widget' : 'openerp.web.ViewEditor.WidgetProperty',
'groups' : 'openerp.web.ViewEditor.GroupsProperty',
'position' : 'openerp.web.ViewEditor.PositionProperty',
'icon' : 'openerp.web.ViewEditor.IconProperty',
'align' : 'openerp.web.ViewEditor.AlignProperty',
'special' : 'openerp.web.ViewEditor.ButtonSpecialProperty',
'type' : 'openerp.web.ViewEditor.ButtonTypeProperty',
'target' : 'openerp.web.ViewEditor.ButtonTargetProperty',
'boolean' : 'openerp.web.ViewEditor.FieldBoolean',
'seleciton_multi' : 'openerp.web.ViewEditor.FieldSelectMulti',
'selection' : 'openerp.web.ViewEditor.FieldSelect',
'char' : 'openerp.web.ViewEditor.FieldChar',
'float' : 'openerp.web.ViewEditor.FieldFloat',
});
};

View File

@ -35,7 +35,6 @@ openerp.web.FormView = openerp.web.View.extend( /** @lends openerp.web.FormView#
this.fields = {};
this.datarecord = {};
this.show_invalid = true;
this.dirty_for_user = false;
this.default_focus_field = null;
this.default_focus_button = null;
this.registry = this.readonly ? openerp.web.form.readonly : openerp.web.form.widgets;
@ -141,7 +140,7 @@ openerp.web.FormView = openerp.web.View.extend( /** @lends openerp.web.FormView#
// null index means we should start a new record
promise = this.on_button_new();
} else {
promise = this.dataset.read_index(_.keys(this.fields_view.fields), this.on_record_loaded);
promise = this.dataset.read_index(_.keys(this.fields_view.fields)).pipe(this.on_record_loaded);
}
this.$element.show();
if (this.sidebar) {
@ -156,6 +155,8 @@ openerp.web.FormView = openerp.web.View.extend( /** @lends openerp.web.FormView#
}
},
on_record_loaded: function(record) {
var self = this,
deferred_stack = $.Deferred.queue();
if (!record) {
throw("Form: No record received");
}
@ -172,35 +173,42 @@ openerp.web.FormView = openerp.web.View.extend( /** @lends openerp.web.FormView#
}
this.$form_header.find('.oe_form_on_readonly').toggle(this.readonly);
this.$form_header.find('.oe_form_on_editable').toggle(!this.readonly);
this.dirty_for_user = false;
this.datarecord = record;
for (var f in this.fields) {
var field = this.fields[f];
_(this.fields).each(function (field, f) {
field.dirty = false;
field.set_value(this.datarecord[f] || false);
field.validate();
}
if (!record.id) {
// New record: Second pass in order to trigger the onchanges
this.show_invalid = false;
for (var f in record) {
var field = this.fields[f];
if (field) {
field.dirty = true;
this.do_onchange(field);
var result = field.set_value(self.datarecord[f] || false);
if (result && _.isFunction(result.promise)) {
deferred_stack.push(result);
}
$.when(result).then(function() {
field.validate();
});
});
deferred_stack.push('force resolution if no fields');
return deferred_stack.then(function() {
if (!record.id) {
// New record: Second pass in order to trigger the onchanges
self.show_invalid = false;
for (var f in record) {
var field = self.fields[f];
if (field) {
field.dirty = true;
self.do_onchange(field);
}
}
}
}
this.on_form_changed();
this.initial_mutating_lock.resolve();
this.show_invalid = true;
this.do_update_pager(record.id == null);
if (this.sidebar) {
this.sidebar.attachments.do_update();
}
if (this.default_focus_field && !this.embedded_view) {
this.default_focus_field.focus();
}
self.on_form_changed();
self.initial_mutating_lock.resolve();
self.show_invalid = true;
self.do_update_pager(record.id == null);
if (self.sidebar) {
self.sidebar.attachments.do_update();
}
if (self.default_focus_field && !self.embedded_view) {
self.default_focus_field.focus();
}
});
},
on_form_changed: function() {
for (var w in this.widgets) {
@ -240,7 +248,7 @@ openerp.web.FormView = openerp.web.View.extend( /** @lends openerp.web.FormView#
try {
processed = processed || [];
if (widget.node.attrs.on_change) {
var onchange = _.trim(widget.node.attrs.on_change);
var onchange = _.str.trim(widget.node.attrs.on_change);
var call = onchange.match(/^\s?(.*?)\((.*?)\)\s?$/);
if (call) {
var method = call[1], args = [];
@ -257,7 +265,7 @@ openerp.web.FormView = openerp.web.View.extend( /** @lends openerp.web.FormView#
};
var parent_fields = null;
_.each(call[2].split(','), function(a, i) {
var field = _.trim(a);
var field = _.str.trim(a);
if (field in argument_replacement) {
args.push(argument_replacement[field](i));
return;
@ -267,11 +275,11 @@ openerp.web.FormView = openerp.web.View.extend( /** @lends openerp.web.FormView#
return;
} else {
var splitted = field.split('.');
if (splitted.length > 1 && _.trim(splitted[0]) === "parent" && self.dataset.parent_view) {
if (splitted.length > 1 && _.str.trim(splitted[0]) === "parent" && self.dataset.parent_view) {
if (parent_fields === null) {
parent_fields = self.dataset.parent_view.get_fields_values();
}
var p_val = parent_fields[_.trim(splitted[1])];
var p_val = parent_fields[_.str.trim(splitted[1])];
if (p_val !== undefined) {
args.push(p_val == null ? false : p_val);
return;
@ -317,7 +325,7 @@ openerp.web.FormView = openerp.web.View.extend( /** @lends openerp.web.FormView#
processed.push(field.name);
if (field.get_value() != value) {
field.set_value(value);
field.dirty = this.dirty_for_user = true;
field.dirty = true;
if (_.indexOf(processed, field.name) < 0) {
this.do_onchange(field, processed);
}
@ -356,12 +364,13 @@ openerp.web.FormView = openerp.web.View.extend( /** @lends openerp.web.FormView#
var keys = _.keys(self.fields_view.fields);
$.when(self.do_set_editable()).then(function() {
if (keys.length) {
self.dataset.default_get(keys).then(self.on_record_loaded).then(function() {
self.dataset.default_get(keys).pipe(self.on_record_loaded).then(function() {
def.resolve();
});
} else {
self.on_record_loaded({});
def.resolve();
self.on_record_loaded({}).then(function() {
def.resolve();
});
}
});
}
@ -402,7 +411,7 @@ openerp.web.FormView = openerp.web.View.extend( /** @lends openerp.web.FormView#
return def.promise();
},
can_be_discarded: function() {
return !this.dirty_for_user || confirm(_t("Warning, the record has been modified, your changes will be discarded."));
return !this.is_dirty() || confirm(_t("Warning, the record has been modified, your changes will be discarded."));
},
/**
* Triggers saving the form's record. Chooses between creating a new
@ -418,8 +427,7 @@ openerp.web.FormView = openerp.web.View.extend( /** @lends openerp.web.FormView#
try {
if (!self.initial_mutating_lock.isResolved() && !self.initial_mutating_lock.isRejected())
return;
var form_dirty = false,
form_invalid = false,
var form_invalid = false,
values = {},
first_invalid_field = null;
for (var f in self.fields) {
@ -431,7 +439,6 @@ openerp.web.FormView = openerp.web.View.extend( /** @lends openerp.web.FormView#
first_invalid_field = f;
}
} else if (f.is_dirty()) {
form_dirty = true;
values[f.name] = f.get_value();
}
}
@ -480,8 +487,8 @@ openerp.web.FormView = openerp.web.View.extend( /** @lends openerp.web.FormView#
// should not happen in the server, but may happen for internal purpose
return $.Deferred().reject();
} else {
this.reload();
return $.when(r).then(success);
return $.when(this.reload()).pipe(function () {
return $.when(r).then(success); }, null);
}
},
/**
@ -528,7 +535,7 @@ openerp.web.FormView = openerp.web.View.extend( /** @lends openerp.web.FormView#
if (self.dataset.index == null || self.dataset.index < 0) {
return $.when(self.on_button_new());
} else {
return self.dataset.read_index(_.keys(self.fields_view.fields), self.on_record_loaded);
return self.dataset.read_index(_.keys(self.fields_view.fields)).pipe(self.on_record_loaded);
}
};
this.reload_lock = this.reload_lock.pipe(act, act);
@ -553,6 +560,11 @@ openerp.web.FormView = openerp.web.View.extend( /** @lends openerp.web.FormView#
return self.dataset.parent_view.recursive_save();
});
},
is_dirty: function() {
return _.any(this.fields, function (value) {
return value.is_dirty();
});
},
is_interactible_record: function() {
var id = this.datarecord.id;
if (!id) {
@ -638,7 +650,7 @@ openerp.web.form.SidebarAttachments = openerp.web.Widget.extend({
},
on_attachment_delete: function(e) {
var self = this, $e = $(e.currentTarget);
var name = _.trim($e.parent().find('a.oe-sidebar-attachments-link').text());
var name = _.str.trim($e.parent().find('a.oe-sidebar-attachments-link').text());
if (confirm("Do you really want to delete the attachment " + name + " ?")) {
this.rpc('/web/dataset/unlink', {
model: 'ir.attachment',
@ -798,8 +810,13 @@ openerp.web.form.Widget = openerp.web.Widget.extend(/** @lends openerp.web.form.
_build_view_fields_values: function() {
var a_dataset = this.view.dataset;
var fields_values = this.view.get_fields_values();
var parent_values = a_dataset.parent_view ? a_dataset.parent_view.get_fields_values() : {};
fields_values.parent = parent_values;
var active_id = a_dataset.ids[a_dataset.index];
_.extend(fields_values, {
active_id: active_id || false,
active_ids: active_id ? [active_id] : [],
active_model: a_dataset.model,
parent: a_dataset.parent_view ? a_dataset.parent_view.get_fields_values() : {}
});
return fields_values;
},
_build_eval_context: function() {
@ -1231,7 +1248,7 @@ openerp.web.form.Field = openerp.web.form.Widget.extend(/** @lends openerp.web.f
}
},
on_ui_change: function() {
this.dirty = this.view.dirty_for_user = true;
this.dirty = true;
this.validate();
if (this.is_valid()) {
this.set_value_from_ui();
@ -1344,54 +1361,58 @@ openerp.web.DateTimeWidget = openerp.web.Widget.extend({
template: "web.datetimepicker",
jqueryui_object: 'datetimepicker',
type_of_date: "datetime",
init: function(parent) {
this._super(parent);
this.name = parent.name;
},
start: function() {
var self = this;
this.$element.find('input').change(this.on_change);
this.$input = this.$element.find('input.oe_datepicker_master');
this.$input_picker = this.$element.find('input.oe_datepicker_container');
this.$input.change(this.on_change);
this.picker({
onSelect: this.on_picker_select,
changeMonth: true,
changeYear: true,
showWeek: true,
showButtonPanel: false
showButtonPanel: true
});
this.$element.find('img.oe_datepicker_trigger').click(function() {
if (!self.readonly) {
self.picker('setDate', self.value ? openerp.web.auto_str_to_date(self.value) : new Date());
self.$element.find('.oe_datepicker').toggle();
self.$input_picker.show();
self.picker('show');
self.$input_picker.hide();
}
});
this.$element.find('.ui-datepicker-inline').removeClass('ui-widget-content ui-corner-all');
this.$element.find('button.oe_datepicker_close').click(function() {
self.$element.find('.oe_datepicker').hide();
});
this.set_readonly(false);
this.value = false;
},
picker: function() {
return $.fn[this.jqueryui_object].apply(this.$element.find('.oe_datepicker_container'), arguments);
return $.fn[this.jqueryui_object].apply(this.$input_picker, arguments);
},
on_picker_select: function(text, instance) {
var date = this.picker('getDate');
this.$element.find('input').val(date ? this.format_client(date) : '').change();
this.$input.val(date ? this.format_client(date) : '').change();
},
set_value: function(value) {
this.value = value;
this.$element.find('input').val(value ? this.format_client(value) : '');
this.$input.val(value ? this.format_client(value) : '');
},
get_value: function() {
return this.value;
},
set_value_from_ui: function() {
var value = this.$element.find('input').val() || false;
var value = this.$input.val() || false;
this.value = this.parse_client(value);
},
set_readonly: function(readonly) {
this.readonly = readonly;
this.$element.find('input').attr('disabled', this.readonly);
this.$input.attr('disabled', this.readonly);
this.$element.find('img.oe_datepicker_trigger').toggleClass('oe_input_icon_disabled', readonly);
},
is_valid: function(required) {
var value = this.$element.find('input').val();
var value = this.$input.val();
if (value === "") {
return !required;
} else {
@ -1404,7 +1425,7 @@ openerp.web.DateTimeWidget = openerp.web.Widget.extend({
}
},
focus: function() {
this.$element.find('input').focus();
this.$input.focus();
},
parse_client: function(v) {
return openerp.web.parse_value(v, {"widget": this.type_of_date});
@ -1421,11 +1442,7 @@ openerp.web.DateTimeWidget = openerp.web.Widget.extend({
openerp.web.DateWidget = openerp.web.DateTimeWidget.extend({
jqueryui_object: 'datepicker',
type_of_date: "date",
on_picker_select: function(text, instance) {
this._super(text, instance);
this.$element.find('.oe_datepicker').hide();
}
type_of_date: "date"
});
openerp.web.form.FieldDatetime = openerp.web.form.Field.extend({
@ -1437,7 +1454,7 @@ openerp.web.form.FieldDatetime = openerp.web.form.Field.extend({
var self = this;
this._super.apply(this, arguments);
this.datewidget = this.build_widget();
this.datewidget.on_change.add(this.on_ui_change);
this.datewidget.on_change.add_last(this.on_ui_change);
this.datewidget.appendTo(this.$element);
},
set_value: function(value) {
@ -1825,7 +1842,7 @@ openerp.web.form.FieldMany2One = openerp.web.form.Field.extend({
if (search_val.length > 0 &&
!_.include(raw_result, search_val) &&
(!self.value || search_val !== self.value[1])) {
values.push({label: _.sprintf(_t('<em>   Create "<strong>%s</strong>"</em>'),
values.push({label: _.str.sprintf(_t('<em>   Create "<strong>%s</strong>"</em>'),
$('<span />').text(search_val).html()), action: function() {
self._quick_create(search_val);
}});
@ -2103,7 +2120,7 @@ openerp.web.form.FieldOne2Many = openerp.web.form.Field.extend({
},
reload_current_view: function() {
var self = this;
self.is_loaded = self.is_loaded.pipe(function() {
return self.is_loaded = self.is_loaded.pipe(function() {
var view = self.viewmanager.views[self.viewmanager.active_view].controller;
if(self.viewmanager.active_view === "list") {
return view.reload_content();
@ -2176,8 +2193,8 @@ openerp.web.form.FieldOne2Many = openerp.web.form.Field.extend({
if (this.dataset.index === null && this.dataset.ids.length > 0) {
this.dataset.index = 0;
}
self.reload_current_view();
this.is_setted.resolve();
self.is_setted.resolve();
return self.reload_current_view();
},
get_value: function() {
var self = this;
@ -2955,7 +2972,7 @@ openerp.web.form.FieldStatus = openerp.web.form.Field.extend({
render_list: function() {
var self = this;
var shown = _.map(((this.node.attrs || {}).statusbar_visible || "").split(","),
function(x) { return _.trim(x); });
function(x) { return _.str.trim(x); });
shown = _.select(shown, function(x) { return x.length > 0; });
if (shown.length == 0) {

View File

@ -295,7 +295,7 @@ openerp.web.ListView = openerp.web.View.extend( /** @lends openerp.web.ListView#
} else {
last = first + limit;
}
this.$element.find('span.oe-pager-state').empty().text(_.sprintf(
this.$element.find('span.oe-pager-state').empty().text(_.str.sprintf(
"[%d to %d] of %d", first + 1, last, total));
this.$element
@ -647,7 +647,7 @@ openerp.web.ListView = openerp.web.View.extend( /** @lends openerp.web.ListView#
return;
}
$footer_cells.filter(_.sprintf('[data-field=%s]', column.id))
$footer_cells.filter(_.str.sprintf('[data-field=%s]', column.id))
.html(openerp.web.format_cell(aggregation, column, undefined, false));
});
},
@ -1127,7 +1127,7 @@ openerp.web.ListView.Groups = openerp.web.Class.extend( /** @lends openerp.web.L
child.datagroup = group;
var $row = child.$row = $('<tr>');
if (group.openable) {
if (group.openable && group.length) {
$row.click(function (e) {
if (!$row.data('open')) {
$row.data('open', true)
@ -1159,7 +1159,13 @@ openerp.web.ListView.Groups = openerp.web.Class.extend( /** @lends openerp.web.L
} catch (e) {
$group_column.html(row_data[group_column.id].value);
}
if (group.openable) {
if (!group.length) {
// Kinda-ugly hack: jquery-ui has no "empty" icon, so set
// wonky background position to ensure nothing is displayed
// there but the rest of the behavior is ui-icon's
$group_column.prepend(
'<span class="ui-icon" style="float: left; background-position: 150px 150px">');
} else if (group.openable) {
// Make openable if not terminal group & group_by_no_leaf
$group_column
.prepend('<span class="ui-icon ui-icon-triangle-1-e" style="float: left;">');
@ -1186,7 +1192,7 @@ openerp.web.ListView.Groups = openerp.web.Class.extend( /** @lends openerp.web.L
format = "%.2f";
}
$('<td>')
.text(_.sprintf(format, value))
.text(_.str.sprintf(format, value))
.appendTo($row);
} else {
$row.append('<td>');
@ -1245,7 +1251,7 @@ openerp.web.ListView.Groups = openerp.web.Class.extend( /** @lends openerp.web.L
var pages = Math.ceil(dataset.ids.length / limit);
self.$row
.find('.oe-pager-state')
.text(_.sprintf('%d/%d', page + 1, pages))
.text(_.str.sprintf('%d/%d', page + 1, pages))
.end()
.find('button[data-pager-action=previous]')
.attr('disabled', page === 0)

View File

@ -42,7 +42,8 @@ openerp.web.TreeView = openerp.web.View.extend(/** @lends openerp.web.TreeView#
model: this.model,
view_id: this.view_id,
view_type: "tree",
toolbar: this.view_manager ? !!this.view_manager.sidebar : false
toolbar: this.view_manager ? !!this.view_manager.sidebar : false,
context: this.dataset.get_context()
}, this.on_loaded);
},
/**
@ -214,17 +215,23 @@ openerp.web.TreeView = openerp.web.View.extend(/** @lends openerp.web.TreeView#
// Get details in listview
activate: function(id) {
var self = this;
var local_context = {
active_model: self.dataset.model,
active_id: id,
active_ids: [id]};
this.rpc('/web/treeview/action', {
id: id,
model: this.dataset.model,
context: new openerp.web.CompoundContext(
this.dataset.get_context(), {
active_model: this.dataset.model,
active_id: id,
active_ids: [id]})
this.dataset.get_context(), local_context)
}, function (actions) {
if (!actions.length) { return; }
var action = actions[0][2];
var c = new openerp.web.CompoundContext(local_context);
if (action.context) {
c.add(action.context);
}
action.context = c;
self.do_action(action);
});
},

View File

@ -210,7 +210,7 @@ session.web.ViewManager = session.web.Widget.extend(/** @lends session.web.View
sidebar_id : self.element_id + '_sidebar_' + view.view_type,
action : self.action,
action_views_ids : views_ids
}, self.flags, view.options || {})
}, self.flags, self.flags[view.view_type] || {}, view.options || {})
});
views_ids[view.view_type] = view.view_id;
});
@ -534,7 +534,7 @@ session.web.ViewManagerAction = session.web.ViewManager.extend(/** @lends oepner
$logs_list = $logs.find('ul').empty();
$logs.toggleClass('oe-has-more', log_records.length > cutoff);
_(log_records.reverse()).each(function (record) {
$(_.sprintf('<li><a href="#">%s</a></li>', record.name))
$(_.str.sprintf('<li><a href="#">%s</a></li>', record.name))
.appendTo($logs_list)
.delegate('a', 'click', function (e) {
self.do_action({
@ -628,7 +628,7 @@ session.web.Sidebar = session.web.Widget.extend({
},
add_section: function(name, code) {
if(!code) code = _.underscored(name);
if(!code) code = _.str.underscored(name);
var $section = this.sections[code];
if(!$section) {
@ -656,7 +656,7 @@ session.web.Sidebar = session.web.Widget.extend({
//
var self = this,
$section = this.add_section(_.titleize(section_code.replace('_', ' ')), section_code),
$section = this.add_section(_.str.titleize(section_code.replace('_', ' ')), section_code),
section_id = $section.attr('id');
if (items) {

View File

@ -18,7 +18,7 @@
</div>
</t>
<t t-name="Interface">
<div id="oe_loading" class="loading"></div>
<div id="oe_loading"></div>
<table border="0" cellpadding="0" cellspacing="0" width="100%" height="100%" class="main_table">
<tr>
<td colspan="2" valign="top">
@ -63,7 +63,9 @@
</table>
</t>
<t t-name="Loading">
<div class="loading">
Loading...
</div>
</t>
<t t-name="Database">
<ul class="db_options" style="padding: 0px; display: inline;">
@ -703,7 +705,7 @@
</t>
<t t-name="Widget">
Unhandled widget
<t t-raw="console.log('Unhandled widget', widget)"/>
<t t-js="dict">console.warn('Unhandled widget', dict.widget);</t>
</t>
<t t-name="WidgetFrame">
<table border="0" width="100%" cellpadding="0" cellspacing="0" class="oe_frame oe_forms">
@ -896,13 +898,13 @@
</t>
<t t-name="web.datetimepicker">
<div class="oe_datepicker_root">
<input type="text" size="1" style="width: 100%"/>
<input type="text" size="1" style="width: 100%"
t-att-name="widget.name"
t-attf-class="oe_datepicker_master field_#{widget.type_of_date}"
/>
<img class="oe_input_icon oe_datepicker_trigger" src="/web/static/src/img/ui/field_calendar.png"
title="Select date" width="16" height="16" border="0"/>
<div class="oe_datepicker ui-widget-content ui-corner-all" style="display: none; position: absolute; z-index: 1;">
<div class="oe_datepicker_container"/>
<button type="button" class="oe_datepicker_close ui-state-default ui-priority-primary ui-corner-all" style="float: right;">Done</button>
</div>
<input type="text" size="1" class="oe_datepicker_container" disabled="disabled"/>
</div>
</t>
<t t-name="FieldSelection">
@ -1070,7 +1072,7 @@
</table>
</t>
<t t-name="WidgetButton">
<button type="button" style="width: 100%" class="button">
<button type="button" class="oe_button">
<img t-if="widget.node.attrs.icon" t-att-src="'/web/static/src/img/icons/' + widget.node.attrs.icon + '.png'" width="16" height="16"/>
<span t-if="widget.string"><t t-esc="widget.string"/></span>
</button>
@ -1152,8 +1154,8 @@
t-att-title="attrs.help"
t-att-class="classes.join(' ')"
t-att-autofocus="attrs.default_focus === '1' ? 'autofocus' : undefined">
<img t-if="attrs.icon" t-att-src="'/web/static/src/img/icons/' + attrs.icon + '.png'" width="16" height="16"/>
<br t-if="attrs.icon and attrs.string"/>
<img t-att-src="'/web/static/src/img/icons/' + (attrs.icon || 'gtk-home') + '.png'" width="16" height="16"/>
<br t-if="attrs.string"/>
<t t-esc="attrs.string"/>
</button>
<span t-name="SearchView.filters" class="filter_label_group"

View File

@ -119,20 +119,24 @@ openerp.web_calendar.CalendarView = openerp.web.View.extend({
scheduler.attachEvent('onDblClick', this.do_edit_event);
scheduler.attachEvent('onBeforeLightbox', this.do_edit_event);
this.mini_calendar = scheduler.renderCalendar({
container: this.sidebar.navigator.element_id,
navigation: true,
date: scheduler._date,
handler: function(date, calendar) {
scheduler.setCurrentView(date, 'day');
}
});
if (this.options.sidebar) {
this.mini_calendar = scheduler.renderCalendar({
container: this.sidebar.navigator.element_id,
navigation: true,
date: scheduler._date,
handler: function(date, calendar) {
scheduler.setCurrentView(date, 'day');
}
});
}
},
refresh_scheduler: function() {
scheduler.setCurrentView(scheduler._date);
},
refresh_minical: function() {
scheduler.updateCalendar(this.mini_calendar);
if (this.options.sidebar) {
scheduler.updateCalendar(this.mini_calendar);
}
},
reload_event: function(id) {
this.dataset.read_ids([id], _.keys(this.fields), this.on_events_loaded);
@ -192,7 +196,7 @@ openerp.web_calendar.CalendarView = openerp.web.View.extend({
scheduler.parse(res_events, 'json');
this.refresh_scheduler();
this.refresh_minical();
if (!no_filter_reload) {
if (!no_filter_reload && this.options.sidebar) {
this.sidebar.responsible.on_events_loaded(sidebar_items);
}
},

View File

@ -103,7 +103,7 @@ openerp.web.form.DashBoard = openerp.web.form.Widget.extend({
}, function(result) {
self.actions_attrs[aid] = {
name: aid,
string: _.trim(result.result.name)
string: _.str.trim(result.result.name)
};
qdict.action = {
attrs : self.actions_attrs[aid]
@ -218,9 +218,35 @@ openerp.web.form.DashBoard = openerp.web.form.Widget.extend({
});
},
on_load_action: function(result) {
var self = this;
var action_orig = _.extend({}, result.result);
var action = result.result;
var self = this,
action = result.result,
action_attrs = this.actions_attrs[action.id],
view_mode = action_attrs.view_mode;
// TODO: Use xmo's python evaluator when ready
if (action_attrs.context) {
action.context = _.extend(action.context || {}, action_attrs.context);
}
if (action_attrs.domain) {
action.domain = action.domain || [];
action.domain.push.apply(action.domain, action_attrs.domain);
}
var action_orig = _.extend({}, action);
if (view_mode && view_mode != action.view_mode) {
var action_view_mode = action.view_mode.split(',');
action.views = _.map(view_mode.split(','), function(mode) {
if (_.indexOf(action_view_mode, mode) < 0) {
return [false, mode == 'tree' ? 'list': mode];
} else {
mode = mode === 'tree' ? 'list' : mode;
return _.find(action.views, function(view) {
return view[1] == mode;
});
}
});
}
action.flags = {
search_view : false,
sidebar : false,
@ -228,7 +254,10 @@ openerp.web.form.DashBoard = openerp.web.form.Widget.extend({
action_buttons : false,
pager: false,
low_profile: true,
display_title: false
display_title: false,
list: {
selectable: false
}
};
var am = new openerp.web.ActionManager(this);
this.action_managers.push(am);
@ -420,7 +449,7 @@ openerp.web_dashboard.ApplicationTiles = openerp.web.View.extend({
var Installer = new openerp.web.DataSet(this, 'base.setup.installer');
Installer.call('default_get', [], function (installed_modules) {
var installed = _(installed_modules).any(function (active, name) {
return _.startsWith(name, 'cat') && active; });
return _.str.startsWith(name, 'cat') && active; });
if(installed) {
self.do_display_root_menu();
@ -521,7 +550,7 @@ openerp.web_dashboard.Widget = openerp.web.View.extend(/** @lends openerp.web_da
},
on_widget_loaded: function (widgets) {
var widget = widgets[0];
var url = _.sprintf(
var url = _.str.sprintf(
'/web_dashboard/widgets/content?session_id=%s&widget_id=%d',
this.session.session_id, widget.id);
this.$element.html(QWeb.render('HomeWidget.content', {

View File

@ -116,7 +116,7 @@
<h1>Welcome to your new OpenERP instance.</h1>
<div class="oe-static-home-banner">
<li>Remember to bookmark this page.</li>
<li>Remember your login: <i><t t-esc="session.login"/></i></li>
<li>Remember your login: <t t-esc="session.username"/></li>
<li>Choose the first OpenERP Application you want to install..</li>
</div>
<div class="oe-static-home-tiles">

View File

@ -233,7 +233,7 @@ openerp.web_graph.GraphView = openerp.web.View.extend({
// second argument is coerced to a str, no good for boolean
r[self.abscissa] = records[0][self.abscissa];
_(records).each(function (record) {
var key = _.sprintf('%s_%s',
var key = _.str.sprintf('%s_%s',
self.ordinate,
record[self.group_field].toLowerCase().replace(/\s/g, '_'));
r[key] = record[self.ordinate];
@ -278,7 +278,7 @@ openerp.web_graph.GraphView = openerp.web.View.extend({
border: false,
width: 1024,
tooltip:{
template: _.sprintf("#%s#, %s=#%s#",
template: _.str.sprintf("#%s#, %s=#%s#",
self.abscissa, group_list[0].text, group_list[0].group)
},
radius: 0,
@ -306,7 +306,7 @@ openerp.web_graph.GraphView = openerp.web.View.extend({
bar_chart.addSeries({
value: "#"+column.group+"#",
tooltip:{
template: _.sprintf("#%s#, %s=#%s#",
template: _.str.sprintf("#%s#, %s=#%s#",
self.abscissa, column.text, column.group)
},
color: column.color

View File

@ -23,6 +23,7 @@ openerp.web_kanban.KanbanView = openerp.web.View.extend({
this.form_dialog = new openerp.web.FormDialog(this, {}, this.options.action_views_ids.form, dataset).start();
this.form_dialog.on_form_dialog_saved.add_last(this.do_reload);
this.aggregates = {};
this.group_operators = ['avg', 'max', 'min', 'sum', 'count'];
this.qweb = new QWeb2.Engine();
this.qweb.debug = openerp.connection.debug;
this.qweb.default_dict = {
@ -58,22 +59,26 @@ openerp.web_kanban.KanbanView = openerp.web.View.extend({
this.transform_qweb_template(child);
this.qweb.add_template(openerp.web.json_node_to_xml(child));
break;
} else if (child.tag === 'field') {
this.extract_aggregates(child);
}
}
},
extract_aggregates: function(node) {
for (var j = 0, jj = this.group_operators.length; j < jj; j++) {
if (node.attrs[this.group_operators[j]]) {
this.aggregates[node.attrs.name] = node.attrs[this.group_operators[j]];
break;
}
}
},
transform_qweb_template: function(node) {
var qweb_prefix = QWeb.prefix,
group_operator = ['avg', 'max', 'min', 'sum', 'count'];
var qweb_prefix = QWeb.prefix;
switch (node.tag) {
case 'field':
node.tag = qweb_prefix;
node.attrs[qweb_prefix + '-esc'] = 'record.' + node.attrs['name'] + '.value';
for (var j = 0, jj = group_operator.length; j < jj; j++) {
if (node.attrs[group_operator[j]]) {
this.aggregates[node.attrs.name] = node.attrs[group_operator[j]];
break;
}
}
this.extract_aggregates(node);
break
case 'button':
case 'a':
@ -87,13 +92,13 @@ openerp.web_kanban.KanbanView = openerp.web.View.extend({
});
if (node.attrs['data-states']) {
var states = _.map(node.attrs['data-states'].split(','), function(state) {
return "record.state.raw_value == '" + _.trim(state) + "'";
return "record.state.raw_value == '" + _.str.trim(state) + "'";
});
node.attrs[qweb_prefix + '-if'] = states.join(' or ');
}
if (node.attrs['data-kanban_states']) {
var states = _.map(node.attrs['data-kanban_states'].split(','), function(state) {
return "record.kanban_state.raw_value == '" + _.trim(state) + "'";
return "record.kanban_state.raw_value == '" + _.str.trim(state) + "'";
});
node.attrs[qweb_prefix + '-if'] = states.join(' or ');
}
@ -372,7 +377,7 @@ openerp.web_kanban.KanbanRecord = openerp.web.Widget.extend({
var self = this,
new_record = {};
_.each(record, function(value, name) {
var r = _.clone(self.view.fields_view.fields[name]);
var r = _.clone(self.view.fields_view.fields[name] || {});
r.raw_value = value;
r.value = openerp.web.format_value(value, r);
new_record[name] = r;
@ -385,7 +390,7 @@ openerp.web_kanban.KanbanRecord = openerp.web.Widget.extend({
widget: this
}
for (var p in this) {
if (_.startsWith(p, 'kanban_')) {
if (_.str.startsWith(p, 'kanban_')) {
ctx[p] = _.bind(this[p], this);
}
}
@ -497,8 +502,10 @@ openerp.web_kanban.KanbanRecord = openerp.web.Widget.extend({
},
kanban_gravatar: function(email, size) {
size = size || 22;
email = _.str.trim(email || '').toLowerCase();
var default_ = _.str.isBlank(email) ? 'mm' : 'identicon';
var email_md5 = $.md5(email);
return 'http://www.gravatar.com/avatar/' + email_md5 + '.png?s=' + size;
return 'http://www.gravatar.com/avatar/' + email_md5 + '.png?s=' + size + '&d=' + default_;
},
kanban_image: function(model, field, id) {
id = id || '';

View File

@ -1,7 +1,9 @@
<template>
<t t-name="KanbanView">
<div class="oe_kanban_header">
<t t-if="widget.options.action_buttons !== false">
<button type="button" class="oe_kanban_button_new">New</button>
</t>
</div>
<div class="oe_kanban_view">
<table style="width:100%;" class="oe_kanban_groups">

View File

@ -133,7 +133,7 @@
<t t-call="Header" />
<div id="content" data-role="content">
<t t-if="!(records.length>0)">
No one record is created
There is no records to show.
</t>
<t t-if="records.length>0">
<ul data-role="listview" data-inset="true" data-theme="d" data-filter="true">

View File

View File

@ -0,0 +1,15 @@
{
"name" : "Process",
"version" : "2.0",
"depends" : ["web"],
"js": [
"static/src/js/process.js"
],
"css": [
"static/src/css/process.css"
],
'qweb': [
"static/src/xml/web_process.css"
],
'active': True
}

View File

@ -0,0 +1,62 @@
a.cta-a {
float: left;
padding: 5px 10px;
border: 1px solid #ccc;
border-radius: 5px;
-moz-border-radius: 5px;
-webkit-border-radius: 5px;
background: #eeeded url(/web_process/static/src/img/cta-a.gif) repeat-x;
box-shadow: 0 1px 0 #fff;
-moz-box-shadow: 0 1px 0 #fff;
-webkit-box-shadow: 0 1px 0 #fff;
color: #8c8c8c;
font-size: 0.9em;
text-transform: uppercase;
font-weight: bold;
text-shadow: #fff 0 1px 0;
margin: 2px;
}
a.cta-a span {
float: left;
padding: 7px 0 5px 5px;
background-position: 0 50%;
background-repeat: no-repeat;
cursor: pointer;
}
a.cta-a strong {
display: block;
color: #393939;
}
.process_h1 {
background:url("/web_process/static/src/img/sep-a.gif") repeat-x scroll 0 90% transparent;
font-size:2em;
font-weight:normal;
padding:0 0 5px 5px;
line-height: 1.2;
}
.process-links {
padding: 5px 10px;
text-align: center;
display: table;
margin: auto;
}
.process-links a.cta-a {
display: table-cell;
}
.process-help-text {
float: left;
padding:5px 10px;
min-height:56px;
font-size: 120%;
}
td.process_fields,button.toggle_fields span:last-child {
display: none;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 650 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 635 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 810 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 108 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 379 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 166 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 128 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 200 B

View File

@ -0,0 +1,309 @@
openerp.web_process = function (openerp) {
var QWeb = openerp.web.qweb;
openerp.web.ViewManager.include({
start: function() {
this._super();
var self = this;
this.process_check();
this.process_help = this.action ? this.action.help : 'Help: Not Defined';
this.model = this.dataset.model;
if(this.action) this.process_model = this.action.res_model;
else this.process_model = this.model;
},
process_check: function() {
var self = this,
grandparent = this.widget_parent && this.widget_parent.widget_parent,
view = this.views[this.views_src[0].view_type],
$process_view = this.$element.find('.oe-process-view');
if (!(grandparent instanceof openerp.web.WebClient) ||
!(view.view_type === this.views_src[0].view_type
&& view.view_id === this.views_src[0].view_id)) {
$process_view.hide();
return;
}
$process_view.click(function() {
self.initialize_process_view();
});
},
initialize_process_view: function() {
var self = this;
$.when(this.fields_get(), this.help(), this.get_process_object()).pipe(function(fields, help, process) {
self.process_fields = fields;
self.process_help = help;
if(process && process.length) {
if(process.length > 1) {
self.process_selection = process;
} else {
self.process_id = process[0][0],
self.process_title = process[0][1];
}
}
return $.Deferred().resolve();
}).pipe(function() {
var def = $.Deferred();
if(self.process_id) {
self.graph_get().done(function(res) {
self.process_notes = res.notes;
self.process_subflows = _.filter(res.nodes, function(x) {
return x.subflow != false;
});
self.process_related = res.related;
def.resolve(res);
});
} else def.resolve();
return def.promise();
}).done(function(res) {
$.when(self.render_process_view()).done(function() {
if(res) self.draw_process_graph(res);
});
});
},
graph_get: function() {
var self = this;
var def = $.Deferred();
this.process_id = parseInt(this.process_id, 10);
this.process_dataset
.call("graph_get",[this.process_id, this.model || this.dataset.model, false, [80,80,150,100]])
.done(function(res) {
self.process_dataset
.call("search_by_model",[self.model || self.dataset.model,self.session.context])
.done(
function(r) {
res['related'] = r;
def.resolve(res);
});
});
return def.promise();
},
fields_get : function() {
var self = this,
def = $.Deferred(),
dataset = new openerp.web.DataSetStatic(this, this.model || this.dataset.model, this.session.context);
dataset
.call('fields_get',[])
.done(function(fields) {
def.resolve(fields);
}).fail(def.reject);
return def.promise();
},
help : function() {
var self = this,
def = $.Deferred();
if(!this.subflow_model) {
def.resolve(this.action ? (this.action.help!=false ? this.action.help : 'Help: Not Defined') : 'Help: Not Defined');
} else {
var dataset = new openerp.web.DataSetSearch(this, "ir.actions.act_window", this.session.context, []);
dataset
.read_slice(['help'],
{
domain: [
['res_model', '=', this.subflow_model],
['name', 'ilike', this.subflow_name]
]
}
).done(function(res) {
def.resolve(res.help || 'Help: Not Defined');
});
}
return def.promise();
},
get_process_object : function() {
var self = this,
def = $.Deferred();
if(this.process_id)
return def.resolve().promise();
this.process_dataset = new openerp.web.DataSetStatic(this, "process.process", this.session.context);
this.process_dataset
.call("search_by_model", [self.process_model,self.session.context])
.done(function(res) {
if (!res.length) {
self.process_model = false;
self.get_process_object().done(def.resolve);
}
else {
def.resolve(res);
}
})
.fail(def.reject);
return def.promise();
},
render_process_view : function() {
this.$element.html(QWeb.render("ProcessView", this));
var self = this;
this.$element.find('#edit_process').click(function() {
self.edit_process_view();
});
var $parent = this.widget_parent.$element;
$parent.find('#change_process').click(function() {
self.process_selection = false,
self.process_id = $parent.find('#select_process').val(),
self.process_title = $.trim($parent.find('#select_process option:selected').text());
self.initialize_process_view();
});
this.$element.find(".toggle_fields").click(function() {
$(this).children().toggle();
self.$element.find('.process_fields').toggle();
});
this.$element.find(".process_subflow").click(function() {
self.process_id = this.id;
self.initialize_process_view();
});
},
draw_process_graph : function(res) {
var self = this,
process_graph = new Graph();
var process_renderer = function(r, n) {
var process_node,
process_node_text,
process_node_desc,
process_set;
var node_button,
node_menu,
img_src;
var bg = "node",
clip_rect = "".concat(n.node.x,",",n.node.y,",150,100");
//Image part
bg = n.node.kind == "subflow" ? "node-subflow" : "node";
bg = n.node.gray ? bg + "-gray" : bg;
img_src = '/web_process/static/src/img/'+ bg + '.png';
r['image'](img_src, n.node.x, n.node.y,150, 100)
.attr({"clip-rect": clip_rect})
.mousedown(function() {
return false;
});
//Node
process_node = r['rect'](n.node.x, n.node.y, 150, 100).attr({stroke: "none"});
// Node text
process_node_text = r.text(n.node.x, n.node.y, (n.node.name))
.attr({"fill": "#fff", "font-weight": "bold", "cursor": "pointer"});
process_node_text.translate((process_node.getBBox().width/ 2) + 5, 10)
if(n.node.subflow) {
process_node_text.click(function() {
self.process_id = n.node.subflow[0];
self.subflow_model = n.node.model;
self.subflow_name = n.node.name;
self.initialize_process_view();
});
}
//Node Description
new_notes = n.node.notes;
if(n.node.notes.length > 25) {
var new_notes= temp_str = '';
var from = to = 0;
while (1) {
from = 25;
temp_str = n.node.notes.substr(to ,25);
if (temp_str.lastIndexOf(" ") < 25 && temp_str.length >= 25) {
from = temp_str.lastIndexOf(" ");
}
new_notes += "\n" + n.node.notes.substr(to , from);
if(new_notes.length > n.node.notes.length) break;
to += from;
}
}
process_node_desc = r.text(n.node.x+85, n.node.y+50, (new_notes));
r['image']('/web/static/src/img/icons/gtk-info.png', n.node.x+20, n.node.y+70, 16, 16)
.attr({"cursor": "pointer", "title": "Help"})
.click(function() {
window.open(n.node.url || "http://doc.openerp.com/v6.0/index.php?model=" + n.node.model);
});
if(n.node.menu) {
r['image']('/web/static/src/img/icons/gtk-jump-to.png', n.node.x+115, n.node.y+70, 16, 16)
.attr({"cursor": "pointer", "title": n.node.menu.name})
.click(function() {
self.jump_to_view(n.node.res_model, n.node.menu.id);
});
}
process_set = r.set().push(process_node);
process_set.mousedown(function() {
return false;
});
return process_set;
};
_.each(res['nodes'],function(node, node_id) {
node['res_model'] = self.model,
node['res_id'] = false,
node['id'] = node_id;
process_graph.addNode(node['name'], {node: node,render: process_renderer});
});
_.each(res['transitions'], function(transitions) {
var src = res['nodes'][transitions['source']];
var dst = res['nodes'][transitions['target']];
// make active
transitions['active'] = src.active && !dst.gray;
process_graph.addEdge(src['name'], dst['name'], {directed : true});
});
var layouter = new Graph.Layout.Ordered(process_graph);
var render_process_graph = new Graph.Renderer.Raphael('process_canvas', process_graph, $('#process_canvas').width(), $('#process_canvas').height());
},
jump_to_view: function(model, id) {
var self = this;
var dataset = new openerp.web.DataSetStatic(this, 'ir.values', this.session.context);
dataset.call('get',
['action', 'tree_but_open',[['ir.ui.menu', id]], dataset.context],
function(res) {
self.$element.empty();
var action = res[0][res[0].length - 1];
self.rpc("/web/action/load", {
action_id: action.id,
context: dataset.context
}, function(result) {
var action_manager = new openerp.web.ActionManager(self);
action_manager.appendTo(self.widget_parent.$element);
action_manager.do_action(result.result);
});
});
},
edit_process_view: function() {
var self = this;
var action_manager = new openerp.web.ActionManager(this);
var dialog = new openerp.web.Dialog(this, {
width: 800,
height: 600,
buttons : {
Cancel : function() {
$(this).dialog('destroy');
},
Save : function() {
var form_view = action_manager.inner_viewmanager.views.form.controller;
form_view.do_save(function() {
self.initialize_process_view();
});
$(this).dialog('destroy');
}
}
}).start().open();
action_manager.appendTo(dialog.$element);
action_manager.do_action({
res_model : 'process.process',
res_id: self.process_id,
views : [[false, 'form']],
type : 'ir.actions.act_window',
auto_search : false,
flags : {
search_view: false,
sidebar : false,
views_switcher : false,
action_buttons : false,
pager: false
}
});
},
});
};
// vim:et fdc=0 fdl=0 foldnestmax=3 fdm=syntax:

View File

@ -0,0 +1,143 @@
<template>
<t t-extend="ViewManager" t-name="ViewManagerAction">
<t t-jquery=".oe-view-manager-header" t-operation="append">
<img class="oe-process-view" src="/web/static/src/img/icons/gtk-help.png" title="ProcessView"/>
</t>
</t>
<t t-name="ProcessView">
<table class="view" border="0" width="100%" height="100%" cellpadding="0" cellspacing="0">
<tr>
<td width="75%" valign="top" class="fields collapsed" style="padding-top:10px;">
<h1 class="process_h1">
<t t-esc="action.name"/> (<t t-esc="model"/>)
</h1>
<p class="process-links">
<a class="cta-a" target="_blank" href="#">
<span>
<strong>Documentation</strong>
Read Documentation Online
</span>
</a>
<a class="cta-a" target="_blank" href="http://www.openerp.com/forum/">
<span>
<strong>Forum</strong>
Community Discussion
</span>
</a>
<a class="cta-a" target="_blank" href="http://www.openerp.com/services/books">
<span>
<strong>Books</strong>
Get the book on Amazon
</span>
</a>
<a class="cta-a" target="_blank" href="http://www.openerp.com/services/subscribe-onsite">
<span>
<strong>Support / Publisher Warranty</strong>
Get the OpenERP Warranty
</span>
</a>
</p>
</td>
</tr>
<tr>
<td>
<p><t t-esc="process_help"/></p>
</td>
</tr>
<tr>
<td>
<h2>
<t t-esc="process_title"/> Process
</h2>
<t t-if="process_notes">
<p>
<strong>Notes:</strong> <t t-esc="process_notes"/>
</p>
<p>
<strong>Last modified by:</strong> N/A
</p>
<t t-if="process_subflows.length">
<strong>Subflows:</strong>
<t t-foreach="process_subflows" t-as="subflow">
<t t-if="subflow.subflow[0] != process_id">
<p>
<a class="process_subflow" t-att-id="subflow.subflow[0]" href="javascript: void(0)">
<t t-esc="subflow.subflow[1]"/>
</a>
</p>
</t>
</t>
</t>
<t t-if="process_related.length and process_related[0][0] != process_id">
<strong>Related:</strong>
<p>
<a class="process_subflow" t-att-id="process_related[0][0]" href="javascript: void(0)">
<t t-esc="process_related[0][1]"/>
</a>
</p>
</t>
</t>
</td>
</tr>
<tr t-if="process_selection">
<td>
<fieldset>
<legend>
Select Process
</legend>
<select id="select_process">
<t t-foreach="process_selection" t-as="prc">
<option t-att-value="prc[0]">
<t t-esc="prc[1]"/>
</option>
</t>
</select>
<button id="change_process">Select</button>
</fieldset>
</td>
</tr>
<tr t-if="process_id">
<td>
<div id="process_canvas" style="overflow: auto;"></div>
</td>
</tr>
<tr t-if="process_id">
<td>
<button id="edit_process">Edit Process</button>
<button class="toggle_fields">
<span>Show Fields</span>
<span>Hide Fields</span>
</button>
</td>
</tr>
<tr t-if="process_id">
<td class="process_fields">
<table>
<t t-foreach="process_fields" t-as="field">
<tr>
<td>
<t t-esc="field"/>
</td>
<td>
<table>
<t t-foreach="field_value" t-as="fld">
<tr>
<td>
<t t-esc="fld"/>:
</td>
<td>
<t t-esc="fld_value"/>
</td>
</tr>
</t>
</table>
</td>
</tr>
</t>
</table>
</td>
</tr>
</table>
</t>
</template>