simplyflow 0.3.3 → 0.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.
- package/dist/simply.flow.js +403 -425
- package/dist/simply.flow.min.js +1 -1
- package/dist/simply.flow.min.js.map +4 -4
- package/package.json +1 -1
- package/src/bind.mjs +83 -527
- package/src/bind.render.mjs +422 -0
- package/src/bind.transformers.mjs +25 -0
package/dist/simply.flow.js
CHANGED
|
@@ -419,7 +419,325 @@
|
|
|
419
419
|
}
|
|
420
420
|
}
|
|
421
421
|
|
|
422
|
+
// src/bind.transformers.mjs
|
|
423
|
+
function escape_html(context, next) {
|
|
424
|
+
let content = context.value.innerHTML;
|
|
425
|
+
if (typeof context.value == "string") {
|
|
426
|
+
content = context.value;
|
|
427
|
+
context.value = { innerHTML: content };
|
|
428
|
+
}
|
|
429
|
+
if (content) {
|
|
430
|
+
content = content.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
431
|
+
context.value.innerHTML = content;
|
|
432
|
+
}
|
|
433
|
+
next(context);
|
|
434
|
+
}
|
|
435
|
+
function fixed_content(context, next) {
|
|
436
|
+
if (typeof context.value == "string") {
|
|
437
|
+
context.value = {};
|
|
438
|
+
} else {
|
|
439
|
+
delete context.value.innerHTML;
|
|
440
|
+
}
|
|
441
|
+
next(context);
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
// src/bind.render.mjs
|
|
445
|
+
function field(context) {
|
|
446
|
+
if (context.templates?.length) {
|
|
447
|
+
fieldByTemplates.call(this, context);
|
|
448
|
+
} else if (Object.hasOwnProperty.call(this.options.renderers, context.element.tagName)) {
|
|
449
|
+
const renderer = this.options.renderers[context.element.tagName];
|
|
450
|
+
if (renderer) {
|
|
451
|
+
renderer.call(this, context);
|
|
452
|
+
}
|
|
453
|
+
} else if (this.options.renderers["*"]) {
|
|
454
|
+
this.options.renderers["*"].call(this, context);
|
|
455
|
+
}
|
|
456
|
+
return context;
|
|
457
|
+
}
|
|
458
|
+
function list(context) {
|
|
459
|
+
if (!Array.isArray(context.value)) {
|
|
460
|
+
console.error("Value is not an array.", context.element, context.path, context.value);
|
|
461
|
+
} else if (!context.templates?.length) {
|
|
462
|
+
console.error("No templates found in", context.element);
|
|
463
|
+
} else {
|
|
464
|
+
arrayByTemplates.call(this, context);
|
|
465
|
+
}
|
|
466
|
+
return context;
|
|
467
|
+
}
|
|
468
|
+
function map(context) {
|
|
469
|
+
if (typeof context.value != "object" || !context.value) {
|
|
470
|
+
console.error("Value is not an object.", context.element, context.path, context.value);
|
|
471
|
+
} else if (!context.templates?.length) {
|
|
472
|
+
console.error("No templates found in", context.element);
|
|
473
|
+
} else {
|
|
474
|
+
objectByTemplates.call(this, context);
|
|
475
|
+
}
|
|
476
|
+
return context;
|
|
477
|
+
}
|
|
478
|
+
function arrayByTemplates(context) {
|
|
479
|
+
const attribute = this.options.attribute;
|
|
480
|
+
let items = context.element.querySelectorAll(":scope > [" + attribute + "-key]");
|
|
481
|
+
let lastKey = 0;
|
|
482
|
+
let skipped = 0;
|
|
483
|
+
context.list = context.value;
|
|
484
|
+
for (let item of items) {
|
|
485
|
+
let currentKey = parseInt(item.getAttribute(attribute + "-key"));
|
|
486
|
+
if (currentKey > lastKey) {
|
|
487
|
+
context.index = lastKey;
|
|
488
|
+
context.element.insertBefore(this.applyTemplate(context), item);
|
|
489
|
+
} else if (currentKey < lastKey) {
|
|
490
|
+
item.remove();
|
|
491
|
+
} else {
|
|
492
|
+
let bindings = Array.from(item.querySelectorAll(`[${attribute}]`));
|
|
493
|
+
if (item.matches(`[${attribute}]`)) {
|
|
494
|
+
bindings.unshift(item);
|
|
495
|
+
}
|
|
496
|
+
let needsReplacement = bindings.find((b) => {
|
|
497
|
+
let databind = b.getAttribute(attribute);
|
|
498
|
+
return databind.substr(0, 5) !== ":root" && databind.substr(0, context.path.length) !== context.path;
|
|
499
|
+
});
|
|
500
|
+
if (!needsReplacement) {
|
|
501
|
+
if (item[Symbol.bindTemplate]) {
|
|
502
|
+
let newTemplate = this.findTemplate(context.templates, context.list[lastKey]);
|
|
503
|
+
if (newTemplate != item[Symbol.bindTemplate]) {
|
|
504
|
+
needsReplacement = true;
|
|
505
|
+
if (!newTemplate) {
|
|
506
|
+
skipped++;
|
|
507
|
+
}
|
|
508
|
+
}
|
|
509
|
+
}
|
|
510
|
+
}
|
|
511
|
+
if (needsReplacement) {
|
|
512
|
+
context.index = lastKey;
|
|
513
|
+
context.element.replaceChild(this.applyTemplate(context), item);
|
|
514
|
+
}
|
|
515
|
+
}
|
|
516
|
+
lastKey++;
|
|
517
|
+
if (lastKey >= context.value.length) {
|
|
518
|
+
break;
|
|
519
|
+
}
|
|
520
|
+
}
|
|
521
|
+
items = context.element.querySelectorAll(":scope > [" + attribute + "-key]");
|
|
522
|
+
let length = items.length + skipped;
|
|
523
|
+
if (length > context.value.length) {
|
|
524
|
+
while (length > context.value.length) {
|
|
525
|
+
let child = context.element.querySelectorAll(":scope > :not(template)")?.[length - 1];
|
|
526
|
+
child?.remove();
|
|
527
|
+
length--;
|
|
528
|
+
}
|
|
529
|
+
} else if (length < context.value.length) {
|
|
530
|
+
while (length < context.value.length) {
|
|
531
|
+
context.index = length;
|
|
532
|
+
context.element.appendChild(this.applyTemplate(context));
|
|
533
|
+
length++;
|
|
534
|
+
}
|
|
535
|
+
}
|
|
536
|
+
}
|
|
537
|
+
function objectByTemplates(context) {
|
|
538
|
+
const attribute = this.options.attribute;
|
|
539
|
+
context.list = context.value;
|
|
540
|
+
let items = Array.from(context.element.querySelectorAll(":scope > [" + attribute + "-key]"));
|
|
541
|
+
for (let key in context.list) {
|
|
542
|
+
context.index = key;
|
|
543
|
+
let item = items.shift();
|
|
544
|
+
if (!item) {
|
|
545
|
+
let clone = this.applyTemplate(context);
|
|
546
|
+
context.element.appendChild(clone);
|
|
547
|
+
continue;
|
|
548
|
+
}
|
|
549
|
+
if (item.getAttribute[attribute + "-key"] != key) {
|
|
550
|
+
items.unshift(item);
|
|
551
|
+
let outOfOrderItem = context.element.querySelector(":scope > [" + attribute + '-key="' + key + '"]');
|
|
552
|
+
if (!outOfOrderItem) {
|
|
553
|
+
let clone = this.applyTemplate(context);
|
|
554
|
+
context.element.insertBefore(clone, item);
|
|
555
|
+
continue;
|
|
556
|
+
} else {
|
|
557
|
+
context.element.insertBefore(outOfOrderItem, item);
|
|
558
|
+
item = outOfOrderItem;
|
|
559
|
+
items = items.filter((i) => i != outOfOrderItem);
|
|
560
|
+
}
|
|
561
|
+
}
|
|
562
|
+
let newTemplate = this.findTemplate(context.templates, context.list[context.index]);
|
|
563
|
+
if (newTemplate != item[Symbol.bindTemplate]) {
|
|
564
|
+
let clone = this.applyTemplate(context);
|
|
565
|
+
context.element.replaceChild(clone, item);
|
|
566
|
+
}
|
|
567
|
+
}
|
|
568
|
+
while (items.length) {
|
|
569
|
+
let item = items.shift();
|
|
570
|
+
item.remove();
|
|
571
|
+
}
|
|
572
|
+
}
|
|
573
|
+
function fieldByTemplates(context) {
|
|
574
|
+
const rendered = context.element.querySelector(":scope > :not(template)");
|
|
575
|
+
const template = this.findTemplate(context.templates, context.value);
|
|
576
|
+
context.parent = getParentPath(context.element);
|
|
577
|
+
if (rendered) {
|
|
578
|
+
if (template) {
|
|
579
|
+
if (rendered?.[Symbol.bindTemplate] != template) {
|
|
580
|
+
const clone = this.applyTemplate(context);
|
|
581
|
+
context.element.replaceChild(clone, rendered);
|
|
582
|
+
}
|
|
583
|
+
} else {
|
|
584
|
+
context.element.removeChild(rendered);
|
|
585
|
+
}
|
|
586
|
+
} else if (template) {
|
|
587
|
+
const clone = this.applyTemplate(context);
|
|
588
|
+
context.element.appendChild(clone);
|
|
589
|
+
}
|
|
590
|
+
}
|
|
591
|
+
function getParentPath(el, attribute) {
|
|
592
|
+
const parentEl = el.parentElement?.closest(`[${attribute}-list],[${attribute}-map]`);
|
|
593
|
+
if (!parentEl) {
|
|
594
|
+
return "";
|
|
595
|
+
}
|
|
596
|
+
if (parentEl.hasAttribute(`${attribute}-list`)) {
|
|
597
|
+
return parentEl.getAttribute(`${attribute}-list`) + ".";
|
|
598
|
+
}
|
|
599
|
+
return parentEl.getAttribute(`${attribute}-map`) + ".";
|
|
600
|
+
}
|
|
601
|
+
function input(context) {
|
|
602
|
+
const el = context.element;
|
|
603
|
+
let value = context.value;
|
|
604
|
+
element(context);
|
|
605
|
+
if (typeof value == "undefined") {
|
|
606
|
+
value = "";
|
|
607
|
+
}
|
|
608
|
+
if (el.type == "checkbox" || el.type == "radio") {
|
|
609
|
+
if (matchValue(el.value, value)) {
|
|
610
|
+
el.checked = true;
|
|
611
|
+
} else {
|
|
612
|
+
el.checked = false;
|
|
613
|
+
}
|
|
614
|
+
} else if (!matchValue(el.value, value)) {
|
|
615
|
+
el.value = "" + value;
|
|
616
|
+
}
|
|
617
|
+
}
|
|
618
|
+
function button(context) {
|
|
619
|
+
element(context);
|
|
620
|
+
setProperties(context.element, context.value, "value");
|
|
621
|
+
}
|
|
622
|
+
function select(context) {
|
|
623
|
+
const el = context.element;
|
|
624
|
+
let value = context.value;
|
|
625
|
+
if (value === null) {
|
|
626
|
+
value = "";
|
|
627
|
+
}
|
|
628
|
+
if (typeof value != "object") {
|
|
629
|
+
if (el.multiple) {
|
|
630
|
+
if (Array.isArray(value)) {
|
|
631
|
+
for (let option of el.options) {
|
|
632
|
+
if (value.indexOf(option.value) === false) {
|
|
633
|
+
option.selected = false;
|
|
634
|
+
} else {
|
|
635
|
+
option.selected = true;
|
|
636
|
+
}
|
|
637
|
+
}
|
|
638
|
+
}
|
|
639
|
+
} else {
|
|
640
|
+
let option = el.options.find((o) => matchValue(o.value, value));
|
|
641
|
+
if (option) {
|
|
642
|
+
option.selected = true;
|
|
643
|
+
option.setAttribute("selected", true);
|
|
644
|
+
}
|
|
645
|
+
}
|
|
646
|
+
} else {
|
|
647
|
+
if (value.options) {
|
|
648
|
+
setSelectOptions(el, value.options);
|
|
649
|
+
}
|
|
650
|
+
if (value.selected) {
|
|
651
|
+
select(Object.asssign({}, context, { value: value.selected }));
|
|
652
|
+
}
|
|
653
|
+
setProperties(el, value, "name", "id", "selectedIndex", "className");
|
|
654
|
+
}
|
|
655
|
+
}
|
|
656
|
+
function addOption(select2, option) {
|
|
657
|
+
if (!option) {
|
|
658
|
+
return;
|
|
659
|
+
}
|
|
660
|
+
if (typeof option !== "object") {
|
|
661
|
+
select2.options.add(new Option("" + option));
|
|
662
|
+
} else if (option.text) {
|
|
663
|
+
select2.options.add(new Option(option.text, option.value, option.defaultSelected, option.selected));
|
|
664
|
+
} else if (typeof option.value != "undefined") {
|
|
665
|
+
select2.options.add(new Option("" + option.value, option.value, option.defaultSelected, option.selected));
|
|
666
|
+
}
|
|
667
|
+
}
|
|
668
|
+
function setSelectOptions(select2, options) {
|
|
669
|
+
select2.innerHTML = "";
|
|
670
|
+
if (Array.isArray(options)) {
|
|
671
|
+
for (const option of options) {
|
|
672
|
+
addOption(select2, option);
|
|
673
|
+
}
|
|
674
|
+
} else if (options && typeof options == "object") {
|
|
675
|
+
for (const option in options) {
|
|
676
|
+
addOption(select2, { text: options[option], value: option });
|
|
677
|
+
}
|
|
678
|
+
}
|
|
679
|
+
}
|
|
680
|
+
function anchor(context) {
|
|
681
|
+
element(context);
|
|
682
|
+
setProperties(context.element, context.value, "target", "href", "name", "newwindow", "nofollow");
|
|
683
|
+
}
|
|
684
|
+
function image(context) {
|
|
685
|
+
setProperties(context.element, context.value, "title", "alt", "src", "id");
|
|
686
|
+
}
|
|
687
|
+
function iframe(context) {
|
|
688
|
+
setProperties(context.element, context.value, "title", "src", "id");
|
|
689
|
+
}
|
|
690
|
+
function meta(context) {
|
|
691
|
+
setProperties(context.element, context.value, "content", "id");
|
|
692
|
+
}
|
|
693
|
+
function element(context) {
|
|
694
|
+
const el = context.element;
|
|
695
|
+
let value = context.value;
|
|
696
|
+
if (typeof value == "undefined" || value == null) {
|
|
697
|
+
value = "";
|
|
698
|
+
}
|
|
699
|
+
let strValue = "" + value;
|
|
700
|
+
if (typeof value != "object" || strValue.substring(0, 8) != "[object ") {
|
|
701
|
+
el.innerHTML = strValue;
|
|
702
|
+
return;
|
|
703
|
+
}
|
|
704
|
+
setProperties(el, value, "innerHTML", "title", "id", "className");
|
|
705
|
+
}
|
|
706
|
+
function setProperties(el, data, ...properties) {
|
|
707
|
+
if (!data || typeof data !== "object") {
|
|
708
|
+
return;
|
|
709
|
+
}
|
|
710
|
+
for (const property of properties) {
|
|
711
|
+
if (typeof data[property] === "undefined") {
|
|
712
|
+
continue;
|
|
713
|
+
}
|
|
714
|
+
if (matchValue(el[property], data[property])) {
|
|
715
|
+
continue;
|
|
716
|
+
}
|
|
717
|
+
if (data[property] === null) {
|
|
718
|
+
el[property] = "";
|
|
719
|
+
} else {
|
|
720
|
+
el[property] = "" + data[property];
|
|
721
|
+
}
|
|
722
|
+
}
|
|
723
|
+
}
|
|
724
|
+
function matchValue(a, b) {
|
|
725
|
+
if (a == ":empty" && !b) {
|
|
726
|
+
return true;
|
|
727
|
+
}
|
|
728
|
+
if (b == ":empty" && !a) {
|
|
729
|
+
return true;
|
|
730
|
+
}
|
|
731
|
+
if ("" + a == "" + b) {
|
|
732
|
+
return true;
|
|
733
|
+
}
|
|
734
|
+
return false;
|
|
735
|
+
}
|
|
736
|
+
|
|
422
737
|
// src/bind.mjs
|
|
738
|
+
if (!Symbol.bindTemplate) {
|
|
739
|
+
Symbol.bindTemplate = Symbol("bindTemplate");
|
|
740
|
+
}
|
|
423
741
|
var SimplyBind = class {
|
|
424
742
|
/**
|
|
425
743
|
* @param Object options - a set of options for this instance, options may include:
|
|
@@ -427,22 +745,33 @@
|
|
|
427
745
|
* - container (HTMLElement) - the dom element to use as the root for all bindings
|
|
428
746
|
* - attribute (string) - the prefix for the field, list and map attributes, e.g. 'data-bind'
|
|
429
747
|
* - transformers (object name:function) - a map of transformer names and functions
|
|
430
|
-
* -
|
|
748
|
+
* - render (object with field, list and map properties)
|
|
431
749
|
*/
|
|
432
750
|
constructor(options) {
|
|
433
751
|
this.bindings = /* @__PURE__ */ new Map();
|
|
434
|
-
const
|
|
752
|
+
const defaultTransformers = {
|
|
435
753
|
escape_html,
|
|
436
754
|
fixed_content
|
|
437
755
|
};
|
|
438
756
|
const defaultOptions = {
|
|
439
757
|
container: document.body,
|
|
440
|
-
attribute: "data-
|
|
441
|
-
transformers:
|
|
442
|
-
|
|
443
|
-
field: [
|
|
444
|
-
list: [
|
|
445
|
-
map: [
|
|
758
|
+
attribute: "data-flow",
|
|
759
|
+
transformers: defaultTransformers,
|
|
760
|
+
render: {
|
|
761
|
+
field: [field],
|
|
762
|
+
list: [list],
|
|
763
|
+
map: [map]
|
|
764
|
+
},
|
|
765
|
+
renderers: {
|
|
766
|
+
"INPUT": input,
|
|
767
|
+
"BUTTON": button,
|
|
768
|
+
"SELECT": select,
|
|
769
|
+
"A": anchor,
|
|
770
|
+
"IMG": image,
|
|
771
|
+
"IFRAME": iframe,
|
|
772
|
+
"META": meta,
|
|
773
|
+
"TEMPLATE": null,
|
|
774
|
+
"*": element
|
|
446
775
|
}
|
|
447
776
|
};
|
|
448
777
|
if (!options?.root) {
|
|
@@ -450,26 +779,26 @@
|
|
|
450
779
|
}
|
|
451
780
|
this.options = Object.assign({}, defaultOptions, options);
|
|
452
781
|
if (options.transformers) {
|
|
453
|
-
this.options.transformers = Object.assign({},
|
|
782
|
+
this.options.transformers = Object.assign({}, defaultTransformers, options?.transformers);
|
|
454
783
|
}
|
|
455
784
|
const attribute = this.options.attribute;
|
|
456
785
|
const bindAttributes = [attribute + "-field", attribute + "-list", attribute + "-map"];
|
|
457
786
|
const transformAttribute = attribute + "-transform";
|
|
458
787
|
const getBindingAttribute = (el) => {
|
|
459
|
-
const foundAttribute = bindAttributes.find((
|
|
788
|
+
const foundAttribute = bindAttributes.find((attr) => el.hasAttribute(attr));
|
|
460
789
|
if (!foundAttribute) {
|
|
461
|
-
console.error("No matching attribute found", el,
|
|
790
|
+
console.error("No matching attribute found", el, bindAttributes);
|
|
462
791
|
}
|
|
463
792
|
return foundAttribute;
|
|
464
793
|
};
|
|
465
|
-
const
|
|
794
|
+
const renderElement = (el) => {
|
|
466
795
|
this.bindings.set(el, throttledEffect(() => {
|
|
467
796
|
if (!el.isConnected) {
|
|
468
797
|
untrack(el, this.getBindingPath(el));
|
|
469
798
|
destroy(this.bindings.get(el));
|
|
470
799
|
return;
|
|
471
800
|
}
|
|
472
|
-
|
|
801
|
+
let context = {
|
|
473
802
|
templates: el.querySelectorAll(":scope > template"),
|
|
474
803
|
attribute: getBindingAttribute(el)
|
|
475
804
|
};
|
|
@@ -484,13 +813,16 @@
|
|
|
484
813
|
let transformers;
|
|
485
814
|
switch (context.attribute) {
|
|
486
815
|
case this.options.attribute + "-field":
|
|
487
|
-
transformers = Array.from(this.options.
|
|
816
|
+
transformers = Array.from(this.options.render.field);
|
|
488
817
|
break;
|
|
489
818
|
case this.options.attribute + "-list":
|
|
490
|
-
transformers = Array.from(this.options.
|
|
819
|
+
transformers = Array.from(this.options.render.list);
|
|
491
820
|
break;
|
|
492
821
|
case this.options.attribute + "-map":
|
|
493
|
-
transformers = Array.from(this.options.
|
|
822
|
+
transformers = Array.from(this.options.render.map);
|
|
823
|
+
break;
|
|
824
|
+
default:
|
|
825
|
+
throw new Error("no valid context attribute specified", context);
|
|
494
826
|
break;
|
|
495
827
|
}
|
|
496
828
|
if (context.element.hasAttribute(transformAttribute)) {
|
|
@@ -515,7 +847,7 @@
|
|
|
515
847
|
const applyBindings = (bindings2) => {
|
|
516
848
|
for (let bindingEl of bindings2) {
|
|
517
849
|
if (!this.bindings.get(bindingEl)) {
|
|
518
|
-
|
|
850
|
+
renderElement(bindingEl);
|
|
519
851
|
}
|
|
520
852
|
}
|
|
521
853
|
};
|
|
@@ -559,11 +891,11 @@
|
|
|
559
891
|
*/
|
|
560
892
|
applyTemplate(context) {
|
|
561
893
|
const path = context.path;
|
|
894
|
+
const parent = context.parent;
|
|
562
895
|
const templates = context.templates;
|
|
563
|
-
const
|
|
896
|
+
const list2 = context.list;
|
|
564
897
|
const index = context.index;
|
|
565
|
-
const
|
|
566
|
-
const value = list ? list[index] : context.value;
|
|
898
|
+
const value = list2 ? list2[index] : context.value;
|
|
567
899
|
let template = this.findTemplate(templates, value);
|
|
568
900
|
if (!template) {
|
|
569
901
|
let result = new DocumentFragment();
|
|
@@ -581,33 +913,47 @@
|
|
|
581
913
|
const attributes = [attribute + "-field", attribute + "-list", attribute + "-map"];
|
|
582
914
|
const bindings = clone.querySelectorAll(`[${attribute}-field],[${attribute}-list],[${attribute}-map]`);
|
|
583
915
|
for (let binding of bindings) {
|
|
584
|
-
|
|
585
|
-
|
|
916
|
+
if (binding.tagName == "TEMPLATE") {
|
|
917
|
+
continue;
|
|
918
|
+
}
|
|
919
|
+
const attr = attributes.find((attr2) => binding.hasAttribute(attr2));
|
|
920
|
+
let bind2 = binding.getAttribute(attr);
|
|
921
|
+
bind2 = this.applyLinks(template.links, bind2);
|
|
586
922
|
if (bind2.substring(0, ":root.".length) == ":root.") {
|
|
587
|
-
binding.setAttribute(
|
|
923
|
+
binding.setAttribute(attr, bind2.substring(":root.".length));
|
|
588
924
|
} else if (bind2 == ":value" && index != null) {
|
|
589
|
-
binding.setAttribute(
|
|
925
|
+
binding.setAttribute(attr, path + "." + index);
|
|
590
926
|
} else if (index != null) {
|
|
591
|
-
binding.setAttribute(
|
|
927
|
+
binding.setAttribute(attr, path + "." + index + "." + bind2);
|
|
592
928
|
} else {
|
|
593
|
-
binding.setAttribute(
|
|
929
|
+
binding.setAttribute(attr, parent + bind2);
|
|
594
930
|
}
|
|
595
931
|
}
|
|
596
932
|
if (typeof index !== "undefined") {
|
|
597
933
|
clone.children[0].setAttribute(attribute + "-key", index);
|
|
598
934
|
}
|
|
599
|
-
|
|
600
|
-
clone.children[0],
|
|
601
|
-
"$bindTemplate",
|
|
602
|
-
{
|
|
603
|
-
value: template,
|
|
604
|
-
enumerable: false,
|
|
605
|
-
writable: true,
|
|
606
|
-
configurable: true
|
|
607
|
-
}
|
|
608
|
-
);
|
|
935
|
+
clone.children[0][Symbol.bindTemplate] = template;
|
|
609
936
|
return clone;
|
|
610
937
|
}
|
|
938
|
+
parseLinks(links) {
|
|
939
|
+
let result = {};
|
|
940
|
+
links = links.split(";").map((link) => link.trim());
|
|
941
|
+
for (let link of links) {
|
|
942
|
+
link = link.split("=");
|
|
943
|
+
result[link[0].trim()] = link[1].trim();
|
|
944
|
+
}
|
|
945
|
+
return result;
|
|
946
|
+
}
|
|
947
|
+
applyLinks(links, value) {
|
|
948
|
+
for (let link in links) {
|
|
949
|
+
if (value.startsWith(link + ".")) {
|
|
950
|
+
return links[link] + value.substr(link.length);
|
|
951
|
+
} else if (value == link) {
|
|
952
|
+
return links[link];
|
|
953
|
+
}
|
|
954
|
+
}
|
|
955
|
+
return value;
|
|
956
|
+
}
|
|
611
957
|
/**
|
|
612
958
|
* Returns the path referenced in either the field, list or map attribute
|
|
613
959
|
* @param HTMLElement el
|
|
@@ -619,9 +965,9 @@
|
|
|
619
965
|
this.options.attribute + "-list",
|
|
620
966
|
this.options.attribute + "-map"
|
|
621
967
|
];
|
|
622
|
-
for (let
|
|
623
|
-
if (el.hasAttribute(
|
|
624
|
-
return el.getAttribute(
|
|
968
|
+
for (let attr of attributes) {
|
|
969
|
+
if (el.hasAttribute(attr)) {
|
|
970
|
+
return el.getAttribute(attr);
|
|
625
971
|
}
|
|
626
972
|
}
|
|
627
973
|
}
|
|
@@ -659,6 +1005,10 @@
|
|
|
659
1005
|
}
|
|
660
1006
|
};
|
|
661
1007
|
let template = Array.from(templates).find(templateMatches);
|
|
1008
|
+
let links = null;
|
|
1009
|
+
if (template?.hasAttribute(this.options.attribute + "-link")) {
|
|
1010
|
+
links = this.parseLinks(template.getAttribute(this.options.attribute + "-link"));
|
|
1011
|
+
}
|
|
662
1012
|
let rel = template?.getAttribute("rel");
|
|
663
1013
|
if (rel) {
|
|
664
1014
|
let replacement = document.querySelector("template#" + rel);
|
|
@@ -667,6 +1017,9 @@
|
|
|
667
1017
|
}
|
|
668
1018
|
template = replacement;
|
|
669
1019
|
}
|
|
1020
|
+
if (template) {
|
|
1021
|
+
template.links = links;
|
|
1022
|
+
}
|
|
670
1023
|
return template;
|
|
671
1024
|
}
|
|
672
1025
|
destroy() {
|
|
@@ -689,399 +1042,24 @@
|
|
|
689
1042
|
}
|
|
690
1043
|
}
|
|
691
1044
|
function untrack(el, path) {
|
|
692
|
-
let
|
|
693
|
-
if (
|
|
694
|
-
|
|
695
|
-
tracking.set(path,
|
|
696
|
-
}
|
|
697
|
-
}
|
|
698
|
-
function matchValue(a, b) {
|
|
699
|
-
if (a == ":empty" && !b) {
|
|
700
|
-
return true;
|
|
701
|
-
}
|
|
702
|
-
if (b == ":empty" && !a) {
|
|
703
|
-
return true;
|
|
704
|
-
}
|
|
705
|
-
if ("" + a == "" + b) {
|
|
706
|
-
return true;
|
|
1045
|
+
let list2 = tracking.get(path);
|
|
1046
|
+
if (list2) {
|
|
1047
|
+
list2 = list2.filter((context) => context.element == el);
|
|
1048
|
+
tracking.set(path, list2);
|
|
707
1049
|
}
|
|
708
|
-
return false;
|
|
709
1050
|
}
|
|
710
1051
|
function getValueByPath(root, path) {
|
|
711
1052
|
let parts = path.split(".");
|
|
712
1053
|
let curr = root;
|
|
713
|
-
let part
|
|
714
|
-
|
|
1054
|
+
let part;
|
|
1055
|
+
part = parts.shift();
|
|
1056
|
+
while (part && curr) {
|
|
1057
|
+
part = decodeURIComponent(part);
|
|
1058
|
+
curr = curr[part];
|
|
715
1059
|
part = parts.shift();
|
|
716
|
-
if (part == ":key") {
|
|
717
|
-
return prevPart;
|
|
718
|
-
} else if (part == ":value") {
|
|
719
|
-
return curr;
|
|
720
|
-
} else if (part == ":root") {
|
|
721
|
-
curr = root;
|
|
722
|
-
} else {
|
|
723
|
-
part = decodeURIComponent(part);
|
|
724
|
-
curr = curr[part];
|
|
725
|
-
prevPart = part;
|
|
726
|
-
}
|
|
727
1060
|
}
|
|
728
1061
|
return curr;
|
|
729
1062
|
}
|
|
730
|
-
function defaultFieldTransformer(context) {
|
|
731
|
-
const el = context.element;
|
|
732
|
-
const templates = context.templates;
|
|
733
|
-
if (templates?.length) {
|
|
734
|
-
transformLiteralByTemplates.call(this, context);
|
|
735
|
-
} else {
|
|
736
|
-
switch (el.tagName) {
|
|
737
|
-
case "INPUT":
|
|
738
|
-
transformInput.call(this, context);
|
|
739
|
-
break;
|
|
740
|
-
case "BUTTON":
|
|
741
|
-
transformButton.call(this, context);
|
|
742
|
-
break;
|
|
743
|
-
case "SELECT":
|
|
744
|
-
transformSelect.call(this, context);
|
|
745
|
-
break;
|
|
746
|
-
case "A":
|
|
747
|
-
transformAnchor.call(this, context);
|
|
748
|
-
break;
|
|
749
|
-
case "IMG":
|
|
750
|
-
transformImage.call(this, context);
|
|
751
|
-
break;
|
|
752
|
-
case "IFRAME":
|
|
753
|
-
transformIframe.call(this, context);
|
|
754
|
-
break;
|
|
755
|
-
case "META":
|
|
756
|
-
transformMeta.call(this, context);
|
|
757
|
-
break;
|
|
758
|
-
case "TEMPLATE":
|
|
759
|
-
break;
|
|
760
|
-
default:
|
|
761
|
-
transformElement.call(this, context);
|
|
762
|
-
break;
|
|
763
|
-
}
|
|
764
|
-
}
|
|
765
|
-
return context;
|
|
766
|
-
}
|
|
767
|
-
function defaultListTransformer(context) {
|
|
768
|
-
const el = context.element;
|
|
769
|
-
const templates = context.templates;
|
|
770
|
-
const path = context.path;
|
|
771
|
-
const value = context.value;
|
|
772
|
-
if (!Array.isArray(value)) {
|
|
773
|
-
console.error("Value is not an array.", el, path, value);
|
|
774
|
-
} else if (!templates?.length) {
|
|
775
|
-
console.error("No templates found in", el);
|
|
776
|
-
} else {
|
|
777
|
-
transformArrayByTemplates.call(this, context);
|
|
778
|
-
}
|
|
779
|
-
return context;
|
|
780
|
-
}
|
|
781
|
-
function defaultMapTransformer(context) {
|
|
782
|
-
const el = context.element;
|
|
783
|
-
const templates = context.templates;
|
|
784
|
-
const path = context.path;
|
|
785
|
-
const value = context.value;
|
|
786
|
-
if (typeof value != "object") {
|
|
787
|
-
console.error("Value is not an object.", el, path, value);
|
|
788
|
-
} else if (!templates?.length) {
|
|
789
|
-
console.error("No templates found in", el);
|
|
790
|
-
} else {
|
|
791
|
-
transformObjectByTemplates.call(this, context);
|
|
792
|
-
}
|
|
793
|
-
return context;
|
|
794
|
-
}
|
|
795
|
-
function transformArrayByTemplates(context) {
|
|
796
|
-
const el = context.element;
|
|
797
|
-
const templates = context.templates;
|
|
798
|
-
const path = context.path;
|
|
799
|
-
const value = context.value;
|
|
800
|
-
const attribute = this.options.attribute;
|
|
801
|
-
let items = el.querySelectorAll(":scope > [" + attribute + "-key]");
|
|
802
|
-
let lastKey = 0;
|
|
803
|
-
let skipped = 0;
|
|
804
|
-
context.list = value;
|
|
805
|
-
for (let item of items) {
|
|
806
|
-
let currentKey = parseInt(item.getAttribute(attribute + "-key"));
|
|
807
|
-
if (currentKey > lastKey) {
|
|
808
|
-
context.index = lastKey;
|
|
809
|
-
el.insertBefore(this.applyTemplate(context), item);
|
|
810
|
-
} else if (currentKey < lastKey) {
|
|
811
|
-
item.remove();
|
|
812
|
-
} else {
|
|
813
|
-
let bindings = Array.from(item.querySelectorAll(`[${attribute}]`));
|
|
814
|
-
if (item.matches(`[${attribute}]`)) {
|
|
815
|
-
bindings.unshift(item);
|
|
816
|
-
}
|
|
817
|
-
let needsReplacement = bindings.find((b) => {
|
|
818
|
-
let databind = b.getAttribute(attribute);
|
|
819
|
-
return databind.substr(0, 5) !== ":root" && databind.substr(0, path.length) !== path;
|
|
820
|
-
});
|
|
821
|
-
if (!needsReplacement) {
|
|
822
|
-
if (item.$bindTemplate) {
|
|
823
|
-
let newTemplate = this.findTemplate(templates, value[lastKey]);
|
|
824
|
-
if (newTemplate != item.$bindTemplate) {
|
|
825
|
-
needsReplacement = true;
|
|
826
|
-
if (!newTemplate) {
|
|
827
|
-
skipped++;
|
|
828
|
-
}
|
|
829
|
-
}
|
|
830
|
-
}
|
|
831
|
-
}
|
|
832
|
-
if (needsReplacement) {
|
|
833
|
-
context.index = lastKey;
|
|
834
|
-
el.replaceChild(this.applyTemplate(context), item);
|
|
835
|
-
}
|
|
836
|
-
}
|
|
837
|
-
lastKey++;
|
|
838
|
-
if (lastKey >= value.length) {
|
|
839
|
-
break;
|
|
840
|
-
}
|
|
841
|
-
}
|
|
842
|
-
items = el.querySelectorAll(":scope > [" + attribute + "-key]");
|
|
843
|
-
let length = items.length + skipped;
|
|
844
|
-
if (length > value.length) {
|
|
845
|
-
while (length > value.length) {
|
|
846
|
-
let child = el.querySelectorAll(":scope > :not(template)")?.[length - 1];
|
|
847
|
-
child?.remove();
|
|
848
|
-
length--;
|
|
849
|
-
}
|
|
850
|
-
} else if (length < value.length) {
|
|
851
|
-
while (length < value.length) {
|
|
852
|
-
context.index = length;
|
|
853
|
-
el.appendChild(this.applyTemplate(context));
|
|
854
|
-
length++;
|
|
855
|
-
}
|
|
856
|
-
}
|
|
857
|
-
}
|
|
858
|
-
function transformObjectByTemplates(context) {
|
|
859
|
-
const el = context.element;
|
|
860
|
-
const templates = context.templates;
|
|
861
|
-
const value = context.value;
|
|
862
|
-
const attribute = this.options.attribute;
|
|
863
|
-
context.list = value;
|
|
864
|
-
let items = Array.from(el.querySelectorAll(":scope > [" + attribute + "-key]"));
|
|
865
|
-
for (let key in context.list) {
|
|
866
|
-
context.index = key;
|
|
867
|
-
let item = items.shift();
|
|
868
|
-
if (!item) {
|
|
869
|
-
let clone = this.applyTemplate(context);
|
|
870
|
-
el.appendChild(clone);
|
|
871
|
-
continue;
|
|
872
|
-
}
|
|
873
|
-
if (item.getAttribute[attribute + "-key"] != key) {
|
|
874
|
-
items.unshift(item);
|
|
875
|
-
let outOfOrderItem = el.querySelector(":scope > [" + attribute + '-key="' + key + '"]');
|
|
876
|
-
if (!outOfOrderItem) {
|
|
877
|
-
let clone = this.applyTemplate(context);
|
|
878
|
-
el.insertBefore(clone, item);
|
|
879
|
-
continue;
|
|
880
|
-
} else {
|
|
881
|
-
el.insertBefore(outOfOrderItem, item);
|
|
882
|
-
item = outOfOrderItem;
|
|
883
|
-
items = items.filter((i) => i != outOfOrderItem);
|
|
884
|
-
}
|
|
885
|
-
}
|
|
886
|
-
let newTemplate = this.findTemplate(templates, value[key]);
|
|
887
|
-
if (newTemplate != item.$bindTemplate) {
|
|
888
|
-
let clone = this.applyTemplate(context);
|
|
889
|
-
el.replaceChild(clone, item);
|
|
890
|
-
}
|
|
891
|
-
}
|
|
892
|
-
while (items.length) {
|
|
893
|
-
let item = items.shift();
|
|
894
|
-
item.remove();
|
|
895
|
-
}
|
|
896
|
-
}
|
|
897
|
-
function getParentPath(el, attribute) {
|
|
898
|
-
const parentEl = el.parentElement?.closest(`[${attribute}-list],[${attribute}-map]`);
|
|
899
|
-
if (!parentEl) {
|
|
900
|
-
return ":root";
|
|
901
|
-
}
|
|
902
|
-
if (parentEl.hasAttribute(`${attribute}-list`)) {
|
|
903
|
-
return parentEl.getAttribute(`${attribute}-list`);
|
|
904
|
-
}
|
|
905
|
-
return parentEl.getAttribute(`${attribute}-map`);
|
|
906
|
-
}
|
|
907
|
-
function transformLiteralByTemplates(context) {
|
|
908
|
-
const el = context.element;
|
|
909
|
-
const templates = context.templates;
|
|
910
|
-
const value = context.value;
|
|
911
|
-
const attribute = this.options.attribute;
|
|
912
|
-
const rendered = el.querySelector(":scope > :not(template)");
|
|
913
|
-
const template = this.findTemplate(templates, value);
|
|
914
|
-
context.parent = getParentPath(el, attribute);
|
|
915
|
-
if (rendered) {
|
|
916
|
-
if (template) {
|
|
917
|
-
if (rendered?.$bindTemplate != template) {
|
|
918
|
-
const clone = this.applyTemplate(context);
|
|
919
|
-
el.replaceChild(clone, rendered);
|
|
920
|
-
}
|
|
921
|
-
} else {
|
|
922
|
-
el.removeChild(rendered);
|
|
923
|
-
}
|
|
924
|
-
} else if (template) {
|
|
925
|
-
const clone = this.applyTemplate(context);
|
|
926
|
-
el.appendChild(clone);
|
|
927
|
-
}
|
|
928
|
-
}
|
|
929
|
-
function transformInput(context) {
|
|
930
|
-
const el = context.element;
|
|
931
|
-
let value = context.value;
|
|
932
|
-
transformElement(context);
|
|
933
|
-
if (typeof value == "undefined") {
|
|
934
|
-
value = "";
|
|
935
|
-
}
|
|
936
|
-
if (el.type == "checkbox" || el.type == "radio") {
|
|
937
|
-
if (matchValue(el.value, value)) {
|
|
938
|
-
el.checked = true;
|
|
939
|
-
} else {
|
|
940
|
-
el.checked = false;
|
|
941
|
-
}
|
|
942
|
-
} else if (!matchValue(el.value, value)) {
|
|
943
|
-
el.value = "" + value;
|
|
944
|
-
}
|
|
945
|
-
}
|
|
946
|
-
function transformButton(context) {
|
|
947
|
-
const el = context.element;
|
|
948
|
-
const value = context.value;
|
|
949
|
-
transformElement(context);
|
|
950
|
-
setProperties(el, value, "value");
|
|
951
|
-
}
|
|
952
|
-
function transformSelect(context) {
|
|
953
|
-
const el = context.element;
|
|
954
|
-
let value = context.value;
|
|
955
|
-
if (value === null) {
|
|
956
|
-
value = "";
|
|
957
|
-
}
|
|
958
|
-
if (typeof value != "object") {
|
|
959
|
-
if (el.multiple) {
|
|
960
|
-
if (Array.isArray(value)) {
|
|
961
|
-
for (let option of el.options) {
|
|
962
|
-
if (value.indexOf(option.value) === false) {
|
|
963
|
-
option.selected = false;
|
|
964
|
-
} else {
|
|
965
|
-
option.selected = true;
|
|
966
|
-
}
|
|
967
|
-
}
|
|
968
|
-
}
|
|
969
|
-
} else {
|
|
970
|
-
let option = el.options.find((o) => matchValue(o.value, value));
|
|
971
|
-
if (option) {
|
|
972
|
-
option.selected = true;
|
|
973
|
-
option.setAttribute("selected", true);
|
|
974
|
-
}
|
|
975
|
-
}
|
|
976
|
-
} else {
|
|
977
|
-
if (value.options) {
|
|
978
|
-
setSelectOptions(el, value.options);
|
|
979
|
-
}
|
|
980
|
-
if (value.selected) {
|
|
981
|
-
transformSelect(Object.asssign({}, context, { value: value.selected }));
|
|
982
|
-
}
|
|
983
|
-
setProperties(el, value, "name", "id", "selectedIndex", "className");
|
|
984
|
-
}
|
|
985
|
-
}
|
|
986
|
-
function addOption(select, option) {
|
|
987
|
-
if (!option) {
|
|
988
|
-
return;
|
|
989
|
-
}
|
|
990
|
-
if (typeof option !== "object") {
|
|
991
|
-
select.options.add(new Option("" + option));
|
|
992
|
-
} else if (option.text) {
|
|
993
|
-
select.options.add(new Option(option.text, option.value, option.defaultSelected, option.selected));
|
|
994
|
-
} else if (typeof option.value != "undefined") {
|
|
995
|
-
select.options.add(new Option("" + option.value, option.value, option.defaultSelected, option.selected));
|
|
996
|
-
}
|
|
997
|
-
}
|
|
998
|
-
function setSelectOptions(select, options) {
|
|
999
|
-
select.innerHTML = "";
|
|
1000
|
-
if (Array.isArray(options)) {
|
|
1001
|
-
for (const option of options) {
|
|
1002
|
-
addOption(select, option);
|
|
1003
|
-
}
|
|
1004
|
-
} else if (options && typeof options == "object") {
|
|
1005
|
-
for (const option in options) {
|
|
1006
|
-
addOption(select, { text: options[option], value: option });
|
|
1007
|
-
}
|
|
1008
|
-
}
|
|
1009
|
-
}
|
|
1010
|
-
function transformAnchor(context) {
|
|
1011
|
-
const el = context.element;
|
|
1012
|
-
const value = context.value;
|
|
1013
|
-
transformElement(context);
|
|
1014
|
-
setProperties(el, value, "title", "target", "href", "name", "newwindow", "nofollow");
|
|
1015
|
-
}
|
|
1016
|
-
function transformImage(context) {
|
|
1017
|
-
const el = context.element;
|
|
1018
|
-
const value = context.value;
|
|
1019
|
-
transformElement(context);
|
|
1020
|
-
setProperties(el, value, "title", "alt", "src");
|
|
1021
|
-
}
|
|
1022
|
-
function transformIframe(context) {
|
|
1023
|
-
const el = context.element;
|
|
1024
|
-
const value = context.value;
|
|
1025
|
-
transformElement(context);
|
|
1026
|
-
setProperties(el, value, "title", "src");
|
|
1027
|
-
}
|
|
1028
|
-
function transformMeta(context) {
|
|
1029
|
-
const el = context.element;
|
|
1030
|
-
const value = context.value;
|
|
1031
|
-
transformElement(context);
|
|
1032
|
-
setProperties(el, value, "content");
|
|
1033
|
-
}
|
|
1034
|
-
function transformElement(context) {
|
|
1035
|
-
const el = context.element;
|
|
1036
|
-
let value = context.value;
|
|
1037
|
-
if (typeof value == "undefined" || value == null) {
|
|
1038
|
-
value = "";
|
|
1039
|
-
}
|
|
1040
|
-
let strValue = "" + value;
|
|
1041
|
-
if (typeof value != "object" || strValue.substring(0, 8) != "[object ") {
|
|
1042
|
-
el.innerHTML = strValue;
|
|
1043
|
-
return;
|
|
1044
|
-
}
|
|
1045
|
-
setProperties(el, value, "innerHTML", "title", "id", "className");
|
|
1046
|
-
}
|
|
1047
|
-
function setProperties(el, data, ...properties) {
|
|
1048
|
-
if (!data || typeof data !== "object") {
|
|
1049
|
-
return;
|
|
1050
|
-
}
|
|
1051
|
-
for (const property of properties) {
|
|
1052
|
-
if (typeof data[property] === "undefined") {
|
|
1053
|
-
continue;
|
|
1054
|
-
}
|
|
1055
|
-
if (matchValue(el[property], data[property])) {
|
|
1056
|
-
continue;
|
|
1057
|
-
}
|
|
1058
|
-
if (data[property] === null) {
|
|
1059
|
-
el[property] = "";
|
|
1060
|
-
} else {
|
|
1061
|
-
el[property] = "" + data[property];
|
|
1062
|
-
}
|
|
1063
|
-
}
|
|
1064
|
-
}
|
|
1065
|
-
function escape_html(context, next) {
|
|
1066
|
-
let content = context.value.innerHTML;
|
|
1067
|
-
if (typeof context.value == "string") {
|
|
1068
|
-
content = context.value;
|
|
1069
|
-
context.value = { innerHTML: content };
|
|
1070
|
-
}
|
|
1071
|
-
if (content) {
|
|
1072
|
-
content = content.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
1073
|
-
context.value.innerHTML = content;
|
|
1074
|
-
}
|
|
1075
|
-
next(context);
|
|
1076
|
-
}
|
|
1077
|
-
function fixed_content(context, next) {
|
|
1078
|
-
if (typeof context.value == "string") {
|
|
1079
|
-
context.value = {};
|
|
1080
|
-
} else {
|
|
1081
|
-
delete context.value.innerHTML;
|
|
1082
|
-
}
|
|
1083
|
-
next(context);
|
|
1084
|
-
}
|
|
1085
1063
|
|
|
1086
1064
|
// src/model.mjs
|
|
1087
1065
|
var model_exports = {};
|
|
@@ -1214,11 +1192,11 @@
|
|
|
1214
1192
|
return function(data) {
|
|
1215
1193
|
this.state.options.columns = options;
|
|
1216
1194
|
return throttledEffect(() => {
|
|
1217
|
-
return data.current.map((
|
|
1195
|
+
return data.current.map((input2) => {
|
|
1218
1196
|
let result = {};
|
|
1219
1197
|
for (let key of Object.keys(this.state.options.columns)) {
|
|
1220
1198
|
if (!this.state.options.columns[key]?.hidden) {
|
|
1221
|
-
result[key] =
|
|
1199
|
+
result[key] = input2[key];
|
|
1222
1200
|
}
|
|
1223
1201
|
}
|
|
1224
1202
|
return result;
|