summaryrefslogtreecommitdiff
path: root/addons/web
diff options
context:
space:
mode:
authorChristophe Simonis <chs@odoo.com>2015-03-04 15:16:10 +0100
committerChristophe Simonis <chs@odoo.com>2015-03-04 15:16:10 +0100
commitbc2fd0515b2ee0dafe05d95a76eccb99b35a418c (patch)
tree0cf1fdbaa92b178ce51db635242e611e7d62173e /addons/web
parent94c33caa784e3017285b55dc68c6726ed50b5f94 (diff)
parent017f346dd36e421877b2a7dfb94b5f805c435238 (diff)
[MERGE] forward port of branch 8.0 up to 017f346
Diffstat (limited to 'addons/web')
-rw-r--r--addons/web/static/lib/py.js/lib/py.js8
-rw-r--r--addons/web/static/src/js/pyeval.js225
-rw-r--r--addons/web/static/test/evals.js16
-rw-r--r--addons/web/views/webclient_templates.xml3
4 files changed, 174 insertions, 78 deletions
diff --git a/addons/web/static/lib/py.js/lib/py.js b/addons/web/static/lib/py.js/lib/py.js
index 2c6c832f9fe..35bb0b5223e 100644
--- a/addons/web/static/lib/py.js/lib/py.js
+++ b/addons/web/static/lib/py.js/lib/py.js
@@ -547,11 +547,13 @@ var py = {};
};
py.PY_call = function (callable, args, kwargs) {
if (!args) {
- args = []; kwargs = {};
- } else if (typeof args === 'object' && !(args instanceof Array)) {
+ args = [];
+ }
+ if (typeof args === 'object' && !(args instanceof Array)) {
kwargs = args;
args = [];
- } else if (!kwargs) {
+ }
+ if (!kwargs) {
kwargs = {};
}
if (callable.__is_type) {
diff --git a/addons/web/static/src/js/pyeval.js b/addons/web/static/src/js/pyeval.js
index 4cb17e70f29..c132b8365fb 100644
--- a/addons/web/static/src/js/pyeval.js
+++ b/addons/web/static/src/js/pyeval.js
@@ -222,7 +222,6 @@
['milliseconds', zero], ['minutes', zero], ['hours', zero],
['weeks', zero]
]);
-
var d = 0, s = 0, m = 0;
var days = args.days.toJSON() + args.weeks.toJSON() * 7;
var seconds = args.seconds.toJSON()
@@ -496,13 +495,14 @@
if (!py.PY_isInstance(other, datetime.timedelta)) {
return py.NotImplemented;
}
+
var s = tmxxx(this.year, this.month, this.day + other.days);
return datetime.date.fromJSON(s.year, s.month, s.day);
},
__radd__: function (other) { return this.__add__(other); },
__sub__: function (other) {
if (py.PY_isInstance(other, datetime.timedelta)) {
- return this.__add__(other.__neg__());
+ return py.PY_add(this, py.PY_negative(other));
}
if (py.PY_isInstance(other, datetime.date)) {
// FIXME: getattr and sub API methods
@@ -562,103 +562,182 @@
return py.PY_call(py.PY_getAttr(d, 'strftime'), [args.format]);
});
- var args = _.map(('year month day hour minute second microsecond '
- + 'years months weeks days hours minutes secondes microseconds '
- + 'weekday leakdays yearday nlyearday').split(' '), function (arg) {
- return [arg, null];
+ var args = _.map(('year month day '
+ + 'years months weeks days '
+ + 'weekday leapdays yearday nlyearday').split(' '), function (arg) {
+ switch (arg) {
+ case 'years':case 'months':case 'days':case 'leapdays':case 'weeks':
+ return [arg, zero];
+ case 'year':case 'month':case 'day':case 'weekday':
+ case 'yearday':case 'nlyearday':
+ return [arg, null];
+ default:
+ throw new Error("Unknown relativedelta argument " + arg);
+ }
});
args.unshift('*');
+ var utils = {
+ divmod: function (x, y) {
+ var rem = x % y;
+ return {
+ div: (x - rem) / y,
+ mod: rem
+ };
+ },
+ monthrange: function (year, month) {
+ if (month < 1 || month > 12) {
+ throw new Error("Illegal month " + month);
+ }
+
+ var day1 = this.weekday(year, month, 1);
+ var ndays = this.mdays[month] + (month == this.February && this.isleap(year));
+ return [day1, ndays];
+ },
+ weekday: function (year, month, day) {
+ var date = py.PY_call(datetime.date, [year, month, day]);
+ return py.PY_call(py.PY_getAttr(date, 'weekday'));
+ },
+ isleap: function (year) {
+ return year % 4 === 0 && (year % 100 !== 0 || year % 400 === 0)
+ },
+ mdays: [0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31],
+ January: 1,
+ February: 2
+ };
var relativedelta = py.type('relativedelta', null, {
__init__: function () {
this.ops = py.PY_parseArgs(arguments, args);
+ this.ops.days = py.float.fromJSON(
+ asJS(this.ops.days) + asJS(this.ops.weeks) * 7
+ );
+
+ var yday = zero;
+ if (this.ops.nlyearday) {
+ yday = this.ops.nlyearday;
+ } else if (this.ops.yearday) {
+ yday = this.ops.yearday;
+ if (asJS(this.ops.yearday) > 59) {
+ this.ops.leapdays = py.float.fromJS(-1);
+ }
+ }
+ if (py.PY_isTrue(yday)) {
+ var ydayidx = [31, 59, 90, 120, 151, 181, 212,
+ 243, 273, 304, 334, 366];
+ for(var idx=0; idx<ydayidx.length; ++idx) {
+ var ydays = ydayidx[idx];
+ if (asJS(yday) <= ydays) {
+ this.ops.month = py.float.fromJSON(idx+1);
+ if (!idx) {
+ this.ops.day = yday;
+ } else {
+ this.ops.day = py.PY_subtract(
+ yday,
+ py.float.fromJSON(ydayidx[idx-1])
+ );
+ }
+ break;
+ }
+ }
+ if (idx === ydayidx.length) {
+ throw new Error("Invalid year day (" + asJS(yday) + ")");
+ }
+ }
+ this._fix();
+ },
+ _fix: function () {
+ var months = asJS(this.ops.months);
+ if (Math.abs(months) > 11) {
+ var s = months > 0 ? 1 : -1;
+ var r = utils.divmod(months * s, 12);
+ this.ops.months = py.float.fromJSON(r.mod*s);
+ this.ops.years = py.float.fromJSON(
+ asJS(this.ops.years) + r.div*s);
+ }
+ this._has_time = 0;
},
__add__: function (other) {
if (!py.PY_isInstance(other, datetime.date)) {
return py.NotImplemented;
}
// TODO: test this whole mess
- var year = asJS(this.ops.year) || asJS(other.year);
- if (asJS(this.ops.years)) {
- year += asJS(this.ops.years);
- }
-
+ var year = (asJS(this.ops.year) || asJS(other.year)) + asJS(this.ops.years);
var month = asJS(this.ops.month) || asJS(other.month);
- if (asJS(this.ops.months)) {
- month += asJS(this.ops.months);
- // FIXME: no divmod in JS?
- while (month < 1) {
- year -= 1;
- month += 12;
+ var months;
+ if (months = asJS(this.ops.months)) {
+ if (Math.abs(months) < 1 || Math.abs(months) > 12) {
+ throw new Error("Can only use relative months between -12 and +12");
}
- while (month > 12) {
+ month += months;
+ if (month > 12) {
year += 1;
month -= 12;
}
+ if (month < 1) {
+ year -= 1;
+ month += 12;
+ }
}
- var lastMonthDay = new Date(year, month, 0).getDate();
- var day = asJS(this.ops.day) || asJS(other.day);
- if (day > lastMonthDay) { day = lastMonthDay; }
- var days_offset = ((asJS(this.ops.weeks) || 0) * 7) + (asJS(this.ops.days) || 0);
- if (days_offset) {
- day = new Date(year, month-1, day + days_offset).getDate();
- }
- // TODO: leapdays?
- // TODO: hours, minutes, seconds? Not used in XML domains
- // TODO: weekday?
- // FIXME: use date.replace
- return py.PY_call(datetime.date, [
- py.float.fromJSON(year),
- py.float.fromJSON(month),
- py.float.fromJSON(day)
- ]);
- },
- __radd__: function (other) {
- return this.__add__(other);
- },
+ var day = Math.min(utils.monthrange(year, month)[1],
+ asJS(this.ops.day) || asJS(other.day));
- __sub__: function (other) {
- if (!py.PY_isInstance(other, datetime.date)) {
- return py.NotImplemented;
- }
- // TODO: test this whole mess
- var year = asJS(this.ops.year) || asJS(other.year);
- if (asJS(this.ops.years)) {
- year -= asJS(this.ops.years);
+ var repl = {
+ year: py.float.fromJSON(year),
+ month: py.float.fromJSON(month),
+ day: py.float.fromJSON(day)
+ };
+
+ var days = asJS(this.ops.days);
+ if (py.PY_isTrue(this.ops.leapdays) && month > 2 && utils.isleap(year)) {
+ days += asJS(this.ops.leapdays);
}
- var month = asJS(this.ops.month) || asJS(other.month);
- if (asJS(this.ops.months)) {
- month -= asJS(this.ops.months);
- // FIXME: no divmod in JS?
- while (month < 1) {
- year -= 1;
- month += 12;
- }
- while (month > 12) {
- year += 1;
- month -= 12;
+ var ret = py.PY_add(
+ py.PY_call(py.PY_getAttr(other, 'replace'), repl),
+ py.PY_call(datetime.timedelta, {
+ days: py.float.fromJSON(days)
+ })
+ );
+
+ if (this.ops.weekday) {
+ // FIXME: only handles numeric weekdays, not decorated
+ var weekday = asJS(this.ops.weekday), nth = 1;
+ var jumpdays = (Math.abs(nth) - 1) * 7;
+
+ var ret_weekday = asJS(py.PY_call(py.PY_getAttr(ret, 'weekday')));
+ if (nth > 0) {
+ jumpdays += (7-ret_weekday+weekday) % 7;
+ } else {
+ jumpdays += (ret_weekday - weekday) % 7;
+ jumpdays *= -1;
}
+ ret = py.PY_add(
+ ret,
+ py.PY_call(datetime.timedelta, {
+ days: py.float.fromJSON(jumpdays)
+ })
+ );
}
- var lastMonthDay = new Date(year, month, 0).getDate();
- var day = asJS(this.ops.day) || asJS(other.day);
- if (day > lastMonthDay) { day = lastMonthDay; }
- var days_offset = ((asJS(this.ops.weeks) || 0) * 7) + (asJS(this.ops.days) || 0);
- if (days_offset) {
- day = new Date(year, month-1, day - days_offset).getDate();
- }
- // TODO: leapdays?
- // TODO: hours, minutes, seconds? Not used in XML domains
- // TODO: weekday?
- return py.PY_call(datetime.date, [
- py.float.fromJSON(year),
- py.float.fromJSON(month),
- py.float.fromJSON(day)
- ]);
+ return ret;
+ },
+ __radd__: function (other) {
+ return this.__add__(other);
},
__rsub__: function (other) {
- return this.__sub__(other);
+ return this.__neg__().__radd__(other);
+ },
+ __neg__: function () {
+ return py.PY_call(relativedelta, {
+ years: py.PY_negative(this.ops.years),
+ months: py.PY_negative(this.ops.months),
+ days: py.PY_negative(this.ops.days),
+ leapdays: this.ops.leapdays,
+ year: this.ops.year,
+ month: this.ops.month,
+ day: this.ops.day,
+ weekday: this.ops.weekday
+ });
}
});
diff --git a/addons/web/static/test/evals.js b/addons/web/static/test/evals.js
index 13ac0f3f3b7..a85f973e874 100644
--- a/addons/web/static/test/evals.js
+++ b/addons/web/static/test/evals.js
@@ -261,9 +261,21 @@ openerp.testing.section('eval.types', {
});
test('relastivedelta', function (instance) {
strictEqual(
- py.eval("(datetime.date(2012, 2, 15) + relativedelta(days=-1)).strftime('%Y-%m-%d 23:59:59')",
+ py.eval("(datetime.date(2012, 2, 15) + relativedelta(days=1)).strftime('%Y-%m-%d')",
instance.web.pyeval.context()),
- "2012-02-14 23:59:59");
+ "2012-02-16");
+ strictEqual(
+ py.eval("(datetime.date(2012, 2, 15) + relativedelta(days=-1)).strftime('%Y-%m-%d')",
+ instance.web.pyeval.context()),
+ "2012-02-14");
+ strictEqual(
+ py.eval("(datetime.date(2012, 2, 1) + relativedelta(days=-1)).strftime('%Y-%m-%d')",
+ instance.web.pyeval.context()),
+ '2012-01-31');
+ strictEqual(
+ py.eval("(datetime.date(2015,2,5)+relativedelta(days=-6,weekday=0)).strftime('%Y-%m-%d')",
+ instance.web.pyeval.context()),
+ '2015-02-02');
});
test('datetime.tojson', function (instance) {
var result = py.eval(
diff --git a/addons/web/views/webclient_templates.xml b/addons/web/views/webclient_templates.xml
index 0e4bd883aee..ff9d25f06e7 100644
--- a/addons/web/views/webclient_templates.xml
+++ b/addons/web/views/webclient_templates.xml
@@ -327,6 +327,9 @@
<t t-call="web.assets_common"/>
<t t-call="web.assets_backend"/>
+ <style>
+ body { overflow: auto !important; }
+ </style>
<script type="text/javascript" id="qunit_config">
localStorage.clear();
QUnit.config.testTimeout = 5 * 60 * 1000;