@jinntec/fore 1.3.0 → 1.5.0

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.
Files changed (44) hide show
  1. package/dist/fore-dev.js +8 -8
  2. package/dist/fore-dev.js.map +1 -1
  3. package/dist/fore.js +7 -7
  4. package/dist/fore.js.map +1 -1
  5. package/index.js +1 -0
  6. package/package.json +1 -1
  7. package/resources/fore.css +6 -1
  8. package/src/ForeElementMixin.js +4 -0
  9. package/src/actions/abstract-action.js +117 -48
  10. package/src/actions/fx-action.js +9 -9
  11. package/src/actions/fx-append.js +1 -1
  12. package/src/actions/fx-confirm.js +1 -1
  13. package/src/actions/fx-copy.js +68 -0
  14. package/src/actions/fx-delete.js +1 -1
  15. package/src/actions/fx-dispatch.js +1 -1
  16. package/src/actions/fx-hide.js +1 -1
  17. package/src/actions/fx-insert.js +1 -1
  18. package/src/actions/fx-message.js +1 -1
  19. package/src/actions/fx-refresh.js +2 -2
  20. package/src/actions/fx-reload.js +1 -1
  21. package/src/actions/fx-replace.js +1 -1
  22. package/src/actions/fx-return.js +1 -1
  23. package/src/actions/fx-send.js +2 -2
  24. package/src/actions/fx-setfocus.js +1 -1
  25. package/src/actions/fx-setvalue.js +1 -1
  26. package/src/actions/fx-show.js +1 -1
  27. package/src/actions/fx-toggle.js +1 -1
  28. package/src/actions/fx-update.js +1 -1
  29. package/src/fore.js +59 -10
  30. package/src/fx-bind.js +5 -0
  31. package/src/fx-fore.js +92 -35
  32. package/src/fx-instance.js +70 -70
  33. package/src/fx-model.js +12 -17
  34. package/src/fx-submission.js +420 -416
  35. package/src/getInScopeContext.js +19 -5
  36. package/src/modelitem.js +3 -1
  37. package/src/ui/abstract-control.js +1 -1
  38. package/src/ui/fx-control.js +2 -2
  39. package/src/ui/fx-repeat-attributes.js +442 -0
  40. package/src/ui/fx-repeat.js +8 -0
  41. package/src/ui/fx-switch.js +9 -1
  42. package/src/ui/fx-trigger.js +19 -18
  43. package/src/xpath-evaluation.js +21 -9
  44. package/src/xpath-util.js +13 -28
package/index.js CHANGED
@@ -15,6 +15,7 @@ import './src/ui/fx-group.js';
15
15
  import './src/ui/fx-hint.js';
16
16
  import './src/ui/fx-output.js';
17
17
  import './src/ui/fx-repeat.js';
18
+ import './src/ui/fx-repeat-attributes.js';
18
19
  import './src/ui/fx-switch.js';
19
20
  import './src/ui/fx-trigger.js';
20
21
  import './src/ui/fx-case.js';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jinntec/fore",
3
- "version": "1.3.0",
3
+ "version": "1.5.0",
4
4
  "description": "Fore - declarative user interfaces in plain HTML",
5
5
  "module": "./index.js",
