tryton-sao 7.6.19 → 7.6.20

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,9 @@
1
1
 
2
+ Version 7.6.20 - 2026-05-02
3
+ ---------------------------
4
+ * Bug fixes (see mercurial logs for details)
5
+
6
+
2
7
  Version 7.6.19 - 2026-04-16
3
8
  ---------------------------
4
9
  * Bug fixes (see mercurial logs for details)
@@ -9687,12 +9687,10 @@ html.accesskey *[accesskey]:after {
9687
9687
  padding: 0 2px;
9688
9688
  position: absolute;
9689
9689
  text-transform: uppercase;
9690
- margin: 0 -1em;
9690
+ left: -1em;
9691
+ right: 0;
9691
9692
  z-index: 5;
9692
9693
  }
9693
- html.accesskey input[accesskey][type="checkbox"]:after {
9694
- background-color: initial;
9695
- }
9696
9694
  html.accesskey *[accesskey] ~ span[data-accesskey] {
9697
9695
  float: right;
9698
9696
  position: relative;
@@ -9703,10 +9701,13 @@ html.accesskey *[accesskey] ~ span[data-accesskey]:after {
9703
9701
  html.accesskey *[accesskey]:after {
9704
9702
  content: attr(accesskey);
9705
9703
  }
9706
- html.accesskey input[accesskey][type="checkbox"] ~ span[data-accesskey],
9707
- html.accesskey input[accesskey][type="checkbox"] ~ span[data-accesskey],
9708
- html.accesskey select[accesskey] ~ span[data-accesskey] {
9709
- bottom: 1em;
9704
+ html.accesskey[dir="rtl"] *[accesskey] ~ span[data-accesskey]:after,
9705
+ html.accesskey[dir="rtl"] *[accesskey]:after {
9706
+ left: 0;
9707
+ right: -1em;
9708
+ }
9709
+ html.accesskey[dir="rtl"] *[accesskey] ~ span[data-accesskey] {
9710
+ float: left;
9710
9711
  }
9711
9712
  .tab-form,
9712
9713
  .tab-board {
@@ -3,7 +3,7 @@
3
3
 
4
4
  /* eslint-disable no-redeclare */
5
5
  var Sao = {
6
- __version__: '7.6.19',
6
+ __version__: '7.6.20',
7
7
  };
8
8
  /* eslint-enable no-redeclare */
9
9
 
@@ -8829,7 +8829,7 @@ var Sao = {
8829
8829
  this.group.parent.id;
8830
8830
  }
8831
8831
  }
8832
- return this.set_default(values);
8832
+ return this.set_default(values).then(() => values);
8833
8833
  });
8834
8834
  }
8835
8835
  return jQuery.when();
@@ -10866,6 +10866,7 @@ var Sao = {
10866
10866
  'class': 'hidden-lg',
10867
10867
  }).appendTo(this.name_el);
10868
10868
  this.view_prm = jQuery.when();
10869
+ this._action_running = false;
10869
10870
  },
