tryton-sao 7.2.20 → 7.2.22

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.
package/CHANGELOG CHANGED
@@ -1,4 +1,14 @@
1
1
 
2
+ Version 7.2.22 - 2025-06-04
3
+ ---------------------------
4
+ * Bug fixes (see mercurial logs for details)
5
+
6
+
7
+ Version 7.2.21 - 2025-05-15
8
+ ---------------------------
9
+ * Bug fixes (see mercurial logs for details)
10
+
11
+
2
12
  Version 7.2.20 - 2025-05-02
3
13
  ---------------------------
4
14
  * Bug fixes (see mercurial logs for details)
@@ -3,7 +3,7 @@
3
3
 
4
4
  /* eslint-disable no-redeclare */
5
5
  var Sao = {
6
- __version__: '7.2.20',
6
+ __version__: '7.2.22',
7
7
  };
8
8
  /* eslint-enable no-redeclare */
9
9
 
@@ -660,6 +660,7 @@ var Sao = {
660
660
  "Incompatible version of the server."),
661
661
  Sao.i18n.gettext("Version mismatch"));
662
662
  } else {
663
+ let url = window.location.hash.substr(1);
663
664
  Sao.Session.get_credentials()
664
665
  .then(function(session) {
665
666
  Sao.Session.current_session = session;
@@ -669,7 +670,7 @@ var Sao = {
669
670
  .then(function(preferences) {
670
671
  Sao.menu(preferences);
671
672
  Sao.user_menu(preferences);
672
- Sao.open_url();
673
+ Sao.open_url(url);
673
674
  Sao.Bus.listen();
674
675
  });
675
676
  }
@@ -7656,16 +7657,19 @@ var Sao = {
7656
7657
  return null;
7657
7658
  }
7658
7659
  var type = '';
7659
- try {
7660
- var xml = data;
7661
- if (xml instanceof Uint8Array) {
7662
- xml = new TextDecoder().decode(data);
7663
- }
7664
- if (jQuery.parseXML(xml)) {
7660
+ var xml = data;
7661
+ if (xml instanceof Uint8Array) {
7662
+ xml = new TextDecoder().decode(data);
7663
+ }
7664
+ // simple test to avoid logging of parsing error
7665
+ if (/^\s*<[\s\S]+>\s*$/.test(xml.trim())) {
7666
+ let parser = new DOMParser();
7667
+ let doc = parser.parseFromString(xml, 'image/svg+xml');
7668
+ if (!doc.querySelector('parsererror')
7669
+ && (doc.documentElement.tagName.toLowerCase() === 'svg' ||
7670
+ doc.getElementsByTagName('svg').length > 0)) {
7665
7671
  type = 'image/svg+xml';
7666
7672
  }
7667
- } catch (e) {
7668
- // continue
7669
7673
  }
7670
7674
  var blob = new Blob([data], {type: type});
7671
7675
  return window.URL.createObjectURL(blob);
@@ -9462,7 +9466,6 @@ var Sao = {
9462
9466
  // XXX to remove once server domains are fixed
9463
9467
  value = null;
9464
9468
  }
9465
- var setdefault = true;
9466
9469
  var original_domain;
9467
9470
  if (!jQuery.isEmptyObject(record.group.domain)) {
9468
9471
  original_domain = inversion.merge(record.group.domain);
@@ -9470,20 +9473,12 @@ var Sao = {
9470
9473
  original_domain = inversion.merge(domain);
9471
9474
  }
9472
9475
  var domain_readonly = original_domain[0] == 'AND';
9476
+ let setdefault;
9473
9477
  if (leftpart.contains('.')) {
9474
- var recordpart = leftpart.split('.', 1)[0];
9475
- var localpart = leftpart.split('.', 1)[1];
9476
- var constraintfields = [];
9477
- if (domain_readonly) {
9478
- for (const leaf of inversion.localize_domain(
9479
- original_domain.slice(1))) {
9480
- constraintfields.push(leaf);
9481
- }
9482
- }
9483
- if ((localpart != 'id') ||
9484
- !~constraintfields.indexOf(recordpart)) {
9485
- setdefault = false;
9486
- }
9478
+ let localpart = leftpart.split('.').slice(1).join('.');
9479
+ setdefault = localpart == 'id';
9480
+ } else {
9481
+ setdefault = true;
9487
9482
  }
9488
9483
  if (setdefault && jQuery.isEmptyObject(pre_validate)) {
9489
9484
  this.set_client(record, value);
@@ -9747,12 +9742,23 @@ var Sao = {
9747
9742
  },
9748
9743
  apply_factor: function(record, value, factor) {
9749
9744
  if (value !== null) {
9745
+ // The default precision is the one used by value (before
9746
+ // applying the factor), per the ecmascript specification
9747
+ // it's the shortest representation of said value.
9748
+ // Once the factor is applied the number might become even
9749
+ // more inexact thus we should rely on the initial
9750
+ // precision + the effect factor will have
9751
+ // https://tc39.es/ecma262/multipage/ecmascript-data-types-and-values.html#sec-numeric-types-number-tostring
9752
+ let default_precision = (value.toString().split('.')[1] || '').length;
9753
+ default_precision += Math.ceil(Math.log10(factor));
9750
9754
  value /= factor;
9751
9755
  var digits = this.digits(record);
9752
9756
  if (digits) {
9753
9757
  // Round to avoid float precision error
9754
9758
  // after the division by factor
9755
9759
  value = value.toFixed(digits[1]);
9760
+ } else {
9761
+ value = value.toFixed(default_precision);
9756
9762
  }
9757
9763
  value = this.convert(value);
9758
9764
  }
@@ -11532,15 +11538,20 @@ var Sao = {
11532
11538
  case 'ok':
11533
11539
  return this.save();
11534
11540
  case 'ko':
11535
- var record_id = this.screen.current_record.id;
11541
+ var record_id = null;
11542
+ if (this.screen.current_record) {
11543
+ record_id = this.screen.current_record.id;
11544
+ }
11536
11545
  return this.reload(false).then(() => {
11537
- if (record_id < 0) {
11538
- return jQuery.Deferred().reject(true);
11539
- }
11540
- else if (this.screen.current_record) {
11541
- if (record_id !=
11542
- this.screen.current_record.id) {
11543
- return jQuery.Deferred().reject();
11546
+ if (record_id !== null) {
11547
+ if (record_id < 0) {
11548
+ return jQuery.Deferred().reject(true);
11549
+ }
11550
+ else if (this.screen.current_record) {
11551
+ if (record_id !=
11552
+ this.screen.current_record.id) {
11553
+ return jQuery.Deferred().reject();
11554
+ }
11544
11555
  }
11545
11556
  }
11546
11557
  });
@@ -16319,7 +16330,8 @@ function eval_pyson(value){
16319
16330
  class_: 'form',
16320
16331
  init: function(languages, widget) {
16321
16332
  var dialog = new Sao.Dialog(
16322
- Sao.i18n.gettext('Translate'), this.class_, 'md');
16333
+ Sao.i18n.gettext('Translate'), this.class_,
16334
+ widget.expand? 'lg' : 'md');
16323
16335
  this.languages = languages;
16324
16336
  this.read(widget, dialog);
16325
16337
  jQuery('<button/>', {
@@ -16410,10 +16422,10 @@ function eval_pyson(value){
16410
16422
  input.uniqueId();
16411
16423
  row.append(jQuery('<label/>', {
16412
16424
  'for': input.attr('id'),
16413
- 'class': 'col-sm-3 control-label',
16425
+ 'class': 'col-sm-2 control-label',
16414
16426
  }).append(' ' + lang.name));
16415
16427
  row.append(jQuery('<div/>', {
16416
- 'class': 'col-sm-9 input-group',
16428
+ 'class': 'col-sm-10 input-group',
16417
16429
  }).append(input)
16418
16430
  .append(jQuery('<span/>', {
16419
16431
  'class': 'input-group-addon',
@@ -21537,7 +21549,8 @@ function eval_pyson(value){
21537
21549
  'type': 'button',
21538
21550
  'title': Sao.i18n.gettext("More"),
21539
21551
  }).text(Sao.i18n.gettext('More')
21540
- ).click(() => {
21552
+ ).one('click', () => {
21553
+ this.tbody.find('tr.more-row').remove();
21541
21554
  var height = this.table.height();
21542
21555
  this.display_size += Sao.config.display_size;
21543
21556
  this.display();
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "tryton-sao",
3
3
  "title": "sao",
4
4
  "description": "Tryton webclient",
5
- "version": "7.2.20",
5
+ "version": "7.2.22",
6
6
  "homepage": "http://www.tryton.org/",
7
7
  "author": {
8
8
  "name": "Tryton"
package/src/common.js CHANGED
@@ -4360,16 +4360,19 @@
4360
4360
  return null;
4361
4361
  }
4362
4362
  var type = '';
4363
- try {
4364
- var xml = data;
4365
- if (xml instanceof Uint8Array) {
4366
- xml = new TextDecoder().decode(data);
4367
- }
4368
- if (jQuery.parseXML(xml)) {
4363
+ var xml = data;
4364
+ if (xml instanceof Uint8Array) {
4365
+ xml = new TextDecoder().decode(data);
4366
+ }
4367
+ // simple test to avoid logging of parsing error
4368
+ if (/^\s*<[\s\S]+>\s*$/.test(xml.trim())) {
4369
+ let parser = new DOMParser();
4370
+ let doc = parser.parseFromString(xml, 'image/svg+xml');
4371
+ if (!doc.querySelector('parsererror')
4372
+ && (doc.documentElement.tagName.toLowerCase() === 'svg' ||
4373
+ doc.getElementsByTagName('svg').length > 0)) {
4369
4374
  type = 'image/svg+xml';
4370
4375
  }
4371
- } catch (e) {
4372
- // continue
4373
4376
  }
4374
4377
  var blob = new Blob([data], {type: type});
4375
4378
  return window.URL.createObjectURL(blob);
package/src/model.js CHANGED
@@ -1781,7 +1781,6 @@
1781
1781
  // XXX to remove once server domains are fixed
1782
1782
  value = null;
1783
1783
  }
1784
- var setdefault = true;
1785
1784
  var original_domain;
1786
1785
  if (!jQuery.isEmptyObject(record.group.domain)) {
1787
1786
  original_domain = inversion.merge(record.group.domain);
@@ -1789,20 +1788,12 @@
1789
1788
  original_domain = inversion.merge(domain);
1790
1789
  }
1791
1790
  var domain_readonly = original_domain[0] == 'AND';
1791
+ let setdefault;
1792
1792
  if (leftpart.contains('.')) {
1793
- var recordpart = leftpart.split('.', 1)[0];
1794
- var localpart = leftpart.split('.', 1)[1];
1795
- var constraintfields = [];
1796
- if (domain_readonly) {
1797
- for (const leaf of inversion.localize_domain(
1798
- original_domain.slice(1))) {
1799
- constraintfields.push(leaf);
1800
- }
1801
- }
1802
- if ((localpart != 'id') ||
1803
- !~constraintfields.indexOf(recordpart)) {
1804
- setdefault = false;
1805
- }
1793
+ let localpart = leftpart.split('.').slice(1).join('.');
1794
+ setdefault = localpart == 'id';
1795
+ } else {
1796
+ setdefault = true;
1806
1797
  }
1807
1798
  if (setdefault && jQuery.isEmptyObject(pre_validate)) {
1808
1799
  this.set_client(record, value);
@@ -2066,12 +2057,23 @@
2066
2057
  },
2067
2058
  apply_factor: function(record, value, factor) {
2068
2059
  if (value !== null) {
2060
+ // The default precision is the one used by value (before
2061
+ // applying the factor), per the ecmascript specification
2062
+ // it's the shortest representation of said value.
2063
+ // Once the factor is applied the number might become even
2064
+ // more inexact thus we should rely on the initial
2065
+ // precision + the effect factor will have
2066
+ // https://tc39.es/ecma262/multipage/ecmascript-data-types-and-values.html#sec-numeric-types-number-tostring
2067
+ let default_precision = (value.toString().split('.')[1] || '').length;
2068
+ default_precision += Math.ceil(Math.log10(factor));
2069
2069
  value /= factor;
2070
2070
  var digits = this.digits(record);
2071
2071
  if (digits) {
2072
2072
  // Round to avoid float precision error
2073
2073
  // after the division by factor
2074
2074
  value = value.toFixed(digits[1]);
2075
+ } else {
2076
+ value = value.toFixed(default_precision);
2075
2077
  }
2076
2078
  value = this.convert(value);
2077
2079
  }
package/src/sao.js CHANGED
@@ -3,7 +3,7 @@
3
3
 
4
4
  /* eslint-disable no-redeclare */
5
5
  var Sao = {
6
- __version__: '7.2.20',
6
+ __version__: '7.2.22',
7
7
  };
8
8
  /* eslint-enable no-redeclare */
9
9
 
@@ -660,6 +660,7 @@ var Sao = {
660
660
  "Incompatible version of the server."),
661
661
  Sao.i18n.gettext("Version mismatch"));
662
662
  } else {
663
+ let url = window.location.hash.substr(1);
663
664
  Sao.Session.get_credentials()
664
665
  .then(function(session) {
665
666
  Sao.Session.current_session = session;
@@ -669,7 +670,7 @@ var Sao = {
669
670
  .then(function(preferences) {
670
671
  Sao.menu(preferences);
671
672
  Sao.user_menu(preferences);
672
- Sao.open_url();
673
+ Sao.open_url(url);
673
674
  Sao.Bus.listen();
674
675
  });
675
676
  }
package/src/tab.js CHANGED
@@ -836,15 +836,20 @@
836
836
  case 'ok':
837
837
  return this.save();
838
838
  case 'ko':
839
- var record_id = this.screen.current_record.id;
839
+ var record_id = null;
840
+ if (this.screen.current_record) {
841
+ record_id = this.screen.current_record.id;
842
+ }
840
843
  return this.reload(false).then(() => {
841
- if (record_id < 0) {
842
- return jQuery.Deferred().reject(true);
843
- }
844
- else if (this.screen.current_record) {
845
- if (record_id !=
846
- this.screen.current_record.id) {
847
- return jQuery.Deferred().reject();
844
+ if (record_id !== null) {
845
+ if (record_id < 0) {
846
+ return jQuery.Deferred().reject(true);
847
+ }
848
+ else if (this.screen.current_record) {
849
+ if (record_id !=
850
+ this.screen.current_record.id) {
851
+ return jQuery.Deferred().reject();
852
+ }
848
853
  }
849
854
  }
850
855
  });
package/src/view/form.js CHANGED
@@ -1413,7 +1413,8 @@ function eval_pyson(value){
1413
1413
  class_: 'form',
1414
1414
  init: function(languages, widget) {
1415
1415
  var dialog = new Sao.Dialog(
1416
- Sao.i18n.gettext('Translate'), this.class_, 'md');
1416
+ Sao.i18n.gettext('Translate'), this.class_,
1417
+ widget.expand? 'lg' : 'md');
1417
1418
  this.languages = languages;
1418
1419
  this.read(widget, dialog);
1419
1420
  jQuery('<button/>', {
@@ -1504,10 +1505,10 @@ function eval_pyson(value){
1504
1505
  input.uniqueId();
1505
1506
  row.append(jQuery('<label/>', {
1506
1507
  'for': input.attr('id'),
1507
- 'class': 'col-sm-3 control-label',
1508
+ 'class': 'col-sm-2 control-label',
1508
1509
  }).append(' ' + lang.name));
1509
1510
  row.append(jQuery('<div/>', {
1510
- 'class': 'col-sm-9 input-group',
1511
+ 'class': 'col-sm-10 input-group',
1511
1512
  }).append(input)
1512
1513
  .append(jQuery('<span/>', {
1513
1514
  'class': 'input-group-addon',
package/src/view/tree.js CHANGED
@@ -945,7 +945,8 @@
945
945
  'type': 'button',
946
946
  'title': Sao.i18n.gettext("More"),
947
947
  }).text(Sao.i18n.gettext('More')
948
- ).click(() => {
948
+ ).one('click', () => {
949
+ this.tbody.find('tr.more-row').remove();
949
950
  var height = this.table.height();
950
951
  this.display_size += Sao.config.display_size;
951
952
  this.display();