6
6
  "publishConfig": {
@@ -130,7 +130,12 @@ fx-hint{
130
130
  display: none;
131
131
  }
132
132
 
133
- fx-model, fx-model *, fx-model ::slotted(fx-instance), fx-instance{
133
+ fx-model,
134
+ fx-model *,
135
+ fx-model ::slotted(fx-instance),
136
+ fx-instance,
137
+ fx-action,
138
+ fx-setvalue{
134
139
  display:none;
135
140
  }
136
141
 
@@ -100,6 +100,10 @@ export const foreElementMixin = superclass =>
100
100
  */
101
101
  evalInContext() {
102
102
  // const inscopeContext = this.getInScopeContext();
103
+ const model = this.getModel();
104
+ if(!model){
105
+ return;
106
+ }
103
107
  let inscopeContext;
104
108
  if (this.hasAttribute('context')) {
105
109
  inscopeContext = getInScopeContext(this.getAttributeNode('context') || this, this.context);
@@ -22,12 +22,39 @@ export class AbstractAction extends foreElementMixin(HTMLElement) {
22
22
  static get properties() {
23
23
  return {
24
24
  ...super.properties,
25
+ /**
26
+ * can be either 'cancel' or 'perform' (default)
27
+ */
28
+ defaultAction:{
29
+ type: String
30
+ },
31
+ /**
32
+ * delay before executing action in milliseconds
33
+ */
34
+ delay: {
35
+ type: Number,
36
+ },
25
37
  /**
26
38
  * detail - event detail object
27
39
  */
28
40
  detail: {
29
41
  type: Object,
30
42
  },
43
+ /**
44
+ * event to listen for
45
+ */
46
+ event: {
47
+ type: Object,
48
+ },
49
+ handler:{
50
+ type:Object,
51
+ },
52
+ /**
53
+ * boolean XPath expression. If true the action will be executed.
54
+ */
55
+ ifExpr: {
56
+ type: String,
57
+ },
31
58
  /**
32
59
  * wether nor not an action needs to run the update cycle
33
60
  */
@@ -35,21 +62,22 @@ export class AbstractAction extends foreElementMixin(HTMLElement) {
35
62
  type: Boolean,
36
63
  },
37
64
  /**
38
- * event to listen for
65
+ * The observer if given is the element on which an event is triggered. It must be an ancestor of the target
66
+ * element of an event.
39
67
  */
40
- event: {
41
- type: Object,
68
+ observer:{
69
+ type:Object,
42
70
  },
43
71
  /**
44
- * id of target element to attach listener to
72
+ * can be either 'stop' or 'continue' (default)
45
73
  */
46
- target: {
74
+ propagate:{
47
75
  type: String,
48
76
  },
49
77
  /**
50
- * boolean XPath expression. If true the action will be executed.
78
+ * id of target element to attach listener to
51
79
  */
52
- ifExpr: {
80
+ target: {
53
81
  type: String,
54
82
  },
55
83
  /**
@@ -59,12 +87,6 @@ export class AbstractAction extends foreElementMixin(HTMLElement) {
59
87
  whileExpr: {
60
88
  type: String,
61
89
  },
62
- /**
63
- * delay before executing action in milliseconds
64
- */
65
- delay: {
66
- type: Number,
67
- },
68
90
  };
69
91
  }
70
92
 
@@ -76,6 +98,7 @@ export class AbstractAction extends foreElementMixin(HTMLElement) {
76
98
 
77
99
  connectedCallback() {
78
100
  this.style.display = 'none';
101
+ this.propagate = this.hasAttribute('propagate')? this.getAttribute('propagate'):'continue';
79
102
  this.repeatContext = undefined;
80
103
 
81
104
  if (this.hasAttribute('event')) {
@@ -117,55 +140,70 @@ export class AbstractAction extends foreElementMixin(HTMLElement) {
117
140
  * @param e
118
141
  */
119
142
  async execute(e) {
143
+ if(this.propagate === 'stop'){
144
+ console.log('event propagation stopped', e)
145
+ e.stopPropagation();
146
+ }
147
+
148
+ let resolveThisEvent = () => {};
149
+ if (e && e.listenerPromises) {
150
+ e.listenerPromises.push(
151
+ new Promise(resolve => {
152
+ resolveThisEvent = resolve;
153
+ }),
154
+ );
155
+ }
156
+
120
157
  // console.log('executing', this);
121
158
 
122
159
  // console.log('executing e', e);
123
160
  // console.log('executing e phase', e.eventPhase);
124
- if(AbstractAction.outermostHandler === null){
161
+ if (AbstractAction.outermostHandler === null) {
162
+ console.time('outermostHandler');
125
163
  console.info(
126
- `%coutermost Action `,
127
- "background:#e65100; color:white; padding:0.3rem; display:inline-block; white-space: nowrap; border-radius:0.3rem;",
128
- this
164
+ `%coutermost Action `,
165
+ 'background:#e65100; color:white; padding:0.3rem; display:inline-block; white-space: nowrap; border-radius:0.3rem;',
166
+ this,
129
167
  );
130
168
  // console.log('starting outermost handler',this);
131
169
  AbstractAction.outermostHandler = this;
132
170
  }
133
171
 
134
- if(AbstractAction.outermostHandler !== this){
172
+ if (AbstractAction.outermostHandler !== this) {
135
173
  console.info(
136
- `%cAction `,
137
- "background:orange; color:white; padding:0.3rem; display:inline-block; white-space: nowrap; border-radius:0.3rem;",
138
- this
174
+ `%cAction `,
175
+ 'background:orange; color:white; padding:0.3rem; display:inline-block; white-space: nowrap; border-radius:0.3rem;',
176
+ this,
139
177
  );
140
178
  }
141
179
  // console.log('>>> outermostHandler', AbstractAction.outermostHandler);
142
180
 
143
- if(e && e.code){
181
+ if (e && e.code) {
144
182
  const vars = new Map();
145
183
  vars.set('code', e.code);
146
184
  // this.setInScopeVariables(vars);
147
- this.setInScopeVariables(new Map([ ...this.inScopeVariables, ...vars]));
185
+ this.setInScopeVariables(new Map([...this.inScopeVariables, ...vars]));
148
186
  }
149
187
 
150
188
  if (e && e.detail) {
151
189
  this.detail = e.detail;
152
190
  const vars = new Map();
153
- Object.keys(e.detail).forEach(function(key,index) {
191
+ Object.keys(e.detail).forEach(function(key, index) {
154
192
  // key: the name of the object key
155
193
  // index: the ordinal position of the key within the object
156
- vars.set(key,e.detail[key]);
194
+ vars.set(key, e.detail[key]);
157
195
  });
158
- if(vars.size !== 0){
159
- console.log("event detail vars", vars);
196
+ if (vars.size !== 0) {
197
+ console.log('event detail vars', vars);
160
198
  }
161
- this.setInScopeVariables(new Map([ ...this.inScopeVariables, ...vars]));
199
+ this.setInScopeVariables(new Map([...this.inScopeVariables, ...vars]));
162
200
  }
163
201
  this.needsUpdate = false;
164
202
 
165
- try{
203
+ try {
166
204
  this.evalInContext();
167
- }catch (error){
168
- console.warn('evaluation faild',error);
205
+ } catch (error) {
206
+ console.warn('evaluation faild', error);
169
207
  }
170
208
  if (this.targetElement && this.targetElement.nodeset) {
171
209
  this.nodeset = this.targetElement.nodeset;
@@ -173,6 +211,7 @@ export class AbstractAction extends foreElementMixin(HTMLElement) {
173
211
 
174
212
  // First check if 'if' condition is true - otherwise exist right away
175
213
  if (this.ifExpr && !evaluateXPathToBoolean(this.ifExpr, getInScopeContext(this), this)) {
214
+ this._finalizePerform(resolveThisEvent);
176
215
  return;
177
216
  }
178
217
 
@@ -196,13 +235,20 @@ export class AbstractAction extends foreElementMixin(HTMLElement) {
196
235
  this.perform();
197
236
 
198
237
  // Go for one more iteration
238
+ if (this.delay) {
239
+ // If we have a delay, fire and forget this.
240
+ // Otherwise, if we have no delay, keep waiting for all iterations to be done.
241
+ // The while is then uninteruptable and immediate
242
+ loop();
243
+ return;
244
+ }
199
245
  await loop();
200
246
  };
201
247
 
202
248
  // After loop is done call actionPerformed to update the model and UI
203
249
  await loop();
204
- this.actionPerformed();
205
- Fore.dispatch(this, 'while-performed', {});
250
+ this._finalizePerform(resolveThisEvent);
251
+
206
252
  return;
207
253
  }
208
254
 
@@ -212,21 +258,28 @@ export class AbstractAction extends foreElementMixin(HTMLElement) {
212
258
  if (!this.ownerDocument.contains(this)) {
213
259
  // We are no longer in the document. Stop working
214
260
  this.actionPerformed();
261
+ resolveThisEvent();
215
262
  return;
216
263
  }
217
264
  }
218
265
 
219
- this.perform();
266
+ await this.perform();
267
+ this._finalizePerform(resolveThisEvent);
268
+ }
269
+
270
+ _finalizePerform(resolveThisEvent) {
220
271
  this.actionPerformed();
221
- if(AbstractAction.outermostHandler === this){
272
+ if (AbstractAction.outermostHandler === this) {
222
273
  AbstractAction.outermostHandler = null;
223
274
  console.info(
224
- `%coutermost Action done`,
225
- "background:#e65100; color:white; padding:0.3rem; display:inline-block; white-space: nowrap; border-radius:0.3rem;",
226
- this
275
+ `%coutermost Action done`,
276
+ 'background:#e65100; color:white; padding:0.3rem; display:inline-block; white-space: nowrap; border-radius:0.3rem;',
277
+ this,
227
278
  );
279
+ console.timeEnd('outermostHandler');
228
280
 
229
281
  }
282
+ resolveThisEvent();
230
283
  }
231
284
 
232
285
  /**
@@ -235,13 +288,7 @@ export class AbstractAction extends foreElementMixin(HTMLElement) {
235
288
  *
236
289
  * This function should not called on any action directly - call execute() instead to ensure proper execution of 'if' and 'while'
237
290
  */
238
- perform() {
239
- console.info(
240
- `%cperform `,
241
- "background:orange; color:white; padding:0.3rem; display:inline-block; white-space: nowrap; border-radius:0.3rem;",
242
- this
243
- );
244
-
291
+ async perform() {
245
292
  //todo: review - this evaluation seems redundant as we already evaluated in execute
246
293
  if (this.isBound() || this.nodeName === 'FX-ACTION') {
247
294
  this.evalInContext();
@@ -252,14 +299,36 @@ export class AbstractAction extends foreElementMixin(HTMLElement) {
252
299
  * calls the update cycle if action signalled that update is needed.
253
300
  */
254
301
  actionPerformed() {
302
+ const model = this.getModel();
303
+ if(!model){
304
+ return;
305
+ }
306
+ if (!model.inited) {
307
+ return;
308
+ }
309
+ if (
310
+ AbstractAction.outermostHandler &&
311
+ !AbstractAction.outermostHandler.ownerDocument.contains(AbstractAction.outermostHandler)
312
+ ) {
313
+ // The old outermosthandler fell out of the document. An error has happened.
314
+ // Just remove the old one and act like we are starting anew.
315
+ console.warn('Unsetting outermost handler');
316
+ AbstractAction.outermostHandler = null;
317
+ }
255
318
  // console.log('actionPerformed action parentNode ', this.parentNode);
256
- // if (this.needsUpdate && AbstractAction.outermostHandler !== this) {
257
- if (this.needsUpdate) {
258
- const model = this.getModel();
319
+ if (
320
+ this.needsUpdate &&
321
+ (AbstractAction.outermostHandler === this || !AbstractAction.outermostHandler)
322
+ ) {
323
+ console.log('Running actionperformed');
259
324
  model.recalculate();
260
325
  model.revalidate();
261
326
  model.parentNode.refresh(true);
262
327
  this.dispatchActionPerformed();
328
+ } else if (this.needsUpdate) {
329
+ // We need an update, but the outermost action handler may not. Make this clear!
330
+ AbstractAction.outermostHandler.needsUpdate = true;
331
+ console.log('Update surpressed!');
263
332
  }
264
333
  }
265
334
 
@@ -31,7 +31,7 @@ export class FxAction extends AbstractAction {
31
31
  `;
32
32
  }
33
33
 
34
- perform() {
34
+ async perform() {
35
35
  super.perform();
36
36
  const { children } = this;
37
37
 
@@ -42,14 +42,14 @@ export class FxAction extends AbstractAction {
42
42
  script.src = this.src;
43
43
  this.appendChild(script);
44
44
  } else {
45
- Array.from(children).forEach(actionOrVar => {
46
- if (actionOrVar.localName === 'fx-var') {
47
- return;
48
- }
49
- const action = actionOrVar;
50
- action.detail = this.detail;
51
- action.execute();
52
- });
45
+ for (const actionOrVar of children) {
46
+ if (actionOrVar.localName === 'fx-var') {
47
+ continue;
48
+ }
49
+ const action = actionOrVar;
50
+ action.detail = this.detail;
51
+ await action.execute();
52
+ }
53
53
  this.dispatchActionPerformed();
54
54
  this.needsUpdate = true;
55
55
  }
@@ -58,7 +58,7 @@ class FxAppend extends AbstractAction {
58
58
  * behavior should be needed for some reason later on, it can be added easier by a providing an 'duplicate' action.
59
59
  *
60
60
  */
61
- perform() {
61
+ async perform() {
62
62
  super.perform();
63
63
 
64
64
  this._dataFromTemplate();
@@ -12,7 +12,7 @@ export class FxConfirm extends FxAction {
12
12
  this.message = this.hasAttribute('message') ? this.getAttribute('message') : null;
13
13
  }
14
14
 
15
- perform() {
15
+ async perform() {
16
16
  if (window.confirm(this.message)) {
17
17
  super.perform();
18
18
  }
@@ -0,0 +1,68 @@
1
+ import '../fx-model.js';
2
+ import {AbstractAction} from './abstract-action.js';
3
+
4
+ /**
5
+ * `fx-copy`
6
+ * todo: demo + tests
7
+ * @customElement
8
+ */
9
+ export default class FxCopy extends AbstractAction {
10
+ static get properties() {
11
+ return {
12
+ ...super.properties,
13
+ ref: {
14
+ type: String,
15
+ },
16
+ to: {
17
+ type: String,
18
+ },
19
+ };
20
+ }
21
+
22
+ constructor() {
23
+ super();
24
+ this.ref = '';
25
+ this.to = '';
26
+ }
27
+
28
+ connectedCallback() {
29
+ if (super.connectedCallback) {
30
+ super.connectedCallback();
31
+ }
32
+
33
+ if (this.hasAttribute('ref')) {
34
+ this.ref = this.getAttribute('ref');
35
+ } else {
36
+ throw new Error('fx-copy must specify a "ref" attribute');
37
+ }
38
+ this.to = this.getAttribute('to');
39
+ }
40
+
41
+ perform() {
42
+ console.log('copying to clipboard')
43
+ super.perform();
44
+
45
+ if(this.nodeset.nodeType === Node.ATTRIBUTE_NODE){
46
+ navigator.clipboard.writeText(this.nodeset.nodeValue);
47
+ }else{
48
+ navigator.clipboard.writeText(this.nodeset);
49
+ }
50
+ }
51
+
52
+ /*
53
+ setValue(modelItem, newVal) {
54
+ const item = modelItem;
55
+ if (!item) return;
56
+
57
+ if (item.value !== newVal) {
58
+ item.value = newVal;
59
+ this.getModel().changed.push(modelItem);
60
+ this.needsUpdate = true;
61
+ }
62
+ }
63
+ */
64
+ }
65
+
66
+ if (!customElements.get('fx-copy')) {
67
+ window.customElements.define('fx-copy', FxCopy);
68
+ }
@@ -22,7 +22,7 @@ class FxDelete extends AbstractAction {
22
22
  *
23
23
  * Will NOT perform delete if nodeset is pointing to document node, document fragment, root node or being readonly.
24
24
  */
25
- perform() {
25
+ async perform() {
26
26
  console.log('##### fx-delete executing...');
27
27
  const inscopeContext = getInScopeContext(this.getAttributeNode('ref') || this, this.ref);
28
28
  this.nodeset = evaluateXPathToNodes(this.ref, inscopeContext, this);
@@ -52,7 +52,7 @@ export class FxDispatch extends AbstractAction {
52
52
 
53
53
  */
54
54
 
55
- perform() {
55
+ async perform() {
56
56
  console.log('### fx-dispatch.perform ', this);
57
57
 
58
58
  const properties = this.querySelectorAll('fx-property');
@@ -17,7 +17,7 @@ export class FxHide extends AbstractAction {
17
17
  }
18
18
  }
19
19
 
20
- perform() {
20
+ async perform() {
21
21
  const dialog = resolveId(this.dialog, this);
22
22
  dialog.hide();
23
23
  Fore.dispatch(dialog,'dialog-hidden',{})
@@ -81,7 +81,7 @@ export class FxInsert extends AbstractAction {
81
81
  return targetSequence.length;
82
82
  }
83
83
 
84
- perform() {
84
+ async perform() {
85
85
  // super.perform();
86
86
 
87
87
  /*
@@ -47,7 +47,7 @@ class FxMessage extends AbstractAction {
47
47
  `;
48
48
  }
49
49
 
50
- perform() {
50
+ async perform() {
51
51
  super.perform();
52
52
  let message;
53
53
  if (this.hasAttribute('value')) {
@@ -9,7 +9,7 @@ import {resolveId} from "../xpath-evaluation.js";
9
9
  *
10
10
  */
11
11
  class FxRefresh extends AbstractAction {
12
- perform() {
12
+ async perform() {
13
13
  if (this.hasAttribute('self')) {
14
14
  const control = Fore.getClosest('fx-control', this);
15
15
  if (control) {
@@ -24,7 +24,7 @@ class FxRefresh extends AbstractAction {
24
24
  if(this.hasAttribute('control')){
25
25
  const targetId = this.getAttribute('control');
26
26
  const ctrl = resolveId(targetId, this);
27
- if (Fore.isUiElement(ctrl.nodeName) && typeof ctrl.refresh === 'function') {
27
+ if (ctrl && Fore.isUiElement(ctrl.nodeName) && typeof ctrl.refresh === 'function') {
28
28
  ctrl.refresh();
29
29
  }
30
30
  return;
@@ -19,7 +19,7 @@ export class FxReload extends AbstractAction {
19
19
  },{once:true});
20
20
  }
21
21
 
22
- perform() {
22
+ async perform() {
23
23
  Fore.dispatch(this, 'reload', {});
24
24
  }
25
25
  }
@@ -32,7 +32,7 @@ export default class FxReplace extends AbstractAction {
32
32
  this.with = this.getAttribute('with');
33
33
  }
34
34
 
35
- perform() {
35
+ async perform() {
36
36
  super.perform();
37
37
  console.log('replace action');
38
38
  // console.log('replace action variables', this.inScopeVariables);
@@ -20,7 +20,7 @@ export class FxReturn extends AbstractAction {
20
20
  // const nonrelevant = this.hasAttribute('nonrelevant') ? this.getAttribute('nonrelevant') : null;
21
21
  }
22
22
 
23
- perform() {
23
+ async perform() {
24
24
  super.perform();
25
25
  console.log('performing return with nodes', this.nodeset);
26
26
 
@@ -22,7 +22,7 @@ class FxSend extends AbstractAction {
22
22
  this.submission = this.getAttribute('submission');
23
23
  }
24
24
 
25
- perform() {
25
+ async perform() {
26
26
  super.perform();
27
27
 
28
28
  console.log('submitting ', this.submission);
@@ -44,7 +44,7 @@ class FxSend extends AbstractAction {
44
44
  throw new Error(`submission with id: ${this.submission} not found`);
45
45
  }
46
46
  console.log('submission', submission);
47
- submission.submit();
47
+ await submission.submit();
48
48
  /*
49
49
  if(submission.replace === 'instance'){
50
50
  this.getModel().updateModel();
@@ -13,7 +13,7 @@ export class FxSetfocus extends AbstractAction {
13
13
  this.control = this.hasAttribute('control') ? this.getAttribute('control') : null;
14
14
  }
15
15
 
16
- perform() {
16
+ async perform() {
17
17
  console.log('setting focus', this.control);
18
18
  // super.perform();
19
19
  const selector = '#'+this.control;
@@ -40,7 +40,7 @@ export default class FxSetvalue extends AbstractAction {
40
40
  this.valueAttr = this.getAttribute('value');
41
41
  }
42
42
 
43
- perform() {
43
+ async perform() {
44
44
  super.perform();
45
45
  let {value} = this;
46
46
  if (this.valueAttr !== null) {
@@ -17,7 +17,7 @@ export class FxShow extends FxAction {
17
17
  }
18
18
  }
19
19
 
20
- perform() {
20
+ async perform() {
21
21
  const targetDlg = resolveId(this.dialog,this);
22
22
  if(!targetDlg){
23
23
  console.error('target dialog with given id does not exist',this.dialog);
@@ -19,7 +19,7 @@ class FxToggle extends AbstractAction {
19
19
  }
20
20
  }
21
21
 
22
- perform() {
22
+ async perform() {
23
23
  super.perform();
24
24
  console.log('### fx-toggle.execute ');
25
25
  if (this.case) {
@@ -7,7 +7,7 @@ import { AbstractAction } from './abstract-action.js';
7
7
  *
8
8
  */
9
9
  class FxUpdate extends AbstractAction {
10
- perform() {
10
+ async perform() {
11
11
  this.getModel().updateModel();
12
12
  }
13
13
  }