sdc_client 0.57.12 → 0.57.15

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.
@@ -1,4 +1,9 @@
1
- import {controllerFactory, runControlFlowFunctions} from "./sdc_controller.js";
1
+ import {
2
+ controllerFactory,
3
+ prepareRefreshProcess,
4
+ runControlFlowFunctions,
5
+ updateEventAndTriggerOnRefresh
6
+ } from "./sdc_controller.js";
2
7
  import {getUrlParam} from "./sdc_params.js";
3
8
  import {app} from "./sdc_main.js";
4
9
  import {trigger} from "./sdc_events.js";
@@ -14,7 +19,7 @@ export const CONTROLLER_CLASS = '_sdc_controller_';
14
19
 
15
20
 
16
21
  export function cleanCache() {
17
- htmlFiles = {};
22
+ htmlFiles = {};
18
23
  }
19
24
 
20
25
  /**
@@ -23,35 +28,35 @@ export function cleanCache() {
23
28
  * doms and returns a list of objects containing also the tag name the dom and the tag
24
29
  * names of the super controller
25
30
  *
26
- * @param {$} $container - jQuery container
31
+ * @param {jquery} $container - jQuery container
27
32
  * @param {Array<string>} tagNameList - a string list with tag names.
28
33
  * @param {AbstractSDC} parentController - controller in surrounding
29
34
  * @return {Array} - a array of objects with all register tags found
30
35
  */
