js-kompo-utils 1.0.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.
Files changed (67) hide show
  1. package/README.md +1 -0
  2. package/app.js +22 -0
  3. package/components/VlApexChart.vue +89 -0
  4. package/components/VlCKEditorTemplate.vue +52 -0
  5. package/components/VlCKEditorWithVars.vue +80 -0
  6. package/components/VlCollapsible.vue +91 -0
  7. package/components/VlCopyBox.vue +61 -0
  8. package/components/VlCreditCardInput.vue +104 -0
  9. package/components/VlDateMonthDay.vue +327 -0
  10. package/components/VlDateTextInput.vue +151 -0
  11. package/components/VlInternationalPhoneInput.vue +902 -0
  12. package/components/VlPartialDate.vue +283 -0
  13. package/components/VlPasswordInput.vue +358 -0
  14. package/components/VlQrCodeScanner.vue +91 -0
  15. package/components/VlSwipeableTab.vue +35 -0
  16. package/components/VlSwipeableTabs.vue +325 -0
  17. package/components/VlText.vue +72 -0
  18. package/components/VlTutorialStepBuilder.vue +671 -0
  19. package/components/VlValidatedInput.vue +262 -0
  20. package/components/data/countries.js +253 -0
  21. package/components/getAllDefaultComponents.js +12 -0
  22. package/docs/architecture.md +71 -0
  23. package/docs/tutorials.md +247 -0
  24. package/docs/usage.md +128 -0
  25. package/functions/index.js +7 -0
  26. package/functions/inputs.js +64 -0
  27. package/functions/loading.js +20 -0
  28. package/kompo-ckeditor-1.0.17/index.js +5 -0
  29. package/kompo-ckeditor-1.0.17/komponents/CKEditor.vue +36 -0
  30. package/kompo-ckeditor-1.0.17/komponents/CKEditorExtended.vue +66 -0
  31. package/kompo-ckeditor-1.0.17/komponents/EditableCKEditor.vue +42 -0
  32. package/kompo-ckeditor-1.0.17/komponents/TranslatableEditor.vue +28 -0
  33. package/kompo-ckeditor-1.0.17/mixins/CKEditor.js +291 -0
  34. package/kompo-ckeditor-1.0.17/mixins/CKEditorUtilities.js +52 -0
  35. package/kompo-ckeditor-1.0.17/mixins/CkUploadAdapter.js +95 -0
  36. package/kompo-ckeditor-1.0.17/mixins/translations/en.js +1 -0
  37. package/kompo-ckeditor-1.0.17/mixins/translations/fr.js +1 -0
  38. package/kompo-ckeditor-1.0.17/plugins/JsonBlockCommand.js +100 -0
  39. package/kompo-ckeditor-1.0.17/plugins/JsonBlockEditing.js +225 -0
  40. package/kompo-ckeditor-1.0.17/plugins/JsonBlockUi.js +21 -0
  41. package/kompo-ckeditor-1.0.17/plugins/MentionPlugin.js +118 -0
  42. package/orchestrator/KompoJsBuilder.js +333 -0
  43. package/package.json +25 -0
  44. package/raw_animations/count-up-animation.js +220 -0
  45. package/raw_animations/magic-poof.js +210 -0
  46. package/tutorials/TutorialConfig.js +34 -0
  47. package/tutorials/TutorialEngine.js +448 -0
  48. package/tutorials/index.js +2 -0
  49. package/tutorials/modules/AutoNext.js +86 -0
  50. package/tutorials/modules/Avatar.js +94 -0
  51. package/tutorials/modules/Bubble.js +617 -0
  52. package/tutorials/modules/Cursor.js +315 -0
  53. package/tutorials/modules/Highlight.js +282 -0
  54. package/tutorials/modules/HoverForcer.js +250 -0
  55. package/tutorials/modules/Mobile.js +148 -0
  56. package/tutorials/modules/Options.js +98 -0
  57. package/tutorials/modules/Overlay.js +142 -0
  58. package/tutorials/modules/Scroll.js +37 -0
  59. package/tutorials/modules/Typewriter.js +132 -0
  60. package/tutorials/step-builder/step-builder-bridge.js +436 -0
  61. package/tutorials/step-builder/utils/bezier-editor.js +379 -0
  62. package/tutorials/step-builder/utils/code-generator.js +127 -0
  63. package/tutorials/step-builder/utils/element-picker.js +125 -0
  64. package/tutorials/tutorial.scss +816 -0
  65. package/tutorials/utils/selectors.js +225 -0
  66. package/tutorials/utils/stability.js +76 -0
  67. package/tutorials/utils/svg.js +46 -0
