tryton-sao 7.6.10 → 7.6.12

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.6.12 - 2025-12-17
3
+ ---------------------------
4
+ * Bug fixes (see mercurial logs for details)
5
+
6
+
7
+ Version 7.6.11 - 2025-11-21
8
+ ---------------------------
9
+ * Bug fixes (see mercurial logs for details)
10
+ * Escape completion content with custom format (issue14363)
11
+
2
12
  Version 7.6.10 - 2025-11-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.6.10',
6
+ __version__: '7.6.12',
7
7
  };
8
8
  /* eslint-enable no-redeclare */
9
9
 
@@ -4625,11 +4625,12 @@ var Sao = {
4625
4625
  var name = clause[0];
4626
4626
  var operator = clause[1];
4627
4627
  var value = clause[2];
4628
- if (name.endsWith('.rec_name')) {
4628
+ if (name.endsWith('.rec_name')
4629
+ && (value || (clause.length > 3))) {
4629
4630
  name = name.slice(0, -9);
4630
4631
  }
4631
4632
  if (!(name in this.fields)) {
4632
- if (this.is_full_text(value)) {
4633
+ if ((value !== null) && this.is_full_text(value)) {
4633
4634
  value = value.slice(1, -1);
4634
4635
  }
4635
4636
  return this.quote(value);
@@ -5551,7 +5552,7 @@ var Sao = {
5551
5552
  break;
5552
5553
  }
5553
5554
  }
5554
- return target + ',' + value;
5555
+ return target + ',' + (value || '');
5555
5556
  };
5556
5557
 
5557
5558
  var converts = {
@@ -6975,7 +6976,10 @@ var Sao = {
6975
6976
  }).appendTo(dialog.body);
6976
6977
  alert_.append(jQuery('<h4/>')
6977
6978
  .text(title)
6978
- .css('white-space', 'pre-wrap'));
6979
+ .css({
6980
+ 'white-space': 'pre-wrap',
6981
+ 'word-break': 'break-all',
6982
+ }));
6979
6983
  alert_.append(jQuery('<p/>').append(jQuery('<a/>', {
6980
6984
  'class': 'btn btn-default',
6981
6985
  role: 'button',
@@ -7181,9 +7185,13 @@ var Sao = {
7181
7185
  },
7182
7186
  _format: function(content) {
7183
7187
  if (this.format) {
7184
- return this.format(content);
7188
+ content = this.format(content);
7189
+ }
7190
+ if (content instanceof jQuery) {
7191
+ return content;
7192
+ } else {
7193
+ return jQuery('<span/>').text(content);
7185
7194
  }
7186
- return jQuery('<span/>').text(content);
7187
7195
  },
7188
7196
  _format_action: function(content) {
7189
7197
  if (this.format_action) {
@@ -8098,7 +8106,7 @@ var Sao = {
8098
8106
  array.save = function() {
8099
8107
  var deferreds = [];
8100
8108
  this.forEach(record => {
8101
- deferreds.push(record.save());
8109
+ deferreds.push(record.save(false));
8102
8110
  });
8103
8111
  if (!jQuery.isEmptyObject(this.record_deleted)) {
8104
8112
  for (const record of this.record_deleted) {
@@ -8381,7 +8389,7 @@ var Sao = {
8381
8389
  return false;
8382
8390
  }
8383
8391
  },
8384
- save: function(force_reload=false) {
8392
+ save: function(force_reload=true) {
8385
8393
  var context = this.get_context();
8386
8394
  if (this._save_prm.state() == 'pending') {
8387
8395
  return this._save_prm.then(() => this.save(force_reload));
@@ -8804,7 +8812,7 @@ var Sao = {
8804
8812
  this.on_change(fieldnames);
8805
8813
  this.on_change_with(fieldnames);
8806
8814
  if (validate) {
8807
- return this.validate(null, true);
8815
+ this.validate(null, true);
8808
8816
  }
8809
8817
  if (modified) {
8810
8818
  this.set_modified();
@@ -11220,7 +11228,7 @@ var Sao = {
11220
11228
  if (other.compare(attributes)) {
11221
11229
  Sao.common.scrollIntoViewIfNeeded(
11222
11230
  tablist.find('a[href="#' + other.id + '"]').tab('show'));
11223
- return;
11231
+ return jQuery.when();
11224
11232
  }
11225
11233
  }
11226
11234
  var tab;
@@ -17312,7 +17320,7 @@ function eval_pyson(value){
17312
17320
  },
17313
17321
  get width() {
17314
17322
  var digits = this.digits;
17315
- if (digits) {
17323
+ if (digits && digits.every(d => d !== null)) {
17316
17324
  return digits.reduce(function(acc, cur) {
17317
17325
  return acc + cur;
17318
17326
  });
@@ -17960,15 +17968,21 @@ function eval_pyson(value){
17960
17968
  } else {
17961
17969
  this._popup = true;
17962
17970
  }
17971
+ let view_ids = (this.attributes.view_ids || '').split(',');
17963
17972
  if (this.has_target(value)) {
17964
17973
  var m2o_id =
17965
17974
  this.id_from_value(record.field_get(this.field_name));
17966
17975
  if (evt && (evt.ctrlKey || evt.metaKey)) {
17976
+ if (!jQuery.isEmptyObject(view_ids)) {
17977
+ // Remove the first tree view as mode is form only
17978
+ view_ids.shift();
17979
+ }
17967
17980
  var params = {};
17968
17981
  params.model = this.get_model();
17969
17982
  params.res_id = m2o_id;
17970
17983
  params.mode = ['form'];
17971
17984
  params.name = this.attributes.string;
17985
+ params.view_ids = view_ids;
17972
17986
  params.context = this.field.get_context(this.record);
17973
17987
  Sao.Tab.create(params);
17974
17988
  this._popup = false;
@@ -18017,8 +18031,7 @@ function eval_pyson(value){
18017
18031
  context: context,
18018
18032
  domain: domain,
18019
18033
  order: order,
18020
- view_ids: (this.attributes.view_ids ||
18021
- '').split(','),
18034
+ view_ids: view_ids,
18022
18035
  views_preload: (this.attributes.views || {}),
18023
18036
  new_: this.create_access,
18024
18037
  search_filter: parser.quote(text),
@@ -23228,9 +23241,11 @@ function eval_pyson(value){
23228
23241
  return;
23229
23242
  }
23230
23243
 
23231
- body = listener = jQuery(document.body);
23244
+ body = jQuery(document.body);
23232
23245
  if (body.hasClass('modal-open')) {
23233
23246
  listener = this.tree.el.parents('.modal').last();
23247
+ } else {
23248
+ listener = this.tree.el.parents('.tab-pane').last();
23234
23249
  }
23235
23250
  const handler = event_ => {
23236
23251
  if ((event_.currentTarget == body[0]) &&
@@ -23243,7 +23258,7 @@ function eval_pyson(value){
23243
23258
  event_.stopPropagation();
23244
23259
  return;
23245
23260
  }
23246
- body.off('click.sao.editabletree');
23261
+ listener.off('click.sao.editabletree');
23247
23262
  this.tree.edit_row(null);
23248
23263
  return true;
23249
23264
  };
@@ -23372,7 +23387,10 @@ function eval_pyson(value){
23372
23387
  }
23373
23388
  }
23374
23389
  this._get_column_td(next_column)
23375
- .find(':input,[tabindex=0]').focus();
23390
+ .find(':input,[tabindex=0]')
23391
+ .filter(':visible')
23392
+ .first()
23393
+ .focus();
23376
23394
  } else {
23377
23395
  var prm = jQuery.when();
23378
23396
  if (!this.tree.screen.group.parent) {
@@ -23421,7 +23439,10 @@ function eval_pyson(value){
23421
23439
  this._get_column_td(
23422
23440
  next_column, next_row)
23423
23441
  .trigger('click')
23442
+ .trigger('click')
23424
23443
  .find(':input,[tabindex=0]')
23444
+ .filter(':visible')
23445
+ .first()
23425
23446
  .focus();
23426
23447
  });
23427
23448
  }
@@ -23775,12 +23796,18 @@ function eval_pyson(value){
23775
23796
  cell = cell.children('a');
23776
23797
  cell.unbind('click');
23777
23798
  Sao.View.Tree.Many2OneColumn._super.update_text.call(this, cell, record);
23799
+ let view_ids = (this.attributes.view_ids || '').split(',');
23800
+ if (!jQuery.isEmptyObject(view_ids)) {
23801
+ // Remove the first tree view as mode is form only
23802
+ view_ids.shift();
23803
+ }
23778
23804
  cell.click(event => {
23779
23805
  event.stopPropagation();
23780
23806
  var params = {};
23781
23807
  params.model = this.attributes.relation;
23782
23808
  params.res_id = this.field.get(record);
23783
23809
  params.mode = ['form'];
23810
+ params.view_ids = view_ids;
23784
23811
  params.name = this.attributes.string;
23785
23812
  params.context = this.field.get_context(record);
23786
23813
  Sao.Tab.create(params);
@@ -24703,7 +24730,7 @@ function eval_pyson(value){
24703
24730
  },
24704
24731
  action: function(data, element) {
24705
24732
  var ids = this.ids[this._action_key(data)];
24706
- var ctx = jQuery.extend({}, this.view.screen.group._context);
24733
+ var ctx = jQuery.extend({}, this.view.screen.group.local_context);
24707
24734
  delete ctx.active_ids;
24708
24735
  delete ctx.active_id;
24709
24736
  Sao.Action.exec_keyword('graph_open', {
@@ -24824,7 +24851,8 @@ function eval_pyson(value){
24824
24851
  Sao.View.Graph.Pie._super._add_id.call(this, key, id);
24825
24852
  },
24826
24853
  _action_key: function(data) {
24827
- return data.id;
24854
+ // data.name is the label used for the x axis
24855
+ return data.name;
24828
24856
  }
24829
24857
  });
24830
24858
 
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.6.10",
5
+ "version": "7.6.12",
6
6
  "homepage": "https://www.tryton.org/",
7
7
  "author": {
8
8
  "name": "Tryton"
package/src/common.js CHANGED
@@ -1276,11 +1276,12 @@
1276
1276
  var name = clause[0];
1277
1277
  var operator = clause[1];
1278
1278
  var value = clause[2];
1279
- if (name.endsWith('.rec_name')) {
1279
+ if (name.endsWith('.rec_name')
1280
+ && (value || (clause.length > 3))) {
1280
1281
  name = name.slice(0, -9);
1281
1282
  }
1282
1283
  if (!(name in this.fields)) {
1283
- if (this.is_full_text(value)) {
1284
+ if ((value !== null) && this.is_full_text(value)) {
1284
1285
  value = value.slice(1, -1);
1285
1286
  }
1286
1287
  return this.quote(value);
@@ -2202,7 +2203,7 @@
2202
2203
  break;
2203
2204
  }
2204
2205
  }
2205
- return target + ',' + value;
2206
+ return target + ',' + (value || '');
2206
2207
  };
2207
2208
 
2208
2209
  var converts = {
@@ -3626,7 +3627,10 @@
3626
3627
  }).appendTo(dialog.body);
3627
3628
  alert_.append(jQuery('<h4/>')
3628
3629
  .text(title)
3629
- .css('white-space', 'pre-wrap'));
3630
+ .css({
3631
+ 'white-space': 'pre-wrap',
3632
+ 'word-break': 'break-all',
3633
+ }));
3630
3634
  alert_.append(jQuery('<p/>').append(jQuery('<a/>', {
3631
3635
  'class': 'btn btn-default',
3632
3636
  role: 'button',
@@ -3832,9 +3836,13 @@
3832
3836
  },
3833
3837
  _format: function(content) {
3834
3838
  if (this.format) {
3835
- return this.format(content);
3839
+ content = this.format(content);
3840
+ }
3841
+ if (content instanceof jQuery) {
3842
+ return content;
3843
+ } else {
3844
+ return jQuery('<span/>').text(content);
3836
3845
  }
3837
- return jQuery('<span/>').text(content);
3838
3846
  },
3839
3847
  _format_action: function(content) {
3840
3848
  if (this.format_action) {
package/src/model.js CHANGED
@@ -315,7 +315,7 @@
315
315
  array.save = function() {
316
316
  var deferreds = [];
317
317
  this.forEach(record => {
318
- deferreds.push(record.save());
318
+ deferreds.push(record.save(false));
319
319
  });
320
320
  if (!jQuery.isEmptyObject(this.record_deleted)) {
321
321
  for (const record of this.record_deleted) {
@@ -598,7 +598,7 @@
598
598
  return false;
599
599
  }
600
600
  },
601
- save: function(force_reload=false) {
601
+ save: function(force_reload=true) {
602
602
  var context = this.get_context();
603
603
  if (this._save_prm.state() == 'pending') {
604
604
  return this._save_prm.then(() => this.save(force_reload));
@@ -1021,7 +1021,7 @@
1021
1021
  this.on_change(fieldnames);
1022
1022
  this.on_change_with(fieldnames);
1023
1023
  if (validate) {
1024
- return this.validate(null, true);
1024
+ this.validate(null, true);
1025
1025
  }
1026
1026
  if (modified) {
1027
1027
  this.set_modified();
package/src/sao.js CHANGED
@@ -3,7 +3,7 @@
3
3
 
4
4
  /* eslint-disable no-redeclare */
5
5
  var Sao = {
6
- __version__: '7.6.10',
6
+ __version__: '7.6.12',
7
7
  };
8
8
  /* eslint-enable no-redeclare */
9
9
 
package/src/tab.js CHANGED
@@ -424,7 +424,7 @@
424
424
  if (other.compare(attributes)) {
425
425
  Sao.common.scrollIntoViewIfNeeded(
426
426
  tablist.find('a[href="#' + other.id + '"]').tab('show'));
427
- return;
427
+ return jQuery.when();
428
428
  }
429
429
  }
430
430
  var tab;
package/src/view/form.js CHANGED
@@ -2204,7 +2204,7 @@ function eval_pyson(value){
2204
2204
  },
2205
2205
  get width() {
2206
2206
  var digits = this.digits;
2207
- if (digits) {
2207
+ if (digits && digits.every(d => d !== null)) {
2208
2208
  return digits.reduce(function(acc, cur) {
2209
2209
  return acc + cur;
2210
2210
  });
@@ -2852,15 +2852,21 @@ function eval_pyson(value){
2852
2852
  } else {
2853
2853
  this._popup = true;
2854
2854
  }
2855
+ let view_ids = (this.attributes.view_ids || '').split(',');
2855
2856
  if (this.has_target(value)) {
2856
2857
  var m2o_id =
2857
2858
  this.id_from_value(record.field_get(this.field_name));
2858
2859
  if (evt && (evt.ctrlKey || evt.metaKey)) {
2860
+ if (!jQuery.isEmptyObject(view_ids)) {
2861
+ // Remove the first tree view as mode is form only
2862
+ view_ids.shift();
2863
+ }
2859
2864
  var params = {};
2860
2865
  params.model = this.get_model();
2861
2866
  params.res_id = m2o_id;
2862
2867
  params.mode = ['form'];
2863
2868
  params.name = this.attributes.string;
2869
+ params.view_ids = view_ids;
2864
2870
  params.context = this.field.get_context(this.record);
2865
2871
  Sao.Tab.create(params);
2866
2872
  this._popup = false;
@@ -2909,8 +2915,7 @@ function eval_pyson(value){
2909
2915
  context: context,
2910
2916
  domain: domain,
2911
2917
  order: order,
2912
- view_ids: (this.attributes.view_ids ||
2913
- '').split(','),
2918
+ view_ids: view_ids,
2914
2919
  views_preload: (this.attributes.views || {}),
2915
2920
  new_: this.create_access,
2916
2921
  search_filter: parser.quote(text),
package/src/view/graph.js CHANGED
@@ -241,7 +241,7 @@
241
241
  },
242
242
  action: function(data, element) {
243
243
  var ids = this.ids[this._action_key(data)];
244
- var ctx = jQuery.extend({}, this.view.screen.group._context);
244
+ var ctx = jQuery.extend({}, this.view.screen.group.local_context);
245
245
  delete ctx.active_ids;
246
246
  delete ctx.active_id;
247
247
  Sao.Action.exec_keyword('graph_open', {
@@ -362,7 +362,8 @@
362
362
  Sao.View.Graph.Pie._super._add_id.call(this, key, id);
363
363
  },
364
364
  _action_key: function(data) {
365
- return data.id;
365
+ // data.name is the label used for the x axis
366
+ return data.name;
366
367
  }
367
368
  });
368
369
 
package/src/view/tree.js CHANGED
@@ -2203,9 +2203,11 @@
2203
2203
  return;
2204
2204
  }
2205
2205
 
2206
- body = listener = jQuery(document.body);
2206
+ body = jQuery(document.body);
2207
2207
  if (body.hasClass('modal-open')) {
2208
2208
  listener = this.tree.el.parents('.modal').last();
2209
+ } else {
2210
+ listener = this.tree.el.parents('.tab-pane').last();
2209
2211
  }
2210
2212
  const handler = event_ => {
2211
2213
  if ((event_.currentTarget == body[0]) &&
@@ -2218,7 +2220,7 @@
2218
2220
  event_.stopPropagation();
2219
2221
  return;
2220
2222
  }
2221
- body.off('click.sao.editabletree');
2223
+ listener.off('click.sao.editabletree');
2222
2224
  this.tree.edit_row(null);
2223
2225
  return true;
2224
2226
  };
@@ -2347,7 +2349,10 @@
2347
2349
  }
2348
2350
  }
2349
2351
  this._get_column_td(next_column)
2350
- .find(':input,[tabindex=0]').focus();
2352
+ .find(':input,[tabindex=0]')
2353
+ .filter(':visible')
2354
+ .first()
2355
+ .focus();
2351
2356
  } else {
2352
2357
  var prm = jQuery.when();
2353
2358
  if (!this.tree.screen.group.parent) {
@@ -2396,7 +2401,10 @@
2396
2401
  this._get_column_td(
2397
2402
  next_column, next_row)
2398
2403
  .trigger('click')
2404
+ .trigger('click')
2399
2405
  .find(':input,[tabindex=0]')
2406
+ .filter(':visible')
2407
+ .first()
2400
2408
  .focus();
2401
2409
  });
2402
2410
  }
@@ -2750,12 +2758,18 @@
2750
2758
  cell = cell.children('a');
2751
2759
  cell.unbind('click');
2752
2760
  Sao.View.Tree.Many2OneColumn._super.update_text.call(this, cell, record);
2761
+ let view_ids = (this.attributes.view_ids || '').split(',');
2762
+ if (!jQuery.isEmptyObject(view_ids)) {
2763
+ // Remove the first tree view as mode is form only
2764
+ view_ids.shift();
2765
+ }
2753
2766
  cell.click(event => {
2754
2767
  event.stopPropagation();
2755
2768
  var params = {};
2756
2769
  params.model = this.attributes.relation;
2757
2770
  params.res_id = this.field.get(record);
2758
2771
  params.mode = ['form'];
2772
+ params.view_ids = view_ids;
2759
2773
  params.name = this.attributes.string;
2760
2774
  params.context = this.field.get_context(record);
2761
2775
  Sao.Tab.create(params);
package/tests/sao.js CHANGED
@@ -2040,6 +2040,9 @@
2040
2040
  [[c(['Reference', null, 'Spam,bar'])], [
2041
2041
  c(['reference.rec_name', 'ilike', '%bar%', 'spam'])
2042
2042
  ]],
2043
+ [[c(['Reference', null, 'Spam,'])], [
2044
+ c(['reference.rec_name', 'ilike', '%', 'spam'])
2045
+ ]],
2043
2046
  [[c(['Reference', null, ['foo', 'bar']])], [
2044
2047
  c(['reference', 'in', ['foo', 'bar']])
2045
2048
  ]],
@@ -2368,6 +2371,7 @@
2368
2371
  [[['multiselection', 'not in', ['foo', 'bar']]], "MultiSelection: !Foo;Bar"],
2369
2372
  [[['reference', 'ilike', '%foo%']], 'Reference: foo'],
2370
2373
  [[['reference', 'ilike', '%bar%', 'spam']], 'Reference: Spam,bar'],
2374
+ [[['reference.rec_name', '=', null, 'spam']], 'Reference: =Spam,'],
2371
2375
  [[['reference', 'in', ['foo', 'bar']]], 'Reference: foo;bar'],
2372
2376
  [[['many2one', 'ilike', '%John%']], 'Many2One: John'],
2373
2377
  [[['many2one.rec_name', 'in', ['John', 'Jane']]], 'Many2One: John;Jane'],