@odoo/o-spreadsheet 15.2.12 → 15.2.14

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -128,14 +128,72 @@
128
128
  // -----------------------------------------------------------------------------
129
129
  // Date Type
130
130
  // -----------------------------------------------------------------------------
131
+ /**
132
+ * A DateTime object that can be used to manipulate spreadsheet dates.
133
+ * Conceptually, a spreadsheet date is simply a number with a date format,
134
+ * and it is timezone-agnostic.
135
+ * This DateTime object consistently uses UTC time to represent a naive date and time.
136
+ */
137
+ class DateTime {
138
+ constructor(year, month, day, hours = 0, minutes = 0, seconds = 0) {
139
+ this.jsDate = new Date(Date.UTC(year, month, day, hours, minutes, seconds, 0));
140
+ }
141
+ static fromTimestamp(timestamp) {
142
+ const date = new Date(timestamp);
143
+ return new DateTime(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate(), date.getUTCHours(), date.getUTCMinutes(), date.getUTCSeconds());
144
+ }
145
+ static now() {
146
+ const now = new Date();
147
+ return new DateTime(now.getFullYear(), now.getMonth(), now.getDate(), now.getHours(), now.getMinutes(), now.getSeconds());
148
+ }
149
+ toString() {
150
+ return this.jsDate.toString();
151
+ }
152
+ getTime() {
153
+ return this.jsDate.getTime();
154
+ }
155
+ getFullYear() {
156
+ return this.jsDate.getUTCFullYear();
157
+ }
158
+ getMonth() {
159
+ return this.jsDate.getUTCMonth();
160
+ }
161
+ getDate() {
162
+ return this.jsDate.getUTCDate();
163
+ }
164
+ getDay() {
165
+ return this.jsDate.getUTCDay();
166
+ }
167
+ getHours() {
168
+ return this.jsDate.getUTCHours();
169
+ }
170
+ getMinutes() {
171
+ return this.jsDate.getUTCMinutes();
172
+ }
173
+ getSeconds() {
174
+ return this.jsDate.getUTCSeconds();
175
+ }
176
+ setDate(date) {
177
+ this.jsDate.setUTCDate(date);
178
+ }
179
+ setHours(hours) {
180
+ this.jsDate.setUTCHours(hours);
181
+ }
182
+ setMinutes(minutes) {
183
+ this.jsDate.setUTCMinutes(minutes);
184
+ }
185
+ setSeconds(seconds) {
186
+ this.jsDate.setUTCSeconds(seconds);
187
+ }
188
+ }
131
189
  // -----------------------------------------------------------------------------
132
190
  // Parsing
133
191
  // -----------------------------------------------------------------------------
134
192
  const CURRENT_MILLENIAL = 2000; // note: don't forget to update this in 2999
135
- const CURRENT_YEAR = new Date().getFullYear();
136
- const INITIAL_1900_DAY$1 = new Date(1899, 11, 30);
137
- const INITIAL_JS_DAY = new Date(0);
138
- const DATE_JS_1900_OFFSET = INITIAL_JS_DAY - INITIAL_1900_DAY$1;
193
+ const CURRENT_YEAR = DateTime.now().getFullYear();
194
+ const INITIAL_1900_DAY$1 = new DateTime(1899, 11, 30);
195
+ const INITIAL_JS_DAY = DateTime.fromTimestamp(0);
196
+ const DATE_JS_1900_OFFSET = INITIAL_JS_DAY.getTime() - INITIAL_1900_DAY$1.getTime();
139
197
  const mdyDateRegexp = /^\d{1,2}(\/|-|\s)\d{1,2}((\/|-|\s)\d{1,4})?$/;
140
198
  const ymdDateRegexp = /^\d{3,4}(\/|-|\s)\d{1,2}(\/|-|\s)\d{1,2}$/;
141
199
  const timeRegexp = /((\d+(:\d+)?(:\d+)?\s*(AM|PM))|(\d+:\d+(:\d+)?))$/;