10870
10871
  menu_def: function() {
10871
10872
  return [
@@ -11015,8 +11016,13 @@ var Sao = {
11015
11016
  this.menu_buttons[item.id] = menuitem;
11016
11017
  link.click(evt => {
11017
11018
  evt.preventDefault();
11018
- if (!menuitem.hasClass('disabled')) {
11019
- this[item.id]();
11019
+ if (!menuitem.hasClass('disabled')
11020
+ && !this._action_running) {
11021
+ this._action_running = true;
11022
+ (this[item.id]() || jQuery.when())
11023
+ .always(() => {
11024
+ this._action_running = false;
11025
+ });
11020
11026
  }
11021
11027
  });
11022
11028
  } else if (!item && previous) {
@@ -11120,17 +11126,14 @@ var Sao = {
11120
11126
  }
11121
11127
  this.buttons[item.id].click(item, event => {
11122
11128
  var item = event.data;
11123
- var button = this.buttons[item.id];
11124
- // Use data instead of disabled prop because the action may
11125
- // actually disable the button.
11126
- if (button.data('disabled')) {
11129
+ if (this._action_running) {
11127
11130
  event.preventDefault();
11128
11131
  return;
11129
11132
  }
11130
- button.data('disabled', true);
11133
+ this._action_running = true;
11131
11134
  (this[item.id](this) || jQuery.when())
11132
- .always(function() {
11133
- button.data('disabled', false);
11135
+ .always(() => {
11136
+ this._action_running = false;
11134
11137
  });
11135
11138
  });
11136
11139
  };
@@ -11757,7 +11760,7 @@ var Sao = {
11757
11760
  } else {
11758
11761
  prm = jQuery.when();
11759
11762
  }
11760
- prm.then(() => {
11763
+ return prm.then(() => {
11761
11764
  var access = Sao.common.MODELACCESS.get(this.screen.model_name);
11762
11765
  if (this.screen.readonly || !(access.write || access.create)) {
11763
11766
  return jQuery.Deferred().reject();
@@ -11859,18 +11862,18 @@ var Sao = {
11859
11862
  },
11860
11863
  previous: function() {
11861
11864
  return this.modified_save().then(() => {
11862
- var prm = this.screen.display_previous();
11863
- this.info_bar.clear();
11864
- this.set_buttons_sensitive();
11865
- return prm;
11865
+ return this.screen.display_previous().then(() => {
11866
+ this.info_bar.clear();
11867
+ this.set_buttons_sensitive();
11868
+ });
11866
11869
  });
11867
11870
  },
11868
11871
  next: function() {
11869
11872
  return this.modified_save().then(() => {
11870
- var prm = this.screen.display_next();
11871
- this.info_bar.clear();
11872
- this.set_buttons_sensitive();
11873
- return prm;
11873
+ return this.screen.display_next().then(() => {
11874
+ this.info_bar.clear();
11875
+ this.set_buttons_sensitive();
11876
+ });
11874
11877
  });
11875
11878
  },
11876
11879
  search: function() {
@@ -15567,7 +15570,8 @@ function eval_pyson(value){
15567
15570
  }
15568
15571
  }
15569
15572
  return jQuery.when.apply(jQuery,promesses)
15570
- .done(() => {
15573
+ .then(() => {
15574
+ let promesses = [];
15571
15575
  var record = this.record;
15572
15576
  for (const name in this.widgets) {
15573
15577
  var widgets = this.widgets[name];
@@ -15579,10 +15583,12 @@ function eval_pyson(value){
15579
15583
  field.set_state(record);
15580
15584
  }
15581
15585
  for (const widget of widgets) {
15582
- widget.display();
15586
+ let prm = widget.display();
15587
+ if (prm) {
15588
+ promesses.push(prm);
15589
+ }
15583
15590
  }
15584
15591
  }
15585
- var promesses = [];
15586
15592
  // We iterate in the reverse order so that the most nested
15587
15593
  // widgets are computed first and set_state methods can rely
15588
15594
  // on their children having their state set
@@ -15597,7 +15603,7 @@ function eval_pyson(value){
15597
15603
  }
15598
15604
  // re-set the grid templates for the StateWidget that are
15599
15605
  // asynchronous
15600
- jQuery.when.apply(jQuery, promesses).done(() => {
15606
+ return jQuery.when.apply(jQuery, promesses).then(() => {
15601
15607
  for (const container of this.containers) {
15602
15608
  container.set_grid_template();
15603
15609
  }
@@ -17432,11 +17438,13 @@ function eval_pyson(value){
17432
17438
  this.el = jQuery('<div/>', {
17433
17439
  'class': this.class_
17434
17440
  });
17441
+ this.group = jQuery('<div/>', {
17442
+ 'class': 'input-group input-group-sm'
17443
+ }).css('width', '100%').appendTo(this.el);
17435
17444
  this.select = this.labelled = jQuery('<select/>', {
17436
17445
  'class': 'form-control input-sm mousetrap',
17437
17446
  'name': attributes.name,
17438
- });
17439
- this.el.append(this.select);
17447
+ }).appendTo(this.group);
17440
17448
  this.select.change(this.focus_out.bind(this));
17441
17449
  Sao.common.selection_mixin.init.call(this);
17442
17450
  this.init_selection();
@@ -17537,11 +17545,14 @@ function eval_pyson(value){
17537
17545
  this.el = jQuery('<div/>', {
17538
17546
  'class': this.class_
17539
17547
  });
17548
+ this.group = jQuery('<div/>', {
17549
+ 'class': 'input-group input-group-sm'
17550
+ }).css('width', '100%').appendTo(this.el);
17540
17551
  this.input = this.labelled = jQuery('<input/>', {
17541
17552
  'type': 'checkbox',
17542
17553
  'class': 'form-control input-sm mousetrap',
17543
17554
  'name': attributes.name,
17544
- }).appendTo(this.el);
17555
+ }).appendTo(this.group);
17545
17556
  this.input.change(this.focus_out.bind(this));
17546
17557
  this.input.click(function() {
17547
17558
  // Dont trigger click if field is readonly as readonly has no
@@ -18804,7 +18815,7 @@ function eval_pyson(value){
18804
18815
  display: function() {
18805
18816
  Sao.View.Form.One2Many._super.display.call(this);
18806
18817
 
18807
- this.prm.done(() => {
18818
+ return this.prm.then(() => {
18808
18819
  this._set_button_sensitive();
18809
18820
 
18810
18821
  var record = this.record;
@@ -18814,9 +18825,8 @@ function eval_pyson(value){
18814
18825
  this.screen.new_group();
18815
18826
  this.screen.current_record = null;
18816
18827
  this.screen.group.parent = null;
18817
- this.screen.display();
18818
18828
  this.screen.screen_container.hide_filter();
18819
- return;
18829
+ return this.screen.display();
18820
18830
  }
18821
18831
 
18822
18832
  var new_group = record.field_get_client(this.field_name);
@@ -18845,13 +18855,13 @@ function eval_pyson(value){
18845
18855
  this.screen.domain = domain;
18846
18856
  }
18847
18857
  this.screen.size_limit = size_limit;
18848
- this.screen.display();
18849
18858
  if (this.attributes.height !== undefined) {
18850
18859
  this.content
18851
18860
  .find('.treeview,.list-form').first()
18852
18861
  .css('min-height', this.attributes.height + 'px')
18853
18862
  .css('max-height', this.attributes.height + 'px');
18854
18863
  }
18864
+ return this.screen.display();
18855
18865
  });
18856
18866
  },
18857
18867
  focus: function() {
@@ -19151,9 +19161,7 @@ function eval_pyson(value){
19151
19161
  return prm;
19152
19162
  },
19153
19163
  set_value: function() {
19154
- if (this.screen.modified()) { // TODO check if required
19155
- this.view.screen.record_modified(false);
19156
- }
19164
+ this.screen.current_view.set_value();
19157
19165
  },
19158
19166
  _update_completion: function(text) {
19159
19167
  if (!this.record) {
@@ -19387,7 +19395,7 @@ function eval_pyson(value){
19387
19395
  display: function() {
19388
19396
  Sao.View.Form.Many2Many._super.display.call(this);
19389
19397
 
19390
- this.prm.done(() => {
19398
+ return this.prm.then(() => {
19391
19399
  var record = this.record;
19392
19400
  var field = this.field;
19393
19401
 
@@ -19395,21 +19403,20 @@ function eval_pyson(value){
19395
19403
  this.screen.new_group();
19396
19404
  this.screen.current_record = null;
19397
19405
  this.screen.group.parent = null;
19398
- this.screen.display();
19399
19406
  this.screen.screen_container.hide_filter();
19400
- return;
19407
+ return this.screen.display();
19401
19408
  }
19402
19409
  var new_group = record.field_get_client(this.field_name);
19403
19410
  if (new_group != this.screen.group) {
19404
19411
  this.screen.set_group(new_group);
19405
19412
  }
19406
- this.screen.display();
19407
19413
  if (this.attributes.height !== undefined) {
19408
19414
  this.content
19409
19415
  .find('.treeview,.list-form').first()
19410
19416
  .css('min-height', this.attributes.height + 'px')
19411
19417
  .css('max-height', this.attributes.height + 'px');
19412
19418
  }
19419
+ return this.screen.display();
19413
19420
  });
19414
19421
  },
19415
19422
  focus: function() {
@@ -23847,6 +23854,10 @@ function eval_pyson(value){
23847
23854
  fields, false, false)) {
23848
23855
  var value = cell.prop('checked');
23849
23856
  this.field.set_client(record, value);
23857
+ if (record !== current_record) {
23858
+ // we can not rely on editable tree handler to save the row
23859
+ record.save();
23860
+ }
23850
23861
  } else {
23851
23862
  evt.preventDefault();
23852
23863
  }
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.19",
5
+ "version": "7.6.20",
6
6
  "homepage": "https://www.tryton.org/",
7
7
  "author": {
8
8
  "name": "Tryton"
package/src/model.js CHANGED
@@ -989,7 +989,7 @@
989
989
  this.group.parent.id;
990
990
  }
991
991
  }
992
- return this.set_default(values);
992
+ return this.set_default(values).then(() => values);
993
993
  });
994
994
  }
995
995
  return jQuery.when();
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.19',
6
+ __version__: '7.6.20',
7
7
  };
8
8
  /* eslint-enable no-redeclare */
9
9
 
package/src/sao.less CHANGED
@@ -515,14 +515,11 @@ html.accesskey {
515
515
  padding: 0 2px;
516
516
  position: absolute;
517
517
  text-transform: uppercase;
518
- margin: 0 -1em;
518
+ left: -1em;
519
+ right: 0;
519
520
  z-index: 5;
520
521
  }
521
522
 
522
- input[accesskey][type="checkbox"]:after {
523
- background-color: initial;
524
- }
525
-
526
523
  *[accesskey] ~ span[data-accesskey] {
527
524
  float: right;
528
525
  position: relative;
@@ -536,11 +533,15 @@ html.accesskey {
536
533
  content: attr(accesskey);
537
534
  }
538
535
 
539
- input[accesskey][type="checkbox"],
540
- input[accesskey][type="checkbox"],
541
- select[accesskey] {
542
- & ~ span[data-accesskey] {
543
- bottom: 1em;
536
+ &[dir="rtl"] {
537
+ *[accesskey] ~ span[data-accesskey]:after,
538
+ *[accesskey]:after {
539
+ left: 0;
540
+ right: -1em;
541
+ }
542
+
543
+ *[accesskey] ~ span[data-accesskey] {
544
+ float: left;
544
545
  }
545
546
  }
546
547
  }
package/src/tab.js CHANGED
@@ -18,6 +18,7 @@
18
18
  'class': 'hidden-lg',
19
19
  }).appendTo(this.name_el);
20
20
  this.view_prm = jQuery.when();
21
+ this._action_running = false;
21
22
  },
22
23
  menu_def: function() {
23
24
  return [
@@ -167,8 +168,13 @@
167
168
  this.menu_buttons[item.id] = menuitem;
168
169
  link.click(evt => {
169
170
  evt.preventDefault();
170
- if (!menuitem.hasClass('disabled')) {
171
- this[item.id]();
171
+ if (!menuitem.hasClass('disabled')
172
+ && !this._action_running) {
173
+ this._action_running = true;
174
+ (this[item.id]() || jQuery.when())
175
+ .always(() => {
176
+ this._action_running = false;
177
+ });
172
178
  }
173
179
  });
174
180
  } else if (!item && previous) {
@@ -272,17 +278,14 @@
272
278
  }
273
279
  this.buttons[item.id].click(item, event => {
274
280
  var item = event.data;
275
- var button = this.buttons[item.id];
276
- // Use data instead of disabled prop because the action may
277
- // actually disable the button.
278
- if (button.data('disabled')) {
281
+ if (this._action_running) {
279
282
  event.preventDefault();
280
283
  return;
281
284
  }
282
- button.data('disabled', true);
285
+ this._action_running = true;
283
286
  (this[item.id](this) || jQuery.when())
284
- .always(function() {
285
- button.data('disabled', false);
287
+ .always(() => {
288
+ this._action_running = false;
286
289
  });
287
290
  });
288
291
  };
@@ -909,7 +912,7 @@
909
912
  } else {
910
913
  prm = jQuery.when();
911
914
  }
912
- prm.then(() => {
915
+ return prm.then(() => {
913
916
  var access = Sao.common.MODELACCESS.get(this.screen.model_name);
914
917
  if (this.screen.readonly || !(access.write || access.create)) {
915
918
  return jQuery.Deferred().reject();
@@ -1011,18 +1014,18 @@
1011
1014
  },
1012
1015
  previous: function() {
1013
1016
  return this.modified_save().then(() => {
1014
- var prm = this.screen.display_previous();
1015
- this.info_bar.clear();
1016
- this.set_buttons_sensitive();
1017
- return prm;
1017
+ return this.screen.display_previous().then(() => {
1018
+ this.info_bar.clear();
1019
+ this.set_buttons_sensitive();
1020
+ });
1018
1021
  });
1019
1022
  },
1020
1023
  next: function() {
1021
1024
  return this.modified_save().then(() => {
1022
- var prm = this.screen.display_next();
1023
- this.info_bar.clear();
1024
- this.set_buttons_sensitive();
1025
- return prm;
1025
+ return this.screen.display_next().then(() => {
1026
+ this.info_bar.clear();
1027
+ this.set_buttons_sensitive();
1028
+ });
1026
1029
  });
1027
1030
  },
1028
1031
  search: function() {
package/src/view/form.js CHANGED
@@ -382,7 +382,8 @@ function eval_pyson(value){
382
382
  }
383
383
  }
384
384
  return jQuery.when.apply(jQuery,promesses)
385
- .done(() => {
385
+ .then(() => {
386
+ let promesses = [];
386
387
  var record = this.record;
387
388
  for (const name in this.widgets) {
388
389
  var widgets = this.widgets[name];
@@ -394,10 +395,12 @@ function eval_pyson(value){
394
395
  field.set_state(record);
395
396
  }
396
397
  for (const widget of widgets) {
397
- widget.display();
398
+ let prm = widget.display();
399
+ if (prm) {
400
+ promesses.push(prm);
401
+ }
398
402
  }
399
403
  }
400
- var promesses = [];
401
404
  // We iterate in the reverse order so that the most nested
402
405
  // widgets are computed first and set_state methods can rely
403
406
  // on their children having their state set
@@ -412,7 +415,7 @@ function eval_pyson(value){
412
415
  }
413
416
  // re-set the grid templates for the StateWidget that are
414
417
  // asynchronous
415
- jQuery.when.apply(jQuery, promesses).done(() => {
418
+ return jQuery.when.apply(jQuery, promesses).then(() => {
416
419
  for (const container of this.containers) {
417
420
  container.set_grid_template();
418
421
  }
@@ -2247,11 +2250,13 @@ function eval_pyson(value){
2247
2250
  this.el = jQuery('<div/>', {
2248
2251
  'class': this.class_
2249
2252
  });
2253
+ this.group = jQuery('<div/>', {
2254
+ 'class': 'input-group input-group-sm'
2255
+ }).css('width', '100%').appendTo(this.el);
2250
2256
  this.select = this.labelled = jQuery('<select/>', {
2251
2257
  'class': 'form-control input-sm mousetrap',
2252
2258
  'name': attributes.name,
2253
- });
2254
- this.el.append(this.select);
2259
+ }).appendTo(this.group);
2255
2260
  this.select.change(this.focus_out.bind(this));
2256
2261
  Sao.common.selection_mixin.init.call(this);
2257
2262
  this.init_selection();
@@ -2352,11 +2357,14 @@ function eval_pyson(value){
2352
2357
  this.el = jQuery('<div/>', {
2353
2358
  'class': this.class_
2354
2359
  });
2360
+ this.group = jQuery('<div/>', {
2361
+ 'class': 'input-group input-group-sm'
2362
+ }).css('width', '100%').appendTo(this.el);
2355
2363
  this.input = this.labelled = jQuery('<input/>', {
2356
2364
  'type': 'checkbox',
2357
2365
  'class': 'form-control input-sm mousetrap',
2358
2366
  'name': attributes.name,
2359
- }).appendTo(this.el);
2367
+ }).appendTo(this.group);
2360
2368
  this.input.change(this.focus_out.bind(this));
2361
2369
  this.input.click(function() {
2362
2370
  // Dont trigger click if field is readonly as readonly has no
@@ -3619,7 +3627,7 @@ function eval_pyson(value){
3619
3627
  display: function() {
3620
3628
  Sao.View.Form.One2Many._super.display.call(this);
3621
3629
 
3622
- this.prm.done(() => {
3630
+ return this.prm.then(() => {
3623
3631
  this._set_button_sensitive();
3624
3632
 
3625
3633
  var record = this.record;
@@ -3629,9 +3637,8 @@ function eval_pyson(value){
3629
3637
  this.screen.new_group();
3630
3638
  this.screen.current_record = null;
3631
3639
  this.screen.group.parent = null;
3632
- this.screen.display();
3633
3640
  this.screen.screen_container.hide_filter();
3634
- return;
3641
+ return this.screen.display();
3635
3642
  }
3636
3643
 
3637
3644
  var new_group = record.field_get_client(this.field_name);
@@ -3660,13 +3667,13 @@ function eval_pyson(value){
3660
3667
  this.screen.domain = domain;
3661
3668
  }
3662
3669
  this.screen.size_limit = size_limit;
3663
- this.screen.display();
3664
3670
  if (this.attributes.height !== undefined) {
3665
3671
  this.content
3666
3672
  .find('.treeview,.list-form').first()
3667
3673
  .css('min-height', this.attributes.height + 'px')
3668
3674
  .css('max-height', this.attributes.height + 'px');
3669
3675
  }
3676
+ return this.screen.display();
3670
3677
  });
3671
3678
  },
3672
3679
  focus: function() {
@@ -3966,9 +3973,7 @@ function eval_pyson(value){
3966
3973
  return prm;
3967
3974
  },
3968
3975
  set_value: function() {
3969
- if (this.screen.modified()) { // TODO check if required
3970
- this.view.screen.record_modified(false);
3971
- }
3976
+ this.screen.current_view.set_value();
3972
3977
  },
3973
3978
  _update_completion: function(text) {
3974
3979
  if (!this.record) {
@@ -4202,7 +4207,7 @@ function eval_pyson(value){
4202
4207
  display: function() {
4203
4208
  Sao.View.Form.Many2Many._super.display.call(this);
4204
4209
 
4205
- this.prm.done(() => {
4210
+ return this.prm.then(() => {
4206
4211
  var record = this.record;
4207
4212
  var field = this.field;
4208
4213
 
@@ -4210,21 +4215,20 @@ function eval_pyson(value){
4210
4215
  this.screen.new_group();
4211
4216
  this.screen.current_record = null;
4212
4217
  this.screen.group.parent = null;
4213
- this.screen.display();
4214
4218
  this.screen.screen_container.hide_filter();
4215
- return;
4219
+ return this.screen.display();
4216
4220
  }
4217
4221
  var new_group = record.field_get_client(this.field_name);
4218
4222
  if (new_group != this.screen.group) {
4219
4223
  this.screen.set_group(new_group);
4220
4224
  }
4221
- this.screen.display();
4222
4225
  if (this.attributes.height !== undefined) {
4223
4226
  this.content
4224
4227
  .find('.treeview,.list-form').first()
4225
4228
  .css('min-height', this.attributes.height + 'px')
4226
4229
  .css('max-height', this.attributes.height + 'px');
4227
4230
  }
4231
+ return this.screen.display();
4228
4232
  });
4229
4233
  },
4230
4234
  focus: function() {
package/src/view/tree.js CHANGED
@@ -2744,6 +2744,10 @@
2744
2744
  fields, false, false)) {
2745
2745
  var value = cell.prop('checked');
2746
2746
  this.field.set_client(record, value);
2747
+ if (record !== current_record) {
2748
+ // we can not rely on editable tree handler to save the row
2749
+ record.save();
2750
+ }
2747
2751
  } else {
2748
2752
  evt.preventDefault();
2749
2753
  }