@odoo/o-spreadsheet 15.0.12 → 15.0.15

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.
@@ -129,14 +129,72 @@ const FORMULA_REF_IDENTIFIER = "|";
129
129
  // -----------------------------------------------------------------------------
130
130
  // Date Type
131
131
  // -----------------------------------------------------------------------------
132
+ /**
133
+ * A DateTime object that can be used to manipulate spreadsheet dates.
134
+ * Conceptually, a spreadsheet date is simply a number with a date format,
135
+ * and it is timezone-agnostic.
136
+ * This DateTime object consistently uses UTC time to represent a naive date and time.
137
+ */
138
+ class DateTime {
139
+ constructor(year, month, day, hours = 0, minutes = 0, seconds = 0) {
140
+ this.jsDate = new Date(Date.UTC(year, month, day, hours, minutes, seconds, 0));
141
+ }
142
+ static fromTimestamp(timestamp) {
143
+ const date = new Date(timestamp);
144
+ return new DateTime(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate(), date.getUTCHours(), date.getUTCMinutes(), date.getUTCSeconds());
145
+ }
146
+ static now() {
147
+ const now = new Date();
148
+ return new DateTime(now.getFullYear(), now.getMonth(), now.getDate(), now.getHours(), now.getMinutes(), now.getSeconds());
149
+ }
150
+ toString() {
151
+ return this.jsDate.toString();
152
+ }
153
+ getTime() {
154
+ return this.jsDate.getTime();
155
+ }
156
+ getFullYear() {
157
+ return this.jsDate.getUTCFullYear();
158
+ }
159
+ getMonth() {
160
+ return this.jsDate.getUTCMonth();
161
+ }
162
+ getDate() {
163
+ return this.jsDate.getUTCDate();
164
+ }
165
+ getDay() {
166
+ return this.jsDate.getUTCDay();
167
+ }
168
+ getHours() {
169
+ return this.jsDate.getUTCHours();
170
+ }
171
+ getMinutes() {
172
+ return this.jsDate.getUTCMinutes();
173
+ }
174
+ getSeconds() {
175
+ return this.jsDate.getUTCSeconds();
176
+ }
177
+ setDate(date) {
178
+ this.jsDate.setUTCDate(date);
179
+ }
180
+ setHours(hours) {
181
+ this.jsDate.setUTCHours(hours);
182
+ }
183
+ setMinutes(minutes) {
184
+ this.jsDate.setUTCMinutes(minutes);
185
+ }
186
+ setSeconds(seconds) {
187
+ this.jsDate.setUTCSeconds(seconds);
188
+ }
189
+ }
132
190
  // -----------------------------------------------------------------------------
133
191
  // Parsing
134
192
  // -----------------------------------------------------------------------------
135
193
  const CURRENT_MILLENIAL = 2000; // note: don't forget to update this in 2999
136
- const CURRENT_YEAR = new Date().getFullYear();
137
- const INITIAL_1900_DAY$1 = new Date(1899, 11, 30);
138
- const INITIAL_JS_DAY = new Date(0);
139
- const DATE_JS_1900_OFFSET = INITIAL_JS_DAY - INITIAL_1900_DAY$1;
194
+ const CURRENT_YEAR = DateTime.now().getFullYear();
195
+ const INITIAL_1900_DAY$1 = new DateTime(1899, 11, 30);
196
+ const INITIAL_JS_DAY = DateTime.fromTimestamp(0);
197
+ const DATE_JS_1900_OFFSET = INITIAL_JS_DAY.getTime() - INITIAL_1900_DAY$1.getTime();
140
198
  const mdyDateRegexp = /^\d{1,2}(\/|-|\s)\d{1,2}((\/|-|\s)\d{1,4})?$/;
141
199
  const ymdDateRegexp = /^\d{3,4}(\/|-|\s)\d{1,2}(\/|-|\s)\d{1,2}$/;
142
200
  const timeRegexp = /((\d+(:\d+)?(:\d+)?\s*(AM|PM))|(\d+:\d+(:\d+)?))$/;
@@ -176,7 +234,7 @@ function parseDateTime(str) {
176
234
  return {
177
235
  value: date.value + time.value,
178
236
  format: date.format + " " + (time.format === "hhhh:mm:ss" ? "hh:mm:ss" : time.format),
179
- 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()),
237
+ 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()),
180
238
  };
181
239
  }
182
240
  return date || time;