31
36
  function findSdcTgs($container, tagNameList, parentController) {
32
- if (!$container) {
33
- return [];
37
+ if (!$container) {
38
+ return [];
39
+ }
40
+ let $children = $container.children();
41
+ let emptyList = [];
42
+ $children.each(function (_, element) {
43
+ let $element = $(element);
44
+ let tagName = $element.prop('tagName').toLowerCase().split('_');
45
+ if ($.inArray(tagName[0], tagNameList) >= 0) {
46
+ emptyList.push({
47
+ tag: tagName[0],
48
+ super: tagName.splice(1) || [],
49
+ dom: $element
50
+ });
51
+
52
+ } else if (tagName[0].startsWith('this.')) {
53
+ $element.addClass(`_bind_to_update_handler sdc_uuid_${parentController._uuid}`)
54
+ } else {
55
+ emptyList = emptyList.concat(findSdcTgs($element, tagNameList, parentController))
34
56
  }
35
- let $children = $container.children();
36
- let emptyList = [];
37
- $children.each(function (_, element) {
38
- let $element = $(element);
39
- let tagName = $element.prop('tagName').toLowerCase().split('_');
40
- if ($.inArray(tagName[0], tagNameList) >= 0) {
41
- emptyList.push({
42
- tag: tagName[0],
43
- super: tagName.splice(1) || [],
44
- dom: $element
45
- });
46
-
47
- } else if (tagName[0].startsWith('this.')) {
48
- $element.addClass(`_bind_to_update_handler sdc_uuid_${parentController._uuid}`)
49
- } else {
50
- emptyList = emptyList.concat(findSdcTgs($element, tagNameList, parentController))
51
- }
52
- });
57
+ });
53
58
 
54
- return emptyList;
59
+ return emptyList;
55
60
  }
56
61
 
57
62
  /**
@@ -64,15 +69,15 @@ function findSdcTgs($container, tagNameList, parentController) {
64
69
  * @returns {string} - the correct URL with prefix.
65
70
  */
66
71
  function replacePlaceholderController(controller, url, urlValues) {
67
- for (let key_idx in controller._urlParams) {
68
- if (controller._urlParams.hasOwnProperty(key_idx)) {
69
- let key = controller._urlParams[key_idx];
70
- let re = RegExp("%\\(" + key + "\\)\\w", "gm");
71
- url = url.replace(re, "" + urlValues.shift());
72
- }
72
+ for (let key_idx in controller._urlParams) {
73
+ if (controller._urlParams.hasOwnProperty(key_idx)) {
74
+ let key = controller._urlParams[key_idx];
75
+ let re = RegExp("%\\(" + key + "\\)\\w", "gm");
76
+ url = url.replace(re, "" + urlValues.shift());
73
77
  }
78
+ }
74
79
 
75
- return url;
80
+ return url;
76
81
  }
77
82
 
78
83
  /**
@@ -87,30 +92,30 @@ function replacePlaceholderController(controller, url, urlValues) {
87
92
  * @returns {Promise<Boolean>} - waits for the file to be loaded.
88
93
  */
89
94
  function loadHTMLFile(path, args, tag, hardReload) {
90
- if (!path) {
91
- return Promise.resolve(false);
92
- } else if (htmlFiles[tag]) {
93
- return Promise.resolve(htmlFiles[tag])
95
+ if (!path) {
96
+ return Promise.resolve(false);
97
+ } else if (htmlFiles[tag]) {
98
+ return Promise.resolve(htmlFiles[tag])
99
+ }
100
+
101
+ args.VERSION = app.VERSION;
102
+ args._method = 'content';
103
+
104
+ return $.get(path, args).then(function (data) {
105
+ if (!hardReload) {
106
+ htmlFiles[tag] = data;
94
107
  }
95
108
 
96
- args.VERSION = app.VERSION;
97
- args._method = 'content';
98
-
99
- return $.get(path, args).then(function (data) {
100
- if (!hardReload) {
101
- htmlFiles[tag] = data;
102
- }
103
-
104
- return data;
105
- }).catch(function (err) {
106
- if (err.status === 301) {
107
- const data = err.responseJSON;
108
- trigger('_RedirectOnView', data['url-link']);
109
- }
110
- trigger('navLoaded', {'controller_name': () => err.status});
109
+ return data;
110
+ }).catch(function (err) {
111
+ if (err.status === 301) {
112
+ const data = err.responseJSON;
113
+ trigger('_RedirectOnView', data['url-link']);
114
+ }
115
+ trigger('navLoaded', {'controller_name': () => err.status});
111
116
 
112
- throw `<sdc-error data-code="${err.status}">${err.responseText}</sdc-error>`;
113
- });
117
+ throw `<sdc-error data-code="${err.status}">${err.responseText}</sdc-error>`;
118
+ });
114
119
  }
115
120
 
116
121
  /**
@@ -119,10 +124,11 @@ function loadHTMLFile(path, args, tag, hardReload) {
119
124
  *
120
125
  * @param {jquery} $container - given container
121
126
  * @param {AbstractSDC} parentController - parent contoller surrounded the container
127
+ * @param {Object} process - Process object containing the refresh process
122
128
  */
123
- function replaceAllTagElementsInContainer($container, parentController) {
124
- parentController = parentController || $container.data(DATA_CONTROLLER_KEY);
125
- return replaceTagElementsInContainer(app.tagNames, $container, parentController);
129
+ function replaceAllTagElementsInContainer($container, parentController, process = null) {
130
+ parentController = parentController || $container.data(DATA_CONTROLLER_KEY);
131
+ return replaceTagElementsInContainer(app.tagNames, $container, parentController, process);
126
132
  }
127
133
 
128
134
  /**
@@ -133,25 +139,25 @@ function replaceAllTagElementsInContainer($container, parentController) {
133
139
  * @returns {string} - the correct URL with prefix.
134
140
  */
135
141
  function parseContentUrl(controller) {
136
- let url = controller.contentUrl;
137
- if (controller && controller._urlParams.length === 0) {
138
- let re = /%\(([^)]+)\)\w/gm;
139
- let matches;
140
- controller._urlParams = [];
141
- while ((matches = re.exec(url))) {
142
- controller._urlParams.push(matches[1]);
143
- controller.contentReload = true;
144
- }
142
+ let url = controller.contentUrl;
143
+ if (controller && controller._urlParams.length === 0) {
144
+ let re = /%\(([^)]+)\)\w/gm;
145
+ let matches;
146
+ controller._urlParams = [];
147
+ while ((matches = re.exec(url))) {
148
+ controller._urlParams.push(matches[1]);
149
+ controller.contentReload = true;
145
150
  }
151
+ }
146
152
 
147
- let params = getUrlParam(controller, controller.$container);
148
- if (controller._urlParams.length) {
149
- url = replacePlaceholderController(controller, url, params);
150
- }
153
+ let params = getUrlParam(controller, controller.$container);
154
+ if (controller._urlParams.length) {
155
+ url = replacePlaceholderController(controller, url, params);
156
+ }
151
157
 
152
- controller.parsedContentUrl = url;
158
+ controller.parsedContentUrl = url;
153
159
 
154
- return {url: url, args: params[params.length - 1]};
160
+ return {url: url, args: params[params.length - 1]};
155
161
  }
156
162
 
157
163
 
@@ -161,10 +167,10 @@ function parseContentUrl(controller) {
161
167
  * @return {AbstractSDC}
162
168
  */
163
169
  export function getController($elem) {
164
- if ($elem.hasClass(CONTROLLER_CLASS)) {
165
- return $elem.data(`${DATA_CONTROLLER_KEY}`);
166
- }
167
- return $elem.closest(`.${CONTROLLER_CLASS}`).data(`${DATA_CONTROLLER_KEY}`);
170
+ if ($elem.hasClass(CONTROLLER_CLASS)) {
171
+ return $elem.data(`${DATA_CONTROLLER_KEY}`);
172
+ }
173
+ return $elem.closest(`.${CONTROLLER_CLASS}`).data(`${DATA_CONTROLLER_KEY}`);
168
174
  }
169
175
 
170
176
  /**
@@ -179,26 +185,26 @@ export function getController($elem) {
179
185
  * @returns {Promise<jQuery>} - the promise waits to the files are loaded. it returns the jQuery object.
180
186
  */
181
187
  export function loadFilesFromController(controller) {
182
- let getElements = {args: {}};
183
- if (controller.contentUrl) {
184
- getElements = parseContentUrl(controller, controller.contentUrl);
185
- controller.contentUrl = getElements.url;
188
+ let getElements = {args: {}};
189
+ if (controller.contentUrl) {
190
+ getElements = parseContentUrl(controller, controller.contentUrl);
191
+ controller.contentUrl = getElements.url;
192
+ }
193
+
194
+ return Promise.all([
195
+ loadHTMLFile(controller.contentUrl, getElements.args, controller._tagName, controller.contentReload)
196
+ ]).then(function (results) {
197
+ let htmlFile = results[0];
198
+ if (htmlFile) {
199
+ try {
200
+ return $(htmlFile);
201
+ } catch {
202
+ return $('<div></div>').append(htmlFile);
203
+ }
186
204
  }
187
205
 
188
- return Promise.all([
189
- loadHTMLFile(controller.contentUrl, getElements.args, controller._tagName, controller.contentReload)
190
- ]).then(function (results) {
191
- let htmlFile = results[0];
192
- if (htmlFile) {
193
- try {
194
- return $(htmlFile);
195
- } catch {
196
- return $('<div></div>').append(htmlFile);
197
- }
198
- }
199
-
200
- return null;
201
- });
206
+ return null;
207
+ });
202
208
  }
203
209
 
204
210
  /**
@@ -212,15 +218,15 @@ export function loadFilesFromController(controller) {
212
218
  * @returns {Promise<jQuery>} - the promise waits to the files are loaded. it returns the jQuery object.
213
219
  */
214
220
  export function reloadHTMLController(controller) {
215
- if (controller.contentUrl) {
216
- let getElements = parseContentUrl(controller, controller.contentUrl);
217
- controller.contentUrl = getElements.url;
218
- return loadHTMLFile(controller.contentUrl, getElements.args, controller._tagName, controller.contentReload);
219
- }
220
-
221
- return new Promise(resolve => {
222
- resolve($());
223
- });
221
+ if (controller.contentUrl) {
222
+ let getElements = parseContentUrl(controller, controller.contentUrl);
223
+ controller.contentUrl = getElements.url;
224
+ return loadHTMLFile(controller.contentUrl, getElements.args, controller._tagName, controller.contentReload);
225
+ }
226
+
227
+ return new Promise(resolve => {
228
+ resolve($());
229
+ });
224
230
  }
225
231
 
226
232
  /**
@@ -229,18 +235,19 @@ export function reloadHTMLController(controller) {
229
235
  * @param {string} tagName
230
236
  * @param {Array<string>} superTagNameList
231
237
  * @param {AbstractSDC} parentController
232
- * @returns {boolean}
238
+ * @param {Object} process - Process object containing the refresh process
239
+ * @returns {Promise}
233
240
  */
234
- function runReplaceTagElementsInContainer($element, tagName, superTagNameList, parentController) {
235
- let controller = $element.data(DATA_CONTROLLER_KEY);
236
- if (controller) {
237
- return replaceAllTagElementsInContainer($element, controller);
238
- }
239
-
240
- controller = controllerFactory(parentController, $element, tagName, superTagNameList);
241
- $element.data(DATA_CONTROLLER_KEY, controller);
242
- $element.addClass(CONTROLLER_CLASS);
243
- return runControlFlowFunctions(controller, $element);
241
+ function runReplaceTagElementsInContainer($element, tagName, superTagNameList, parentController, process) {
242
+ let controller = $element.data(DATA_CONTROLLER_KEY);
243
+ if (controller) {
244
+ return replaceAllTagElementsInContainer($element, controller, process);
245
+ }
246
+
247
+ controller = controllerFactory(parentController, $element, tagName, superTagNameList);
248
+ $element.data(DATA_CONTROLLER_KEY, controller);
249
+ $element.addClass(CONTROLLER_CLASS);
250
+ return runControlFlowFunctions(controller, process);
244
251
  }
245
252
 
246
253
 
@@ -250,19 +257,20 @@ function runReplaceTagElementsInContainer($element, tagName, superTagNameList, p
250
257
  *
251
258
  * @param {AbstractSDC} controller - js controller instance
252
259
  * @param {jquery} $html - jQuery loaded content
260
+ * @param {Object} process - Process object containing the refresh process
253
261
  * @return {Promise}
254
262
  */
255
- export function runControllerFillContent(controller, $html) {
256
- if ($html && $html.length > 0) {
257
- controller.$container.empty();
258
- controller.$container.attr(controller._tagName, '');
259
- for (let mixinKey in controller._mixins) {
260
- controller.$container.attr(controller._mixins[mixinKey]._tagName, '');
261
- }
262
- controller.$container.append($html);
263
+ export function runControllerFillContent(controller, $html, process = null) {
264
+ if ($html && $html.length > 0) {
265
+ controller.$container.empty();
266
+ controller.$container.attr(controller._tagName, '');
267
+ for (let mixinKey in controller._mixins) {
268
+ controller.$container.attr(controller._mixins[mixinKey]._tagName, '');
263
269
  }
270
+ controller.$container.append($html);
271
+ }
264
272
 
265
- return replaceAllTagElementsInContainer(controller.$container, controller);
273
+ return replaceAllTagElementsInContainer(controller.$container, controller, process);
266
274
  }
267
275
 
268
276
 
@@ -275,171 +283,185 @@ export function runControllerFillContent(controller, $html) {
275
283
  * @param {Array<string>} tagList - list of all registered tags
276
284
  * @param {jquery} $container - jQuery container to find the tags
277
285
  * @param {AbstractSDC} parentController - controller in surrounding
286
+ * @param {Object} process - Process object containing the refresh process
278
287
  */
279
- export function replaceTagElementsInContainer(tagList, $container, parentController) {
280
- return new Promise((resolve) => {
288
+ export function replaceTagElementsInContainer(tagList, $container, parentController, process) {
289
+ return new Promise((resolve) => {
281
290
 
282
- let tagDescriptionElements = findSdcTgs($container, tagList, parentController);
283
- let tagCount = tagDescriptionElements.length;
291
+ let tagDescriptionElements = findSdcTgs($container, tagList, parentController);
292
+ let tagCount = tagDescriptionElements.length;
284
293
 
285
- if (tagCount === 0) {
286
- return resolve();
287
- }
294
+ if (tagCount === 0) {
295
+ return resolve();
296
+ }
288
297
 
289
- for (let elementIndex = 0; elementIndex < tagDescriptionElements.length; elementIndex++) {
290
- runReplaceTagElementsInContainer(tagDescriptionElements[elementIndex].dom,
291
- tagDescriptionElements[elementIndex].tag,
292
- tagDescriptionElements[elementIndex].super,
293
- parentController).then(() => {
294
- tagCount--;
295
- if (tagCount === 0) {
296
- return resolve();
297
- }
298
- });
298
+ for (let elementIndex = 0; elementIndex < tagDescriptionElements.length; elementIndex++) {
299
+ runReplaceTagElementsInContainer(tagDescriptionElements[elementIndex].dom,
300
+ tagDescriptionElements[elementIndex].tag,
301
+ tagDescriptionElements[elementIndex].super,
302
+ parentController, process).then(() => {
303
+ tagCount--;
304
+ if (tagCount === 0) {
305
+ return resolve();
299
306
  }
300
- });
307
+ });
308
+ }
309
+ });
301
310
  }
302
311
 
303
- export function reloadMethodHTML(controller, $container) {
304
- return _reloadMethodHTML(controller, $container ?? controller.$container)
312
+ export function reloadMethodHTML(controller, $container, process) {
313
+ return _reloadMethodHTML(controller, $container ?? controller.$container, process)
305
314
  }
306
315
 
307
- function _reloadMethodHTML(controller, $dom) {
308
- const plist = [];
316
+ function _reloadMethodHTML(controller, $dom, process) {
317
+ const plist = [];
318
+
319
+ $dom.find(`._bind_to_update_handler.sdc_uuid_${controller._uuid}`).each(function () {
320
+ const $this = $(this);
321
+ let result = undefined;
322
+ if ($this.hasClass(`_with_handler`)) {
323
+ result = $this.data('handler');
324
+ } else {
325
+ let controller_handler = this.tagName.toLowerCase().replace(/^this./, '');
326
+ if (controller[controller_handler]) {
327
+ result = controller[controller_handler];
328
+ }
329
+ }
309
330
 
310
- $dom.find(`._bind_to_update_handler.sdc_uuid_${controller._uuid}`).each(function () {
311
- const $this = $(this);
312
- let result = undefined;
313
- if ($this.hasClass(`_with_handler`)) {
314
- result = $this.data('handler');
315
- } else {
316
- let controller_handler = this.tagName.toLowerCase().replace(/^this./, '');
317
- if (controller[controller_handler]) {
318
- result = controller[controller_handler];
319
- }
320
- }
321
331
 
332
+ if (typeof result === 'function') {
333
+ result = result.bind(controller)($this.data());
334
+ }
335
+ if (result !== undefined) {
336
+ plist.push(Promise.resolve(result).then((x) => {
337
+ let $newContent = $(`<div></div>`);
338
+ $newContent.append(x);
322
339
 
323
- if (typeof result === 'function') {
324
- result = result.bind(controller)($this.data());
325
- }
326
- if (result !== undefined) {
327
- plist.push(Promise.resolve(result).then((x) => {
328
- let $newContent = $(`<div></div>`);
329
- $newContent.append(x);
330
- $newContent = $this.clone().empty().append($newContent);
331
- return controller.reconcile($newContent, $this);
332
- }));
340
+ if ($this.html() === '') {
341
+ $this.append('<div></div>');
333
342
  }
334
343
 
335
- });
344
+ return app.reconcile(controller, $newContent, $this.children(), process);
345
+ }));
346
+ }
347
+
348
+ });
336
349
 
337
- return Promise.all(plist);
350
+ return Promise.all(plist);
338
351
  }
339
352
 
340
353
 
341
354
  function getNodeKey(node) {
342
- if (node[0].nodeType === 3) {
343
- return `TEXT__${node[0].nodeValue}`;
344
- }
345
- const res = [node[0].tagName];
346
- if (node[0].nodeName === 'INPUT') {
347
- [['name', ''], ['type', 'text'], ['id', '']].forEach(([key, defaultValue]) => {
348
- const attr = node.attr(key) ?? defaultValue;
349
- if (attr) {
350
- res.push(attr);
351
- }
352
- });
353
- }
354
- return res.join('__');
355
+ if (node[0].nodeType === 3) {
356
+ return `TEXT__${node[0].nodeValue}`;
357
+ }
358
+ const res = [node[0].tagName];
359
+ if (node[0].nodeName === 'INPUT') {
360
+ [['name', ''], ['type', 'text'], ['id', '']].forEach(([key, defaultValue]) => {
361
+ const attr = node.attr(key) ?? defaultValue;
362
+ if (attr) {
363
+ res.push(attr);
364
+ }
365
+ });
366
+ }
367
+ return res.join('__');
355
368
  }
356
369
 
357
- function reconcileTree($element, id = [], parent = null) {
358
- id.push(getNodeKey($element));
359
- const obj = {
360
- $element,
361
- id: id.join('::'),
362
- depth: id.length,
363
- idx: 0,
364
- op: null,
365
- parent
366
- };
367
- return [obj].concat($element.contents().toArray().map((x) => reconcileTree($(x), id.slice(), obj)).flat());
370
+ function reconcileTree({$element, id = [], parent = null}) {
371
+ id.push(getNodeKey($element));
372
+ const obj = {
373
+ $element,
374
+ id: id.join('::'),
375
+ depth: id.length,
376
+ idx: 0,
377
+ getRealParent: () => parent,
378
+ getIdx: function () {
379
+ this.idx = (this.getRealParent()?.getIdx() ?? -1) + $element.index() + 1;
380
+ return this.idx;
381
+ },
382
+ op: null,
383
+ parent
384
+ };
385
+ obj.getIdx.bind(obj);
386
+ return [obj].concat($element.contents().toArray().map((x) => reconcileTree({
387
+ $element: $(x),
388
+ id: id.slice(),
389
+ parent: obj
390
+ })).flat());
368
391
 
369
392
  }
370
393
 
371
394
 
372
395
  export function reconcile($virtualNode, $realNode) {
373
- const $old = reconcileTree($realNode);
374
- const $new = reconcileTree($virtualNode);
375
- $old.map((x, i) => x.idx = i);
376
- $new.map((x, i) => x.idx = i);
377
- const depth = Math.max(...$new.concat($old).map(x => x.depth));
378
- const op_steps = lcbDiff($old, $new, depth);
379
- let opIdx = 0;
380
- let toRemove = [];
381
-
382
- op_steps.forEach(op_step => {
383
- const {op, $element, idx} = op_step;
384
- if (op.type === 'keep_counterpart') {
385
-
386
- if (op.counterpart.idx + opIdx !== idx) {
387
- const elemBefore = op_step.getBefore();
388
- if (!elemBefore) {
389
- op_step.getRealParent().$element.prepend(op.counterpart.$element);
390
- } else {
391
- op.counterpart.$element.insertAfter(elemBefore.$element);
392
- }
393
- }
394
-
395
- syncAttributes(op.counterpart.$element, $element);
396
- if ($element.hasClass(CONTROLLER_CLASS)) {
397
- $element.data(DATA_CONTROLLER_KEY).$container = op.counterpart.$element;
398
- $element.data(DATA_CONTROLLER_KEY, null);
399
- }
400
-
401
- toRemove.push($element);
402
-
403
- } else if (op.type === 'delete') {
404
- $element.safeRemove();
405
- opIdx--;
406
- } else if (op.type === 'insert_ignore') {
407
- opIdx++;
408
- } else if (op.type === 'insert') {
409
- opIdx++;
410
- const {after, target} = op_step.op;
411
- if (after) {
412
- $element.insertAfter(after.$element);
413
- } else if (target) {
414
- target.$element.prepend($element);
415
- }
416
396
 
397
+ const $old = reconcileTree({$element: $realNode});
398
+ const $new = reconcileTree({$element: $virtualNode});
399
+ $old.map((x, i) => x.idx = i);
400
+ $new.map((x, i) => x.idx = i);
401
+ const depth = Math.max(...$new.concat($old).map(x => x.depth));
402
+ const op_steps = lcbDiff($old, $new, depth);
403
+ let toRemove = [];
404
+ window.MAIN = $realNode;
405
+ window.OPS = op_steps;
406
+
407
+ op_steps.forEach((op_step, i) => {
408
+ const {op, $element, idx} = op_step;
409
+
410
+ if (op.type === 'keep_counterpart') {
411
+ let cIdx = op.counterpart.getIdx();
412
+ if (cIdx !== idx) {
413
+ const elemBefore = op_step.getBefore();
414
+ if (!elemBefore) {
415
+ op_step.getRealParent().$element.prepend(op.counterpart.$element);
416
+ } else {
417
+ op.counterpart.$element.insertAfter(elemBefore.$element);
417
418
  }
418
- });
419
+ }
420
+
421
+ syncAttributes(op.counterpart.$element, $element);
422
+ if ($element.hasClass(CONTROLLER_CLASS)) {
423
+ $element.data(DATA_CONTROLLER_KEY).$container = op.counterpart.$element;
424
+ $element.data(DATA_CONTROLLER_KEY, null);
425
+ }
426
+
427
+ toRemove.push($element);
428
+ } else if (op.type === 'delete') {
429
+ $element.safeRemove();
430
+ } else if (op.type === 'insert') {
431
+ const {after, target} = op_step.op;
432
+ if (after) {
433
+ $element.insertAfter(after.$element);
434
+ } else if (target) {
435
+ target.$element.prepend($element);
436
+ }
419
437
 
420
- toRemove.forEach(($element) => $element.safeRemove());
438
+ }
439
+ });
440
+
441
+ toRemove.forEach(($element) => $element.safeRemove());
421
442
  }
422
443
 
423
444
  function syncAttributes($real, $virtual) {
424
- const realAttrs = $real[0].attributes ?? [];
425
- const virtualAttrs = $virtual[0].attributes ?? [];
426
- // Remove missing attrs
427
- [...realAttrs].forEach(attr => {
428
- if (!$virtual.is(`[${attr.name}]`)) {
429
- $real.removeAttr(attr.name);
430
- }
431
- });
445
+ const realAttrs = $real[0].attributes ?? [];
446
+ const virtualAttrs = $virtual[0].attributes ?? [];
447
+ // Remove missing attrs
448
+ [...realAttrs].forEach(attr => {
449
+ if (!$virtual.is(`[${attr.name}]`)) {
450
+ $real.removeAttr(attr.name);
451
+ }
452
+ });
432
453
 
433
- // Add or update
434
- [...virtualAttrs].forEach(attr => {
435
- if (!attr.name.startsWith(`data`) && $real.attr(attr.name) !== attr.value) {
436
- $real.attr(attr.name, attr.value);
437
- }
438
- });
454
+ // Add or update
455
+ [...virtualAttrs].forEach(attr => {
456
+ if (!attr.name.startsWith(`data`) && $real.attr(attr.name) !== attr.value) {
457
+ $real.attr(attr.name, attr.value);
458
+ }
459
+ });
439
460
 
440
- Object.entries($virtual.data()).forEach(([key, value]) => {
441
- $real.data(key, value);
442
- });
461
+ $real.removeData();
462
+ Object.entries($virtual.data()).forEach(([key, value]) => {
463
+ $real.data(key, value);
464
+ });
443
465
  }
444
466
 
445
467
  /**
@@ -451,79 +473,110 @@ function syncAttributes($real, $virtual) {
451
473
  * @returns {*|*[]}
452
474
  */
453
475
  function lcbDiff(oldNodes, newNodes, depth) {
454
- newNodes.filter(x => x.depth === depth && !x.op).forEach((newNode) => {
455
- const oldNode = oldNodes.find((tempOldNode) => {
456
- return !tempOldNode.op && tempOldNode.id === newNode.id;
457
- });
458
-
459
- if (oldNode) {
460
- const keepTreeBranch = (oldNode, newNode) => {
461
- oldNode.op = {type: 'keep', idx: newNode.idx};
462
- newNode.op = {type: 'keep_counterpart', counterpart: oldNode};
463
- oldNode = oldNode.parent;
464
- if (!oldNode || oldNode.op) {
465
- return;
466
- }
467
- newNode = newNode.parent;
468
- keepTreeBranch(oldNode, newNode);
469
-
470
- }
471
- keepTreeBranch(oldNode, newNode);
472
- }
476
+ newNodes.filter(x => x.depth === depth && !x.op).forEach((newNode) => {
477
+ const oldNode = oldNodes.find((tempOldNode) => {
478
+ return !tempOldNode.op && tempOldNode.id === newNode.id;
473
479
  });
474
- if (depth > 1) {
475
- return lcbDiff(oldNodes, newNodes, depth - 1);
476
- }
477
480
 
478
- oldNodes.forEach((x, i) => {
479
- if (!x.op) {
480
- const idx = (oldNodes[i - 1]?.op.idx ?? -1) + 1;
481
- x.op = {type: 'delete', idx}
481
+ if (oldNode) {
482
+ const keepTreeBranch = (oldNode, newNode) => {
483
+ oldNode.op = {type: 'keep', idx: newNode.idx};
484
+ newNode.op = {type: 'keep_counterpart', counterpart: oldNode};
485
+ oldNode = oldNode.parent;
486
+ newNode = newNode.parent;
487
+ if (!oldNode || oldNode.op || newNode?.op) {
488
+ return;
482
489
  }
483
- });
490
+ keepTreeBranch(oldNode, newNode);
484
491
 
485
- function getRealParent(element) {
486
- if (!element.parent) {
487
- return null;
488
- }
489
- return element.parent.op.type === 'keep_counterpart' ? element.parent.op.counterpart : element.parent;
492
+ }
493
+ keepTreeBranch(oldNode, newNode);
490
494
  }
495
+ });
496
+ if (depth > 1) {
497
+ return lcbDiff(oldNodes, newNodes, depth - 1);
498
+ }
499
+
500
+ oldNodes.forEach((x, i) => {
501
+ if (!x.op) {
502
+ const idx = (oldNodes[i - 1]?.op.idx ?? -1) + 1;
503
+ x.op = {type: 'delete', idx}
504
+ }
505
+ });
491
506
 
492
- function getBefore(element, idx) {
493
- const startDepth = element.depth;
494
- while (idx >= 0 && element.depth >= startDepth) {
495
- idx -= 1;
496
- element = newNodes[idx];
497
- if (element.depth === startDepth) {
498
- return element.op.type === 'keep_counterpart' ? element.op.counterpart : element;
499
- }
500
- }
507
+ function getRealParent(element) {
508
+ if (!element.parent) {
509
+ return null;
510
+ }
511
+ return element.parent.op.type === 'keep_counterpart' ? element.parent.op.counterpart : element.parent;
512
+ }
513
+
514
+ function getBefore(element, idx) {
515
+ const startDepth = element.depth;
516
+ while (idx >= 1 && element.depth >= startDepth) {
517
+ idx -= 1;
518
+ element = newNodes[idx];
519
+ if (element.depth === startDepth) {
520
+ return element.op.type === 'keep_counterpart' ? element.op.counterpart : element;
521
+ }
522
+ }
523
+
524
+ return null
501
525
 
502
- return null
526
+ }
503
527
 
528
+ newNodes.forEach((x, i) => {
529
+ x.getBefore = () => getBefore(x, i);
530
+ x.getRealParent = () => getRealParent(x);
531
+
532
+ if (!x.op) {
533
+ const target = x.getRealParent();
534
+ const type = target?.op.type === 'insert' ? 'insert_ignore' : 'insert';
535
+ x.op = {type, target, after: x.getBefore()}
504
536
  }
537
+ });
505
538
 
506
- newNodes.forEach((x, i) => {
507
- x.getBefore = () => getBefore(x, i);
508
- x.getRealParent = () => getRealParent(x);
539
+ const tagged = [
540
+ ...oldNodes,
541
+ ...newNodes,
542
+ ];
509
543
 
510
- if (!x.op) {
511
- const target = x.getRealParent();
512
- const type = target?.op.type === 'insert' ? 'insert_ignore' : 'insert';
513
- x.op = {type, target, after: x.getBefore()}
514
- }
515
- });
516
544
 
517
- const tagged = [
518
- ...oldNodes,
519
- ...newNodes,
520
- ];
545
+ return tagged.sort((a, b) => {
546
+ const aVal = a.op?.idx ?? a.idx;
547
+ const bVal = b.op?.idx ?? b.idx;
521
548
 
549
+ return aVal - bVal;
550
+ });
551
+ }
522
552
 
523
- return tagged.sort((a, b) => {
524
- const aVal = a.op?.idx ?? a.idx;
525
- const bVal = b.op?.idx ?? b.idx;
553
+ /**
554
+ *
555
+ * @param {jquery} $dom
556
+ * @param {AbstractSDC} leafController
557
+ * @param {Object} process - Process object containing the refresh process
558
+ * @return {Promise<void>}
559
+ */
560
+
561
+ export function refresh($dom, leafController, process = null) {
562
+ if (!leafController) {
563
+ leafController = getController($dom);
564
+ }
526
565
 
527
- return aVal - bVal;
566
+ if (!leafController) {
567
+ return Promise.resolve();
568
+ }
569
+
570
+ const {refreshProcess, isRunningProcess} = prepareRefreshProcess(process, leafController);
571
+
572
+ $dom ??= leafController.$container;
573
+
574
+ return replaceTagElementsInContainer(app.tagNames, $dom, leafController, process).then(() => {
575
+ reloadMethodHTML(leafController, $dom, refreshProcess).then(() => {
576
+ if (!isRunningProcess) {
577
+ updateEventAndTriggerOnRefresh(refreshProcess);
578
+ }
528
579
  });
580
+
581
+ });
529
582
  }