neo.mjs 10.0.0-alpha.5 → 10.0.0-beta.2
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/ServiceWorker.mjs +2 -2
- package/apps/colors/view/GridContainer.mjs +1 -1
- package/apps/covid/view/AttributionComponent.mjs +1 -1
- package/apps/covid/view/HeaderContainer.mjs +6 -6
- package/apps/covid/view/MainContainerController.mjs +5 -5
- package/apps/covid/view/TableContainerController.mjs +1 -1
- package/apps/covid/view/country/Gallery.mjs +13 -13
- package/apps/covid/view/country/Helix.mjs +13 -13
- package/apps/covid/view/country/HistoricalDataTable.mjs +1 -1
- package/apps/email/view/Viewport.mjs +2 -2
- package/apps/form/view/SideNavList.mjs +1 -1
- package/apps/portal/index.html +1 -1
- package/apps/portal/resources/data/examples_devmode.json +26 -27
- package/apps/portal/resources/data/examples_dist_dev.json +26 -27
- package/apps/portal/resources/data/examples_dist_esm.json +25 -26
- package/apps/portal/resources/data/examples_dist_prod.json +26 -27
- package/apps/portal/view/HeaderToolbar.mjs +3 -3
- package/apps/portal/view/about/Container.mjs +2 -2
- package/apps/portal/view/about/MemberContainer.mjs +3 -3
- package/apps/portal/view/blog/List.mjs +7 -7
- package/apps/portal/view/examples/List.mjs +4 -4
- package/apps/portal/view/home/ContentBox.mjs +2 -2
- package/apps/portal/view/home/FeatureSection.mjs +3 -3
- package/apps/portal/view/home/FooterContainer.mjs +7 -7
- package/apps/portal/view/home/parts/AfterMath.mjs +3 -3
- package/apps/portal/view/home/parts/MainNeo.mjs +3 -3
- package/apps/portal/view/home/parts/References.mjs +6 -6
- package/apps/portal/view/learn/ContentComponent.mjs +102 -111
- package/apps/portal/view/learn/PageSectionsContainer.mjs +1 -1
- package/apps/portal/view/learn/PageSectionsList.mjs +2 -2
- package/apps/portal/view/services/Component.mjs +16 -16
- package/apps/realworld/view/FooterComponent.mjs +1 -1
- package/apps/realworld/view/HeaderComponent.mjs +8 -8
- package/apps/realworld/view/HomeComponent.mjs +6 -6
- package/apps/realworld/view/article/CommentComponent.mjs +4 -4
- package/apps/realworld/view/article/Component.mjs +14 -14
- package/apps/realworld/view/article/CreateCommentComponent.mjs +3 -3
- package/apps/realworld/view/article/CreateComponent.mjs +3 -3
- package/apps/realworld/view/article/PreviewComponent.mjs +1 -1
- package/apps/realworld/view/article/TagListComponent.mjs +2 -2
- package/apps/realworld/view/user/ProfileComponent.mjs +8 -8
- package/apps/realworld/view/user/SettingsComponent.mjs +4 -4
- package/apps/realworld/view/user/SignUpComponent.mjs +4 -4
- package/apps/realworld2/view/FooterComponent.mjs +1 -1
- package/apps/realworld2/view/HomeContainer.mjs +3 -3
- package/apps/realworld2/view/article/DetailsContainer.mjs +1 -1
- package/apps/realworld2/view/article/PreviewComponent.mjs +7 -7
- package/apps/realworld2/view/article/TagListComponent.mjs +2 -2
- package/apps/realworld2/view/user/ProfileContainer.mjs +1 -1
- package/apps/route/view/center/CardAdministration.mjs +2 -2
- package/apps/route/view/center/CardAdministrationDenied.mjs +1 -1
- package/apps/route/view/center/CardContact.mjs +2 -2
- package/apps/route/view/center/CardHome.mjs +1 -1
- package/apps/route/view/center/CardSection1.mjs +1 -1
- package/apps/route/view/center/CardSection2.mjs +1 -1
- package/apps/sharedcovid/view/AttributionComponent.mjs +1 -1
- package/apps/sharedcovid/view/HeaderContainer.mjs +6 -6
- package/apps/sharedcovid/view/MainContainerController.mjs +5 -5
- package/apps/sharedcovid/view/TableContainerController.mjs +1 -1
- package/apps/sharedcovid/view/country/Gallery.mjs +13 -13
- package/apps/sharedcovid/view/country/Helix.mjs +13 -13
- package/apps/sharedcovid/view/country/HistoricalDataTable.mjs +1 -1
- package/apps/shareddialog/childapps/shareddialog2/view/MainContainer.mjs +1 -1
- package/apps/shareddialog/view/MainContainer.mjs +1 -1
- package/buildScripts/createApp.mjs +2 -2
- package/examples/table/cellEditing/MainContainer.mjs +1 -1
- package/examples/table/container/MainContainer.mjs +3 -3
- package/examples/table/nestedRecordFields/Viewport.mjs +6 -6
- package/examples/tableFiltering/MainContainer.mjs +1 -1
- package/examples/tablePerformance/MainContainer.mjs +1 -1
- package/examples/tablePerformance/MainContainer2.mjs +1 -1
- package/examples/tablePerformance/MainContainer3.mjs +2 -2
- package/examples/tableStore/MainContainer.mjs +2 -2
- package/learn/Glossary.md +261 -0
- package/learn/UsingTheseTopics.md +2 -2
- package/learn/benefits/ConfigSystem.md +538 -28
- package/learn/benefits/Effort.md +47 -2
- package/learn/benefits/Features.md +50 -32
- package/learn/benefits/FormsEngine.md +68 -38
- package/learn/benefits/MultiWindow.md +33 -7
- package/learn/benefits/OffTheMainThread.md +2 -2
- package/learn/benefits/Quick.md +45 -12
- package/learn/benefits/RPCLayer.md +75 -0
- package/learn/benefits/Speed.md +16 -11
- package/learn/gettingstarted/ComponentModels.md +4 -4
- package/learn/gettingstarted/Config.md +6 -6
- package/learn/gettingstarted/DescribingTheUI.md +4 -4
- package/learn/gettingstarted/Events.md +6 -6
- package/learn/gettingstarted/Extending.md +4 -4
- package/learn/gettingstarted/References.md +6 -6
- package/learn/gettingstarted/Workspaces.md +6 -6
- package/learn/guides/ApplicationBootstrap.md +26 -26
- package/learn/guides/ComponentsAndContainers.md +12 -12
- package/learn/guides/ConfigSystemDeepDive.md +280 -0
- package/learn/guides/CustomComponents.md +2 -2
- package/learn/guides/DeclarativeComponentTreesVsImperativeVdom.md +17 -17
- package/learn/guides/InstanceLifecycle.md +295 -1
- package/learn/guides/MainThreadAddons.md +475 -0
- package/learn/guides/PortalApp.md +2 -2
- package/learn/guides/StateProviders.md +12 -12
- package/learn/guides/WorkingWithVDom.md +14 -14
- package/learn/guides/events/CustomEvents.md +16 -16
- package/learn/guides/events/DomEvents.md +12 -12
- package/learn/javascript/ClassFeatures.md +3 -2
- package/learn/javascript/Classes.md +8 -8
- package/learn/javascript/NewNode.md +4 -4
- package/learn/javascript/Overrides.md +8 -8
- package/learn/javascript/Super.md +10 -8
- package/learn/tree.json +52 -51
- package/learn/tutorials/Earthquakes.md +54 -57
- package/learn/tutorials/TodoList.md +4 -4
- package/package.json +2 -2
- package/resources/scss/src/apps/portal/learn/ContentComponent.scss +12 -0
- package/resources/scss/src/table/{View.scss → Body.scss} +1 -1
- package/resources/scss/src/table/plugin/CellEditing.scss +1 -1
- package/resources/scss/theme-dark/table/{View.scss → Body.scss} +1 -1
- package/resources/scss/theme-light/table/{View.scss → Body.scss} +1 -1
- package/resources/scss/theme-neo-light/Global.scss +1 -2
- package/resources/scss/theme-neo-light/table/{View.scss → Body.scss} +1 -1
- package/src/DefaultConfig.mjs +2 -2
- package/src/Main.mjs +8 -7
- package/src/Neo.mjs +16 -2
- package/src/button/Base.mjs +2 -2
- package/src/calendar/view/SettingsContainer.mjs +2 -2
- package/src/calendar/view/YearComponent.mjs +9 -9
- package/src/calendar/view/calendars/ColorsList.mjs +1 -1
- package/src/calendar/view/calendars/List.mjs +1 -1
- package/src/calendar/view/month/Component.mjs +15 -15
- package/src/calendar/view/week/Component.mjs +12 -12
- package/src/calendar/view/week/EventDragZone.mjs +4 -4
- package/src/calendar/view/week/TimeAxisComponent.mjs +3 -3
- package/src/component/Base.mjs +17 -2
- package/src/component/Carousel.mjs +2 -2
- package/src/component/Chip.mjs +3 -3
- package/src/component/Circle.mjs +2 -2
- package/src/component/DateSelector.mjs +8 -8
- package/src/component/Helix.mjs +1 -1
- package/src/component/Label.mjs +3 -18
- package/src/component/Legend.mjs +3 -3
- package/src/component/MagicMoveText.mjs +6 -14
- package/src/component/Process.mjs +3 -3
- package/src/component/Progress.mjs +1 -1
- package/src/component/StatusBadge.mjs +2 -2
- package/src/component/Timer.mjs +2 -2
- package/src/component/Toast.mjs +5 -3
- package/src/container/AccordionItem.mjs +2 -2
- package/src/container/Base.mjs +1 -1
- package/src/core/Base.mjs +77 -14
- package/src/core/Util.mjs +14 -2
- package/src/date/DayViewComponent.mjs +2 -2
- package/src/date/SelectorContainer.mjs +1 -1
- package/src/draggable/grid/header/toolbar/SortZone.mjs +21 -21
- package/src/draggable/table/header/toolbar/SortZone.mjs +1 -1
- package/src/form/field/CheckBox.mjs +4 -4
- package/src/form/field/FileUpload.mjs +25 -39
- package/src/form/field/Range.mjs +1 -1
- package/src/form/field/Text.mjs +3 -3
- package/src/form/field/TextArea.mjs +2 -3
- package/src/grid/Body.mjs +8 -5
- package/src/grid/_export.mjs +1 -1
- package/src/list/Color.mjs +2 -2
- package/src/main/DeltaUpdates.mjs +157 -98
- package/src/main/addon/AmCharts.mjs +61 -84
- package/src/main/addon/Base.mjs +161 -42
- package/src/main/addon/GoogleMaps.mjs +9 -16
- package/src/main/addon/HighlightJS.mjs +2 -13
- package/src/main/addon/IntersectionObserver.mjs +21 -21
- package/src/main/addon/MonacoEditor.mjs +32 -64
- package/src/manager/ClassHierarchy.mjs +114 -0
- package/src/menu/List.mjs +1 -1
- package/src/plugin/Popover.mjs +2 -2
- package/src/sitemap/Component.mjs +1 -1
- package/src/table/{View.mjs → Body.mjs} +25 -22
- package/src/table/Container.mjs +43 -43
- package/src/table/_export.mjs +2 -2
- package/src/table/plugin/CellEditing.mjs +19 -19
- package/src/tooltip/Base.mjs +1 -6
- package/src/tree/Accordion.mjs +3 -3
- package/src/vdom/Helper.mjs +19 -22
- package/src/worker/App.mjs +1 -2
- package/src/worker/Base.mjs +7 -5
- package/src/worker/Canvas.mjs +2 -3
- package/src/worker/Data.mjs +5 -7
- package/src/worker/Task.mjs +2 -3
- package/src/worker/VDom.mjs +3 -4
- package/src/worker/mixin/RemoteMethodAccess.mjs +5 -2
- package/learn/guides/MainThreadAddonExample.md +0 -15
- package/learn/guides/MainThreadAddonIntro.md +0 -44
@@ -1,6 +1,5 @@
|
|
1
|
-
import Field
|
2
|
-
import NeoArray
|
3
|
-
import StringUtil from '../../util/String.mjs';
|
1
|
+
import Field from './Base.mjs';
|
2
|
+
import NeoArray from '../../util/Array.mjs';
|
4
3
|
|
5
4
|
const
|
6
5
|
sizeRE = /^(\d+)(kb|mb|gb)?$/i,
|
@@ -352,7 +351,7 @@ class FileUpload extends Field {
|
|
352
351
|
onConstructed() {
|
353
352
|
super.onConstructed(...arguments);
|
354
353
|
|
355
|
-
this.vdom.cn[4].
|
354
|
+
this.vdom.cn[4].text = this.chooseFile;
|
356
355
|
}
|
357
356
|
|
358
357
|
/**
|
@@ -392,12 +391,9 @@ class FileUpload extends Field {
|
|
392
391
|
*/
|
393
392
|
onInputValueChange({ files }) {
|
394
393
|
const
|
395
|
-
me
|
396
|
-
{
|
397
|
-
|
398
|
-
cls
|
399
|
-
} = me,
|
400
|
-
body = me.vdom.cn[1];
|
394
|
+
me = this,
|
395
|
+
{cls, types} = me,
|
396
|
+
body = me.vdom.cn[1];
|
401
397
|
|
402
398
|
if (files.length) {
|
403
399
|
NeoArray.remove(cls, 'neo-field-empty');
|
@@ -406,17 +402,16 @@ class FileUpload extends Field {
|
|
406
402
|
const
|
407
403
|
file = files.item(0),
|
408
404
|
pointPos = file.name.lastIndexOf('.'),
|
409
|
-
type = pointPos > -1 ? file.name.slice(pointPos + 1) : ''
|
410
|
-
escapedFileName = StringUtil.escapeHtml(file.name);
|
405
|
+
type = pointPos > -1 ? file.name.slice(pointPos + 1) : '';
|
411
406
|
|
412
407
|
if (me.types && !types[type]) {
|
413
|
-
body.cn[0].
|
414
|
-
body.cn[1].
|
408
|
+
body.cn[0].text = file.name;
|
409
|
+
body.cn[1].text = `${me.invalidFileFormat} (.${type}) ${me.formatSize(file.size)}`;
|
415
410
|
me.error = me.pleaseUseTheseTypes?.replace('{allowedFileTypes}', Object.keys(types).join(' .'))
|
416
411
|
}
|
417
412
|
else if (file.size > me.maxSize) {
|
418
|
-
body.cn[0].
|
419
|
-
body.cn[1].
|
413
|
+
body.cn[0].text = file.name;
|
414
|
+
body.cn[1].text = me.formatSize(file.size);
|
420
415
|
me.error = me.fileSizeMoreThan?.replace('{allowedFileSize}', String(me._maxSize).toUpperCase());
|
421
416
|
}
|
422
417
|
// If it passes the type and maxSize check, upload it
|
@@ -448,7 +443,7 @@ class FileUpload extends Field {
|
|
448
443
|
await me.timeout(100);
|
449
444
|
me.focus(me.vdom.cn[2].id);
|
450
445
|
|
451
|
-
me.vdom.cn[1].cn[0].
|
446
|
+
me.vdom.cn[1].cn[0].text = file.name;
|
452
447
|
me.update();
|
453
448
|
me.state = 'uploading';
|
454
449
|
|
@@ -492,10 +487,10 @@ class FileUpload extends Field {
|
|
492
487
|
|
493
488
|
(vdom.style || (vdom.style = {}))['--upload-progress'] = `${progress}turn`;
|
494
489
|
|
495
|
-
vdom.cn[1].cn[1].
|
490
|
+
vdom.cn[1].cn[1].text = `${this.uploading}... (${Math.round(progress * 100)}%)`;
|
496
491
|
|
497
492
|
this.uploadSize = loaded;
|
498
|
-
this.update()
|
493
|
+
this.update()
|
499
494
|
}
|
500
495
|
|
501
496
|
onUploadAbort(e) {
|
@@ -665,15 +660,15 @@ class FileUpload extends Field {
|
|
665
660
|
afterSetDocument(document) {
|
666
661
|
if (document) {
|
667
662
|
const
|
668
|
-
me
|
669
|
-
{
|
663
|
+
me = this,
|
664
|
+
{cls} = me;
|
670
665
|
|
671
666
|
NeoArray.remove(cls, 'neo-field-empty');
|
672
667
|
me.cls = cls;
|
673
668
|
|
674
669
|
me.documentId = document.id;
|
675
670
|
me.fileSize = me.formatSize(document.size);
|
676
|
-
me.vdom.cn[1].cn[0].
|
671
|
+
me.vdom.cn[1].cn[0].text = document.fileName;
|
677
672
|
me.state = me.documentStatusMap[document.status];
|
678
673
|
}
|
679
674
|
}
|
@@ -704,15 +699,15 @@ class FileUpload extends Field {
|
|
704
699
|
isChangeEventNeeded = true;
|
705
700
|
break;
|
706
701
|
case 'upload-failed':
|
707
|
-
status.
|
702
|
+
status.text = `${me.uploadFailed}${isNaN(me.progress) ? '' : `... (${Math.round(me.progress * 100)}%)`}`;
|
708
703
|
isChangeEventNeeded = true;
|
709
704
|
break;
|
710
705
|
case 'processing':
|
711
|
-
status.
|
706
|
+
status.text = `${me.scanning}... (${me.formatSize(me.uploadSize)})`;
|
712
707
|
vdom.inert = true;
|
713
708
|
break;
|
714
709
|
case 'scan-failed':
|
715
|
-
status.
|
710
|
+
status.text = `${me.malwareFoundInFile}. \u2022 ${me.fileSize}`;
|
716
711
|
me.error = me.pleaseCheck;
|
717
712
|
isChangeEventNeeded = true;
|
718
713
|
break;
|
@@ -721,19 +716,19 @@ class FileUpload extends Field {
|
|
721
716
|
anchor.href = me.createUrl(me.downloadUrl, {
|
722
717
|
[me.documentIdParameter] : me.documentId
|
723
718
|
});
|
724
|
-
status.
|
719
|
+
status.text = me.fileSize;
|
725
720
|
isChangeEventNeeded = true;
|
726
721
|
break;
|
727
722
|
case 'not-downloadable':
|
728
|
-
status.
|
723
|
+
status.text = me.document ? me.fileSize : `${me.successfullyUploaded} \u2022 ${me.fileSize}`;
|
729
724
|
isChangeEventNeeded = true;
|
730
725
|
break;
|
731
726
|
case 'deleted':
|
732
|
-
status.
|
727
|
+
status.text = me.fileWasDeleted;
|
733
728
|
isChangeEventNeeded = true;
|
734
729
|
break;
|
735
730
|
case 'error':
|
736
|
-
status.
|
731
|
+
status.text = me.fileIsInAnErrorState;
|
737
732
|
me.error = me.pleaseCheck;
|
738
733
|
isChangeEventNeeded = true;
|
739
734
|
}
|
@@ -812,16 +807,7 @@ class FileUpload extends Field {
|
|
812
807
|
}
|
813
808
|
|
814
809
|
afterSetError(text) {
|
815
|
-
|
816
|
-
this.vdom.cn[5].cn = [{
|
817
|
-
vtype : 'text',
|
818
|
-
html : text
|
819
|
-
}];
|
820
|
-
}
|
821
|
-
else {
|
822
|
-
this.vdom.cn[5].cn = [];
|
823
|
-
}
|
824
|
-
|
810
|
+
this.vdom.cn[5].cn = text ? [{vtype : 'text', text}] : [];
|
825
811
|
this.validate();
|
826
812
|
this.update();
|
827
813
|
}
|
package/src/form/field/Range.mjs
CHANGED
package/src/form/field/Text.mjs
CHANGED
@@ -788,8 +788,8 @@ class Text extends Field {
|
|
788
788
|
showLabel = me.labelPosition === 'top',
|
789
789
|
subLabel = me.vdom.cn[1];
|
790
790
|
|
791
|
-
subLabel.html = value;
|
792
791
|
subLabel.removeDom = !showLabel;
|
792
|
+
subLabel.text = value;
|
793
793
|
|
794
794
|
me.update()
|
795
795
|
}
|
@@ -1494,9 +1494,9 @@ class Text extends Field {
|
|
1494
1494
|
errorNode = errorWrapper.cn[0];
|
1495
1495
|
|
1496
1496
|
if (value) {
|
1497
|
-
errorNode.
|
1497
|
+
errorNode.text = value
|
1498
1498
|
} else {
|
1499
|
-
delete errorNode.
|
1499
|
+
delete errorNode.text
|
1500
1500
|
}
|
1501
1501
|
|
1502
1502
|
errorWrapper.removeDom = !value;
|
@@ -1,5 +1,4 @@
|
|
1
|
-
import
|
2
|
-
import Text from './Text.mjs';
|
1
|
+
import Text from './Text.mjs';
|
3
2
|
|
4
3
|
/**
|
5
4
|
*
|
@@ -162,7 +161,7 @@ class TextArea extends Text {
|
|
162
161
|
inputEl = me.getInputEl();
|
163
162
|
|
164
163
|
if (inputEl) {
|
165
|
-
inputEl.
|
164
|
+
inputEl.text = value
|
166
165
|
}
|
167
166
|
|
168
167
|
super.afterSetValue(value, oldValue);
|
package/src/grid/Body.mjs
CHANGED
@@ -419,9 +419,8 @@ class GridBody extends Component {
|
|
419
419
|
* @param {Number} data.rowIndex
|
420
420
|
* @returns {Object}
|
421
421
|
*/
|
422
|
-
applyRendererOutput(
|
423
|
-
let
|
424
|
-
me = this,
|
422
|
+
applyRendererOutput({cellId, column, columnIndex, record, rowIndex}) {
|
423
|
+
let me = this,
|
425
424
|
gridContainer = me.parent,
|
426
425
|
{selectedCells, store} = me,
|
427
426
|
cellCls = ['neo-grid-cell'],
|
@@ -461,7 +460,7 @@ class GridBody extends Component {
|
|
461
460
|
|
462
461
|
switch (Neo.typeOf(rendererOutput)) {
|
463
462
|
case 'Object': {
|
464
|
-
if (rendererOutput.html) {
|
463
|
+
if (rendererOutput.html || rendererOutput.text) {
|
465
464
|
rendererOutput.cls && cellCls.push(...rendererOutput.cls);
|
466
465
|
} else {
|
467
466
|
rendererOutput = [rendererOutput];
|
@@ -522,7 +521,11 @@ class GridBody extends Component {
|
|
522
521
|
}
|
523
522
|
|
524
523
|
if (Neo.typeOf(rendererOutput) === 'Object') {
|
525
|
-
|
524
|
+
if (Object.hasOwn(rendererOutput, 'html')) {
|
525
|
+
cellConfig.html = rendererOutput.html || ''
|
526
|
+
} else {
|
527
|
+
cellConfig.text = rendererOutput.text || ''
|
528
|
+
}
|
526
529
|
} else {
|
527
530
|
cellConfig.cn = rendererOutput
|
528
531
|
}
|
package/src/grid/_export.mjs
CHANGED
package/src/list/Color.mjs
CHANGED
@@ -5,7 +5,13 @@ import {voidAttributes} from '../vdom/domConstants.mjs';
|
|
5
5
|
const NeoConfig = Neo.config;
|
6
6
|
|
7
7
|
/**
|
8
|
-
*
|
8
|
+
* Manages and applies the Virtual DOM (VDom) delta updates generated by `Neo.vdom.Helper` to the real browser DOM.
|
9
|
+
* This class acts as the bridge between the VDom worker's calculated changes and the actual rendering on the main thread.
|
10
|
+
* It orchestrates various DOM manipulation operations such as node insertions, removals, moves, attribute updates,
|
11
|
+
* and handles dynamic renderer switching based on `Neo.config.useDomApiRenderer`.
|
12
|
+
*
|
13
|
+
* As a singleton per browser window, it provides a centralized and efficient mechanism for synchronized DOM updates,
|
14
|
+
* ensuring the UI accurately reflects the application state.
|
9
15
|
* @class Neo.main.DeltaUpdates
|
10
16
|
* @extends Neo.core.Base
|
11
17
|
* @singleton
|
@@ -48,19 +54,6 @@ class DeltaUpdates extends Base {
|
|
48
54
|
* @protected
|
49
55
|
*/
|
50
56
|
logDeltasIntervalId = 0
|
51
|
-
/**
|
52
|
-
* Private property to store the dynamically loaded renderer module.
|
53
|
-
* @member {Neo.main.render.DomApiRenderer|Neo.main.render.DomApiRenderer|null} #renderer=null
|
54
|
-
* @private
|
55
|
-
*/
|
56
|
-
#renderer = null
|
57
|
-
/**
|
58
|
-
* Private property to signal that the renderer module has been loaded.
|
59
|
-
* This will be a Promise that resolves when the module is ready.
|
60
|
-
* @private
|
61
|
-
* @member {Promise<void>|null} #_readyPromise
|
62
|
-
*/
|
63
|
-
#_readyPromise = null
|
64
57
|
|
65
58
|
/**
|
66
59
|
* @param {Object} config
|
@@ -68,11 +61,10 @@ class DeltaUpdates extends Base {
|
|
68
61
|
construct(config) {
|
69
62
|
super.construct(config);
|
70
63
|
|
71
|
-
let
|
72
|
-
{environment} = NeoConfig;
|
64
|
+
let {environment} = NeoConfig;
|
73
65
|
|
74
66
|
if (NeoConfig.renderCountDeltas) {
|
75
|
-
|
67
|
+
this.renderCountDeltas = true
|
76
68
|
}
|
77
69
|
|
78
70
|
// We need different publicPath values for the main thread inside the webpack based dist envs,
|
@@ -80,24 +72,6 @@ class DeltaUpdates extends Base {
|
|
80
72
|
if (environment === 'dist/development' || environment === 'dist/production') {
|
81
73
|
__webpack_require__.p = NeoConfig.basePath.substring(6)
|
82
74
|
}
|
83
|
-
|
84
|
-
// Initiate the asynchronous loading of the renderer here.
|
85
|
-
me.#_readyPromise = (async () => {
|
86
|
-
try {
|
87
|
-
let module;
|
88
|
-
|
89
|
-
if (NeoConfig.useDomApiRenderer) {
|
90
|
-
module = await import('./render/DomApiRenderer.mjs')
|
91
|
-
} else {
|
92
|
-
module = await import('./render/StringBasedRenderer.mjs')
|
93
|
-
}
|
94
|
-
|
95
|
-
me.#renderer = module.default
|
96
|
-
} catch (err) {
|
97
|
-
console.error('DeltaUpdates: Failed to load renderer module:', err);
|
98
|
-
throw err // Re-throw to propagate initialization failures
|
99
|
-
}
|
100
|
-
})()
|
101
75
|
}
|
102
76
|
|
103
77
|
/**
|
@@ -130,8 +104,13 @@ class DeltaUpdates extends Base {
|
|
130
104
|
}
|
131
105
|
|
132
106
|
/**
|
133
|
-
*
|
134
|
-
*
|
107
|
+
* Changes the tag name (nodeName) of an existing HTMLElement in the DOM.
|
108
|
+
* This operation is performed by creating a new HTML element with the desired `nodeName`,
|
109
|
+
* meticulously copying all attributes and the `innerHTML` from the original `node` to the new one,
|
110
|
+
* and then seamlessly replacing the original `node` with the newly created element within its parent.
|
111
|
+
*
|
112
|
+
* @param {HTMLElement} node The existing DOM HTMLElement whose tag name needs to be changed.
|
113
|
+
* @param {String} nodeName The new tag name (e.g., 'div', 'span', 'p') for the element.
|
135
114
|
*/
|
136
115
|
changeNodeName(node, nodeName) {
|
137
116
|
let {attributes} = node,
|
@@ -160,21 +139,49 @@ class DeltaUpdates extends Base {
|
|
160
139
|
DomAccess.getElement(id)?.focus()
|
161
140
|
}
|
162
141
|
|
142
|
+
/**
|
143
|
+
* Imports either (if not already imported):
|
144
|
+
* `Neo.main.render.DomApiRenderer` if Neo.config.useDomApiRenderer === true
|
145
|
+
* `Neo.main.render.StringBasedRenderer` if Neo.config.useDomApiRenderer === false
|
146
|
+
* @returns {Promise<void>}
|
147
|
+
* @protected
|
148
|
+
*/
|
149
|
+
async importRenderer() {
|
150
|
+
const {render} = Neo.main;
|
151
|
+
|
152
|
+
if (NeoConfig.useDomApiRenderer) {
|
153
|
+
if (!render?.DomApiRenderer) {
|
154
|
+
await import('./render/DomApiRenderer.mjs')
|
155
|
+
}
|
156
|
+
} else {
|
157
|
+
if (!render?.StringBasedRenderer) {
|
158
|
+
await import('./render/StringBasedRenderer.mjs')
|
159
|
+
}
|
160
|
+
}
|
161
|
+
}
|
162
|
+
|
163
|
+
/**
|
164
|
+
* @returns {Promise<void>}
|
165
|
+
*/
|
166
|
+
async initAsync() {
|
167
|
+
super.initAsync();
|
168
|
+
|
169
|
+
let me = this;
|
170
|
+
|
171
|
+
// Subscribe to global Neo.config changes for dynamic renderer switching.
|
172
|
+
Neo.worker.Manager.on({
|
173
|
+
neoConfigChange: me.onNeoConfigChange,
|
174
|
+
scope : me
|
175
|
+
});
|
176
|
+
|
177
|
+
await me.importRenderer()
|
178
|
+
}
|
179
|
+
|
163
180
|
/**
|
164
181
|
* Inserts a new node into the DOM tree based on delta updates.
|
165
182
|
* This method handles both string-based (outerHTML) and direct DOM API (vnode) mounting.
|
166
183
|
* It ensures the node is inserted at the correct index within the parent.
|
167
|
-
*
|
168
|
-
* Implementation Details & Considerations:
|
169
|
-
* - `parentNode.children` contains only element nodes (tags).
|
170
|
-
* - `parentNode.childNodes` contains all nodes, including text and comment nodes.
|
171
|
-
* - Since every `vtype:'text'` is wrapped inside a comment block (as an ID),
|
172
|
-
* calculating a "realIndex" is necessary for string-based insertions to
|
173
|
-
* correctly account for non-element nodes.
|
174
|
-
* - `insertAdjacentHTML()` is generally faster than creating a node via template,
|
175
|
-
* but it's only available for manipulating children (elements), not `childNodes` (all nodes).
|
176
|
-
* - For performance, in cases where there are no comment nodes (i.e., no wrapped text nodes),
|
177
|
-
* the method prioritizes `insertAdjacentHTML()` when `useDomApiRenderer` is false.
|
184
|
+
* This method is synchronous and *expects* the appropriate renderer (DomApiRenderer or StringBasedRenderer) to be already loaded.
|
178
185
|
*
|
179
186
|
* @param {Object} delta
|
180
187
|
* @param {Boolean} delta.hasLeadingTextChildren Flag to honor leading comments, which require special treatment.
|
@@ -184,33 +191,47 @@ class DeltaUpdates extends Base {
|
|
184
191
|
* @param {Neo.vdom.VNode} [delta.vnode] The VNode representation of the new node (for direct DOM API mounting).
|
185
192
|
*/
|
186
193
|
insertNode({hasLeadingTextChildren, index, outerHTML, parentId, vnode}) {
|
187
|
-
|
188
|
-
|
189
|
-
// This method is synchronous and *expects* the renderer to be loaded
|
190
|
-
if (!me.#renderer) {
|
191
|
-
console.error('DeltaUpdates renderer not ready during insertNode!');
|
192
|
-
return
|
193
|
-
}
|
194
|
+
this.checkRendererAvailability();
|
194
195
|
|
195
|
-
|
196
|
+
let {render} = Neo.main,
|
197
|
+
parentNode = DomAccess.getElementOrBody(parentId);
|
196
198
|
|
197
199
|
if (parentNode) {
|
198
200
|
if (NeoConfig.useDomApiRenderer) {
|
199
|
-
|
201
|
+
render.DomApiRenderer.createDomTree({index, isRoot: true, parentNode, vnode})
|
200
202
|
} else {
|
201
|
-
|
203
|
+
render.StringBasedRenderer.insertNodeAsString({hasLeadingTextChildren, index, outerHTML, parentNode})
|
204
|
+
}
|
205
|
+
}
|
206
|
+
}
|
207
|
+
|
208
|
+
/**
|
209
|
+
*
|
210
|
+
*/
|
211
|
+
checkRendererAvailability() {
|
212
|
+
const {render} = Neo.main;
|
213
|
+
|
214
|
+
if (NeoConfig.useDomApiRenderer) {
|
215
|
+
if (!render?.DomApiRenderer) {
|
216
|
+
throw new Error('Neo.main.DeltaUpdates: DomApiRenderer is not loaded yet!')
|
217
|
+
}
|
218
|
+
} else {
|
219
|
+
if (!render?.StringBasedRenderer) {
|
220
|
+
throw new Error('Neo.main.DeltaUpdates: StringBasedRenderer is not loaded yet!')
|
202
221
|
}
|
203
222
|
}
|
204
223
|
}
|
205
224
|
|
206
225
|
/**
|
207
|
-
* Moves an existing DOM node to a new position within its parent
|
208
|
-
*
|
209
|
-
*
|
226
|
+
* Moves an existing DOM node to a new position within its parent or to a new parent.
|
227
|
+
* This method directly manipulates the DOM using the pre-calculated physical index,
|
228
|
+
* accounting for potential text nodes wrapped in comments.
|
229
|
+
* It performs a direct sibling swap when an element is immediately followed by its target position,
|
230
|
+
* which is necessary to prevent attempting to replace a node with itself.
|
210
231
|
*
|
211
232
|
* @param {Object} delta
|
212
233
|
* @param {String} delta.id The ID of the DOM node to move.
|
213
|
-
* @param {Number} delta.index The physical index at which to insert the node
|
234
|
+
* @param {Number} delta.index The physical index at which to insert the node within the target parent's childNodes.
|
214
235
|
* @param {String} delta.parentId The ID of the target parent DOM node.
|
215
236
|
*/
|
216
237
|
moveNode({id, index, parentId}) {
|
@@ -239,8 +260,25 @@ class DeltaUpdates extends Base {
|
|
239
260
|
}
|
240
261
|
|
241
262
|
/**
|
263
|
+
* Handler for global Neo.config changes.
|
264
|
+
* If the `Neo.config.useDomApiRenderer` value changes, this method dynamically loads the renderer.
|
265
|
+
* @param {Object} config
|
266
|
+
* @return {Promise<void>}
|
267
|
+
*/
|
268
|
+
async onNeoConfigChange(config) {
|
269
|
+
if (Object.hasOwn(config, 'useDomApiRenderer')) {
|
270
|
+
await this.importRenderer()
|
271
|
+
}
|
272
|
+
}
|
273
|
+
|
274
|
+
/**
|
275
|
+
* Clears all child nodes of a given parent DOM node.
|
276
|
+
* This is achieved by setting its `innerHTML` property to an empty string,
|
277
|
+
* which is generally considered the fastest and most efficient way to remove
|
278
|
+
* all children from a DOM element in modern browsers.
|
279
|
+
*
|
242
280
|
* @param {Object} delta
|
243
|
-
* @param {String} delta.parentId
|
281
|
+
* @param {String} delta.parentId The ID of the parent DOM node whose children will be removed.
|
244
282
|
*/
|
245
283
|
removeAll({parentId}) {
|
246
284
|
let node = DomAccess.getElement(parentId);
|
@@ -251,9 +289,13 @@ class DeltaUpdates extends Base {
|
|
251
289
|
}
|
252
290
|
|
253
291
|
/**
|
292
|
+
* Removes a DOM node from its parent.
|
293
|
+
* This method handles both standard HTML elements and virtual text nodes,
|
294
|
+
* which are typically wrapped within comment nodes in the DOM.
|
295
|
+
*
|
254
296
|
* @param {Object} delta
|
255
|
-
* @param {String} delta.id
|
256
|
-
* @param {String} delta.parentId
|
297
|
+
* @param {String} delta.id The ID of the DOM node to remove.
|
298
|
+
* @param {String} delta.parentId The ID of the parent DOM node (required for text node removal).
|
257
299
|
*/
|
258
300
|
removeNode({id, parentId}) {
|
259
301
|
const node = DomAccess.getElement(id);
|
@@ -289,10 +331,17 @@ class DeltaUpdates extends Base {
|
|
289
331
|
}
|
290
332
|
|
291
333
|
/**
|
334
|
+
* Replaces an existing child DOM node (`fromId`) with a new DOM node (`toId`)
|
335
|
+
* within a specified parent DOM node (`parentId`).
|
336
|
+
* This operation directly invokes the native `Node.replaceChild()` API,
|
337
|
+
* performing an atomic swap of the elements in the DOM tree.
|
338
|
+
* It is typically used when a specific DOM element needs to be completely
|
339
|
+
* exchanged for a different one at the same position.
|
340
|
+
*
|
292
341
|
* @param {Object} delta
|
293
|
-
* @param {String} delta.fromId
|
294
|
-
* @param {String} delta.parentId
|
295
|
-
* @param {String} delta.toId
|
342
|
+
* @param {String} delta.fromId The ID of the existing child DOM node to be replaced.
|
343
|
+
* @param {String} delta.parentId The ID of the parent DOM node containing the child to be replaced.
|
344
|
+
* @param {String} delta.toId The ID of the new DOM node that will replace the old one.
|
296
345
|
*/
|
297
346
|
replaceChild({fromId, parentId, toId}) {
|
298
347
|
let node = DomAccess.getElement(parentId);
|
@@ -301,26 +350,20 @@ class DeltaUpdates extends Base {
|
|
301
350
|
}
|
302
351
|
|
303
352
|
/**
|
353
|
+
* Updates various properties of an existing DOM node based on the provided delta.
|
354
|
+
* This includes updating attributes, class names, inner HTML, node name, and inline styles.
|
355
|
+
* It handles specific cases for attribute types (e.g., boolean attributes, 'value')
|
356
|
+
* and style properties (e.g., '!important').
|
357
|
+
*
|
304
358
|
* @param {Object} delta
|
305
|
-
* @param {String}
|
306
|
-
* @param {
|
307
|
-
|
308
|
-
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
}
|
314
|
-
}
|
315
|
-
|
316
|
-
/**
|
317
|
-
* @param {Object} delta
|
318
|
-
* @param {Object} [delta.attributes]
|
319
|
-
* @param {String} [delta.cls]
|
320
|
-
* @param {String} [delta.id]
|
321
|
-
* @param {String} [delta.innerHTML]
|
322
|
-
* @param {String} [delta.outerHTML]
|
323
|
-
* @param {Object} [delta.style]
|
359
|
+
* @param {String} delta.id The ID of the DOM node to update.
|
360
|
+
* @param {Object} [delta.attributes] An object containing attribute key-value pairs to update or remove (if value is null/empty).
|
361
|
+
* @param {Object} [delta.cls] An object containing 'add' and/or 'remove' arrays for CSS classes.
|
362
|
+
* @param {String} [delta.innerHTML] The new inner HTML content for the node.
|
363
|
+
* @param {String} [delta.nodeName] The new tag name for the node (will trigger a node replacement).
|
364
|
+
* @param {String} [delta.outerHTML] The new outer HTML content for the node (will trigger a node replacement).
|
365
|
+
* @param {Object} [delta.style] An object containing CSS style properties to update. Values can include '!important'.
|
366
|
+
* @param {String} [delta.textContent] The new text content for the node (replaces innerHTML if present).
|
324
367
|
*/
|
325
368
|
updateNode(delta) {
|
326
369
|
let me = this,
|
@@ -384,16 +427,25 @@ class DeltaUpdates extends Base {
|
|
384
427
|
})
|
385
428
|
}
|
386
429
|
break
|
430
|
+
case 'textContent':
|
431
|
+
node.textContent = value;
|
432
|
+
break
|
387
433
|
}
|
388
434
|
})
|
389
435
|
}
|
390
436
|
}
|
391
437
|
|
392
438
|
/**
|
439
|
+
* Updates the text content of a virtual text node within the DOM.
|
440
|
+
* Virtual text nodes are rendered within the DOM as a pair of HTML comments,
|
441
|
+
* with their content embedded between them. This method locates the specific
|
442
|
+
* text node by its ID (embedded in the start comment tag) within its parent's
|
443
|
+
* innerHTML and replaces its content using a regular expression.
|
444
|
+
*
|
393
445
|
* @param {Object} delta
|
394
|
-
* @param {String} delta.id
|
395
|
-
* @param {String} delta.parentId
|
396
|
-
* @param {String} delta.value
|
446
|
+
* @param {String} delta.id The unique ID of the virtual text node, which is embedded in its opening comment tag.
|
447
|
+
* @param {String} delta.parentId The ID of the parent DOM node whose `innerHTML` contains the virtual text node.
|
448
|
+
* @param {String} delta.value The new text content to be applied to the virtual text node.
|
397
449
|
*/
|
398
450
|
updateVtext({id, parentId, value}) {
|
399
451
|
let node = DomAccess.getElement(parentId),
|
@@ -405,17 +457,24 @@ class DeltaUpdates extends Base {
|
|
405
457
|
}
|
406
458
|
|
407
459
|
/**
|
460
|
+
* Applies a set of VDom delta updates to the real DOM.
|
461
|
+
* This method is the core entry point for rendering changes initiated from the VDom worker.
|
462
|
+
* It iterates through the provided deltas and dispatches them to specific DOM manipulation
|
463
|
+
* methods (e.g., insertNode, removeNode, updateNode) based on their `action` property.
|
464
|
+
* This method expects the appropriate renderer (DomApiRenderer or StringBasedRenderer)
|
465
|
+
* to be loaded based on `Neo.config.useDomApiRenderer`.
|
466
|
+
*
|
408
467
|
* @param {Object} data
|
409
|
-
* @param {Object|Object[]} data.deltas
|
410
|
-
*
|
411
|
-
*
|
468
|
+
* @param {Object|Object[]} data.deltas An array of delta objects, or a single delta object,
|
469
|
+
* representing changes to be applied to the DOM.
|
470
|
+
* Each delta object contains an `action` property
|
471
|
+
* (e.g., 'insertNode', 'removeNode', 'updateNode', 'moveNode')
|
472
|
+
* and additional properties relevant to the specific action.
|
473
|
+
* @param {String} data.id The unique ID of the request, used for sending a reply back to the origin.
|
474
|
+
* @param {String} [data.origin='app'] The origin of the message (e.g., 'app'), used for sending replies.
|
412
475
|
*/
|
413
476
|
update(data) {
|
414
|
-
|
415
|
-
if (!this.#renderer) {
|
416
|
-
console.error('DeltaUpdates renderer not ready during insertNode!');
|
417
|
-
return
|
418
|
-
}
|
477
|
+
this.checkRendererAvailability();
|
419
478
|
|
420
479
|
let me = this,
|
421
480
|
{deltas} = data,
|