sdc_client 0.58.6 → 0.158.1
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/.github/workflows/node.js.yml +2 -2
- package/.idea/inspectionProfiles/Project_Default.xml +17 -0
- package/.idea/workspace.xml +122 -23
- package/.readthedocs.yaml +13 -0
- package/dist/index.js +70 -51
- package/dist/ugly.index.js +1 -1
- package/docs/api-reference.rst +225 -0
- package/docs/conf.py +11 -0
- package/docs/controllers.rst +228 -0
- package/docs/events-and-dom.rst +120 -0
- package/docs/getting-started.rst +143 -0
- package/docs/index.rst +22 -0
- package/docs/models.rst +351 -0
- package/docs/overview.rst +66 -0
- package/docs/requirements.txt +1 -0
- package/eslint.config.js +60 -0
- package/gulp/gulp.jsx +15 -13
- package/package.json +13 -3
- package/src/index.js +44 -11
- package/src/simpleDomControl/AbstractSDC.js +287 -286
- package/src/simpleDomControl/sdc_controller.js +157 -132
- package/src/simpleDomControl/sdc_dom_events.js +99 -88
- package/src/simpleDomControl/sdc_events.js +39 -40
- package/src/simpleDomControl/sdc_main.js +88 -67
- package/src/simpleDomControl/sdc_model.js +1513 -0
- package/src/simpleDomControl/sdc_params.js +44 -29
- package/src/simpleDomControl/sdc_server_call.js +153 -154
- package/src/simpleDomControl/sdc_socket.js +8 -829
- package/src/simpleDomControl/sdc_test_utils.js +77 -80
- package/src/simpleDomControl/sdc_utils.js +295 -176
- package/src/simpleDomControl/sdc_view.js +245 -177
- package/test/model.test.js +332 -0
- package/test/models/Author.js +145 -0
- package/test/models/Book.js +112 -0
- package/test/models/BookContent.js +114 -0
- package/test/models/SdcUser.js +75 -0
- package/test/models/src.js +8 -0
- package/test/sdc_model_dates.ai.test.js +57 -0
- package/test/sdc_server_call.ai.test.js +267 -0
|
@@ -2,11 +2,11 @@ import {
|
|
|
2
2
|
controllerFactory,
|
|
3
3
|
prepareRefreshProcess,
|
|
4
4
|
runControlFlowFunctions,
|
|
5
|
-
updateEventAndTriggerOnRefresh
|
|
5
|
+
updateEventAndTriggerOnRefresh,
|
|
6
6
|
} from "./sdc_controller.js";
|
|
7
|
-
import {getUrlParam, prepareData} from "./sdc_params.js";
|
|
8
|
-
import {app} from "./sdc_main.js";
|
|
9
|
-
import {trigger} from "./sdc_events.js";
|
|
7
|
+
import { getUrlParam, prepareData } from "./sdc_params.js";
|
|
8
|
+
import { app } from "./sdc_main.js";
|
|
9
|
+
import { trigger } from "./sdc_events.js";
|
|
10
10
|
|
|
11
11
|
/**
|
|
12
12
|
* List of HTML files.
|
|
@@ -14,9 +14,8 @@ import {trigger} from "./sdc_events.js";
|
|
|
14
14
|
*/
|
|
15
15
|
let htmlFiles = {};
|
|
16
16
|
|
|
17
|
-
export const DATA_CONTROLLER_KEY =
|
|
18
|
-
export const CONTROLLER_CLASS =
|
|
19
|
-
|
|
17
|
+
export const DATA_CONTROLLER_KEY = "_controller_";
|
|
18
|
+
export const CONTROLLER_CLASS = "_sdc_controller_";
|
|
20
19
|
|
|
21
20
|
export function cleanCache() {
|
|
22
21
|
htmlFiles = {};
|
|
@@ -41,18 +40,21 @@ function findSdcTgs($container, tagNameList, parentController) {
|
|
|
41
40
|
let emptyList = [];
|
|
42
41
|
$children.each(function (_, element) {
|
|
43
42
|
let $element = $(element);
|
|
44
|
-
let tagName = $element.prop(
|
|
43
|
+
let tagName = $element.prop("tagName").toLowerCase().split("_");
|
|
45
44
|
if ($.inArray(tagName[0], tagNameList) >= 0) {
|
|
46
45
|
emptyList.push({
|
|
47
46
|
tag: tagName[0],
|
|
48
47
|
super: tagName.splice(1) || [],
|
|
49
|
-
dom: $element
|
|
48
|
+
dom: $element,
|
|
50
49
|
});
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
50
|
+
} else if (tagName[0].startsWith("this.")) {
|
|
51
|
+
$element.addClass(
|
|
52
|
+
`_bind_to_update_handler sdc_uuid_${parentController._uuid}`,
|
|
53
|
+
);
|
|
54
54
|
} else {
|
|
55
|
-
emptyList = emptyList.concat(
|
|
55
|
+
emptyList = emptyList.concat(
|
|
56
|
+
findSdcTgs($element, tagNameList, parentController),
|
|
57
|
+
);
|
|
56
58
|
}
|
|
57
59
|
});
|
|
58
60
|
|
|
@@ -90,33 +92,35 @@ function replacePlaceholderController(controller, url, urlValues) {
|
|
|
90
92
|
* @returns {Promise<jQuery|Boolean>} - waits for the file to be loaded.
|
|
91
93
|
*/
|
|
92
94
|
function loadHTMLFile(controller, args) {
|
|
93
|
-
const {contentUrl, _tagName, contentReload} = controller
|
|
95
|
+
const { contentUrl, _tagName, contentReload } = controller;
|
|
94
96
|
if (!contentUrl) {
|
|
95
97
|
return Promise.resolve(false);
|
|
96
98
|
} else if (htmlFiles[_tagName]) {
|
|
97
|
-
return Promise.resolve(htmlFiles[_tagName])
|
|
99
|
+
return Promise.resolve(htmlFiles[_tagName]);
|
|
98
100
|
}
|
|
99
101
|
|
|
100
102
|
args.VERSION = app.VERSION;
|
|
101
|
-
args._method =
|
|
103
|
+
args._method = "content";
|
|
102
104
|
|
|
103
|
-
return $.get(contentUrl, args)
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
105
|
+
return $.get(contentUrl, args)
|
|
106
|
+
.then(function (data) {
|
|
107
|
+
if (!contentReload) {
|
|
108
|
+
htmlFiles[_tagName] = data;
|
|
109
|
+
}
|
|
107
110
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
111
|
+
return data;
|
|
112
|
+
})
|
|
113
|
+
.catch(function (err) {
|
|
114
|
+
if (err.status === 301) {
|
|
115
|
+
const data = err.responseJSON;
|
|
116
|
+
trigger("_RedirectOnView", data["url-link"]);
|
|
117
|
+
}
|
|
118
|
+
if (typeof controller.confirmPageLoaded === "function") {
|
|
119
|
+
trigger("navLoaded", { controller_name: () => err.status });
|
|
120
|
+
}
|
|
117
121
|
|
|
118
|
-
|
|
119
|
-
|
|
122
|
+
throw `<sdc-error data-code="${err.status}">${err.responseText}</sdc-error>`;
|
|
123
|
+
});
|
|
120
124
|
}
|
|
121
125
|
|
|
122
126
|
/**
|
|
@@ -127,9 +131,18 @@ function loadHTMLFile(controller, args) {
|
|
|
127
131
|
* @param {AbstractSDC} parentController - parent contoller surrounded the container
|
|
128
132
|
* @param {Object} process - Process object containing the refresh process
|
|
129
133
|
*/
|
|
130
|
-
function replaceAllTagElementsInContainer(
|
|
134
|
+
function replaceAllTagElementsInContainer(
|
|
135
|
+
$container,
|
|
136
|
+
parentController,
|
|
137
|
+
process = null,
|
|
138
|
+
) {
|
|
131
139
|
parentController = parentController || $container.data(DATA_CONTROLLER_KEY);
|
|
132
|
-
return replaceTagElementsInContainer(
|
|
140
|
+
return replaceTagElementsInContainer(
|
|
141
|
+
app.tagNames,
|
|
142
|
+
$container,
|
|
143
|
+
parentController,
|
|
144
|
+
process,
|
|
145
|
+
);
|
|
133
146
|
}
|
|
134
147
|
|
|
135
148
|
/**
|
|
@@ -158,10 +171,9 @@ function parseContentUrl(controller) {
|
|
|
158
171
|
|
|
159
172
|
controller.parsedContentUrl = url;
|
|
160
173
|
|
|
161
|
-
return {url: url, args: params[params.length - 1]};
|
|
174
|
+
return { url: url, args: params[params.length - 1] };
|
|
162
175
|
}
|
|
163
176
|
|
|
164
|
-
|
|
165
177
|
/**
|
|
166
178
|
*
|
|
167
179
|
* @param {jquery} $elem
|
|
@@ -186,26 +198,26 @@ export function getController($elem) {
|
|
|
186
198
|
* @returns {Promise<jQuery>} - the promise waits to the files are loaded. it returns the jQuery object.
|
|
187
199
|
*/
|
|
188
200
|
export function loadFilesFromController(controller) {
|
|
189
|
-
let getElements = {args: {}};
|
|
201
|
+
let getElements = { args: {} };
|
|
190
202
|
if (controller.contentUrl) {
|
|
191
203
|
getElements = parseContentUrl(controller);
|
|
192
204
|
controller.contentUrl = getElements.url;
|
|
193
205
|
}
|
|
194
206
|
|
|
195
|
-
return Promise.all([
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
207
|
+
return Promise.all([loadHTMLFile(controller, getElements.args)]).then(
|
|
208
|
+
function (results) {
|
|
209
|
+
let htmlFile = results[0];
|
|
210
|
+
if (htmlFile) {
|
|
211
|
+
try {
|
|
212
|
+
return $(htmlFile);
|
|
213
|
+
} catch {
|
|
214
|
+
return $("<div></div>").append(htmlFile);
|
|
215
|
+
}
|
|
204
216
|
}
|
|
205
|
-
}
|
|
206
217
|
|
|
207
|
-
|
|
208
|
-
|
|
218
|
+
return null;
|
|
219
|
+
},
|
|
220
|
+
);
|
|
209
221
|
}
|
|
210
222
|
|
|
211
223
|
/**
|
|
@@ -225,7 +237,7 @@ export function reloadHTMLController(controller) {
|
|
|
225
237
|
return loadHTMLFile(controller, getElements.args);
|
|
226
238
|
}
|
|
227
239
|
|
|
228
|
-
return new Promise(resolve => {
|
|
240
|
+
return new Promise((resolve) => {
|
|
229
241
|
resolve($());
|
|
230
242
|
});
|
|
231
243
|
}
|
|
@@ -239,19 +251,29 @@ export function reloadHTMLController(controller) {
|
|
|
239
251
|
* @param {Object} process - Process object containing the refresh process
|
|
240
252
|
* @returns {Promise}
|
|
241
253
|
*/
|
|
242
|
-
function runReplaceTagElementsInContainer(
|
|
254
|
+
function runReplaceTagElementsInContainer(
|
|
255
|
+
$element,
|
|
256
|
+
tagName,
|
|
257
|
+
superTagNameList,
|
|
258
|
+
parentController,
|
|
259
|
+
process,
|
|
260
|
+
) {
|
|
243
261
|
let controller = $element.data(DATA_CONTROLLER_KEY);
|
|
244
262
|
if (controller) {
|
|
245
263
|
return replaceAllTagElementsInContainer($element, controller, process);
|
|
246
264
|
}
|
|
247
265
|
|
|
248
|
-
controller = controllerFactory(
|
|
266
|
+
controller = controllerFactory(
|
|
267
|
+
parentController,
|
|
268
|
+
$element,
|
|
269
|
+
tagName,
|
|
270
|
+
superTagNameList,
|
|
271
|
+
);
|
|
249
272
|
$element.data(DATA_CONTROLLER_KEY, controller);
|
|
250
273
|
$element.addClass(CONTROLLER_CLASS);
|
|
251
274
|
return runControlFlowFunctions(controller, process);
|
|
252
275
|
}
|
|
253
276
|
|
|
254
|
-
|
|
255
277
|
/**
|
|
256
278
|
* runControllerFillContent empties the registered tag and replaces it by the controller
|
|
257
279
|
* content. It sets the CSS tags for the relation with the CSS files.
|
|
@@ -264,17 +286,20 @@ function runReplaceTagElementsInContainer($element, tagName, superTagNameList, p
|
|
|
264
286
|
export function runControllerFillContent(controller, $html, process = null) {
|
|
265
287
|
if ($html && $html.length > 0) {
|
|
266
288
|
controller.$container.empty();
|
|
267
|
-
controller.$container.attr(controller._tagName,
|
|
289
|
+
controller.$container.attr(controller._tagName, "");
|
|
268
290
|
for (let mixinKey in controller._mixins) {
|
|
269
|
-
controller.$container.attr(controller._mixins[mixinKey]._tagName,
|
|
291
|
+
controller.$container.attr(controller._mixins[mixinKey]._tagName, "");
|
|
270
292
|
}
|
|
271
293
|
controller.$container.append($html);
|
|
272
294
|
}
|
|
273
295
|
|
|
274
|
-
return replaceAllTagElementsInContainer(
|
|
296
|
+
return replaceAllTagElementsInContainer(
|
|
297
|
+
controller.$container,
|
|
298
|
+
controller,
|
|
299
|
+
process,
|
|
300
|
+
);
|
|
275
301
|
}
|
|
276
302
|
|
|
277
|
-
|
|
278
303
|
/**
|
|
279
304
|
* replaceTagElementsInContainer Finds all registered tags in a container. But it ignores
|
|
280
305
|
* registered tags in registered tags. For each registered tag it loads the content.
|
|
@@ -286,21 +311,36 @@ export function runControllerFillContent(controller, $html, process = null) {
|
|
|
286
311
|
* @param {AbstractSDC} parentController - controller in surrounding
|
|
287
312
|
* @param {Object} process - Process object containing the refresh process
|
|
288
313
|
*/
|
|
289
|
-
export function replaceTagElementsInContainer(
|
|
314
|
+
export function replaceTagElementsInContainer(
|
|
315
|
+
tagList,
|
|
316
|
+
$container,
|
|
317
|
+
parentController,
|
|
318
|
+
process,
|
|
319
|
+
) {
|
|
290
320
|
return new Promise((resolve) => {
|
|
291
|
-
|
|
292
|
-
|
|
321
|
+
let tagDescriptionElements = findSdcTgs(
|
|
322
|
+
$container,
|
|
323
|
+
tagList,
|
|
324
|
+
parentController,
|
|
325
|
+
);
|
|
293
326
|
let tagCount = tagDescriptionElements.length;
|
|
294
327
|
|
|
295
328
|
if (tagCount === 0) {
|
|
296
329
|
return resolve();
|
|
297
330
|
}
|
|
298
331
|
|
|
299
|
-
for (
|
|
300
|
-
|
|
332
|
+
for (
|
|
333
|
+
let elementIndex = 0;
|
|
334
|
+
elementIndex < tagDescriptionElements.length;
|
|
335
|
+
elementIndex++
|
|
336
|
+
) {
|
|
337
|
+
runReplaceTagElementsInContainer(
|
|
338
|
+
tagDescriptionElements[elementIndex].dom,
|
|
301
339
|
tagDescriptionElements[elementIndex].tag,
|
|
302
340
|
tagDescriptionElements[elementIndex].super,
|
|
303
|
-
parentController,
|
|
341
|
+
parentController,
|
|
342
|
+
process,
|
|
343
|
+
).then(() => {
|
|
304
344
|
tagCount--;
|
|
305
345
|
if (tagCount === 0) {
|
|
306
346
|
return resolve();
|
|
@@ -311,136 +351,157 @@ export function replaceTagElementsInContainer(tagList, $container, parentControl
|
|
|
311
351
|
}
|
|
312
352
|
|
|
313
353
|
export function reloadMethodHTML(controller, $container, process) {
|
|
314
|
-
return _reloadMethodHTML(
|
|
354
|
+
return _reloadMethodHTML(
|
|
355
|
+
controller,
|
|
356
|
+
$container ?? controller.$container,
|
|
357
|
+
process,
|
|
358
|
+
);
|
|
315
359
|
}
|
|
316
360
|
|
|
317
361
|
function _reloadMethodHTML(controller, $dom, process) {
|
|
318
362
|
const plist = [];
|
|
319
363
|
|
|
320
|
-
$dom
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
result =
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
if (typeof result === 'function') {
|
|
334
|
-
const newData = prepareData($this.data());
|
|
335
|
-
result = result.bind(controller)(newData);
|
|
336
|
-
}
|
|
337
|
-
if (result) {
|
|
338
|
-
plist.push(Promise.resolve(result).then((x) => {
|
|
339
|
-
let $newContent = $(`<div></div>`);
|
|
340
|
-
$newContent.append(x);
|
|
341
|
-
|
|
342
|
-
if ($this.html() === '') {
|
|
343
|
-
$this.append('<div></div>');
|
|
364
|
+
$dom
|
|
365
|
+
.find(`._bind_to_update_handler.sdc_uuid_${controller._uuid}`)
|
|
366
|
+
.each(function () {
|
|
367
|
+
const $this = $(this);
|
|
368
|
+
let result = undefined;
|
|
369
|
+
if ($this.hasClass(`_with_handler`)) {
|
|
370
|
+
result = $this.data("handler");
|
|
371
|
+
} else {
|
|
372
|
+
let controller_handler = this.tagName
|
|
373
|
+
.toLowerCase()
|
|
374
|
+
.replace(/^this./, "");
|
|
375
|
+
if (controller[controller_handler]) {
|
|
376
|
+
result = controller[controller_handler];
|
|
344
377
|
}
|
|
378
|
+
}
|
|
345
379
|
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
380
|
+
if (typeof result === "function") {
|
|
381
|
+
const newData = prepareData($this.data());
|
|
382
|
+
result = result.bind(controller)(newData);
|
|
383
|
+
}
|
|
384
|
+
if (result) {
|
|
385
|
+
plist.push(
|
|
386
|
+
Promise.resolve(result).then((x) => {
|
|
387
|
+
let $newContent = $(`<div></div>`);
|
|
388
|
+
$newContent.append(x);
|
|
389
|
+
|
|
390
|
+
if ($this.html() === "") {
|
|
391
|
+
$this.append("<div></div>");
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
return app.reconcile(
|
|
395
|
+
controller,
|
|
396
|
+
$newContent,
|
|
397
|
+
$this.children(),
|
|
398
|
+
process,
|
|
399
|
+
);
|
|
400
|
+
}),
|
|
401
|
+
);
|
|
402
|
+
}
|
|
403
|
+
});
|
|
351
404
|
|
|
352
405
|
return Promise.all(plist);
|
|
353
406
|
}
|
|
354
407
|
|
|
355
|
-
|
|
356
408
|
function getNodeKey(node) {
|
|
357
409
|
if (node[0].nodeType === 3) {
|
|
358
410
|
return `TEXT__${node[0].nodeValue}`;
|
|
359
411
|
}
|
|
360
412
|
const res = [node[0].tagName];
|
|
361
|
-
if (node[0].nodeName ===
|
|
362
|
-
[
|
|
413
|
+
if (node[0].nodeName === "INPUT") {
|
|
414
|
+
[
|
|
415
|
+
["name", ""],
|
|
416
|
+
["type", "text"],
|
|
417
|
+
["id", ""],
|
|
418
|
+
].forEach(([key, defaultValue]) => {
|
|
363
419
|
const attr = node.attr(key) ?? defaultValue;
|
|
364
420
|
if (attr) {
|
|
365
421
|
res.push(attr);
|
|
366
422
|
}
|
|
367
423
|
});
|
|
368
424
|
}
|
|
369
|
-
return res.join(
|
|
425
|
+
return res.join("__");
|
|
370
426
|
}
|
|
371
427
|
|
|
372
|
-
function reconcileTree({$element, id = [], parent = null}) {
|
|
428
|
+
function reconcileTree({ $element, id = [], parent = null }) {
|
|
373
429
|
id.push(getNodeKey($element));
|
|
374
430
|
const obj = {
|
|
375
431
|
$element,
|
|
376
|
-
id: id.join(
|
|
432
|
+
id: id.join("::"),
|
|
377
433
|
depth: id.length,
|
|
378
434
|
idx: 0,
|
|
379
435
|
getRealParent: () => parent,
|
|
380
436
|
getIdx: function () {
|
|
381
|
-
this.idx = Math.max(
|
|
437
|
+
this.idx = Math.max(
|
|
438
|
+
0,
|
|
439
|
+
(this.getRealParent()?.getIdx() ?? -1) + $element.index() + 1,
|
|
440
|
+
);
|
|
382
441
|
return this.idx;
|
|
383
442
|
},
|
|
384
443
|
op: null,
|
|
385
|
-
parent
|
|
444
|
+
parent,
|
|
386
445
|
};
|
|
387
446
|
obj.getIdx.bind(obj);
|
|
388
|
-
return [obj].concat(
|
|
389
|
-
$element
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
447
|
+
return [obj].concat(
|
|
448
|
+
$element
|
|
449
|
+
.contents()
|
|
450
|
+
.toArray()
|
|
451
|
+
.map((x) =>
|
|
452
|
+
reconcileTree({
|
|
453
|
+
$element: $(x),
|
|
454
|
+
id: id.slice(),
|
|
455
|
+
parent: obj,
|
|
456
|
+
}),
|
|
457
|
+
)
|
|
458
|
+
.flat(),
|
|
459
|
+
);
|
|
394
460
|
}
|
|
395
461
|
|
|
396
|
-
|
|
397
462
|
export function reconcile($virtualNode, $realNode) {
|
|
398
|
-
|
|
399
|
-
const $
|
|
400
|
-
|
|
401
|
-
$
|
|
402
|
-
|
|
403
|
-
const depth = Math.max(...$new.concat($old).map(x => x.depth));
|
|
463
|
+
const $old = reconcileTree({ $element: $realNode });
|
|
464
|
+
const $new = reconcileTree({ $element: $virtualNode });
|
|
465
|
+
$old.map((x, i) => (x.idx = i));
|
|
466
|
+
$new.map((x, i) => (x.idx = i));
|
|
467
|
+
const depth = Math.max(...$new.concat($old).map((x) => x.depth));
|
|
404
468
|
const op_steps = lcbDiff($old, $new, depth);
|
|
405
469
|
let toRemove = [];
|
|
406
470
|
window.MAIN = $realNode;
|
|
407
471
|
window.OPS = op_steps;
|
|
408
472
|
|
|
409
473
|
op_steps.forEach((op_step, i) => {
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
}
|
|
421
|
-
}
|
|
422
|
-
|
|
423
|
-
syncAttributes(op.counterpart.$element, $element);
|
|
424
|
-
if ($element.hasClass(CONTROLLER_CLASS)) {
|
|
425
|
-
$element.data(DATA_CONTROLLER_KEY).$container = op.counterpart.$element;
|
|
426
|
-
$element.data(DATA_CONTROLLER_KEY, null);
|
|
474
|
+
const { op, $element, idx } = op_step;
|
|
475
|
+
|
|
476
|
+
if (op.type === "keep_counterpart") {
|
|
477
|
+
let cIdx = op.counterpart.getIdx();
|
|
478
|
+
if (cIdx !== idx) {
|
|
479
|
+
const elemBefore = op_step.getBefore();
|
|
480
|
+
if (!elemBefore) {
|
|
481
|
+
op_step.getRealParent().$element.prepend(op.counterpart.$element);
|
|
482
|
+
} else {
|
|
483
|
+
op.counterpart.$element.insertAfter(elemBefore.$element);
|
|
427
484
|
}
|
|
485
|
+
}
|
|
428
486
|
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
$element.
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
if (after) {
|
|
435
|
-
$element.insertAfter(after.$element);
|
|
436
|
-
} else if (target) {
|
|
437
|
-
target.$element.prepend($element);
|
|
438
|
-
}
|
|
487
|
+
syncAttributes(op.counterpart.$element, $element);
|
|
488
|
+
if ($element.hasClass(CONTROLLER_CLASS)) {
|
|
489
|
+
$element.data(DATA_CONTROLLER_KEY).$container = op.counterpart.$element;
|
|
490
|
+
$element.data(DATA_CONTROLLER_KEY, null);
|
|
491
|
+
}
|
|
439
492
|
|
|
493
|
+
toRemove.push($element);
|
|
494
|
+
} else if (op.type === "delete") {
|
|
495
|
+
$element.safeRemove();
|
|
496
|
+
} else if (op.type === "insert") {
|
|
497
|
+
const { after, target } = op_step.op;
|
|
498
|
+
if (after) {
|
|
499
|
+
$element.insertAfter(after.$element);
|
|
500
|
+
} else if (target) {
|
|
501
|
+
target.$element.prepend($element);
|
|
440
502
|
}
|
|
441
503
|
}
|
|
442
|
-
)
|
|
443
|
-
;
|
|
504
|
+
});
|
|
444
505
|
|
|
445
506
|
toRemove.forEach(($element) => $element.safeRemove());
|
|
446
507
|
}
|
|
@@ -449,14 +510,14 @@ function syncAttributes($real, $virtual) {
|
|
|
449
510
|
const realAttrs = $real[0].attributes ?? [];
|
|
450
511
|
const virtualAttrs = $virtual[0].attributes ?? [];
|
|
451
512
|
// Remove missing attrs
|
|
452
|
-
[...realAttrs].forEach(attr => {
|
|
513
|
+
[...realAttrs].forEach((attr) => {
|
|
453
514
|
if (!$virtual.is(`[${attr.name}]`)) {
|
|
454
515
|
$real.removeAttr(attr.name);
|
|
455
516
|
}
|
|
456
517
|
});
|
|
457
518
|
|
|
458
519
|
// Add or update
|
|
459
|
-
[...virtualAttrs].forEach(attr => {
|
|
520
|
+
[...virtualAttrs].forEach((attr) => {
|
|
460
521
|
if (!attr.name.startsWith(`data`) && $real.attr(attr.name) !== attr.value) {
|
|
461
522
|
$real.attr(attr.name, attr.value);
|
|
462
523
|
}
|
|
@@ -477,26 +538,27 @@ function syncAttributes($real, $virtual) {
|
|
|
477
538
|
* @returns {*|*[]}
|
|
478
539
|
*/
|
|
479
540
|
function lcbDiff(oldNodes, newNodes, depth) {
|
|
480
|
-
newNodes
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
541
|
+
newNodes
|
|
542
|
+
.filter((x) => x.depth === depth && !x.op)
|
|
543
|
+
.forEach((newNode) => {
|
|
544
|
+
const oldNode = oldNodes.find((tempOldNode) => {
|
|
545
|
+
return !tempOldNode.op && tempOldNode.id === newNode.id;
|
|
546
|
+
});
|
|
484
547
|
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
548
|
+
if (oldNode) {
|
|
549
|
+
const keepTreeBranch = (oldNode, newNode) => {
|
|
550
|
+
oldNode.op = { type: "keep", idx: newNode.idx };
|
|
551
|
+
newNode.op = { type: "keep_counterpart", counterpart: oldNode };
|
|
552
|
+
oldNode = oldNode.parent;
|
|
553
|
+
newNode = newNode.parent;
|
|
554
|
+
if (!oldNode || oldNode.op || newNode?.op) {
|
|
555
|
+
return;
|
|
556
|
+
}
|
|
557
|
+
keepTreeBranch(oldNode, newNode);
|
|
558
|
+
};
|
|
494
559
|
keepTreeBranch(oldNode, newNode);
|
|
495
|
-
|
|
496
560
|
}
|
|
497
|
-
|
|
498
|
-
}
|
|
499
|
-
});
|
|
561
|
+
});
|
|
500
562
|
if (depth > 1) {
|
|
501
563
|
return lcbDiff(oldNodes, newNodes, depth - 1);
|
|
502
564
|
}
|
|
@@ -504,7 +566,7 @@ function lcbDiff(oldNodes, newNodes, depth) {
|
|
|
504
566
|
oldNodes.forEach((x, i) => {
|
|
505
567
|
if (!x.op) {
|
|
506
568
|
const idx = (oldNodes[i - 1]?.op.idx ?? -1) + 1;
|
|
507
|
-
x.op = {type:
|
|
569
|
+
x.op = { type: "delete", idx };
|
|
508
570
|
}
|
|
509
571
|
});
|
|
510
572
|
|
|
@@ -512,7 +574,9 @@ function lcbDiff(oldNodes, newNodes, depth) {
|
|
|
512
574
|
if (!element.parent) {
|
|
513
575
|
return null;
|
|
514
576
|
}
|
|
515
|
-
return element.parent.op.type ===
|
|
577
|
+
return element.parent.op.type === "keep_counterpart"
|
|
578
|
+
? element.parent.op.counterpart
|
|
579
|
+
: element.parent;
|
|
516
580
|
}
|
|
517
581
|
|
|
518
582
|
function getBefore(element, idx) {
|
|
@@ -521,12 +585,13 @@ function lcbDiff(oldNodes, newNodes, depth) {
|
|
|
521
585
|
idx -= 1;
|
|
522
586
|
element = newNodes[idx];
|
|
523
587
|
if (element.depth === startDepth) {
|
|
524
|
-
return element.op.type ===
|
|
588
|
+
return element.op.type === "keep_counterpart"
|
|
589
|
+
? element.op.counterpart
|
|
590
|
+
: element;
|
|
525
591
|
}
|
|
526
592
|
}
|
|
527
593
|
|
|
528
|
-
return null
|
|
529
|
-
|
|
594
|
+
return null;
|
|
530
595
|
}
|
|
531
596
|
|
|
532
597
|
newNodes.forEach((x, i) => {
|
|
@@ -535,16 +600,12 @@ function lcbDiff(oldNodes, newNodes, depth) {
|
|
|
535
600
|
|
|
536
601
|
if (!x.op) {
|
|
537
602
|
const target = x.getRealParent();
|
|
538
|
-
const type = target?.op.type ===
|
|
539
|
-
x.op = {type, target, after: x.getBefore()}
|
|
603
|
+
const type = target?.op.type === "insert" ? "insert_ignore" : "insert";
|
|
604
|
+
x.op = { type, target, after: x.getBefore() };
|
|
540
605
|
}
|
|
541
606
|
});
|
|
542
607
|
|
|
543
|
-
const tagged = [
|
|
544
|
-
...oldNodes,
|
|
545
|
-
...newNodes,
|
|
546
|
-
];
|
|
547
|
-
|
|
608
|
+
const tagged = [...oldNodes, ...newNodes];
|
|
548
609
|
|
|
549
610
|
return tagged.sort((a, b) => {
|
|
550
611
|
const aVal = a.op?.idx ?? a.idx;
|
|
@@ -571,16 +632,23 @@ export function refresh($dom, leafController, process = null) {
|
|
|
571
632
|
return Promise.resolve();
|
|
572
633
|
}
|
|
573
634
|
|
|
574
|
-
const {refreshProcess, isRunningProcess} = prepareRefreshProcess(
|
|
635
|
+
const { refreshProcess, isRunningProcess } = prepareRefreshProcess(
|
|
636
|
+
process,
|
|
637
|
+
leafController,
|
|
638
|
+
);
|
|
575
639
|
|
|
576
640
|
$dom ??= leafController.$container;
|
|
577
641
|
|
|
578
|
-
return replaceTagElementsInContainer(
|
|
642
|
+
return replaceTagElementsInContainer(
|
|
643
|
+
app.tagNames,
|
|
644
|
+
$dom,
|
|
645
|
+
leafController,
|
|
646
|
+
process,
|
|
647
|
+
).then(() => {
|
|
579
648
|
return reloadMethodHTML(leafController, $dom, refreshProcess).then(() => {
|
|
580
649
|
if (!isRunningProcess) {
|
|
581
650
|
updateEventAndTriggerOnRefresh(refreshProcess);
|
|
582
651
|
}
|
|
583
652
|
});
|
|
584
|
-
|
|
585
653
|
});
|
|
586
|
-
}
|
|
654
|
+
}
|