@@ -175,7 +233,7 @@
175
233
  return {
176
234
  value: date.value + time.value,
177
235
  format: date.format + " " + (time.format === "hhhh:mm:ss" ? "hh:mm:ss" : time.format),
178
- jsDate: new Date(date.jsDate.getFullYear() + time.jsDate.getFullYear() - 1899, date.jsDate.getMonth() + time.jsDate.getMonth() - 11, date.jsDate.getDate() + time.jsDate.getDate() - 30, date.jsDate.getHours() + time.jsDate.getHours(), date.jsDate.getMinutes() + time.jsDate.getMinutes(), date.jsDate.getSeconds() + time.jsDate.getSeconds()),
236
+ jsDate: new DateTime(date.jsDate.getFullYear() + time.jsDate.getFullYear() - 1899, date.jsDate.getMonth() + time.jsDate.getMonth() - 11, date.jsDate.getDate() + time.jsDate.getDate() - 30, date.jsDate.getHours() + time.jsDate.getHours(), date.jsDate.getMinutes() + time.jsDate.getMinutes(), date.jsDate.getSeconds() + time.jsDate.getSeconds()),
179
237
  };
180
238
  }
181
239
  return date || time;
@@ -192,13 +250,13 @@
192
250
  const day = Number(parts[dayIndex]);
193
251
  const leadingZero = (parts[monthIndex].length === 2 && month < 10) || (parts[dayIndex].length === 2 && day < 10);
194
252
  const year = parts[yearIndex] ? inferYear(parts[yearIndex]) : CURRENT_YEAR;
195
- const jsDate = new Date(year, month - 1, day);
253
+ const jsDate = new DateTime(year, month - 1, day);
196
254
  const sep = str.match(/\/|-|\s/)[0];
197
255
  if (jsDate.getMonth() !== month - 1 || jsDate.getDate() !== day) {
198
256
  // invalid date
199
257
  return null;
200
258
  }
201
- const delta = jsDate - INITIAL_1900_DAY$1;
259
+ const delta = jsDate.getTime() - INITIAL_1900_DAY$1.getTime();
202
260
  let format = leadingZero ? `mm${sep}dd` : `m${sep}d`;
