alchemy-widget 0.2.0 → 0.2.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.
@@ -5,14 +5,18 @@
5
5
  *
6
6
  * @author Jelle De Loecker <jelle@elevenways.be>
7
7
  * @since 0.1.0
8
- * @version 0.1.0
8
+ * @version 0.2.1
9
9
  *
10
10
  * @param {Object} config
11
11
  */
12
12
  const Widget = Function.inherits('Alchemy.Base', 'Alchemy.Widget', function Widget(config) {
13
13
 
14
14
  // The configuration of this widget
15
- this.config = config || {};
15
+ if (config) {
16
+ this.config = config;
17
+ }
18
+
19
+ this.originalconfig = this.config;
16
20
 
17
21
  // Are we currently editing?
18
22
  this.editing = false;
@@ -72,6 +76,24 @@ Widget.setProperty(function element() {
72
76
  return this.widget = element;
73
77
  });
74
78
 
79
+ /**
80
+ * The config object
81
+ *
82
+ * @author Jelle De Loecker <jelle@elevenways.be>
83
+ * @since 0.2.1
84
+ * @version 0.2.1
85
+ *
86
+ * @type {Object}
87
+ */
88
+ Widget.enforceProperty(function config(new_value) {
89
+
90
+ if (!new_value) {
91
+ new_value = {};
92
+ }
93
+
94
+ return new_value;
95
+ });
96
+
75
97
  /**
76
98
  * A reference to the renderer
77
99
  *
@@ -96,12 +118,37 @@ Widget.enforceProperty(function hawkejs_renderer(new_value) {
96
118
  return new_value;
97
119
  });
98
120
 
121
+ /**
122
+ * Visibility of the widget
123
+ *
124
+ * @author Jelle De Loecker <jelle@elevenways.be>
125
+ * @since 0.2.1
126
+ * @version 0.2.1
127
+ *
128
+ * @type {Boolean}
129
+ */
130
+ Widget.enforceProperty(function is_hidden(new_value) {
131
+
132
+ if (new_value == null) {
133
+ new_value = this.config.hidden;
134
+
135
+ if (new_value == null) {
136
+ new_value = false;
137
+ }
138
+ } else {
139
+ this.config.hidden = new_value;
140
+ this.queueVisibilityUpdate();
141
+ }
142
+
143
+ return new_value;
144
+ });
145
+
99
146
  /**
100
147
  * Prepare the schema & actions
101
148
  *
102
149
  * @author Jelle De Loecker <jelle@elevenways.be>
103
150
  * @since 0.1.0
104
- * @version 0.2.0
151
+ * @version 0.2.1
105
152
  */
106
153
  Widget.constitute(function prepareSchema() {
107
154
 
@@ -126,6 +173,19 @@ Widget.constitute(function prepareSchema() {
126
173
  array: true,
127
174
  });
128
175
 
176
+ // Should this widget be hidden?
177
+ this.schema.addField('hidden', 'Boolean', {
178
+ title : 'Should this widget be hidden?',
179
+ description : 'Hidden widgets are only visible during editing',
180
+ default : false,
181
+ });
182
+
183
+ this.schema.addField('language', 'String', {
184
+ title : 'Language override',
185
+ description : 'If the content of this widget is in a different language, set it here',
186
+ widget_config_editable : true,
187
+ });
188
+
129
189
  // Add the "copy to clipboard" action
130
190
  let copy = this.createAction('copy', 'Copy to clipboard');
131
191
 
@@ -167,6 +227,36 @@ Widget.constitute(function prepareSchema() {
167
227
 
168
228
  save.setIcon('floppy-disk');
169
229
 
230
+ // Add the hide action
231
+ let hide = this.createAction('hide', 'Hide');
232
+
233
+ hide.close_actionbar = true;
234
+
235
+ hide.setHandler(function hideAction(widget_el, handle) {
236
+ widget_el.instance.is_hidden = true;
237
+ });
238
+
239
+ hide.setTester(function hideTester(widget_el, handle) {
240
+ return !widget_el.instance.is_hidden;
241
+ });
242
+
243
+ hide.setIcon('eye-slash');
244
+
245
+ // Add the show action
246
+ let show = this.createAction('show', 'Show');
247
+
248
+ show.close_actionbar = true;
249
+
250
+ show.setHandler(function showAction(widget_el, handle) {
251
+ widget_el.instance.is_hidden = false;
252
+ });
253
+
254
+ show.setTester(function showTester(widget_el, handle) {
255
+ return widget_el.instance.is_hidden;
256
+ });
257
+
258
+ show.setIcon('eye');
259
+
170
260
  // Add the remove action
171
261
  let remove = this.createAction('remove', 'Remove');
172
262
 
@@ -537,7 +627,7 @@ Widget.setMethod(function _createWidgetElement() {
537
627
  *
538
628
  * @author Jelle De Loecker <jelle@elevenways.be>
539
629
  * @since 0.1.0
540
- * @version 0.1.0
630
+ * @version 0.2.2
541
631
  *
542
632
  * @return {HTMLElement}
543
633
  */
@@ -551,28 +641,69 @@ Widget.setMethod(function _createPopulatedWidgetElement() {
551
641
 
552
642
  this.widget = element;
553
643
 
554
- // See if it can be populated
555
- if (typeof this.populateWidget == 'function') {
556
- this.populateWidget(element);
557
- }
644
+ this.loadWidget();
558
645
 
559
646
  return element;
560
647
  });
561
648
 
649
+ /**
650
+ * Load the widget element: populate it & finalize it
651
+ *
652
+ * @author Jelle De Loecker <jelle@elevenways.be>
653
+ * @since 0.2.2
654
+ * @version 0.2.2
655
+ *
656
+ * @return {Promise|null}
657
+ */
658
+ Widget.setMethod(function loadWidget() {
659
+
660
+ let populate = this.populateWidget();
661
+
662
+ if (Pledge.isThenable(populate)) {
663
+ let pledge = new Pledge();
664
+
665
+ Pledge.done(populate, (err, result) => {
666
+
667
+ if (err) {
668
+ pledge.reject(err);
669
+ }
670
+
671
+ pledge.resolve(this.finalizePopulatedWidget());
672
+ });
673
+
674
+ return pledge;
675
+ } else {
676
+ return this.finalizePopulatedWidget();
677
+ }
678
+ });
679
+
680
+ /**
681
+ * Populate the actual widget
682
+ *
683
+ * @author Jelle De Loecker <jelle@elevenways.be>
684
+ * @since 0.2.1
685
+ * @version 0.2.1
686
+ */
687
+ Widget.setMethod(function populateWidget() {
688
+ // Does nothing on its own
689
+ });
690
+
562
691
  /**
563
692
  * Populate the contents of the widget
564
693
  *
565
694
  * @author Jelle De Loecker <jelle@elevenways.be>
566
695
  * @since 0.1.0
567
- * @version 0.1.6
696
+ * @version 0.2.1
568
697
  */
569
- Widget.setMethod(function populateWidget() {
698
+ Widget.setMethod(function finalizePopulatedWidget() {
570
699
 
571
- if (this.config && this.config.wrapper_class_names) {
700
+ const config = this.config;
701
+
702
+ if (config.wrapper_class_names) {
572
703
  let name,
573
704
  i;
574
705
 
575
- let class_names = Array.cast(this.config.wrapper_class_names);
706
+ let class_names = Array.cast(config.wrapper_class_names);
576
707
 
577
708
  for (i = 0; i < class_names.length; i++) {
578
709
  name = class_names[i];
@@ -580,6 +711,12 @@ Widget.setMethod(function populateWidget() {
580
711
  }
581
712
  }
582
713
 
714
+ if (config.language) {
715
+ this.widget.setAttribute('lang', config.language);
716
+ } else {
717
+ this.widget.removeAttribute('lang');
718
+ }
719
+
583
720
  let child_classes = this.widget.child_class;
584
721
 
585
722
  if (child_classes) {
@@ -590,6 +727,68 @@ Widget.setMethod(function populateWidget() {
590
727
  Hawkejs.addClasses(children[i], child_classes);
591
728
  }
592
729
  }
730
+
731
+ let child_roles = this.widget.child_role;
732
+
733
+ if (child_roles) {
734
+ let children = this.widget.children,
735
+ child,
736
+ i;
737
+
738
+ for (i = 0; i < children.length; i++) {
739
+ child = children[i];
740
+
741
+ if (!child.hasAttribute('role')) {
742
+ child.setAttribute('role', child_roles);
743
+ }
744
+ }
745
+ }
746
+
747
+ this.checkVisibility();
748
+ });
749
+
750
+ /**
751
+ * Queue a widget element visibility update
752
+ *
753
+ * @author Jelle De Loecker <jelle@elevenways.be>
754
+ * @since 0.2.1
755
+ * @version 0.2.1
756
+ */
757
+ Widget.setMethod(function queueVisibilityUpdate() {
758
+
759
+ if (this._visibility_update_queue) {
760
+ clearTimeout(this._visibility_update_queue);
761
+ }
762
+
763
+ this._visibility_update_queue = setTimeout(() => {
764
+ this.checkVisibility();
765
+ this._visibility_update_queue = null;
766
+ }, 50);
767
+ });
768
+
769
+ /**
770
+ * Check the widget element visibility
771
+ *
772
+ * @author Jelle De Loecker <jelle@elevenways.be>
773
+ * @since 0.2.1
774
+ * @version 0.2.1
775
+ */
776
+ Widget.setMethod(function checkVisibility() {
777
+
778
+ let should_be_hidden = this.is_hidden;
779
+
780
+ if (this.editing) {
781
+ this.widget.hidden = false;
782
+ } else {
783
+ this.widget.hidden = should_be_hidden;
784
+ }
785
+
786
+ if (should_be_hidden) {
787
+ this.widget.classList.add('aw-hidden');
788
+ } else {
789
+ this.widget.classList.remove('aw-hidden');
790
+ }
791
+
593
792
  });
594
793
 
595
794
  /**
@@ -597,7 +796,7 @@ Widget.setMethod(function populateWidget() {
597
796
  *
598
797
  * @author Jelle De Loecker <jelle@elevenways.be>
599
798
  * @since 0.1.0
600
- * @version 0.1.6
799
+ * @version 0.2.1
601
800
  */
602
801
  Widget.setMethod(async function startEditor() {
603
802
 
@@ -617,6 +816,8 @@ Widget.setMethod(async function startEditor() {
617
816
  if (typeof this._startEditor == 'function') {
618
817
  this._startEditor();
619
818
  }
819
+
820
+ this.checkVisibility();
620
821
  });
621
822
 
622
823
  /**
@@ -624,7 +825,7 @@ Widget.setMethod(async function startEditor() {
624
825
  *
625
826
  * @author Jelle De Loecker <jelle@elevenways.be>
626
827
  * @since 0.1.0
627
- * @version 0.1.0
828
+ * @version 0.2.1
628
829
  */
629
830
  Widget.setMethod(function stopEditor() {
630
831
 
@@ -638,7 +839,13 @@ Widget.setMethod(function stopEditor() {
638
839
 
639
840
  if (typeof this._stopEditor == 'function') {
640
841
  this._stopEditor();
842
+
843
+ // Remove the editing class again
844
+ // (some editors will try to restore the original classes)
845
+ this.widget.classList.remove('aw-editing');
641
846
  }
847
+
848
+ this.checkVisibility();
642
849
  });
643
850
 
644
851
  /**
@@ -646,13 +853,13 @@ Widget.setMethod(function stopEditor() {
646
853
  *
647
854
  * @author Jelle De Loecker <jelle@elevenways.be>
648
855
  * @since 0.1.0
649
- * @version 0.1.6
856
+ * @version 0.2.2
650
857
  */
651
858
  Widget.setMethod(async function rerender() {
652
859
 
653
860
  Hawkejs.removeChildren(this.widget);
654
861
 
655
- await this.populateWidget();
862
+ await this.loadWidget();
656
863
 
657
864
  if (this.editing) {
658
865
  this.startEditor();
@@ -38,12 +38,32 @@ Container.constitute(function prepareSchema() {
38
38
  *
39
39
  * @author Jelle De Loecker <jelle@elevenways.be>
40
40
  * @since 0.1.0
41
- * @version 0.1.0
41
+ * @version 0.2.2
42
+ */
43
+ Container.setMethod(function initContainer() {
44
+ return this.loadWidget();
45
+ });
46
+
47
+ /**
48
+ * Populate the widget
49
+ *
50
+ * @author Jelle De Loecker <jelle@elevenways.be>
51
+ * @since 0.2.1
52
+ * @version 0.2.1
42
53
  *
43
54
  * @return {HTMLElement}
44
55
  */
45
- Container.setMethod(function initContainer() {
46
- this.populateWidget();
56
+ Container.setMethod(function populateWidget() {
57
+
58
+ const widgets = this.config.widgets;
59
+
60
+ if (widgets?.length) {
61
+ let widget;
62
+
63
+ for (widget of widgets) {
64
+ this.widget.addWidget(widget.type, widget.config);
65
+ }
66
+ }
47
67
  });
48
68
 
49
69
  /**
@@ -133,8 +133,6 @@ Tabs.setMethod(function populateWidget() {
133
133
  }
134
134
 
135
135
  Hawkejs.replaceChildren(this.widget, wrapper);
136
-
137
- return populateWidget.super.call(this);
138
136
  });
139
137
 
140
138
  /**
@@ -180,7 +178,7 @@ Tabs.setMethod(function _startEditor() {
180
178
  *
181
179
  * @author Jelle De Loecker <jelle@elevenways.be>
182
180
  * @since 0.2.0
183
- * @version 0.2.0
181
+ * @version 0.2.2
184
182
  */
185
183
  Tabs.setMethod(function _stopEditor() {
186
184
 
@@ -191,5 +189,5 @@ Tabs.setMethod(function _stopEditor() {
191
189
  sub_widget.stopEditor();
192
190
  }
193
191
 
194
- this.populateWidget();
192
+ this.loadWidget();
195
193
  });
@@ -0,0 +1,60 @@
1
+ /**
2
+ * The Widget Template class
3
+ *
4
+ * @constructor
5
+ *
6
+ * @author Jelle De Loecker <jelle@elevenways.be>
7
+ * @since 0.2.1
8
+ * @version 0.2.1
9
+ *
10
+ * @param {Object} data
11
+ */
12
+ const Template = Function.inherits('Alchemy.Widget.Sourcecode', 'HawkejsTemplate');
13
+
14
+ /**
15
+ * Populate the widget
16
+ *
17
+ * @author Jelle De Loecker <jelle@elevenways.be>
18
+ * @since 0.2.1
19
+ * @version 0.2.1
20
+ *
21
+ * @param {HTMLElement} widget
22
+ */
23
+ Template.setMethod(async function populateWidget() {
24
+
25
+ let input = this.config.sourcecode;
26
+
27
+ if (input) {
28
+ input = input.trim();
29
+ }
30
+
31
+ Hawkejs.removeChildren(this.widget);
32
+
33
+ if (input) {
34
+
35
+ let hawkejs = this.hawkejs_renderer.hawkejs,
36
+ hash = Object.checksum(input),
37
+ name = 'interpret_' + hash,
38
+ fnc;
39
+
40
+ if (hawkejs.templates[name]) {
41
+ fnc = hawkejs.templates[name];
42
+ } else {
43
+ fnc = hawkejs.compile({
44
+ template_name : name,
45
+ template : input
46
+ });
47
+ }
48
+
49
+ let variables = {};
50
+ let placeholder = this.hawkejs_renderer.addSubtemplate(fnc, {print: false}, variables);
51
+
52
+ // If the widget is already part of the DOM,
53
+ // it's being edited and we need to manually kickstart the renderer
54
+ if (Blast.isBrowser && document.body.contains(this.widget)) {
55
+ await placeholder.getContent();
56
+ }
57
+
58
+ this.widget.append(placeholder);
59
+ }
60
+ });
@@ -78,18 +78,18 @@ Header.constitute(function addActions() {
78
78
  *
79
79
  * @author Jelle De Loecker <jelle@elevenways.be>
80
80
  * @since 0.1.0
81
- * @version 0.1.0
81
+ * @version 0.2.1
82
82
  *
83
83
  * @return {Object}
84
84
  */
85
85
  Header.setMethod(function syncConfig() {
86
86
 
87
- let header = this.widget.children[0],
87
+ let header = this.widget.querySelector('h1, h2, h3, h4, h5'),
88
88
  content = '',
89
89
  level = 1;
90
90
 
91
91
  if (header) {
92
- content = header.innerHTML;
92
+ content = header.textContent;
93
93
  level = parseInt(header.tagName[1]);
94
94
  }
95
95
 
@@ -104,7 +104,7 @@ Header.setMethod(function syncConfig() {
104
104
  *
105
105
  * @author Jelle De Loecker <jelle@elevenways.be>
106
106
  * @since 0.1.0
107
- * @version 0.1.0
107
+ * @version 0.2.1
108
108
  *
109
109
  * @param {HTMLElement} widget
110
110
  */
@@ -113,11 +113,9 @@ Header.setMethod(function populateWidget() {
113
113
  let level = this.config.level || 1;
114
114
 
115
115
  let header = this.createElement('h' + level);
116
- header.innerHTML = this.config.content || 'header level ' + level;
116
+ header.textContent = this.config.content || 'header level ' + level;
117
117
 
118
118
  this.widget.append(header);
119
-
120
- populateWidget.super.call(this);
121
119
  });
122
120
 
123
121
  /**
@@ -1,3 +1,4 @@
1
+
1
2
  /**
2
3
  * The Widget HTML class
3
4
  *
@@ -23,19 +24,67 @@ Html.constitute(function prepareSchema() {
23
24
  this.schema.addField('html', 'Html');
24
25
  });
25
26
 
27
+ /**
28
+ * Start the editor
29
+ *
30
+ * @author Jelle De Loecker <jelle@elevenways.be>
31
+ * @since 0.2.1
32
+ * @version 0.2.1
33
+ */
34
+ Html.setMethod(async function _startEditor() {
35
+
36
+ if (this.ckeditor) {
37
+ this.ckeditor.destroy();
38
+ }
39
+
40
+ let ckeditor_path = hawkejs.scene.exposed.ckeditor_path;
41
+
42
+ if (!ckeditor_path) {
43
+ return;
44
+ }
45
+
46
+ await hawkejs.require(ckeditor_path);
47
+
48
+ const options = {
49
+ toolbar: hawkejs.scene.exposed.ckeditor_toolbar,
50
+ updateSourceElementOnDestroy: true,
51
+ removePlugins: ['Markdown'],
52
+ simpleUpload: {
53
+ uploadUrl: alchemy.routeUrl('AlchemyWidgets#uploadImage'),
54
+ withCredentials: true,
55
+ },
56
+ };
57
+
58
+ let editor = await InlineEditor.create(this.widget, options);
59
+
60
+ this.ckeditor = editor;
61
+ });
62
+
63
+ /**
64
+ * Stop the editor
65
+ *
66
+ * @author Jelle De Loecker <jelle@elevenways.be>
67
+ * @since 0.2.1
68
+ * @version 0.2.1
69
+ */
70
+ Html.setMethod(function _stopEditor() {
71
+ if (this.ckeditor) {
72
+ this.ckeditor.destroy();
73
+ this.ckeditor = null;
74
+ }
75
+ });
76
+
26
77
  /**
27
78
  * Populate the widget
28
79
  *
29
80
  * @author Jelle De Loecker <jelle@elevenways.be>
30
81
  * @since 0.1.0
31
- * @version 0.1.0
82
+ * @version 0.2.1
32
83
  *
33
84
  * @param {HTMLElement} widget
34
85
  */
35
86
  Html.setMethod(function populateWidget() {
36
87
  this.widget.innerHTML = this.config.html;
37
-
38
- populateWidget.super.call(this);
39
88
  });
40
89
 
41
90
  /**
@@ -28,14 +28,12 @@ Markdown.constitute(function prepareSchema() {
28
28
  *
29
29
  * @author Jelle De Loecker <jelle@elevenways.be>
30
30
  * @since 0.1.0
31
- * @version 0.1.0
31
+ * @version 0.2.1
32
32
  *
33
33
  * @param {HTMLElement} widget
34
34
  */
35
35
  Markdown.setMethod(function populateWidget() {
36
36
 
37
- populateWidget.super.call(this);
38
-
39
37
  let source = this.config.markdown || '';
40
38
 
41
39
  if (!source) {
@@ -76,14 +74,14 @@ Markdown.setMethod(async function _startEditor() {
76
74
  *
77
75
  * @author Jelle De Loecker <jelle@elevenways.be>
78
76
  * @since 0.1.0
79
- * @version 0.1.0
77
+ * @version 0.2.2
80
78
  */
81
79
  Markdown.setMethod(function _stopEditor() {
82
80
 
83
81
  Hawkejs.removeChildren(this.widget);
84
82
  this.easy_mde = null;
85
83
 
86
- this.populateWidget();
84
+ return this.loadWidget();
87
85
  });
88
86
 
89
87
  /**
@@ -67,7 +67,7 @@ Partial.constitute(function prepareSchema() {
67
67
  *
68
68
  * @author Jelle De Loecker <jelle@elevenways.be>
69
69
  * @since 0.1.6
70
- * @version 0.1.6
70
+ * @version 0.2.1
71
71
  *
72
72
  * @param {HTMLElement} widget
73
73
  */
@@ -105,8 +105,6 @@ Partial.setMethod(async function populateWidget() {
105
105
 
106
106
  this.widget.append(placeholder);
107
107
  }
108
-
109
- populateWidget.super.call(this);
110
108
  });
111
109
 
112
110
  /**
@@ -163,7 +161,7 @@ Partial.setMethod(function _startEditor() {
163
161
  *
164
162
  * @author Jelle De Loecker <jelle@elevenways.be>
165
163
  * @since 0.1.6
166
- * @version 0.1.6
164
+ * @version 0.2.2
167
165
  */
168
166
  Partial.setMethod(function _stopEditor() {
169
167
 
@@ -174,7 +172,7 @@ Partial.setMethod(function _stopEditor() {
174
172
  sub_widget.stopEditor();
175
173
  }
176
174
 
177
- this.populateWidget();
175
+ return this.loadWidget();
178
176
  });
179
177
 
180
178
  /**
@@ -37,14 +37,12 @@ Sourcecode.setProperty('sourcecode_field', 'sourcecode');
37
37
  *
38
38
  * @author Jelle De Loecker <jelle@elevenways.be>
39
39
  * @since 0.1.0
40
- * @version 0.1.0
40
+ * @version 0.2.1
41
41
  *
42
42
  * @param {HTMLElement} widget
43
43
  */
44
44
  Sourcecode.setMethod(function populateWidget() {
45
45
 
46
- populateWidget.super.call(this);
47
-
48
46
  let source = this.config[this.sourcecode_field] || '';
49
47
 
50
48
  if (!source) {
@@ -82,13 +80,13 @@ Sourcecode.setMethod(function _startEditor() {
82
80
  *
83
81
  * @author Jelle De Loecker <jelle@elevenways.be>
84
82
  * @since 0.1.0
85
- * @version 0.1.0
83
+ * @version 0.2.2
86
84
  */
87
85
  Sourcecode.setMethod(function _stopEditor() {
88
86
 
89
87
  Hawkejs.removeChildren(this.widget);
90
88
 
91
- this.populateWidget();
89
+ return this.loadWidget();
92
90
  });
93
91
 
94
92
  /**