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.
- package/.idea/workspace.xml +11 -20
- package/dist/index.js +7 -7
- package/dist/ugly.index.js +1 -1
- package/package.json +2 -2
- package/src/simpleDomControl/AbstractSDC.js +4 -4
- package/src/simpleDomControl/sdc_controller.js +69 -17
- package/src/simpleDomControl/sdc_dom_events.js +1 -1
- package/src/simpleDomControl/sdc_main.js +361 -367
- package/src/simpleDomControl/sdc_socket.js +7 -4
- package/src/simpleDomControl/sdc_utils.js +1 -1
- package/src/simpleDomControl/sdc_view.js +364 -311
- package/test/dist.test.js +1 -1
- package/test/view.test.js +18 -1
|
@@ -1,4 +1,9 @@
|
|
|
1
|
-
import {
|
|
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
|
-
|
|
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 {
|
|
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
|
-
|
|
33
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
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
|
-
|
|
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
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
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
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
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
|
-
|
|
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
|
-
|
|
125
|
-
|
|
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
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
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
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
153
|
+
let params = getUrlParam(controller, controller.$container);
|
|
154
|
+
if (controller._urlParams.length) {
|
|
155
|
+
url = replacePlaceholderController(controller, url, params);
|
|
156
|
+
}
|
|
151
157
|
|
|
152
|
-
|
|
158
|
+
controller.parsedContentUrl = url;
|
|
153
159
|
|
|
154
|
-
|
|
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
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
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
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
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
|
|
189
|
-
|
|
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
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
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
|
-
* @
|
|
238
|
+
* @param {Object} process - Process object containing the refresh process
|
|
239
|
+
* @returns {Promise}
|
|
233
240
|
*/
|
|
234
|
-
function runReplaceTagElementsInContainer($element, tagName, superTagNameList, parentController) {
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
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
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
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
|
-
|
|
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
|
-
|
|
288
|
+
export function replaceTagElementsInContainer(tagList, $container, parentController, process) {
|
|
289
|
+
return new Promise((resolve) => {
|
|
281
290
|
|
|
282
|
-
|
|
283
|
-
|
|
291
|
+
let tagDescriptionElements = findSdcTgs($container, tagList, parentController);
|
|
292
|
+
let tagCount = tagDescriptionElements.length;
|
|
284
293
|
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
294
|
+
if (tagCount === 0) {
|
|
295
|
+
return resolve();
|
|
296
|
+
}
|
|
288
297
|
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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 (
|
|
324
|
-
|
|
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
|
-
|
|
350
|
+
return Promise.all(plist);
|
|
338
351
|
}
|
|
339
352
|
|
|
340
353
|
|
|
341
354
|
function getNodeKey(node) {
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
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
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
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
|
-
|
|
438
|
+
}
|
|
439
|
+
});
|
|
440
|
+
|
|
441
|
+
toRemove.forEach(($element) => $element.safeRemove());
|
|
421
442
|
}
|
|
422
443
|
|
|
423
444
|
function syncAttributes($real, $virtual) {
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
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
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
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
|
-
|
|
441
|
-
|
|
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
|
-
|
|
455
|
-
|
|
456
|
-
|
|
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
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
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
|
-
|
|
486
|
-
|
|
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
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
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
|
-
|
|
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
|
-
|
|
507
|
-
|
|
508
|
-
|
|
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
|
-
|
|
518
|
-
|
|
519
|
-
|
|
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
|
-
|
|
524
|
-
|
|
525
|
-
|
|
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
|
-
|
|
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
|
}
|