203
261
  if (parts[yearIndex]) {
204
262
  format = isMDY ? format + sep + "yyyy" : "yyyy" + sep + format;
@@ -258,7 +316,7 @@
258
316
  if (hours >= 24) {
259
317
  format = "hhhh:mm:ss";
260
318
  }
261
- const jsDate = new Date(1899, 11, 30, hours, minutes, seconds);
319
+ const jsDate = new DateTime(1899, 11, 30, hours, minutes, seconds);
262
320
  return {
263
321
  value: hours / 24 + minutes / 1440 + seconds / 86400,
264
322
  format: format,
@@ -272,7 +330,7 @@
272
330
  // -----------------------------------------------------------------------------
273
331
  function numberToJsDate(value) {
274
332
  const truncValue = Math.trunc(value);
275
- let date = new Date(truncValue * 86400 * 1000 - DATE_JS_1900_OFFSET);
333
+ let date = DateTime.fromTimestamp(truncValue * 86400 * 1000 - DATE_JS_1900_OFFSET);
276
334
  let time = value - truncValue;
277
335
  time = time < 0 ? 1 + time : time;
278
336
  const hours = Math.round(time * 24);
@@ -345,7 +403,7 @@
345
403
  .map((p) => {
346
404
  switch (p) {
347
405
  case "hhhh":
348
- const helapsedHours = Math.floor((jsDate.getTime() - INITIAL_1900_DAY$1) / (60 * 60 * 1000));
406
+ const helapsedHours = Math.floor((jsDate.getTime() - INITIAL_1900_DAY$1.getTime()) / (60 * 60 * 1000));
349
407
  return helapsedHours.toString();
350
408
  case "hh":
351
409
  return hours.toString().padStart(2, "0");
@@ -2706,13 +2764,6 @@
2706
2764
  }
2707
2765
 
2708
2766
  //------------------------------------------------------------------------------
2709
- /**
2710
- * Stringify an object, like JSON.stringify, except that the first level of keys
2711
- * is ordered.
2712
- */
2713
- function stringify(obj) {
2714
- return JSON.stringify(obj, Object.keys(obj).sort());
2715
- }
2716
2767
  /**
2717
2768
  * Remove quotes from a quoted string
2718
2769
  * ```js
@@ -2871,7 +2922,7 @@
2871
2922
  function isDateTime(str) {
2872
2923
  return parseDateTime(str) !== null;
2873
2924
  }
2874
- const MARKDOWN_LINK_REGEX = /^\[([^\[]+)\]\((.+)\)$/;
2925
+ const MARKDOWN_LINK_REGEX = /^\[(.+)\]\((.+)\)$/;
2875
2926
  //link must start with http or https
2876
2927
  //https://stackoverflow.com/a/3809435/4760614
2877
2928
  const WEB_LINK_REGEX = /^https?:\/\/(www\.)?[-a-zA-Z0-9@:%._\+~#=]{2,256}\.[a-z]{2,4}\b([-a-zA-Z0-9@:%_\+.~#?&//=]*)$/;
@@ -2937,7 +2988,7 @@
2937
2988
  */
2938
2989
  function getItemId(item, itemsDic) {
2939
2990
  for (let [key, value] of Object.entries(itemsDic)) {
2940
- if (stringify(value) === stringify(item)) {
2991
+ if (deepEquals(value, item)) {
2941
2992
  return parseInt(key, 10);
2942
2993
  }
2943
2994
  }
@@ -4747,7 +4798,7 @@
4747
4798
  DVARP: DVARP
4748
4799
  });
4749
4800
 
4750
- const INITIAL_1900_DAY = new Date(1899, 11, 30);
4801
+ const INITIAL_1900_DAY = new DateTime(1899, 11, 30);
4751
4802
  const DEFAULT_TYPE = 1;
4752
4803
  const DEFAULT_WEEKEND = 1;
4753
4804
  function isLeapYear(year) {
@@ -4776,7 +4827,7 @@
4776
4827
  if (_year < 1900) {
4777
4828
  _year += 1900;
4778
4829
  }
4779
- const jsDate = new Date(_year, _month - 1, _day);
4830
+ const jsDate = new DateTime(_year, _month - 1, _day);
4780
4831
  const delta = jsDate.getTime() - INITIAL_1900_DAY.getTime();
4781
4832
  assert(() => delta >= 0, _lt(`The function [[FUNCTION_NAME]] result must be greater than or equal 01/01/1900.`));
4782
4833
  return Math.round(delta / 86400000);
@@ -4849,7 +4900,7 @@
4849
4900
  const yStart = _startDate.getFullYear();
4850
4901
  const mStart = _startDate.getMonth();
4851
4902
  const dStart = _startDate.getDate();
4852
- const jsDate = new Date(yStart, mStart + _months, dStart);
4903
+ const jsDate = new DateTime(yStart, mStart + _months, dStart);
4853
4904
  const delta = jsDate.getTime() - INITIAL_1900_DAY.getTime();
4854
4905
  return Math.round(delta / 86400000);
4855
4906
  },
@@ -4871,7 +4922,7 @@
4871
4922
  const _months = Math.trunc(toNumber(months));
4872
4923
  const yStart = _startDate.getFullYear();
4873
4924
  const mStart = _startDate.getMonth();
4874
- const jsDate = new Date(yStart, mStart + _months + 1, 0);
4925
+ const jsDate = new DateTime(yStart, mStart + _months + 1, 0);
4875
4926
  const delta = jsDate.getTime() - INITIAL_1900_DAY.getTime();
4876
4927
  return Math.round(delta / 86400000);
4877
4928
  },
@@ -4911,17 +4962,17 @@
4911
4962
  // The first week of the year is the week that contains the first
4912
4963
  // Thursday of the year.
4913
4964
  let firstThursday = 1;
4914
- while (new Date(y, 0, firstThursday).getDay() !== 4) {
4965
+ while (new DateTime(y, 0, firstThursday).getDay() !== 4) {
4915
4966
  firstThursday += 1;
4916
4967
  }
4917
- const firstDayOfFirstWeek = new Date(y, 0, firstThursday - 3);
4968
+ const firstDayOfFirstWeek = new DateTime(y, 0, firstThursday - 3);
4918
4969
  // The last week of the year is the week that contains the last Thursday of
4919
4970
  // the year.
4920
4971
  let lastThursday = 31;
4921
- while (new Date(y, 11, lastThursday).getDay() !== 4) {
4972
+ while (new DateTime(y, 11, lastThursday).getDay() !== 4) {
4922
4973
  lastThursday -= 1;
4923
4974
  }
4924
- const lastDayOfLastWeek = new Date(y, 11, lastThursday + 3);
4975
+ const lastDayOfLastWeek = new DateTime(y, 11, lastThursday + 3);
4925
4976
  // B - If our date > lastDayOfLastWeek then it's in the weeks of the year after
4926
4977
  // If our date < firstDayOfFirstWeek then it's in the weeks of the year before
4927
4978
  let offsetYear;
@@ -4947,17 +4998,17 @@
4947
4998
  case 1:
4948
4999
  // firstDay is the 1st day of the 1st week of the year after
4949
5000
  // firstDay = lastDayOfLastWeek + 1 Day
4950
- firstDay = new Date(y, 11, lastThursday + 3 + 1);
5001
+ firstDay = new DateTime(y, 11, lastThursday + 3 + 1);
4951
5002
  break;
4952
5003
  case -1:
4953
5004
  // firstDay is the 1st day of the 1st week of the previous year.
4954
5005
  // The first week of the previous year is the week that contains the
4955
5006
  // first Thursday of the previous year.
4956
5007
  let firstThursdayPreviousYear = 1;
4957
- while (new Date(y - 1, 0, firstThursdayPreviousYear).getDay() !== 4) {
5008
+ while (new DateTime(y - 1, 0, firstThursdayPreviousYear).getDay() !== 4) {
4958
5009
  firstThursdayPreviousYear += 1;
4959
5010
  }
4960
- firstDay = new Date(y - 1, 0, firstThursdayPreviousYear - 3);
5011
+ firstDay = new DateTime(y - 1, 0, firstThursdayPreviousYear - 3);
4961
5012
  break;
4962
5013
  }
4963
5014
  const dif = (_date.getTime() - firstDay.getTime()) / 86400000;
@@ -5096,8 +5147,8 @@
5096
5147
  });
5097
5148
  }
5098
5149
  const invertDate = _startDate.getTime() > _endDate.getTime();
5099
- const stopDate = new Date((invertDate ? _startDate : _endDate).getTime());
5100
- let stepDate = new Date((invertDate ? _endDate : _startDate).getTime());
5150
+ const stopDate = DateTime.fromTimestamp((invertDate ? _startDate : _endDate).getTime());
5151
+ let stepDate = DateTime.fromTimestamp((invertDate ? _endDate : _startDate).getTime());
5101
5152
  const timeStopDate = stopDate.getTime();
5102
5153
  let timeStepDate = stepDate.getTime();
5103
5154
  let netWorkingDay = 0;
@@ -5121,8 +5172,7 @@
5121
5172
  returns: ["DATE"],
5122
5173
  returnFormat: { specificFormat: "m/d/yyyy hh:mm:ss" },
5123
5174
  compute: function () {
5124
- let today = new Date();
5125
- today.setMilliseconds(0);
5175
+ let today = DateTime.now();
5126
5176
  const delta = today.getTime() - INITIAL_1900_DAY.getTime();
5127
5177
  const time = today.getHours() / 24 + today.getMinutes() / 1440 + today.getSeconds() / 86400;
5128
5178
  return Math.floor(delta / 86400000) + time;
@@ -5196,8 +5246,8 @@
5196
5246
  returns: ["DATE"],
5197
5247
  returnFormat: { specificFormat: "m/d/yyyy" },
5198
5248
  compute: function () {
5199
- const today = new Date();
5200
- const jsDate = new Date(today.getFullYear(), today.getMonth(), today.getDate());
5249
+ const today = DateTime.now();
5250
+ const jsDate = new DateTime(today.getFullYear(), today.getMonth(), today.getDate());
5201
5251
  const delta = jsDate.getTime() - INITIAL_1900_DAY.getTime();
5202
5252
  return Math.round(delta / 86400000);
5203
5253
  },
@@ -5253,10 +5303,10 @@
5253
5303
  }
5254
5304
  const y = _date.getFullYear();
5255
5305
  let dayStart = 1;
5256
- let startDayOfFirstWeek = new Date(y, 0, dayStart);
5306
+ let startDayOfFirstWeek = new DateTime(y, 0, dayStart);
5257
5307
  while (startDayOfFirstWeek.getDay() !== startDayOfWeek) {
5258
5308
  dayStart += 1;
5259
- startDayOfFirstWeek = new Date(y, 0, dayStart);
5309
+ startDayOfFirstWeek = new DateTime(y, 0, dayStart);
5260
5310
  }
5261
5311
  const dif = (_date.getTime() - startDayOfFirstWeek.getTime()) / 86400000;
5262
5312
  if (dif < 0) {
@@ -5310,7 +5360,7 @@
5310
5360
  timesHoliday.add(holiday.getTime());
5311
5361
  });
5312
5362
  }
5313
- let stepDate = new Date(_startDate.getTime());
5363
+ let stepDate = DateTime.fromTimestamp(_startDate.getTime());
5314
5364
  let timeStepDate = stepDate.getTime();
5315
5365
  const unitDay = Math.sign(_numDays);
5316
5366
  let stepDay = Math.abs(_numDays);
@@ -9402,7 +9452,7 @@
9402
9452
  */
9403
9453
  function getBorderId(border) {
9404
9454
  for (let [key, value] of Object.entries(borders)) {
9405
- if (stringify(value) === stringify(border)) {
9455
+ if (deepEquals(value, border)) {
9406
9456
  return parseInt(key, 10);
9407
9457
  }
9408
9458
  }
@@ -9640,12 +9690,10 @@
9640
9690
  * starting an async evaluation even if it has been moved or re-allocated
9641
9691
  */
9642
9692
  getCellById(cellId) {
9643
- for (const sheet of Object.values(this.cells)) {
9644
- if (sheet[cellId]) {
9645
- return sheet[cellId];
9646
- }
9647
- }
9648
- return undefined;
9693
+ // this must be as fast as possible
9694
+ const position = this.getters.getCellPosition(cellId);
9695
+ const sheet = this.cells[position.sheetId];
9696
+ return sheet[cellId];
9649
9697
  }
9650
9698
  /**
9651
9699
  * Try to infer the cell format based on the formula dependencies.
@@ -23410,9 +23458,9 @@
23410
23458
  * Apply the changes of the given HistoryChange to the state
23411
23459
  */
23412
23460
  function applyChange(change, target) {
23413
- let val = change.root;
23414
- let key = change.path[change.path.length - 1];
23415
- for (let pathIndex = 0; pathIndex < change.path.slice(0, -1).length; pathIndex++) {
23461
+ let val = change.path[0];
23462
+ const key = change.path[change.path.length - 1];
23463
+ for (let pathIndex = 1; pathIndex < change.path.slice(0, -1).length; pathIndex++) {
23416
23464
  const p = change.path[pathIndex];
23417
23465
  if (val[p] === undefined) {
23418
23466
  const nextPath = change.path[pathIndex + 1];
@@ -23868,13 +23916,14 @@
23868
23916
  }
23869
23917
  addChange(...args) {
23870
23918
  const val = args.pop();
23871
- const [root, ...path] = args;
23919
+ const root = args[0];
23872
23920
  let value = root;
23873
- let key = path[path.length - 1];
23874
- for (let pathIndex = 0; pathIndex <= path.length - 2; pathIndex++) {
23875
- const p = path[pathIndex];
23921
+ let key = args[args.length - 1];
23922
+ const pathLength = args.length - 2;
23923
+ for (let pathIndex = 1; pathIndex <= pathLength; pathIndex++) {
23924
+ const p = args[pathIndex];
23876
23925
  if (value[p] === undefined) {
23877
- const nextPath = path[pathIndex + 1];
23926
+ const nextPath = args[pathIndex + 1];
23878
23927
  value[p] = createEmptyStructure(nextPath);
23879
23928
  }
23880
23929
  value = value[p];
@@ -23883,8 +23932,7 @@
23883
23932
  return;
23884
23933
  }
23885
23934
  this.changes.push({
23886
- root,
23887
- path,
23935
+ path: args,
23888
23936
  before: value[key],
23889
23937
  after: val,
23890
23938
  });
@@ -25924,7 +25972,10 @@
25924
25972
  */
25925
25973
  checkDispatchAllowed(command) {
25926
25974
  const results = this.handlers.map((handler) => handler.allowDispatch(command));
25927
- return new DispatchResult(results.flat());
25975
+ if (results.some((r) => r !== 0 /* Success */)) {
25976
+ return new DispatchResult(results.flat());
25977
+ }
25978
+ return DispatchResult.Success;
25928
25979
  }
25929
25980
  finalize() {
25930
25981
  this.status = 3 /* Finalizing */;
@@ -31388,9 +31439,9 @@
31388
31439
  Object.defineProperty(exports, '__esModule', { value: true });
31389
31440
 
31390
31441
 
31391
- __info__.version = '15.2.12';
31392
- __info__.date = '2023-11-16T11:57:04.728Z';
31393
- __info__.hash = 'd0fd7c1';
31442
+ __info__.version = '15.2.14';
31443
+ __info__.date = '2024-01-12T13:37:05.872Z';
31444
+ __info__.hash = '6515f7c';
31394
31445
 
31395
31446
 
31396
31447
  })(this.o_spreadsheet = this.o_spreadsheet || {}, owl);