tryton-sao 7.4.17 → 7.4.19

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.4.19 - 2025-10-20
3
+ ---------------------------
4
+ * Bug fixes (see mercurial logs for details)
5
+ * Use sandboxed iframe to display document (issue14290)
6
+
7
+ Version 7.4.18 - 2025-10-02
8
+ ---------------------------
9
+ * Bug fixes (see mercurial logs for details)
10
+
11
+
2
12
  Version 7.4.17 - 2025-09-15
3
13
  ---------------------------
4
14
  * Bug fixes (see mercurial logs for details)
@@ -10271,17 +10271,34 @@ img.icon {
10271
10271
  min-width: 120px;
10272
10272
  }
10273
10273
  .form .form-document object,
10274
- .board .form-document object {
10274
+ .board .form-document object,
10275
+ .form .form-document img,
10276
+ .board .form-document img {
10275
10277
  object-fit: scale-down;
10276
10278
  object-position: center top;
10279
+ }
10280
+ .form .form-document iframe,
10281
+ .board .form-document iframe {
10282
+ border: 0;
10283
+ }
10284
+ .form .form-document object,
10285
+ .board .form-document object,
10286
+ .form .form-document iframe,
10287
+ .board .form-document iframe,
10288
+ .form .form-document img,
10289
+ .board .form-document img {
10277
10290
  width: 100%;
10278
10291
  min-height: 50vh;
10279
10292
  height: 100%;
10280
10293
  }
10281
10294
  @media screen and (max-width: 767px) {
10282
10295
  .form .form-document object,
10283
- .board .form-document object {
10284
- min-height: 25vh;
10296
+ .board .form-document object,
10297
+ .form .form-document iframe,
10298
+ .board .form-document iframe,
10299
+ .form .form-document img,
10300
+ .board .form-document img {
10301
+ min-height: 50vh;
10285
10302
  }
10286
10303
  }
10287
10304
  .form label,
@@ -3,7 +3,7 @@
3
3
 
4
4
  /* eslint-disable no-redeclare */
5
5
  var Sao = {
6
- __version__: '7.4.17',
6
+ __version__: '7.4.19',
7
7
  };
8
8
  /* eslint-enable no-redeclare */
9
9
 
@@ -149,6 +149,16 @@ var Sao = {
149
149
  }
150
150
  }
151
151
 
152
+ if (!Array.prototype.toReversed) {
153
+ Object.defineProperty(Array.prototype, 'toReversed', {
154
+ value: function toReversed() {
155
+ return this.slice().reverse();
156
+ },
157
+ writable: true,
158
+ configurable: true,
159
+ });
160
+ }
161
+
152
162
  Sao.setdefault = function(object, key, value) {
153
163
  if (!Object.prototype.hasOwnProperty.call(object, key)) {
154
164
  object[key] = value;
@@ -19731,15 +19741,42 @@ function eval_pyson(value){
19731
19741
  'class': this.class_,
19732
19742
  });
19733
19743
 
19734
- this.object = jQuery('<object/>', {
19744
+ this.content = this._create_content().appendTo(this.el);
19745
+ },
19746
+ _create_content: function(mimetype, url) {
19747
+ let tag_name = 'iframe';
19748
+ if (mimetype) {
19749
+ if (mimetype.startsWith('image/')) {
19750
+ tag_name = 'img';
19751
+ } else if (mimetype == 'application/pdf') {
19752
+ tag_name = 'object';
19753
+ }
19754
+ }
19755
+ let content = jQuery(`<${tag_name}/>`, {
19735
19756
  'class': 'center-block',
19736
- }).appendTo(this.el);
19737
- if (attributes.height) {
19738
- this.object.css('height', parseInt(attributes.height, 10));
19757
+ });
19758
+ if (tag_name == 'iframe') {
19759
+ content.attr('sandbox', '');
19760
+ }
19761
+ if (this.attributes.height) {
19762
+ content.css('height', parseInt(this.attributes.height, 10));
19739
19763
  }
19740
- if (attributes.width) {
19741
- this.object.css('width', parseInt(attributes.width, 10));
19764
+ if (this.attributes.width) {
19765
+ content.css('width', parseInt(this.attributes.width, 10));
19766
+ }
19767
+ if (url) {
19768
+ // set onload before data/src to be always called
19769
+ content.get().onload = function() {
19770
+ this.onload = null;
19771
+ window.URL.revokeObjectURL(url);
19772
+ };
19773
+ if (tag_name== 'object') {
19774
+ content.attr('data', url);
19775
+ } else {
19776
+ content.attr('src', url);
19777
+ }
19742
19778
  }
19779
+ return content;
19743
19780
  },
19744
19781
  display: function() {
19745
19782
  Sao.View.Form.Document._super.display.call(this);
@@ -19755,34 +19792,30 @@ function eval_pyson(value){
19755
19792
  filename = filename_field.get_client(record);
19756
19793
  }
19757
19794
  data.done(data => {
19758
- var url, blob;
19759
19795
  if (record !== this.record) {
19760
19796
  return;
19761
19797
  }
19762
19798
  // in case onload was not yet triggered
19763
- window.URL.revokeObjectURL(this.object.attr('data'));
19799
+ let url = this.content.attr('data') ||
19800
+ this.content.attr('src');
19801
+ window.URL.revokeObjectURL(url);
19802
+ let mimetype;
19764
19803
  if (!data) {
19765
19804
  url = null;
19766
19805
  } else {
19767
- var mimetype = Sao.common.guess_mimetype(filename);
19806
+ mimetype = Sao.common.guess_mimetype(filename);
19768
19807
  if (mimetype == 'application/octet-binary') {
19769
19808
  mimetype = null;
19770
19809
  }
19771
- blob = new Blob([data], {
19810
+ let blob = new Blob([data], {
19772
19811
  'type': mimetype,
19773
19812
  });
19774
19813
  url = window.URL.createObjectURL(blob);
19775
19814
  }
19776
19815
  // duplicate object to force refresh on buggy browsers
19777
- const object = this.object.clone();
19778
- // set onload before data to be always called
19779
- object.get(0).onload = function() {
19780
- this.onload = null;
19781
- window.URL.revokeObjectURL(url);
19782
- };
19783
- object.attr('data', url);
19784
- this.object.replaceWith(object);
19785
- this.object = object;
19816
+ let content = this._create_content(mimetype, url);
19817
+ this.content.replaceWith(content);
19818
+ this.content = content;
19786
19819
  });
19787
19820
  },
19788
19821
  });
@@ -24220,20 +24253,15 @@ function eval_pyson(value){
24220
24253
  }
24221
24254
  };
24222
24255
  }
24256
+ let keys = this._data_keys(data);
24223
24257
  var color = this.view.attributes.color || Sao.config.graph_color;
24224
24258
  var rgb = Sao.common.hex2rgb(
24225
24259
  Sao.common.COLOR_SCHEMES[color] || color);
24226
24260
  var maxcolor = Math.max.apply(null, rgb);
24227
- var keys = [];
24228
- var i, yfield;
24229
- for (i = 0; i < this.yfields.length; i++) {
24230
- yfield = this.yfields[i];
24231
- keys.push(yfield.key || yfield.name);
24232
- }
24233
24261
  var colors = Sao.common.generateColorscheme(
24234
24262
  color, keys, maxcolor / (keys.length || 1));
24235
- for (i = 0; i < this.yfields.length; i++) {
24236
- yfield = this.yfields[i];
24263
+ for (let i = 0; i < this.yfields.length; i++) {
24264
+ let yfield = this.yfields[i];
24237
24265
  if (yfield.color) {
24238
24266
  colors[yfield.key || yfield.name] = yfield.color;
24239
24267
  }
@@ -24245,6 +24273,14 @@ function eval_pyson(value){
24245
24273
  };
24246
24274
  return c3_config;
24247
24275
  },
24276
+ _data_keys: function(data) {
24277
+ let keys = [];
24278
+ for (let i = 0; i < this.yfields.length; i++) {
24279
+ let yfield = this.yfields[i];
24280
+ keys.push(yfield.key || yfield.name);
24281
+ }
24282
+ return keys;
24283
+ },
24248
24284
  action: function(data, element) {
24249
24285
  var ids = this.ids[this._action_key(data)];
24250
24286
  var ctx = jQuery.extend({}, this.view.screen.group._context);
@@ -24343,8 +24379,16 @@ function eval_pyson(value){
24343
24379
 
24344
24380
  config.data.columns = pie_columns;
24345
24381
  config.data.names = pie_names;
24382
+ config.data.order = null;
24346
24383
  return config;
24347
24384
  },
24385
+ _data_keys: function(data) {
24386
+ let keys = [];
24387
+ for (let i = 0; i < data.columns[1].length - 1; i++) {
24388
+ keys.push(i);
24389
+ };
24390
+ return keys;
24391
+ },
24348
24392
  _add_id: function(key, id) {
24349
24393
  var type = this.xfield.type;
24350
24394
  if ((type == 'date') || (type == 'datetime')) {
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.4.17",
5
+ "version": "7.4.19",
6
6
  "homepage": "https://www.tryton.org/",
7
7
  "author": {
8
8
  "name": "Tryton"
package/src/sao.js CHANGED
@@ -3,7 +3,7 @@
3
3
 
4
4
  /* eslint-disable no-redeclare */
5
5
  var Sao = {
6
- __version__: '7.4.17',
6
+ __version__: '7.4.19',
7
7
  };
8
8
  /* eslint-enable no-redeclare */
9
9
 
@@ -149,6 +149,16 @@ var Sao = {
149
149
  }
150
150
  }
151
151
 
152
+ if (!Array.prototype.toReversed) {
153
+ Object.defineProperty(Array.prototype, 'toReversed', {
154
+ value: function toReversed() {
155
+ return this.slice().reverse();
156
+ },
157
+ writable: true,
158
+ configurable: true,
159
+ });
160
+ }
161
+
152
162
  Sao.setdefault = function(object, key, value) {
153
163
  if (!Object.prototype.hasOwnProperty.call(object, key)) {
154
164
  object[key] = value;
package/src/sao.less CHANGED
@@ -980,14 +980,19 @@ img.icon {
980
980
  }
981
981
  }
982
982
  .form-document {
983
- object {
983
+ object, img {
984
984
  object-fit: scale-down;
985
985
  object-position: center top;
986
+ }
987
+ iframe {
988
+ border: 0;
989
+ }
990
+ object, iframe, img {
986
991
  width: 100%;
987
992
  min-height: 50vh;
988
993
  height: 100%;
989
994
  @media screen and (max-width: @screen-xs-max) {
990
- min-height: 25vh;
995
+ min-height: 50vh;
991
996
  }
992
997
  }
993
998
  }
package/src/view/form.js CHANGED
@@ -4783,15 +4783,42 @@ function eval_pyson(value){
4783
4783
  'class': this.class_,
4784
4784
  });
4785
4785
 
4786
- this.object = jQuery('<object/>', {
4786
+ this.content = this._create_content().appendTo(this.el);
4787
+ },
4788
+ _create_content: function(mimetype, url) {
4789
+ let tag_name = 'iframe';
4790
+ if (mimetype) {
4791
+ if (mimetype.startsWith('image/')) {
4792
+ tag_name = 'img';
4793
+ } else if (mimetype == 'application/pdf') {
4794
+ tag_name = 'object';
4795
+ }
4796
+ }
4797
+ let content = jQuery(`<${tag_name}/>`, {
4787
4798
  'class': 'center-block',
4788
- }).appendTo(this.el);
4789
- if (attributes.height) {
4790
- this.object.css('height', parseInt(attributes.height, 10));
4799
+ });
4800
+ if (tag_name == 'iframe') {
4801
+ content.attr('sandbox', '');
4802
+ }
4803
+ if (this.attributes.height) {
4804
+ content.css('height', parseInt(this.attributes.height, 10));
4791
4805
  }
4792
- if (attributes.width) {
4793
- this.object.css('width', parseInt(attributes.width, 10));
4806
+ if (this.attributes.width) {
4807
+ content.css('width', parseInt(this.attributes.width, 10));
4794
4808
  }
4809
+ if (url) {
4810
+ // set onload before data/src to be always called
4811
+ content.get().onload = function() {
4812
+ this.onload = null;
4813
+ window.URL.revokeObjectURL(url);
4814
+ };
4815
+ if (tag_name== 'object') {
4816
+ content.attr('data', url);
4817
+ } else {
4818
+ content.attr('src', url);
4819
+ }
4820
+ }
4821
+ return content;
4795
4822
  },
4796
4823
  display: function() {
4797
4824
  Sao.View.Form.Document._super.display.call(this);
@@ -4807,34 +4834,30 @@ function eval_pyson(value){
4807
4834
  filename = filename_field.get_client(record);
4808
4835
  }
4809
4836
  data.done(data => {
4810
- var url, blob;
4811
4837
  if (record !== this.record) {
4812
4838
  return;
4813
4839
  }
4814
4840
  // in case onload was not yet triggered
4815
- window.URL.revokeObjectURL(this.object.attr('data'));
4841
+ let url = this.content.attr('data') ||
4842
+ this.content.attr('src');
4843
+ window.URL.revokeObjectURL(url);
4844
+ let mimetype;
4816
4845
  if (!data) {
4817
4846
  url = null;
4818
4847
  } else {
4819
- var mimetype = Sao.common.guess_mimetype(filename);
4848
+ mimetype = Sao.common.guess_mimetype(filename);
4820
4849
  if (mimetype == 'application/octet-binary') {
4821
4850
  mimetype = null;
4822
4851
  }
4823
- blob = new Blob([data], {
4852
+ let blob = new Blob([data], {
4824
4853
  'type': mimetype,
4825
4854
  });
4826
4855
  url = window.URL.createObjectURL(blob);
4827
4856
  }
4828
4857
  // duplicate object to force refresh on buggy browsers
4829
- const object = this.object.clone();
4830
- // set onload before data to be always called
4831
- object.get(0).onload = function() {
4832
- this.onload = null;
4833
- window.URL.revokeObjectURL(url);
4834
- };
4835
- object.attr('data', url);
4836
- this.object.replaceWith(object);
4837
- this.object = object;
4858
+ let content = this._create_content(mimetype, url);
4859
+ this.content.replaceWith(content);
4860
+ this.content = content;
4838
4861
  });
4839
4862
  },
4840
4863
  });
package/src/view/graph.js CHANGED
@@ -211,20 +211,15 @@
211
211
  }
212
212
  };
213
213
  }
214
+ let keys = this._data_keys(data);
214
215
  var color = this.view.attributes.color || Sao.config.graph_color;
215
216
  var rgb = Sao.common.hex2rgb(
216
217
  Sao.common.COLOR_SCHEMES[color] || color);
217
218
  var maxcolor = Math.max.apply(null, rgb);
218
- var keys = [];
219
- var i, yfield;
220
- for (i = 0; i < this.yfields.length; i++) {
221
- yfield = this.yfields[i];
222
- keys.push(yfield.key || yfield.name);
223
- }
224
219
  var colors = Sao.common.generateColorscheme(
225
220
  color, keys, maxcolor / (keys.length || 1));
226
- for (i = 0; i < this.yfields.length; i++) {
227
- yfield = this.yfields[i];
221
+ for (let i = 0; i < this.yfields.length; i++) {
222
+ let yfield = this.yfields[i];
228
223
  if (yfield.color) {
229
224
  colors[yfield.key || yfield.name] = yfield.color;
230
225
  }
@@ -236,6 +231,14 @@
236
231
  };
237
232
  return c3_config;
238
233
  },
234
+ _data_keys: function(data) {
235
+ let keys = [];
236
+ for (let i = 0; i < this.yfields.length; i++) {
237
+ let yfield = this.yfields[i];
238
+ keys.push(yfield.key || yfield.name);
239
+ }
240
+ return keys;
241
+ },
239
242
  action: function(data, element) {
240
243
  var ids = this.ids[this._action_key(data)];
241
244
  var ctx = jQuery.extend({}, this.view.screen.group._context);
@@ -334,8 +337,16 @@
334
337
 
335
338
  config.data.columns = pie_columns;
336
339
  config.data.names = pie_names;
340
+ config.data.order = null;
337
341
  return config;
338
342
  },
343
+ _data_keys: function(data) {
344
+ let keys = [];
345
+ for (let i = 0; i < data.columns[1].length - 1; i++) {
346
+ keys.push(i);
347
+ };
348
+ return keys;
349
+ },
339
350
  _add_id: function(key, id) {
340
351
  var type = this.xfield.type;
341
352
  if ((type == 'date') || (type == 'datetime')) {