@@ -0,0 +1,225 @@
1
+ import {Plugin} from 'ckeditor5';
2
+ // Ensure highlight.js is imported in the environment (e.g., via global script)
3
+ import hljs from 'highlight.js'; // (optional, if using bundling)
4
+ import { JsonBlockCommand } from './JsonBlockCommand';
5
+
6
+ import json from 'highlight.js/lib/languages/json';
7
+ import 'highlight.js/styles/atom-one-dark.css'; // or the theme of your choice
8
+ import { padStart } from 'lodash';
9
+
10
+ hljs.registerLanguage('json', json);
11
+
12
+ const TAB_SIZE = window.TAB_SIZE || 2;
13
+
14
+ function getJsonText(jsonBlockElement) {
15
+ let text = '';
16
+ for (const child of jsonBlockElement.getChildren()) {
17
+ if (child.is('$text')) {
18
+ text += child.data;
19
+ } else if (child.name === 'softBreak') {
20
+ text += '\n';
21
+ }
22
+ }
23
+ return text;
24
+ }
25
+
26
+ export class JsonBlockEditing extends Plugin {
27
+ static get pluginName() { return 'JsonBlockEditing'; }
28
+
29
+ init() {
30
+ const editor = this.editor;
31
+ const schema = editor.model.schema;
32
+ const conversion = editor.conversion;
33
+ const model = editor.model;
34
+
35
+ // **Schema**: Register the 'jsonBlock' model element
36
+ schema.register('jsonBlock', {
37
+ allowWhere: '$block',
38
+ allowContentOf: '$block',
39
+ isBlock: true,
40
+ isLimit: true // This is key!
41
+ });
42
+ // Restrict attributes within the jsonBlock (only plain text, no styles)
43
+ schema.addAttributeCheck((context, attributeName) => {
44
+ if (context.endsWith('jsonBlock')) {
45
+ // Do not allow any formatting attributes in text within the JSON block
46
+ return false;
47
+ }
48
+ });
49
+
50
+ // **Upcast Conversion (view -> model)**: from <pre class="json-block"><code class="language-json"> to model
51
+ conversion.for('upcast').elementToElement({
52
+ view: {
53
+ name: 'pre',
54
+ classes: 'json-block'
55
+ },
56
+ model: (viewElement, { writer }) => {
57
+ const jsonBlock = writer.createElement('jsonBlock');
58
+
59
+ return jsonBlock;
60
+ }
61
+ });
62
+
63
+ // Add dynamic highlighting using highlight.js without interfering with editing
64
+ conversion.for('downcast').elementToElement({
65
+ model: 'jsonBlock',
66
+ view: (modelItem, conversionApi) => {
67
+ const { writer } = conversionApi;
68
+
69
+ const pre = writer.createContainerElement('pre', { class: 'json-block' });
70
+
71
+ return pre;
72
+ }
73
+ });
74
+
75
+ // Intercept the Enter key within jsonBlock to insert a new line instead of exiting the block
76
+ editor.editing.view.document.on('enter', (evt, data) => {
77
+ const pos = editor.model.document.selection.getFirstPosition();
78
+ if (pos.parent.is('element', 'jsonBlock')) {
79
+ editor.model.change(writer => {
80
+ // Insert a newline character at the current position
81
+ writer.insertText('\n', pos);
82
+ });
83
+ evt.stop(); // prevent default behavior (exiting or splitting the block)
84
+ }
85
+ }, { priority: 'high' });
86
+
87
+ editor.editing.view.document.on('keydown', (evt, data) => {
88
+ const selection = model.document.selection;
89
+ const position = selection.getFirstPosition();
90
+
91
+ // Detect if Tab is pressed
92
+ if (data.keyCode === 9) {
93
+ model.change(writer => {
94
+ writer.insertText(''.padStart(TAB_SIZE, ' '), position);
95
+ });
96
+
97
+ data.preventDefault();
98
+ evt.stop();
99
+ }
100
+ });
101
+
102
+ editor.editing.view.document.on('blur', (evt, data) => {
103
+ const pos = editor.model.document.selection.getFirstPosition();
104
+ const jsonBlock = pos.findAncestor('jsonBlock');
105
+ if (jsonBlock) {
106
+ editor.model.change(writer => {
107
+ let jsonTextWithMentions = '';
108
+ let jsonMappingMentions = [];
109
+ for (const child of jsonBlock.getChildren()) {
110
+ if (child.is('$text')) {
111
+ jsonTextWithMentions += child.data;
112
+ } else if (child.hasAttribute('data-mention')) {
113
+ const mention = child.getAttribute('data-mention');
114
+ jsonTextWithMentions += '{{ ' + mention + ' }}'; // Use the mention name for JSON
115
+ jsonMappingMentions[mention] = '<span class="mention" contenteditable="false" data-mention="' + mention + '" data-original="' + child.getAttribute('data-original') + '">' + child.getAttribute('data-original') + '</span>';
116
+ } else if (child.name === 'softBreak') {
117
+ jsonTextWithMentions += '\n';
118
+ }
119
+ }
120
+
121
+ try {
122
+ let formatted = JSON.stringify(JSON.parse(jsonTextWithMentions), null, 2);
123
+ const mentionRegex = /\{\{\s*[a-zA-Z_]*?\s\}\}/;
124
+ const splitLines = [];
125
+
126
+ let remainingLine = formatted;
127
+ let match;
128
+
129
+ while ((match = mentionRegex.exec(remainingLine)) !== null) {
130
+ const parts = remainingLine.split(match[0]);
131
+
132
+ if (parts[0]) {
133
+ splitLines.push(parts[0]); // Agregar texto antes del mention
134
+ }
135
+
136
+ splitLines.push(jsonMappingMentions[match[0].replaceAll(/[\{\}\s]/g, '')]); // Agregar el mention como un nodo intermedio
137
+
138
+ remainingLine = parts[1];
139
+ }
140
+
141
+ if (remainingLine) {
142
+ splitLines.push(remainingLine); // Agregar texto después del mention
143
+ }
144
+
145
+ const previousChildren = Array.from(jsonBlock.getChildren());
146
+
147
+ previousChildren.forEach((child) => {
148
+ if (child.is('$text')) {
149
+ writer.remove(child)
150
+ }
151
+ })
152
+
153
+ let insertPosition = writer.createPositionAt(jsonBlock, 'end');
154
+
155
+ for (const line of splitLines) {
156
+ // If it has <>, it's a mention span
157
+ if (line.startsWith('<') && line.endsWith('>')) {
158
+ const mentionElement = writer.createElement('mention', {
159
+ 'data-mention': line.match(/data-mention="([^"]+)"/)[1],
160
+ 'data-original': line.match(/data-original="([^"]+)"/)[1]
161
+ });
162
+
163
+ writer.insert(mentionElement, insertPosition);
164
+ // Actualizar la posición después de insertar
165
+ insertPosition = writer.createPositionAfter(mentionElement);
166
+ } else {
167
+ // Si es texto, insertarlo en la posición actual
168
+ writer.insertText(line, insertPosition);
169
+ // Actualizar la posición después de insertar
170
+ insertPosition = writer.createPositionAt(jsonBlock, 'end');
171
+ }
172
+ }
173
+
174
+ previousChildren.forEach((child) => {
175
+ if (!child.is('$text')) {
176
+ writer.remove(child)
177
+ }
178
+ })
179
+
180
+
181
+ } catch (e) {
182
+ // If JSON is invalid, do nothing
183
+ }
184
+ });
185
+ }
186
+ });
187
+
188
+ // Register the 'jsonBlock' command
189
+ editor.commands.add('jsonBlock', new JsonBlockCommand(editor));
190
+
191
+ // Selection management for highlighting/validation (see below)
192
+ this._setupHighlightAndValidation();
193
+ }
194
+
195
+ _setupHighlightAndValidation() {
196
+ const editor = this.editor;
197
+ const model = editor.model;
198
+ const view = editor.editing.view;
199
+
200
+ // Detect changes in the JSON block content for validation
201
+ model.document.on('change:data', () => {
202
+ const jsonBlock = model.document.selection.getFirstPosition().findAncestor('jsonBlock');
203
+ if (!jsonBlock) return;
204
+ // Validate JSON syntax of the current content
205
+ const jsonText = getJsonText(jsonBlock);
206
+ let isValid = true;
207
+ try {
208
+ if (jsonText.trim() !== '') {
209
+ JSON.parse(jsonText);
210
+ }
211
+ } catch (e) {
212
+ isValid = false;
213
+ }
214
+ // Update CSS classes in the view based on validity (e.g., red/green border)
215
+ const viewElement = editor.editing.mapper.toViewElement(jsonBlock);
216
+ if (!viewElement) return; // ✅ Protect against errors if the block was removed
217
+
218
+ view.change(writer => {
219
+ writer.removeClass([ 'json-valid', 'json-invalid' ], viewElement);
220
+ writer.addClass(isValid ? 'json-valid' : 'json-invalid', viewElement);
221
+ writer.setAttribute('data-validity', isValid ? 'Valid JSON' : 'Invalid JSON', viewElement);
222
+ });
223
+ });
224
+ }
225
+ }
@@ -0,0 +1,21 @@
1
+ import {ButtonView, Plugin} from 'ckeditor5';
2
+
3
+ export class JsonBlockUI extends Plugin {
4
+ init() {
5
+ const editor = this.editor;
6
+ editor.ui.componentFactory.add('jsonBlock', locale => {
7
+ const command = editor.commands.get('jsonBlock');
8
+ const button = new ButtonView(locale);
9
+ button.set({
10
+ label: 'JSON Block',
11
+ withText: true, // Displays the label as text (you could use a custom icon)
12
+ tooltip: 'Insert a JSON block'
13
+ });
14
+ // Bind the button state to the command
15
+ button.bind('isOn', 'isEnabled').to(command, 'value', 'isEnabled');
16
+ // Execute the command when clicked
17
+ this.listenTo(button, 'execute', () => editor.execute('jsonBlock'));
18
+ return button;
19
+ });
20
+ }
21
+ }
@@ -0,0 +1,118 @@
1
+ import { Plugin } from 'ckeditor5';
2
+
3
+ export default class MentionPlugin extends Plugin {
4
+ init() {
5
+ const editor = this.editor;
6
+
7
+ editor.model.schema.register('mention', {
8
+ isInline: true,
9
+ isObject: true,
10
+ allowWhere: '$text',
11
+ allowAttributes: ['data-mention', 'data-original']
12
+ });
13
+
14
+ // Allow data-mention as an attribute in $text:
15
+ editor.model.schema.extend('$text', {
16
+ allowAttributes: ['data-mention', 'data-original']
17
+ });
18
+
19
+ // Upcast the <span class="mention" data-mention="..."> view to the model:
20
+ editor.conversion.for('upcast').elementToElement({
21
+ view: {
22
+ name: 'span',
23
+ classes: 'mention'
24
+ },
25
+ model: (viewElement, { writer }) => {
26
+ return writer.createElement('mention', {
27
+ 'data-mention': viewElement.getAttribute('data-mention'),
28
+ 'data-original': viewElement.getAttribute('data-original') || viewElement.getChild(0).data
29
+ });
30
+ }
31
+ });
32
+
33
+ editor.conversion.for('downcast').elementToElement({
34
+ model: 'mention',
35
+ view: (modelItem, { writer }) => {
36
+ const dataMention = modelItem.getAttribute('data-mention');
37
+ const dataOriginal = modelItem.getAttribute('data-original');
38
+
39
+ // Create the <span> element with attributes and inner content
40
+ const span = writer.createContainerElement('span', {
41
+ class: 'mention',
42
+ 'data-mention': dataMention,
43
+ 'data-original': dataOriginal,
44
+ 'contenteditable': 'false'
45
+ });
46
+
47
+ // Set the inner content of the <span> to the value of data-original
48
+ const textNode = writer.createText(dataOriginal);
49
+ writer.insert(writer.createPositionAt(span, 0), textNode);
50
+
51
+ return span;
52
+ }
53
+ });
54
+
55
+ // Implement a robust postfixer to maintain mention integrity
56
+ editor.model.document.registerPostFixer(writer => {
57
+ let wasFixed = false;
58
+ const changes = editor.model.document.differ.getChanges();
59
+
60
+ function isSpanNode(node) {
61
+ return node && node.is('$text') && node.hasAttribute('data-mention');
62
+ }
63
+
64
+ for (const change of changes) {
65
+ if (change.type === 'remove') {
66
+ const position = change.position;
67
+
68
+ if (isSpanNode(position.nodeAfter) && position.nodeBefore.getAttribute('data-original') != position.nodeBefore._data) {
69
+ writer.remove(position.nodeAfter);
70
+ wasFixed = true;
71
+ } else if (isSpanNode(position.nodeBefore) && position.nodeAfter.getAttribute('data-original') != position.nodeAfter._data) {
72
+ writer.remove(position.nodeBefore);
73
+ wasFixed = true;
74
+ }
75
+ }
76
+ }
77
+
78
+ return wasFixed;
79
+ });
80
+
81
+ // Add a patch to handle the `document-selection-wrong-position` error when clicking on a mention span
82
+ editor.editing.view.document.on('mousedown', (evt, data) => {
83
+ try {
84
+ const domTarget = data.domTarget;
85
+
86
+ if (domTarget.nodeName === 'SPAN' && domTarget.classList.contains('mention')) {
87
+ const domMention = domTarget.closest('.mention');
88
+ const viewMention = editor.editing.view.domConverter.mapDomToView(domMention);
89
+
90
+ if (viewMention) {
91
+ const modelMention = editor.editing.mapper.toModelElement(viewMention);
92
+ if (modelMention) {
93
+ editor.editing.view.focus();
94
+
95
+ editor.model.change(writer => {
96
+ // Select the span element completely
97
+ const range = writer.createRangeIn(modelMention);
98
+ writer.setSelection(range);
99
+ });
100
+
101
+ // Prevent default behavior to avoid invalid selection
102
+ data.preventDefault();
103
+ evt.stop();
104
+ }
105
+ }
106
+ }
107
+ } catch (error) {
108
+ if (error.name === 'CKEditorError' && error.message.includes('document-selection-wrong-position')) {
109
+ editor.model.change(writer => {
110
+ writer.setSelection(editor.model.document.getRoot(), 'end');
111
+ });
112
+ } else {
113
+ throw error;
114
+ }
115
+ }
116
+ });
117
+ }
118
+ }
@@ -0,0 +1,333 @@
1
+ export class KompoJsConfigBuilder {
2
+ components = {};
3
+ bootstrapCallback = null;
4
+ filesToImport = new Set();
5
+ includeTutorialEngine = true;
6
+ tutorialEngineConfig = {};
7
+ includeJquery = true;
8
+ includeCkEditor = true;
9
+ includeKompoMaps = true;
10
+ vuePlugins = [];
11
+ windowDecorators = [];
12
+ windowUtilsObject = {};
13
+ appSelector = '#app';
14
+
15
+ beforeStepCallbacks = {};
16
+ afterStepCallbacks = {};
17
+
18
+ /**
19
+ * @param {string} componentName
20
+ * @returns {KompoJsConfigBuilder}
21
+ */
22
+ excludeComponent(componentName) {
23
+ delete this.components[componentName];
24
+
25
+ return this;
26
+ }
27
+
28
+ /**
29
+ * @param {string} componentName
30
+ * @param {object} componentDefinition - A resolved Vue component object
31
+ * @returns {KompoJsConfigBuilder}
32
+ */
33
+ addComponent(componentName, componentDefinition) {
34
+ this.components[componentName] = componentDefinition;
35
+ return this;
36
+ }
37
+
38
+ /**
39
+ * @param {{[key: string]: object}} components - Map of name to resolved Vue component objects
40
+ * @returns {KompoJsConfigBuilder}
41
+ */
42
+ addComponents(components) {
43
+ for (const [componentName, componentDefinition] of Object.entries(components)) {
44
+ this.addComponent(componentName, componentDefinition);
45
+ }
46
+
47
+ return this;
48
+ }
49
+
50
+ /**
51
+ * @param {string[]} componentNames
52
+ * @returns {KompoJsConfigBuilder}
53
+ */
54
+ excludeComponents(componentNames) {
55
+ for (const componentName of componentNames) {
56
+ this.excludeComponent(componentName);
57
+ }
58
+ return this;
59
+ }
60
+
61
+ bootstrap(callback) {
62
+ this.bootstrapCallback = callback;
63
+ return this;
64
+ }
65
+
66
+ /**
67
+ * @param {Function} callback - A callback that requires/imports the file, e.g. () => require('./file.js')
68
+ * @returns {KompoJsConfigBuilder}
69
+ */
70
+ addFileToImport(callback) {
71
+ this.filesToImport.add(callback);
72
+ return this;
73
+ }
74
+
75
+ /**
76
+ * @param {Function[]} callbacks
77
+ * @returns {KompoJsConfigBuilder}
78
+ */
79
+ addFilesToImport(callbacks) {
80
+ for (const callback of callbacks) {
81
+ this.addFileToImport(callback);
82
+ }
83
+ return this;
84
+ }
85
+
86
+ excludeFileToImport(callback) {
87
+ this.filesToImport.delete(callback);
88
+ return this;
89
+ }
90
+
91
+ excludeFilesToImport(callbacks) {
92
+ for (const callback of callbacks) {
93
+ this.excludeFileToImport(callback);
94
+ }
95
+ return this;
96
+ }
97
+
98
+ withTutorialEngine(config = {}) {
99
+ this.includeTutorialEngine = true;
100
+ this.tutorialEngineConfig = config;
101
+ return this;
102
+ }
103
+
104
+ withoutTutorialEngine() {
105
+ this.includeTutorialEngine = false;
106
+ return this;
107
+ }
108
+
109
+ withJquery() {
110
+ this.includeJquery = true;
111
+ return this;
112
+ }
113
+
114
+ withoutJquery() {
115
+ this.includeJquery = false;
116
+ return this;
117
+ }
118
+
119
+ withCkEditor() {
120
+ this.includeCkEditor = true;
121
+ return this;
122
+ }
123
+
124
+ withoutCkEditor() {
125
+ this.includeCkEditor = false;
126
+ return this;
127
+ }
128
+
129
+ withKompoMaps() {
130
+ this.includeKompoMaps = true;
131
+ return this;
132
+ }
133
+
134
+ withoutKompoMaps() {
135
+ this.includeKompoMaps = false;
136
+ return this;
137
+ }
138
+
139
+ /**
140
+ * @param {object} plugin - A Vue plugin to register via Vue.use()
141
+ * @returns {KompoJsConfigBuilder}
142
+ */
143
+ addVuePlugin(plugin) {
144
+ this.vuePlugins.push(plugin);
145
+ return this;
146
+ }
147
+
148
+ addWindowDecorator(decorator) {
149
+ this.windowDecorators.push(decorator);
150
+ return this;
151
+ }
152
+
153
+ addWindowUtilsItem(key, value) {
154
+ this.windowUtilsObject[key] = value;
155
+ return this;
156
+ }
157
+
158
+ mergeWindowUtils(utilsObject) {
159
+ this.windowUtilsObject = {
160
+ ...this.windowUtilsObject,
161
+ ...utilsObject
162
+ };
163
+ return this;
164
+ }
165
+
166
+ setAppSelector(selector) {
167
+ this.appSelector = selector;
168
+ return this;
169
+ }
170
+
171
+ addBeforeStepCallback(stepName, callback) {
172
+ if (!this.beforeStepCallbacks[stepName]) {
173
+ this.beforeStepCallbacks[stepName] = [];
174
+ }
175
+ this.beforeStepCallbacks[stepName].push(callback);
176
+ return this;
177
+ }
178
+
179
+ addAfterStepCallback(stepName, callback) {
180
+ if (!this.afterStepCallbacks[stepName]) {
181
+ this.afterStepCallbacks[stepName] = [];
182
+ }
183
+ this.afterStepCallbacks[stepName].push(callback);
184
+ return this;
185
+ }
186
+ }
187
+
188
+ export class KompoJsInitializer {
189
+
190
+ static ESSENTIAL_STEPS = new Set([
191
+ 'bootstrapExecution',
192
+ 'bootVue',
193
+ 'instanceApp',
194
+ ]);
195
+
196
+ /**
197
+ * @param {KompoJsConfigBuilder} config
198
+ */
199
+ constructor(config, window) {
200
+ this.config = config;
201
+ this.window = window;
202
+ }
203
+
204
+ initialize() {
205
+ this._callStep('bootstrapExecution');
206
+
207
+ this._callStep('requireFilesToImport');
208
+
209
+ this._callStep('bootJqueryIfRequired');
210
+
211
+ this._callStep('bootVue');
212
+
213
+ this._callStep('decorateWindow');
214
+
215
+ this._callStep('bootCkEditorIfRequired');
216
+
217
+ this._callStep('bootMapsIfRequired');
218
+
219
+ this._callStep('bootTutorialEngineIfRequired');
220
+
221
+ this._callStep('instanceApp');
222
+ }
223
+
224
+ _callStep(stepName) {
225
+ const isEssential = KompoJsInitializer.ESSENTIAL_STEPS.has(stepName);
226
+
227
+ if (isEssential) {
228
+ this._executeStep(stepName);
229
+ } else {
230
+ try {
231
+ this._executeStep(stepName);
232
+ } catch (error) {
233
+ console.error(`[KompoJs] Non-essential step "${stepName}" failed:`, error);
234
+ }
235
+ }
236
+ }
237
+
238
+ _executeStep(stepName) {
239
+ if (this.config.beforeStepCallbacks[stepName]) {
240
+ for (const callback of this.config.beforeStepCallbacks[stepName]) {
241
+ callback();
242
+ }
243
+ }
244
+
245
+ this[stepName]();
246
+
247
+ if (this.config.afterStepCallbacks[stepName]) {
248
+ for (const callback of this.config.afterStepCallbacks[stepName]) {
249
+ callback();
250
+ }
251
+ }
252
+ }
253
+
254
+ bootstrapExecution() {
255
+ if (this.config.bootstrapCallback) {
256
+ this.config.bootstrapCallback();
257
+ }
258
+ }
259
+
260
+ requireFilesToImport() {
261
+ for (const callback of this.config.filesToImport) {
262
+ try {
263
+ callback();
264
+ } catch (error) {
265
+ console.error('[KompoJs] File import failed:', error);
266
+ }
267
+ }
268
+ }
269
+
270
+ bootJqueryIfRequired() {
271
+ if (this.config.includeJquery) {
272
+ this.window.$ = this.window.jQuery = require('jquery');
273
+ }
274
+ }
275
+
276
+ bootVue() {
277
+ const Vue = require('vue/dist/vue');
278
+ this.window.Vue = Vue;
279
+
280
+ require('vue-kompo');
281
+
282
+ for (const plugin of this.config.vuePlugins) {
283
+ Vue.use(plugin);
284
+ }
285
+
286
+ for (const [componentName, componentDefinition] of Object.entries(this.config.components)) {
287
+ Vue.component(componentName, componentDefinition);
288
+ }
289
+ }
290
+
291
+ decorateWindow() {
292
+ for (const [key, value] of Object.entries(this.config.windowUtilsObject)) {
293
+ if (!this.window.utils) {
294
+ this.window.utils = {};
295
+ }
296
+
297
+ this.window.utils[key] = value;
298
+ this.window[key] = value;
299
+ }
300
+
301
+ for (const decorator of this.config.windowDecorators) {
302
+ decorator(this.window);
303
+ }
304
+ }
305
+
306
+ bootCkEditorIfRequired() {
307
+ if (this.config.includeCkEditor) {
308
+ require('../kompo-ckeditor-1.0.17/index.js');
309
+ }
310
+ }
311
+
312
+ bootMapsIfRequired() {
313
+ if (this.config.includeKompoMaps) {
314
+ this.window.GoogleMapsStyle = require('kompo-googlemaps/styles/silver').default;
315
+ require('kompo-googlemaps');
316
+ }
317
+ }
318
+
319
+ bootTutorialEngineIfRequired() {
320
+ if (this.config.includeTutorialEngine) {
321
+ const { TutorialEngine } = require('../tutorials/TutorialEngine.js');
322
+ const engine = new TutorialEngine(this.config.tutorialEngineConfig);
323
+ engine.preload = TutorialEngine.preload;
324
+ this.window.TutorialEngine = engine;
325
+ }
326
+ }
327
+
328
+ instanceApp() {
329
+ new this.window.Vue({
330
+ el: this.config.appSelector,
331
+ });
332
+ }
333
+ }