tryton-sao 7.8.7 → 7.8.9

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.8.9 - 2026-05-02
3
+ --------------------------
4
+ * Bug fixes (see mercurial logs for details)
5
+
6
+
7
+ Version 7.8.8 - 2026-04-16
8
+ --------------------------
9
+ * Bug fixes (see mercurial logs for details)
10
+
11
+
2
12
  Version 7.8.7 - 2026-03-18
3
13
  --------------------------
4
14
  * Bug fixes (see mercurial logs for details)
package/COPYRIGHT CHANGED
@@ -1,4 +1,4 @@
1
- Copyright (C) 2012-2025 Nicolas Évrard.
1
+ Copyright (C) 2012-2026 Nicolas Évrard.
2
2
  Copyright (C) 2012-2026 Cédric Krier.
3
3
  Copyright (C) 2012-2014 Bertrand Chenal.
4
4
  Copyright (C) 2012-2026 B2CK SPRL.
@@ -9758,12 +9758,10 @@ html.accesskey *[accesskey]:after {
9758
9758
  padding: 0 2px;
9759
9759
  position: absolute;
9760
9760
  text-transform: uppercase;
9761
- margin: 0 -1em;
9761
+ left: -1em;
9762
+ right: 0;
9762
9763
  z-index: 5;
9763
9764
  }
9764
- html.accesskey input[accesskey][type="checkbox"]:after {
9765
- background-color: initial;
9766
- }
9767
9765
  html.accesskey *[accesskey] ~ span[data-accesskey] {
9768
9766
  float: right;
9769
9767
  position: relative;
@@ -9774,10 +9772,13 @@ html.accesskey *[accesskey] ~ span[data-accesskey]:after {
9774
9772
  html.accesskey *[accesskey]:after {
9775
9773
  content: attr(accesskey);
9776
9774
  }
9777
- html.accesskey input[accesskey][type="checkbox"] ~ span[data-accesskey],
9778
- html.accesskey input[accesskey][type="checkbox"] ~ span[data-accesskey],
9779
- html.accesskey select[accesskey] ~ span[data-accesskey] {
9780
- bottom: 1em;
9775
+ html.accesskey[dir="rtl"] *[accesskey] ~ span[data-accesskey]:after,
9776
+ html.accesskey[dir="rtl"] *[accesskey]:after {
9777
+ left: 0;
9778
+ right: -1em;
9779
+ }
9780
+ html.accesskey[dir="rtl"] *[accesskey] ~ span[data-accesskey] {
9781
+ float: left;
9781
9782
  }
9782
9783
  .tab-form,
9783
9784
  .tab-board {
@@ -3,7 +3,7 @@
3
3
 
4
4
  /* eslint-disable no-redeclare */
5
5
  var Sao = {
6
- __version__: '7.8.7',
6
+ __version__: '7.8.9',
7
7
  };
8
8
  /* eslint-enable no-redeclare */
9
9
 
@@ -2986,6 +2986,7 @@ var Sao = {
2986
2986
  if (service_window.closed) {
2987
2987
  window.clearInterval(timer);
2988
2988
  session.database = database;
2989
+ session.login = null;
2989
2990
  session.restore();
2990
2991
  if (session.session) {
2991
2992
  dfd.resolve(session);
@@ -3204,6 +3205,9 @@ var Sao = {
3204
3205
  });
3205
3206
  }).prependTo(dialog.footer);
3206
3207
  dialog.modal.find('.modal-dialog').removeClass('modal-sm');
3208
+ prm.fail(() => {
3209
+ session.login = null;
3210
+ });
3207
3211
  return dialog;
3208
3212
  },
3209
3213
  });
@@ -5389,6 +5393,7 @@ var Sao = {
5389
5393
  let [, thousandSeparator] = /^10(.)?000/.exec(format(10000));
5390
5394
  let [, decimalSign] = /^0(.)1$/.exec(format(0.1));
5391
5395
  return Number(string
5396
+ .replaceAll(' ', '')
5392
5397
  .replaceAll(thousandSeparator, '')
5393
5398
  .replace(decimalSign, '.'));
5394
5399
  }
@@ -8791,7 +8796,7 @@ var Sao = {
8791
8796
  this.group.parent.id;
8792
8797
  }
8793
8798
  }