@@ -193,13 +251,13 @@ function parseDate(str, dateFormat) {
193
251
  const day = Number(parts[dayIndex]);
194
252
  const leadingZero = (parts[monthIndex].length === 2 && month < 10) || (parts[dayIndex].length === 2 && day < 10);
195
253
  const year = parts[yearIndex] ? inferYear(parts[yearIndex]) : CURRENT_YEAR;
196
- const jsDate = new Date(year, month - 1, day);
254
+ const jsDate = new DateTime(year, month - 1, day);
197
255
  const sep = str.match(/\/|-|\s/)[0];
198
256
  if (jsDate.getMonth() !== month - 1 || jsDate.getDate() !== day) {
199
257
  // invalid date
200
258
  return null;
201
259
  }
202
- const delta = jsDate - INITIAL_1900_DAY$1;
260
+ const delta = jsDate.getTime() - INITIAL_1900_DAY$1.getTime();
203
261
  let format = leadingZero ? `mm${sep}dd` : `m${sep}d`;
204
262
  if (parts[yearIndex]) {
205
263
  format = isMDY ? format + sep + "yyyy" : "yyyy" + sep + format;
@@ -259,7 +317,7 @@ function parseTime(str) {
259
317
  if (hours >= 24) {
260
318
  format = "hhhh:mm:ss";
261
319
  }
262
- const jsDate = new Date(1899, 11, 30, hours, minutes, seconds);
320
+ const jsDate = new DateTime(1899, 11, 30, hours, minutes, seconds);
263
321
  return {
264
322
  value: hours / 24 + minutes / 1440 + seconds / 86400,
265
323
  format: format,
@@ -273,7 +331,7 @@ function parseTime(str) {
273
331
  // -----------------------------------------------------------------------------
274
332
  function numberToJsDate(value) {
275
333
  const truncValue = Math.trunc(value);
276
- let date = new Date(truncValue * 86400 * 1000 - DATE_JS_1900_OFFSET);
334
+ let date = DateTime.fromTimestamp(truncValue * 86400 * 1000 - DATE_JS_1900_OFFSET);
277
335
  let time = value - truncValue;
278
336
  time = time < 0 ? 1 + time : time;
279
337
  const hours = Math.round(time * 24);
@@ -346,7 +404,7 @@ function formatJSTime(jsDate, format) {
346
404
  .map((p) => {
347
405
  switch (p) {
348
406
  case "hhhh":
349
- const helapsedHours = Math.floor((jsDate.getTime() - INITIAL_1900_DAY$1) / (60 * 60 * 1000));
407
+ const helapsedHours = Math.floor((jsDate.getTime() - INITIAL_1900_DAY$1.getTime()) / (60 * 60 * 1000));
350
408
  return helapsedHours.toString();
351
409
  case "hh":
352
410
  return hours.toString().padStart(2, "0");
@@ -2701,13 +2759,6 @@ for (let font of fontSizes) {
2701
2759
  }
2702
2760
 
2703
2761
  //------------------------------------------------------------------------------
2704
- /**
2705
- * Stringify an object, like JSON.stringify, except that the first level of keys
2706
- * is ordered.
2707
- */
2708
- function stringify(obj) {
2709
- return JSON.stringify(obj, Object.keys(obj).sort());
2710
- }
2711
2762
  /**
2712
2763
  * Escapes a string to use as a literal string in a RegExp.
2713
2764
  * @url https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions#Escaping
@@ -2853,7 +2904,7 @@ function isBoolean(str) {
2853
2904
  function isDateTime(str) {
2854
2905
  return parseDateTime(str) !== null;
2855
2906
  }
2856
- const MARKDOWN_LINK_REGEX = /^\[([^\[]+)\]\((.+)\)$/;
2907
+ const MARKDOWN_LINK_REGEX = /^\[(.+)\]\((.+)\)$/;
2857
2908
  //link must start with http or https
2858
2909
  //https://stackoverflow.com/a/3809435/4760614
2859
2910
  const WEB_LINK_REGEX = /^https?:\/\/(www\.)?[-a-zA-Z0-9@:%._\+~#=]{2,256}\.[a-z]{2,4}\b([-a-zA-Z0-9@:%_\+.~#?&//=]*)$/;
@@ -4756,7 +4807,7 @@ var database = /*#__PURE__*/Object.freeze({
4756
4807
  DVARP: DVARP
4757
4808
  });
4758
4809
 
4759
- const INITIAL_1900_DAY = new Date(1899, 11, 30);
4810
+ const INITIAL_1900_DAY = new DateTime(1899, 11, 30);
4760
4811
  const DEFAULT_TYPE = 1;
4761
4812
  const DEFAULT_WEEKEND = 1;
4762
4813
  function isLeapYear(year) {
@@ -4785,7 +4836,7 @@ const DATE = {
4785
4836
  if (_year < 1900) {
4786
4837
  _year += 1900;
4787
4838
  }
4788
- const jsDate = new Date(_year, _month - 1, _day);
4839
+ const jsDate = new DateTime(_year, _month - 1, _day);
4789
4840
  const delta = jsDate.getTime() - INITIAL_1900_DAY.getTime();
4790
4841
  assert(() => delta >= 0, _lt(`The function [[FUNCTION_NAME]] result must be greater than or equal 01/01/1900.`));
4791
4842
  return Math.round(delta / 86400000);
@@ -4858,7 +4909,7 @@ const EDATE = {
4858
4909
  const yStart = _startDate.getFullYear();
4859
4910
  const mStart = _startDate.getMonth();
4860
4911
  const dStart = _startDate.getDate();
4861
- const jsDate = new Date(yStart, mStart + _months, dStart);
4912
+ const jsDate = new DateTime(yStart, mStart + _months, dStart);
4862
4913
  const delta = jsDate.getTime() - INITIAL_1900_DAY.getTime();
4863
4914
  return Math.round(delta / 86400000);
4864
4915
  },
@@ -4880,7 +4931,7 @@ const EOMONTH = {
4880
4931
  const _months = Math.trunc(toNumber(months));
4881
4932
  const yStart = _startDate.getFullYear();
4882
4933
  const mStart = _startDate.getMonth();
4883
- const jsDate = new Date(yStart, mStart + _months + 1, 0);
4934
+ const jsDate = new DateTime(yStart, mStart + _months + 1, 0);
4884
4935
  const delta = jsDate.getTime() - INITIAL_1900_DAY.getTime();
4885
4936
  return Math.round(delta / 86400000);
4886
4937
  },
@@ -4920,17 +4971,17 @@ const ISOWEEKNUM = {
4920
4971
  // The first week of the year is the week that contains the first
4921
4972
  // Thursday of the year.
4922
4973
  let firstThursday = 1;
4923
- while (new Date(y, 0, firstThursday).getDay() !== 4) {
4974
+ while (new DateTime(y, 0, firstThursday).getDay() !== 4) {
4924
4975
  firstThursday += 1;
4925
4976
  }
4926
- const firstDayOfFirstWeek = new Date(y, 0, firstThursday - 3);
4977
+ const firstDayOfFirstWeek = new DateTime(y, 0, firstThursday - 3);
4927
4978
  // The last week of the year is the week that contains the last Thursday of
4928
4979
  // the year.
4929
4980
  let lastThursday = 31;
4930
- while (new Date(y, 11, lastThursday).getDay() !== 4) {
4981
+ while (new DateTime(y, 11, lastThursday).getDay() !== 4) {
4931
4982
  lastThursday -= 1;
4932
4983
  }
4933
- const lastDayOfLastWeek = new Date(y, 11, lastThursday + 3);
4984
+ const lastDayOfLastWeek = new DateTime(y, 11, lastThursday + 3);
4934
4985
  // B - If our date > lastDayOfLastWeek then it's in the weeks of the year after
4935
4986
  // If our date < firstDayOfFirstWeek then it's in the weeks of the year before
4936
4987
  let offsetYear;
@@ -4956,17 +5007,17 @@ const ISOWEEKNUM = {
4956
5007
  case 1:
4957
5008
  // firstDay is the 1st day of the 1st week of the year after
4958
5009
  // firstDay = lastDayOfLastWeek + 1 Day
4959
- firstDay = new Date(y, 11, lastThursday + 3 + 1);
5010
+ firstDay = new DateTime(y, 11, lastThursday + 3 + 1);
4960
5011
  break;
4961
5012
  case -1:
4962
5013
  // firstDay is the 1st day of the 1st week of the previous year.
4963
5014
  // The first week of the previous year is the week that contains the
4964
5015
  // first Thursday of the previous year.
4965
5016
  let firstThursdayPreviousYear = 1;
4966
- while (new Date(y - 1, 0, firstThursdayPreviousYear).getDay() !== 4) {
5017
+ while (new DateTime(y - 1, 0, firstThursdayPreviousYear).getDay() !== 4) {
4967
5018
  firstThursdayPreviousYear += 1;
4968
5019
  }
4969
- firstDay = new Date(y - 1, 0, firstThursdayPreviousYear - 3);
5020
+ firstDay = new DateTime(y - 1, 0, firstThursdayPreviousYear - 3);
4970
5021
  break;
4971
5022
  }
4972
5023
  const dif = (_date.getTime() - firstDay.getTime()) / 86400000;
@@ -5105,8 +5156,8 @@ const NETWORKDAYS_INTL = {
5105
5156
  });
5106
5157
  }
5107
5158
  const invertDate = _startDate.getTime() > _endDate.getTime();
5108
- const stopDate = new Date((invertDate ? _startDate : _endDate).getTime());
5109
- let stepDate = new Date((invertDate ? _endDate : _startDate).getTime());
5159
+ const stopDate = DateTime.fromTimestamp((invertDate ? _startDate : _endDate).getTime());
5160
+ let stepDate = DateTime.fromTimestamp((invertDate ? _endDate : _startDate).getTime());
5110
5161
  const timeStopDate = stopDate.getTime();
5111
5162
  let timeStepDate = stepDate.getTime();
5112
5163
  let netWorkingDay = 0;
@@ -5130,8 +5181,7 @@ const NOW = {
5130
5181
  returns: ["DATE"],
5131
5182
  returnFormat: { specificFormat: "m/d/yyyy hh:mm:ss" },
5132
5183
  compute: function () {
5133
- let today = new Date();
5134
- today.setMilliseconds(0);
5184
+ let today = DateTime.now();
5135
5185
  const delta = today.getTime() - INITIAL_1900_DAY.getTime();
5136
5186
  const time = today.getHours() / 24 + today.getMinutes() / 1440 + today.getSeconds() / 86400;
5137
5187
  return Math.floor(delta / 86400000) + time;
@@ -5205,8 +5255,8 @@ const TODAY = {
5205
5255
  returns: ["DATE"],
5206
5256
  returnFormat: { specificFormat: "m/d/yyyy" },
5207
5257
  compute: function () {
5208
- const today = new Date();
5209
- const jsDate = new Date(today.getFullYear(), today.getMonth(), today.getDate());
5258
+ const today = DateTime.now();
5259
+ const jsDate = new DateTime(today.getFullYear(), today.getMonth(), today.getDate());
5210
5260
  const delta = jsDate.getTime() - INITIAL_1900_DAY.getTime();
5211
5261
  return Math.round(delta / 86400000);
5212
5262
  },
@@ -5262,10 +5312,10 @@ const WEEKNUM = {
5262
5312
  }
5263
5313
  const y = _date.getFullYear();
5264
5314
  let dayStart = 1;
5265
- let startDayOfFirstWeek = new Date(y, 0, dayStart);
5315
+ let startDayOfFirstWeek = new DateTime(y, 0, dayStart);
5266
5316
  while (startDayOfFirstWeek.getDay() !== startDayOfWeek) {
5267
5317
  dayStart += 1;
5268
- startDayOfFirstWeek = new Date(y, 0, dayStart);
5318
+ startDayOfFirstWeek = new DateTime(y, 0, dayStart);
5269
5319
  }
5270
5320
  const dif = (_date.getTime() - startDayOfFirstWeek.getTime()) / 86400000;
5271
5321
  if (dif < 0) {
@@ -5319,7 +5369,7 @@ const WORKDAY_INTL = {
5319
5369
  timesHoliday.add(holiday.getTime());
5320
5370
  });
5321
5371
  }
5322
- let stepDate = new Date(_startDate.getTime());
5372
+ let stepDate = DateTime.fromTimestamp(_startDate.getTime());
5323
5373
  let timeStepDate = stepDate.getTime();
5324
5374
  const unitDay = Math.sign(_numDays);
5325
5375
  let stepDay = Math.abs(_numDays);
@@ -9426,7 +9476,7 @@ class BordersPlugin extends CorePlugin {
9426
9476
  */
9427
9477
  function getBorderId(border) {
9428
9478
  for (let [key, value] of Object.entries(borders)) {
9429
- if (stringify(value) === stringify(border)) {
9479
+ if (deepEquals(value, border)) {
9430
9480
  return parseInt(key, 10);
9431
9481
  }
9432
9482
  }
@@ -9622,7 +9672,7 @@ class CellPlugin extends CorePlugin {
9622
9672
  */
9623
9673
  function getStyleId(style) {
9624
9674
  for (let [key, value] of Object.entries(styles)) {
9625
- if (stringify(value) === stringify(style)) {
9675
+ if (deepEquals(value, style)) {
9626
9676
  return parseInt(key, 10);
9627
9677
  }
9628
9678
  }
@@ -9676,12 +9726,10 @@ class CellPlugin extends CorePlugin {
9676
9726
  * starting an async evaluation even if it has been moved or re-allocated
9677
9727
  */
9678
9728
  getCellById(cellId) {
9679
- for (const sheet of Object.values(this.cells)) {
9680
- if (sheet[cellId]) {
9681
- return sheet[cellId];
9682
- }
9683
- }
9684
- return undefined;
9729
+ // this must be as fast as possible
9730
+ const position = this.getters.getCellPosition(cellId);
9731
+ const sheet = this.cells[position.sheetId];
9732
+ return sheet[cellId];
9685
9733
  }
9686
9734
  /**
9687
9735
  * Reconstructs the original formula string based on a normalized form and its dependencies
@@ -15850,7 +15898,7 @@ const CSS$i = css$k /* scss */ `
15850
15898
  }
15851
15899
  .o-input-count {
15852
15900
  width: fit-content;
15853
- padding: 4 0 4 4;
15901
+ padding: 4px 0 4px 4px;
15854
15902
  }
15855
15903
  }
15856
15904
  }
@@ -23502,9 +23550,9 @@ function revertChanges(revisions) {
23502
23550
  * Apply the changes of the given HistoryChange to the state
23503
23551
  */
23504
23552
  function applyChange(change, target) {
23505
- let val = change.root;
23506
- let key = change.path[change.path.length - 1];
23507
- for (let pathIndex = 0; pathIndex < change.path.slice(0, -1).length; pathIndex++) {
23553
+ let val = change.path[0];
23554
+ const key = change.path[change.path.length - 1];
23555
+ for (let pathIndex = 1; pathIndex < change.path.slice(0, -1).length; pathIndex++) {
23508
23556
  const p = change.path[pathIndex];
23509
23557
  if (val[p] === undefined) {
23510
23558
  const nextPath = change.path[pathIndex + 1];
@@ -23960,13 +24008,14 @@ class StateObserver {
23960
24008
  }
23961
24009
  addChange(...args) {
23962
24010
  const val = args.pop();
23963
- const [root, ...path] = args;
24011
+ const root = args[0];
23964
24012
  let value = root;
23965
- let key = path[path.length - 1];
23966
- for (let pathIndex = 0; pathIndex <= path.length - 2; pathIndex++) {
23967
- const p = path[pathIndex];
24013
+ let key = args[args.length - 1];
24014
+ const pathLength = args.length - 2;
24015
+ for (let pathIndex = 1; pathIndex <= pathLength; pathIndex++) {
24016
+ const p = args[pathIndex];
23968
24017
  if (value[p] === undefined) {
23969
- const nextPath = path[pathIndex + 1];
24018
+ const nextPath = args[pathIndex + 1];
23970
24019
  value[p] = createEmptyStructure(nextPath);
23971
24020
  }
23972
24021
  value = value[p];
@@ -23975,8 +24024,7 @@ class StateObserver {
23975
24024
  return;
23976
24025
  }
23977
24026
  this.changes.push({
23978
- root,
23979
- path,
24027
+ path: args,
23980
24028
  before: value[key],
23981
24029
  after: val,
23982
24030
  });
@@ -26034,7 +26082,10 @@ class Model extends owl__namespace.core.EventBus {
26034
26082
  */
26035
26083
  checkDispatchAllowed(command) {
26036
26084
  const results = this.handlers.map((handler) => handler.allowDispatch(command));
26037
- return new DispatchResult(results.flat());
26085
+ if (results.some((r) => r !== 0 /* Success */)) {
26086
+ return new DispatchResult(results.flat());
26087
+ }
26088
+ return DispatchResult.Success;
26038
26089
  }
26039
26090
  finalize() {
26040
26091
  this.status = 3 /* Finalizing */;
@@ -31456,6 +31507,6 @@ exports.registries = registries;
31456
31507
  exports.setTranslationMethod = setTranslationMethod;
31457
31508
 
31458
31509
 
31459
- __info__.version = '15.0.12';
31460
- __info__.date = '2023-11-02T09:28:12.777Z';
31461
- __info__.hash = 'e82bd99';
31510
+ __info__.version = '15.0.15';
31511
+ __info__.date = '2024-01-12T13:39:45.422Z';
31512
+ __info__.hash = 'c87764c';
@@ -922,7 +922,7 @@ declare class StateObserver {
922
922
  commands: CoreCommand[];
923
923
  };
924
924
  addCommand(command: CoreCommand): void;
925
- addChange(...args: any[]): void;
925
+ addChange(...args: [...HistoryChange["path"], any]): void;
926
926
  }
927
927
 
928
928
  /**
@@ -3890,8 +3890,7 @@ declare type EvalContext = {
3890
3890
  };
3891
3891
 
3892
3892
  interface HistoryChange {
3893
- root: any;
3894
- path: (string | number)[];
3893
+ path: [any, ...(number | string)[]];
3895
3894
  before: any;
3896
3895
  after: any;
3897
3896
  }