[MERGE]resove conflict and merge with main branch.
bzr revid: vme@tinyerp.com-20111122061753-5uxqy3mxw0eedthn
|
@ -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':
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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(){
|
||||
|
|
|
@ -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(){
|
||||
|
|
|
@ -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': '&&',
|
||||
|
|
|
@ -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,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""").replace(/'/g,"'").replace(/\//g,"/")};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);
|
|
@ -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, '&').replace(/</g, '<').replace(/>/g, '>').replace(/"/g, '"').replace(/'/g, ''').replace(/\//g,'/');
|
||||
};
|
||||
|
||||
// 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);
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""").replace(/'/g,"'")}),unescapeHTML:d(function(a){return a.replace(/</g,"<").replace(/>/g,
|
||||
">").replace(/"/g,'"').replace(/'/g,"'").replace(/&/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);
|
|
@ -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;
|
||||
|
|
|
@ -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'));
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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':
|
||||
|
|
|
@ -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}
|
||||
);
|
||||
|
|
|
@ -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',
|
||||
});
|
||||
};
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
});
|
||||
},
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
},
|
||||
|
|
|
@ -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', {
|
||||
|
|
|
@ -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">
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 || '';
|
||||
|
|
|
@ -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">
|
||||
|
|
|
@ -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">
|
||||
|
|
|
@ -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
|
||||
}
|
|
@ -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;
|
||||
}
|
After Width: | Height: | Size: 650 B |
After Width: | Height: | Size: 635 B |
After Width: | Height: | Size: 810 B |
After Width: | Height: | Size: 6.4 KiB |
After Width: | Height: | Size: 108 B |
After Width: | Height: | Size: 4.4 KiB |
After Width: | Height: | Size: 379 B |
After Width: | Height: | Size: 3.1 KiB |
After Width: | Height: | Size: 3.1 KiB |
After Width: | Height: | Size: 6.7 KiB |
After Width: | Height: | Size: 6.7 KiB |
After Width: | Height: | Size: 3.1 KiB |
After Width: | Height: | Size: 166 B |
After Width: | Height: | Size: 43 B |
After Width: | Height: | Size: 128 B |
After Width: | Height: | Size: 200 B |
|
@ -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:
|
|
@ -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>
|