8794
- return this.set_default(values);
8799
+ return this.set_default(values).then(() => values);
8795
8800
  });
8796
8801
  }
8797
8802
  return jQuery.when();
@@ -10372,10 +10377,7 @@ var Sao = {
10372
10377
  if (record2) {
10373
10378
  let to_update = Object.fromEntries(
10374
10379
  Object.entries(vals).filter(
10375
- ([k, v]) => {
10376
- !Object.prototype.hasOwnProperty.call(
10377
- vals_to_set, k)
10378
- }
10380
+ ([k, v]) => !Object.hasOwn(vals_to_set, k)
10379
10381
  ));
10380
10382
  record2.set_on_change(to_update);
10381
10383
  }
@@ -10831,6 +10833,7 @@ var Sao = {
10831
10833
  'class': 'hidden-lg',
10832
10834
  }).appendTo(this.name_el);
10833
10835
  this.view_prm = jQuery.when();
10836
+ this._action_running = false;
10834
10837
  },
10835
10838
  menu_def: function() {
10836
10839
  return [
@@ -10954,6 +10957,8 @@ var Sao = {
10954
10957
  if (this.info_bar) {
10955
10958
  this.el.append(this.info_bar.el);
10956
10959
  }
10960
+
10961
+ this._chat = null;
10957
10962
  },
10958
10963
  set_menu: function(menu) {
10959
10964
  var previous;
@@ -10978,8 +10983,13 @@ var Sao = {
10978
10983
  this.menu_buttons[item.id] = menuitem;
10979
10984
  link.click(evt => {
10980
10985
  evt.preventDefault();
10981
- if (!menuitem.hasClass('disabled')) {
10982
- this[item.id]();
10986
+ if (!menuitem.hasClass('disabled')
10987
+ && !this._action_running) {
10988
+ this._action_running = true;
10989
+ (this[item.id]() || jQuery.when())
10990
+ .always(() => {
10991
+ this._action_running = false;
10992
+ });
10983
10993
  }
10984
10994
  });
10985
10995
  } else if (!item && previous) {
@@ -11083,17 +11093,14 @@ var Sao = {
11083
11093
  }
11084
11094
  this.buttons[item.id].click(item, event => {
11085
11095
  var item = event.data;
11086
- var button = this.buttons[item.id];
11087
- // Use data instead of disabled prop because the action may
11088
- // actually disable the button.
11089
- if (button.data('disabled')) {
11096
+ if (this._action_running) {
11090
11097
  event.preventDefault();
11091
11098
  return;
11092
11099
  }
11093
- button.data('disabled', true);
11100
+ this._action_running = true;
11094
11101
  (this[item.id](this) || jQuery.when())
11095
- .always(function() {
11096
- button.data('disabled', false);
11102
+ .always(() => {
11103
+ this._action_running = false;
11097
11104
  });
11098
11105
  });
11099
11106
  };
@@ -11163,6 +11170,9 @@ var Sao = {
11163
11170
  tabs.trigger('ready');
11164
11171
  if (this._chat) {
11165
11172
  this._chat.unregister();
11173
+ let chat = this.sidebar_content.find('.chat');
11174
+ chat.remove();
11175
+ this._chat = null;
11166
11176
  }
11167
11177
  });
11168
11178
  },
@@ -11717,7 +11727,7 @@ var Sao = {
11717
11727
  } else {
11718
11728
  prm = jQuery.when();
11719
11729
  }
11720
- prm.then(() => {
11730
+ return prm.then(() => {
11721
11731
  var access = Sao.common.MODELACCESS.get(this.screen.model_name);
11722
11732
  if (this.screen.readonly || !(access.write || access.create)) {
11723
11733
  return jQuery.Deferred().reject();
@@ -11759,6 +11769,8 @@ var Sao = {
11759
11769
  }
11760
11770
  return set_cursor;
11761
11771
  });
11772
+ } else {
11773
+ this.refresh_resources(true);
11762
11774
  }
11763
11775
  return set_cursor;
11764
11776
  })
@@ -11817,18 +11829,18 @@ var Sao = {
11817
11829
  },
11818
11830
  previous: function() {
11819
11831
  return this.modified_save().then(() => {
11820
- var prm = this.screen.display_previous();
11821
- this.info_bar.clear();
11822
- this.set_buttons_sensitive();
11823
- return prm;
11832
+ return this.screen.display_previous().then(() => {
11833
+ this.info_bar.clear();
11834
+ this.set_buttons_sensitive();
11835
+ });
11824
11836
  });
11825
11837
  },
11826
11838
  next: function() {
11827
11839
  return this.modified_save().then(() => {
11828
- var prm = this.screen.display_next();
11829
- this.info_bar.clear();
11830
- this.set_buttons_sensitive();
11831
- return prm;
11840
+ return this.screen.display_next().then(() => {
11841
+ this.info_bar.clear();
11842
+ this.set_buttons_sensitive();
11843
+ });
11832
11844
  });
11833
11845
  },
11834
11846
  search: function() {
@@ -12222,6 +12234,8 @@ var Sao = {
12222
12234
  let chat = this.sidebar_content.find('.chat');
12223
12235
  if (chat.length) {
12224
12236
  chat.remove();
12237
+ this._chat.unregister()
12238
+ this._chat = null;
12225
12239
  } else {
12226
12240
  if (this.screen.current_reference) {
12227
12241
  this._chat = new Sao.Chat(this.screen.current_reference);
@@ -13105,8 +13119,14 @@ var Sao = {
13105
13119
  break;
13106
13120
  case 'selection':
13107
13121
  case 'multiselection':
13122
+ var selection = jQuery.extend([], field.selection);
13123
+ if (field.sort === undefined || field.sort) {
13124
+ selection.sort(function(a, b) {
13125
+ return a[1].localeCompare(b[1]);
13126
+ });
13127
+ }
13108
13128
  entry = new Sao.ScreenContainer.Selection(
13109
- field.selection, prefix + field.name);
13129
+ selection, prefix + field.name);
13110
13130
  input = entry.el;
13111
13131
  input.prop('size', field.selection.length);
13112
13132
  break;
@@ -14736,7 +14756,7 @@ var Sao = {
14736
14756
  if (this.current_view &&
14737
14757
  ~['tree', 'graph', 'calendar'].indexOf(this.current_view.view_type) &&
14738
14758
  !this.group.parent) {
14739
- return this.search_filter();
14759
+ return this.search_filter(this.screen_container.get_text());
14740
14760
  }
14741
14761
  } else if (action == 'reload menu') {
14742
14762
  return Sao.Session.current_session.reload_context()
@@ -15523,7 +15543,8 @@ function eval_pyson(value){
15523
15543
  }
15524
15544
  }
15525
15545
  return jQuery.when.apply(jQuery,promesses)
15526
- .done(() => {
15546
+ .then(() => {
15547
+ let promesses = [];
15527
15548
  var record = this.record;
15528
15549
  for (const name in this.widgets) {
15529
15550
  var widgets = this.widgets[name];
@@ -15535,10 +15556,12 @@ function eval_pyson(value){
15535
15556
  field.set_state(record);
15536
15557
  }
15537
15558
  for (const widget of widgets) {
15538
- widget.display();
15559
+ let prm = widget.display();
15560
+ if (prm) {
15561
+ promesses.push(prm);
15562
+ }
15539
15563
  }
15540
15564
  }
15541
- var promesses = [];
15542
15565
  // We iterate in the reverse order so that the most nested
15543
15566
  // widgets are computed first and set_state methods can rely
15544
15567
  // on their children having their state set
@@ -15553,7 +15576,7 @@ function eval_pyson(value){
15553
15576
  }
15554
15577
  // re-set the grid templates for the StateWidget that are
15555
15578
  // asynchronous
15556
- jQuery.when.apply(jQuery, promesses).done(() => {
15579
+ return jQuery.when.apply(jQuery, promesses).then(() => {
15557
15580
  for (const container of this.containers) {
15558
15581
  container.set_grid_template();
15559
15582
  }
@@ -17390,11 +17413,13 @@ function eval_pyson(value){
17390
17413
  this.el = jQuery('<div/>', {
17391
17414
  'class': this.class_
17392
17415
  });
17416
+ this.group = jQuery('<div/>', {
17417
+ 'class': 'input-group input-group-sm'
17418
+ }).css('width', '100%').appendTo(this.el);
17393
17419
  this.select = this.labelled = jQuery('<select/>', {
17394
17420
  'class': 'form-control input-sm mousetrap',
17395
17421
  'name': attributes.name,
17396
- });
17397
- this.el.append(this.select);
17422
+ }).appendTo(this.group);
17398
17423
  this.select.change(this.focus_out.bind(this));
17399
17424
  Sao.common.selection_mixin.init.call(this);
17400
17425
  this.init_selection();
@@ -17495,11 +17520,14 @@ function eval_pyson(value){
17495
17520
  this.el = jQuery('<div/>', {
17496
17521
  'class': this.class_
17497
17522
  });
17523
+ this.group = jQuery('<div/>', {
17524
+ 'class': 'input-group input-group-sm'
17525
+ }).css('width', '100%').appendTo(this.el);
17498
17526
  this.input = this.labelled = jQuery('<input/>', {
17499
17527
  'type': 'checkbox',
17500
17528
  'class': 'form-control input-sm mousetrap',
17501
17529
  'name': attributes.name,
17502
- }).appendTo(this.el);
17530
+ }).appendTo(this.group);
17503
17531
  this.input.change(this.focus_out.bind(this));
17504
17532
  this.input.click(function() {
17505
17533
  // Dont trigger click if field is readonly as readonly has no
@@ -18762,7 +18790,7 @@ function eval_pyson(value){
18762
18790
  display: function() {
18763
18791
  Sao.View.Form.One2Many._super.display.call(this);
18764
18792
 
18765
- this.prm.done(() => {
18793
+ return this.prm.then(() => {
18766
18794
  this._set_button_sensitive();
18767
18795
 
18768
18796
  var record = this.record;
@@ -18772,9 +18800,8 @@ function eval_pyson(value){
18772
18800
  this.screen.new_group();
18773
18801
  this.screen.current_record = null;
18774
18802
  this.screen.group.parent = null;
18775
- this.screen.display();
18776
18803
  this.screen.screen_container.hide_filter();
18777
- return;
18804
+ return this.screen.display();
18778
18805
  }
18779
18806
 
18780
18807
  var new_group = record.field_get_client(this.field_name);
@@ -18803,13 +18830,13 @@ function eval_pyson(value){
18803
18830
  this.screen.domain = domain;
18804
18831
  }
18805
18832
  this.screen.size_limit = size_limit;
18806
- this.screen.display();
18807
18833
  if (this.attributes.height !== undefined) {
18808
18834
  this.content
18809
18835
  .find('.treeview,.list-form').first()
18810
18836
  .css('min-height', this.attributes.height + 'px')
18811
18837
  .css('max-height', this.attributes.height + 'px');
18812
18838
  }
18839
+ return this.screen.display();
18813
18840
  });
18814
18841
  },
18815
18842
  focus: function() {
@@ -19109,9 +19136,7 @@ function eval_pyson(value){
19109
19136
  return prm;
19110
19137
  },
19111
19138
  set_value: function() {
19112
- if (this.screen.modified()) { // TODO check if required
19113
- this.view.screen.record_modified(false);
19114
- }
19139
+ this.screen.current_view.set_value();
19115
19140
  },
19116
19141
  _update_completion: function(text) {
19117
19142
  if (!this.record) {
@@ -19345,7 +19370,7 @@ function eval_pyson(value){
19345
19370
  display: function() {
19346
19371
  Sao.View.Form.Many2Many._super.display.call(this);
19347
19372
 
19348
- this.prm.done(() => {
19373
+ return this.prm.then(() => {
19349
19374
  var record = this.record;
19350
19375
  var field = this.field;
19351
19376
 
@@ -19353,21 +19378,20 @@ function eval_pyson(value){
19353
19378
  this.screen.new_group();
19354
19379
  this.screen.current_record = null;
19355
19380
  this.screen.group.parent = null;
19356
- this.screen.display();
19357
19381
  this.screen.screen_container.hide_filter();
19358
- return;
19382
+ return this.screen.display();
19359
19383
  }
19360
19384
  var new_group = record.field_get_client(this.field_name);
19361
19385
  if (new_group != this.screen.group) {
19362
19386
  this.screen.set_group(new_group);
19363
19387
  }
19364
- this.screen.display();
19365
19388
  if (this.attributes.height !== undefined) {
19366
19389
  this.content
19367
19390
  .find('.treeview,.list-form').first()
19368
19391
  .css('min-height', this.attributes.height + 'px')
19369
19392
  .css('max-height', this.attributes.height + 'px');
19370
19393
  }
19394
+ return this.screen.display();
19371
19395
  });
19372
19396
  },
19373
19397
  focus: function() {
@@ -21490,6 +21514,8 @@ function eval_pyson(value){
21490
21514
  'reset_width',
21491
21515
  [this.screen.model_name, window.screen.width],
21492
21516
  {});
21517
+ Sao.Session.current_session.cache.clear(
21518
+ `model.${this.screen.model_name}.fields_view_get`);
21493
21519
 
21494
21520
  for (let column of this.columns) {
21495
21521
  if (column.col.data('default-width')) {
@@ -21539,7 +21565,7 @@ function eval_pyson(value){
21539
21565
 
21540
21566
  let tree_column_width = (
21541
21567
  Sao.Screen.tree_column_width[this.screen.model_name] || {});
21542
- let width = tree_column_width[name];
21568
+ let width = tree_column_width[column.attributes.name];
21543
21569
  if (width || column.attributes.width) {
21544
21570
  if (!width) {
21545
21571
  width = column.attributes.width;
@@ -23824,6 +23850,10 @@ function eval_pyson(value){
23824
23850
  fields, false, false)) {
23825
23851
  var value = cell.prop('checked');
23826
23852
  this.field.set_client(record, value);
23853
+ if (record !== current_record) {
23854
+ // we can not rely on editable tree handler to save the row
23855
+ record.save();
23856
+ }
23827
23857
  } else {
23828
23858
  evt.preventDefault();
23829
23859
  }
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.8.7",
5
+ "version": "7.8.9",
6
6
  "homepage": "https://www.tryton.org/",
7
7
  "author": {
8
8
  "name": "Tryton"
package/src/common.js CHANGED
@@ -2086,6 +2086,7 @@
2086
2086
  let [, thousandSeparator] = /^10(.)?000/.exec(format(10000));
2087
2087
  let [, decimalSign] = /^0(.)1$/.exec(format(0.1));
2088
2088
  return Number(string
2089
+ .replaceAll(' ', '')
2089
2090
  .replaceAll(thousandSeparator, '')
2090
2091
  .replace(decimalSign, '.'));
2091
2092
  }
package/src/model.js CHANGED
@@ -990,7 +990,7 @@
990
990
  this.group.parent.id;
991
991
  }
992
992
  }
993
- return this.set_default(values);
993
+ return this.set_default(values).then(() => values);
994
994
  });
995
995
  }
996
996
  return jQuery.when();
@@ -2571,10 +2571,7 @@
2571
2571
  if (record2) {
2572
2572
  let to_update = Object.fromEntries(
2573
2573
  Object.entries(vals).filter(
2574
- ([k, v]) => {
2575
- !Object.prototype.hasOwnProperty.call(
2576
- vals_to_set, k)
2577
- }
2574
+ ([k, v]) => !Object.hasOwn(vals_to_set, k)
2578
2575
  ));
2579
2576
  record2.set_on_change(to_update);
2580
2577
  }
package/src/sao.js CHANGED
@@ -3,7 +3,7 @@
3
3
 
4
4
  /* eslint-disable no-redeclare */
5
5
  var Sao = {
6
- __version__: '7.8.7',
6
+ __version__: '7.8.9',
7
7
  };
8
8
  /* eslint-enable no-redeclare */
9
9
 
package/src/sao.less CHANGED
@@ -607,14 +607,11 @@ html.accesskey {
607
607
  padding: 0 2px;
608
608
  position: absolute;
609
609
  text-transform: uppercase;
610
- margin: 0 -1em;
610
+ left: -1em;
611
+ right: 0;
611
612
  z-index: 5;
612
613
  }
613
614
 
614
- input[accesskey][type="checkbox"]:after {
615
- background-color: initial;
616
- }
617
-
618
615
  *[accesskey] ~ span[data-accesskey] {
619
616
  float: right;
620
617
  position: relative;
@@ -628,11 +625,15 @@ html.accesskey {
628
625
  content: attr(accesskey);
629
626
  }
630
627
 
631
- input[accesskey][type="checkbox"],
632
- input[accesskey][type="checkbox"],
633
- select[accesskey] {
634
- & ~ span[data-accesskey] {
635
- bottom: 1em;
628
+ &[dir="rtl"] {
629
+ *[accesskey] ~ span[data-accesskey]:after,
630
+ *[accesskey]:after {
631
+ left: 0;
632
+ right: -1em;
633
+ }
634
+
635
+ *[accesskey] ~ span[data-accesskey] {
636
+ float: left;
636
637
  }
637
638
  }
638
639
  }
package/src/screen.js CHANGED
@@ -501,8 +501,14 @@
501
501
  break;
502
502
  case 'selection':
503
503
  case 'multiselection':
504
+ var selection = jQuery.extend([], field.selection);
505
+ if (field.sort === undefined || field.sort) {
506
+ selection.sort(function(a, b) {
507
+ return a[1].localeCompare(b[1]);
508
+ });
509
+ }
504
510
  entry = new Sao.ScreenContainer.Selection(
505
- field.selection, prefix + field.name);
511
+ selection, prefix + field.name);
506
512
  input = entry.el;
507
513
  input.prop('size', field.selection.length);
508
514
  break;
@@ -2132,7 +2138,7 @@
2132
2138
  if (this.current_view &&
2133
2139
  ~['tree', 'graph', 'calendar'].indexOf(this.current_view.view_type) &&
2134
2140
  !this.group.parent) {
2135
- return this.search_filter();
2141
+ return this.search_filter(this.screen_container.get_text());
2136
2142
  }
2137
2143
  } else if (action == 'reload menu') {
2138
2144
  return Sao.Session.current_session.reload_context()
package/src/session.js CHANGED
@@ -346,6 +346,7 @@
346
346
  if (service_window.closed) {
347
347
  window.clearInterval(timer);
348
348
  session.database = database;
349
+ session.login = null;
349
350
  session.restore();
350
351
  if (session.session) {
351
352
  dfd.resolve(session);
@@ -564,6 +565,9 @@
564
565
  });
565
566
  }).prependTo(dialog.footer);
566
567
  dialog.modal.find('.modal-dialog').removeClass('modal-sm');
568
+ prm.fail(() => {
569
+ session.login = null;
570
+ });
567
571
  return dialog;
568
572
  },
569
573
  });
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 [
@@ -141,6 +142,8 @@
141
142
  if (this.info_bar) {
142
143
  this.el.append(this.info_bar.el);
143
144
  }
145
+
146
+ this._chat = null;
144
147
  },
145
148
  set_menu: function(menu) {
146
149
  var previous;
@@ -165,8 +168,13 @@
165
168
  this.menu_buttons[item.id] = menuitem;
166
169
  link.click(evt => {
167
170
  evt.preventDefault();
168
- if (!menuitem.hasClass('disabled')) {
169
- 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
+ });
170
178
  }
171
179
  });
172
180
  } else if (!item && previous) {
@@ -270,17 +278,14 @@
270
278
  }
271
279
  this.buttons[item.id].click(item, event => {
272
280
  var item = event.data;
273
- var button = this.buttons[item.id];
274
- // Use data instead of disabled prop because the action may
275
- // actually disable the button.
276
- if (button.data('disabled')) {
281
+ if (this._action_running) {
277
282
  event.preventDefault();
278
283
  return;
279
284
  }
280
- button.data('disabled', true);
285
+ this._action_running = true;
281
286
  (this[item.id](this) || jQuery.when())
282
- .always(function() {
283
- button.data('disabled', false);
287
+ .always(() => {
288
+ this._action_running = false;
284
289
  });
285
290
  });
286
291
  };
@@ -350,6 +355,9 @@
350
355
  tabs.trigger('ready');
351
356
  if (this._chat) {
352
357
  this._chat.unregister();
358
+ let chat = this.sidebar_content.find('.chat');
359
+ chat.remove();
360
+ this._chat = null;
353
361
  }
354
362
  });
355
363
  },
@@ -904,7 +912,7 @@
904
912
  } else {
905
913
  prm = jQuery.when();
906
914
  }
907
- prm.then(() => {
915
+ return prm.then(() => {
908
916
  var access = Sao.common.MODELACCESS.get(this.screen.model_name);
909
917
  if (this.screen.readonly || !(access.write || access.create)) {
910
918
  return jQuery.Deferred().reject();
@@ -946,6 +954,8 @@
946
954
  }
947
955
  return set_cursor;
948
956
  });
957
+ } else {
958
+ this.refresh_resources(true);
949
959
  }
950
960
  return set_cursor;
951
961
  })
@@ -1004,18 +1014,18 @@
1004
1014
  },
1005
1015
  previous: function() {
1006
1016
  return this.modified_save().then(() => {
1007
- var prm = this.screen.display_previous();
1008
- this.info_bar.clear();
1009
- this.set_buttons_sensitive();
1010
- return prm;
1017
+ return this.screen.display_previous().then(() => {
1018
+ this.info_bar.clear();
1019
+ this.set_buttons_sensitive();
1020
+ });
1011
1021
  });
1012
1022
  },
1013
1023
  next: function() {
1014
1024
  return this.modified_save().then(() => {
1015
- var prm = this.screen.display_next();
1016
- this.info_bar.clear();
1017
- this.set_buttons_sensitive();
1018
- return prm;
1025
+ return this.screen.display_next().then(() => {
1026
+ this.info_bar.clear();
1027
+ this.set_buttons_sensitive();
1028
+ });
1019
1029
  });
1020
1030
  },
1021
1031
  search: function() {
@@ -1409,6 +1419,8 @@
1409
1419
  let chat = this.sidebar_content.find('.chat');
1410
1420
  if (chat.length) {
1411
1421
  chat.remove();
1422
+ this._chat.unregister()
1423
+ this._chat = null;
1412
1424
  } else {
1413
1425
  if (this.screen.current_reference) {
1414
1426
  this._chat = new Sao.Chat(this.screen.current_reference);
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
  }
@@ -2249,11 +2252,13 @@ function eval_pyson(value){
2249
2252
  this.el = jQuery('<div/>', {
2250
2253
  'class': this.class_
2251
2254
  });
2255
+ this.group = jQuery('<div/>', {
2256
+ 'class': 'input-group input-group-sm'
2257
+ }).css('width', '100%').appendTo(this.el);
2252
2258
  this.select = this.labelled = jQuery('<select/>', {
2253
2259
  'class': 'form-control input-sm mousetrap',
2254
2260
  'name': attributes.name,
2255
- });
2256
- this.el.append(this.select);
2261
+ }).appendTo(this.group);
2257
2262
  this.select.change(this.focus_out.bind(this));
2258
2263
  Sao.common.selection_mixin.init.call(this);
2259
2264
  this.init_selection();
@@ -2354,11 +2359,14 @@ function eval_pyson(value){
2354
2359
  this.el = jQuery('<div/>', {
2355
2360
  'class': this.class_
2356
2361
  });
2362
+ this.group = jQuery('<div/>', {
2363
+ 'class': 'input-group input-group-sm'
2364
+ }).css('width', '100%').appendTo(this.el);
2357
2365
  this.input = this.labelled = jQuery('<input/>', {
2358
2366
  'type': 'checkbox',
2359
2367
  'class': 'form-control input-sm mousetrap',
2360
2368
  'name': attributes.name,
2361
- }).appendTo(this.el);
2369
+ }).appendTo(this.group);
2362
2370
  this.input.change(this.focus_out.bind(this));
2363
2371
  this.input.click(function() {
2364
2372
  // Dont trigger click if field is readonly as readonly has no
@@ -3621,7 +3629,7 @@ function eval_pyson(value){
3621
3629
  display: function() {
3622
3630
  Sao.View.Form.One2Many._super.display.call(this);
3623
3631
 
3624
- this.prm.done(() => {
3632
+ return this.prm.then(() => {
3625
3633
  this._set_button_sensitive();
3626
3634
 
3627
3635
  var record = this.record;
@@ -3631,9 +3639,8 @@ function eval_pyson(value){
3631
3639
  this.screen.new_group();
3632
3640
  this.screen.current_record = null;
3633
3641
  this.screen.group.parent = null;
3634
- this.screen.display();
3635
3642
  this.screen.screen_container.hide_filter();
3636
- return;
3643
+ return this.screen.display();
3637
3644
  }
3638
3645
 
3639
3646
  var new_group = record.field_get_client(this.field_name);
@@ -3662,13 +3669,13 @@ function eval_pyson(value){
3662
3669
  this.screen.domain = domain;
3663
3670
  }
3664
3671
  this.screen.size_limit = size_limit;
3665
- this.screen.display();
3666
3672
  if (this.attributes.height !== undefined) {
3667
3673
  this.content
3668
3674
  .find('.treeview,.list-form').first()
3669
3675
  .css('min-height', this.attributes.height + 'px')
3670
3676
  .css('max-height', this.attributes.height + 'px');
3671
3677
  }
3678
+ return this.screen.display();
3672
3679
  });
3673
3680
  },
3674
3681
  focus: function() {
@@ -3968,9 +3975,7 @@ function eval_pyson(value){
3968
3975
  return prm;
3969
3976
  },
3970
3977
  set_value: function() {
3971
- if (this.screen.modified()) { // TODO check if required
3972
- this.view.screen.record_modified(false);
3973
- }
3978
+ this.screen.current_view.set_value();
3974
3979
  },
3975
3980
  _update_completion: function(text) {
3976
3981
  if (!this.record) {
@@ -4204,7 +4209,7 @@ function eval_pyson(value){
4204
4209
  display: function() {
4205
4210
  Sao.View.Form.Many2Many._super.display.call(this);
4206
4211
 
4207
- this.prm.done(() => {
4212
+ return this.prm.then(() => {
4208
4213
  var record = this.record;
4209
4214
  var field = this.field;
4210
4215
 
@@ -4212,21 +4217,20 @@ function eval_pyson(value){
4212
4217
  this.screen.new_group();
4213
4218
  this.screen.current_record = null;
4214
4219
  this.screen.group.parent = null;
4215
- this.screen.display();
4216
4220
  this.screen.screen_container.hide_filter();
4217
- return;
4221
+ return this.screen.display();
4218
4222
  }
4219
4223
  var new_group = record.field_get_client(this.field_name);
4220
4224
  if (new_group != this.screen.group) {
4221
4225
  this.screen.set_group(new_group);
4222
4226
  }
4223
- this.screen.display();
4224
4227
  if (this.attributes.height !== undefined) {
4225
4228
  this.content
4226
4229
  .find('.treeview,.list-form').first()
4227
4230
  .css('min-height', this.attributes.height + 'px')
4228
4231
  .css('max-height', this.attributes.height + 'px');
4229
4232
  }
4233
+ return this.screen.display();
4230
4234
  });
4231
4235
  },
4232
4236
  focus: function() {
package/src/view/tree.js CHANGED
@@ -426,6 +426,8 @@
426
426
  'reset_width',
427
427
  [this.screen.model_name, window.screen.width],
428
428
  {});
429
+ Sao.Session.current_session.cache.clear(
430
+ `model.${this.screen.model_name}.fields_view_get`);
429
431
 
430
432
  for (let column of this.columns) {
431
433
  if (column.col.data('default-width')) {
@@ -475,7 +477,7 @@
475
477
 
476
478
  let tree_column_width = (
477
479
  Sao.Screen.tree_column_width[this.screen.model_name] || {});
478
- let width = tree_column_width[name];
480
+ let width = tree_column_width[column.attributes.name];
479
481
  if (width || column.attributes.width) {
480
482
  if (!width) {
481
483
  width = column.attributes.width;
@@ -2760,6 +2762,10 @@
2760
2762
  fields, false, false)) {
2761
2763
  var value = cell.prop('checked');
2762
2764
  this.field.set_client(record, value);
2765
+ if (record !== current_record) {
2766
+ // we can not rely on editable tree handler to save the row
2767
+ record.save();
2768
+ }
2763
2769
  } else {
2764
2770
  evt.preventDefault();
2765
2771
  }