alchemy-widget 0.1.5 → 0.2.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 (36) hide show
  1. package/CHANGELOG.md +29 -0
  2. package/assets/stylesheets/alchemy_widgets.scss +426 -0
  3. package/bootstrap.js +6 -0
  4. package/controller/alchemy_widgets_controller.js +85 -9
  5. package/element/00-widget_base_element.js +154 -6
  6. package/element/05-widget_element.js +112 -19
  7. package/element/10-container_elements.js +15 -15
  8. package/element/11-alchemy_widgets_list_element.js +2 -2
  9. package/element/20-add_area_element.js +23 -23
  10. package/element/table_of_contents_element.js +104 -8
  11. package/element/widget_actionbar_element.js +92 -0
  12. package/element/widget_context_element.js +39 -23
  13. package/element/widget_toolbar_element.js +300 -38
  14. package/helper/widget_action.js +19 -18
  15. package/helper/widgets/00-widget.js +160 -37
  16. package/helper/widgets/01-container.js +12 -7
  17. package/helper/widgets/05-list.js +1 -1
  18. package/helper/widgets/alchemy_field_widget.js +112 -0
  19. package/helper/widgets/alchemy_form_widget.js +183 -0
  20. package/helper/widgets/alchemy_table_widget.js +71 -0
  21. package/helper/widgets/alchemy_tabs_widget.js +195 -0
  22. package/helper/widgets/header.js +4 -4
  23. package/helper/widgets/markdown.js +17 -10
  24. package/helper/widgets/partial.js +215 -0
  25. package/helper/widgets/sourcecode.js +4 -4
  26. package/helper/widgets/table_of_contents.js +2 -2
  27. package/helper/widgets/text.js +14 -4
  28. package/helper/widgets_helper.js +26 -0
  29. package/package.json +4 -3
  30. package/view/elements/table_of_contents.hwk +23 -9
  31. package/view/form/inputs/edit/widget.hwk +2 -2
  32. package/view/form/inputs/edit/widgets.hwk +2 -2
  33. package/view/widget/elements/al_widget_toolbar.hwk +49 -0
  34. package/view/widget/widget_config.hwk +7 -4
  35. package/assets/stylesheets/alchemy-widget-symbols.scss +0 -191
  36. package/assets/stylesheets/alchemy-widgets.scss +0 -258
@@ -0,0 +1,215 @@
1
+ /**
2
+ * The Partial Widget class
3
+ *
4
+ * @constructor
5
+ *
6
+ * @author Jelle De Loecker <jelle@elevenways.be>
7
+ * @since 0.1.6
8
+ * @version 0.1.6
9
+ *
10
+ * @param {Object} data
11
+ */
12
+ const Partial = Function.inherits('Alchemy.Widget', 'Partial');
13
+
14
+ /**
15
+ * Make this an abstract class
16
+ */
17
+ Partial.makeAbstractClass();
18
+
19
+ /**
20
+ * Get the type name
21
+ *
22
+ * @author Jelle De Loecker <jelle@elevenways.be>
23
+ * @since 0.1.6
24
+ * @version 0.1.6
25
+ */
26
+ Partial.setStatic(function createClassTypeName() {
27
+ return 'partial_' + this.name.underscore();
28
+ });
29
+
30
+ /**
31
+ * Set the template to use
32
+ *
33
+ * @author Jelle De Loecker <jelle@elevenways.be>
34
+ * @since 0.1.6
35
+ * @version 0.1.6
36
+ */
37
+ Partial.setStatic(function setTemplateFile(name) {
38
+ this.constitute(function _setTemplateFile() {
39
+ this.template_file = name;
40
+ });
41
+ });
42
+
43
+ /**
44
+ * Prepare the schema
45
+ *
46
+ * @author Jelle De Loecker <jelle@elevenways.be>
47
+ * @since 0.1.6
48
+ * @version 0.1.6
49
+ */
50
+ Partial.constitute(function prepareSchema() {
51
+
52
+ this.schema.addField('view', 'String', {
53
+ title : 'Partial View',
54
+ description : 'The actual HWK template to use for rendering this widget',
55
+ });
56
+
57
+ let contents = this.createSchema();
58
+
59
+ contents.addField('name', 'String');
60
+ contents.addField('content', 'Widgets');
61
+
62
+ this.schema.addField('contents', contents, {array: true});
63
+ });
64
+
65
+ /**
66
+ * Populate the widget
67
+ *
68
+ * @author Jelle De Loecker <jelle@elevenways.be>
69
+ * @since 0.1.6
70
+ * @version 0.1.6
71
+ *
72
+ * @param {HTMLElement} widget
73
+ */
74
+ Partial.setMethod(async function populateWidget() {
75
+
76
+ let view = this.constructor.template_file || this.config.view;
77
+
78
+ if (view) {
79
+
80
+ let options = {
81
+ print : false,
82
+ };
83
+
84
+ let variables = {};
85
+
86
+ await this.addVariablesForRender(variables);
87
+
88
+ if (this.config?.contents?.length) {
89
+ for (let entry of this.config.contents) {
90
+ variables[entry.name] = entry.contents;
91
+ }
92
+ }
93
+
94
+ variables.config = this.config;
95
+
96
+ let placeholder = this.hawkejs_renderer.addSubtemplate(view, options, variables);
97
+
98
+ // If the widget is already part of the DOM,
99
+ // it's being edited and we need to manually kickstart the renderer
100
+ if (Blast.isBrowser && document.body.contains(this.widget)) {
101
+ await placeholder.getContent();
102
+ }
103
+
104
+ Hawkejs.removeChildren(this.widget);
105
+
106
+ this.widget.append(placeholder);
107
+ }
108
+
109
+ populateWidget.super.call(this);
110
+ });
111
+
112
+ /**
113
+ * Allow adding variables for rendering the partial
114
+ *
115
+ * @author Jelle De Loecker <jelle@elevenways.be>
116
+ * @since 0.1.
117
+ * @version 0.1.
118
+ */
119
+ Partial.setMethod(function addVariablesForRender(variables) {
120
+ // To be optionally implemented by child widgets
121
+ });
122
+
123
+ /**
124
+ * Get all the sub widgets by their name
125
+ *
126
+ * @author Jelle De Loecker <jelle@elevenways.be>
127
+ * @since 0.1.6
128
+ * @version 0.1.6
129
+ *
130
+ * @return {Object}
131
+ */
132
+ Partial.setMethod(function getSubWidgets() {
133
+
134
+ let elements = this.widget.queryAllNotNested('[data-section-name]'),
135
+ result = {};
136
+
137
+ for (let element of elements) {
138
+ result[element.dataset.sectionName] = element;
139
+ }
140
+
141
+ return result;
142
+ });
143
+
144
+ /**
145
+ * Start the editor
146
+ *
147
+ * @author Jelle De Loecker <jelle@elevenways.be>
148
+ * @since 0.1.6
149
+ * @version 0.1.6
150
+ */
151
+ Partial.setMethod(function _startEditor() {
152
+
153
+ let sub_widgets = this.getSubWidgets();
154
+
155
+ for (let name in sub_widgets) {
156
+ let sub_widget = sub_widgets[name];
157
+ sub_widget.startEditor();
158
+ }
159
+ });
160
+
161
+ /**
162
+ * Stop the editor
163
+ *
164
+ * @author Jelle De Loecker <jelle@elevenways.be>
165
+ * @since 0.1.6
166
+ * @version 0.1.6
167
+ */
168
+ Partial.setMethod(function _stopEditor() {
169
+
170
+ let sub_widgets = this.getSubWidgets();
171
+
172
+ for (let name in sub_widgets) {
173
+ let sub_widget = sub_widgets[name];
174
+ sub_widget.stopEditor();
175
+ }
176
+
177
+ this.populateWidget();
178
+ });
179
+
180
+ /**
181
+ * Update the config values
182
+ *
183
+ * @author Jelle De Loecker <jelle@elevenways.be>
184
+ * @since 0.1.6
185
+ * @version 0.1.6
186
+ *
187
+ * @return {Object}
188
+ */
189
+ Partial.setMethod(function syncConfig() {
190
+
191
+ let sub_widgets = this.getSubWidgets(),
192
+ contents = this.config.contents;
193
+
194
+ if (!contents) {
195
+ contents = [];
196
+ this.config.contents = contents;
197
+ }
198
+
199
+ for (let name in sub_widgets) {
200
+ let sub_widget = sub_widgets[name];
201
+ let widget_config = contents.findByPath('name', name);
202
+
203
+ if (!widget_config) {
204
+ widget_config = {
205
+ name,
206
+ };
207
+
208
+ contents.push(widget_config);
209
+ }
210
+
211
+ widget_config.contents = sub_widget.value;
212
+ }
213
+
214
+ return this.config;
215
+ });
@@ -65,13 +65,13 @@ Sourcecode.setMethod(function populateWidget() {
65
65
  *
66
66
  * @author Jelle De Loecker <jelle@elevenways.be>
67
67
  * @since 0.1.0
68
- * @version 0.1.0
68
+ * @version 0.2.0
69
69
  */
70
70
  Sourcecode.setMethod(function _startEditor() {
71
71
 
72
72
  Hawkejs.removeChildren(this.widget);
73
73
 
74
- let input = this.createElement('alchemy-code-input');
74
+ let input = this.createElement('al-code-input');
75
75
  input.textContent = this.config[this.sourcecode_field] || '';
76
76
 
77
77
  this.widget.append(input);
@@ -96,13 +96,13 @@ Sourcecode.setMethod(function _stopEditor() {
96
96
  *
97
97
  * @author Jelle De Loecker <jelle@elevenways.be>
98
98
  * @since 0.1.0
99
- * @version 0.1.0
99
+ * @version 0.2.0
100
100
  *
101
101
  * @return {Object}
102
102
  */
103
103
  Sourcecode.setMethod(function syncConfig() {
104
104
 
105
- let input = this.widget.querySelector('alchemy-code-input, textarea');
105
+ let input = this.widget.querySelector('al-code-input, textarea');
106
106
 
107
107
  if (input) {
108
108
  this.config[this.sourcecode_field] = input.value;
@@ -16,13 +16,13 @@ const Toc = Function.inherits('Alchemy.Widget', 'TableOfContents');
16
16
  *
17
17
  * @author Jelle De Loecker <jelle@elevenways.be>
18
18
  * @since 0.1.2
19
- * @version 0.1.2
19
+ * @version 0.2.0
20
20
  */
21
21
  Toc.setMethod(function populateWidget() {
22
22
 
23
23
  populateWidget.super.call(this);
24
24
 
25
- let toc = this.createElement('table-of-contents');
25
+ let toc = this.createElement('al-toc');
26
26
 
27
27
  if (this.config.parent_selector) {
28
28
  toc.parent_selector = this.config.parent_selector;
@@ -28,18 +28,28 @@ Text.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.1.6
32
32
  *
33
33
  * @param {HTMLElement} widget
34
34
  */
35
35
  Text.setMethod(function populateWidget() {
36
36
 
37
+ let tag_name;
38
+
37
39
  populateWidget.super.call(this);
38
40
 
39
- let paragraph = this.createElement('p');
40
- paragraph.textContent = this.config.content || '';
41
+ if (this.widget.dataset.textElementTag) {
42
+ tag_name = this.widget.dataset.textElementTag;
43
+ }
44
+
45
+ if (!tag_name) {
46
+ tag_name = 'p';
47
+ }
48
+
49
+ let text_element = this.createElement(tag_name);
50
+ text_element.textContent = this.config.content || '';
41
51
 
42
- this.widget.append(paragraph);
52
+ this.widget.append(text_element);
43
53
  });
44
54
 
45
55
  /**
@@ -0,0 +1,26 @@
1
+ /**
2
+ * The Widgets helper
3
+ *
4
+ * @author Jelle De Loecker <jelle@elevenways.be>
5
+ * @since 0.2.0
6
+ * @version 0.2.0
7
+ *
8
+ * @param {ViewRender} view
9
+ */
10
+ const Widgets = Function.inherits('Alchemy.Helper', 'Widgets');
11
+
12
+ /**
13
+ * Function to execute on the client side, when the scene is made
14
+ *
15
+ * @author Jelle De Loecker <jelle@elevenways.be>
16
+ * @since 0.2.0
17
+ * @version 0.2.0
18
+ *
19
+ * @param {Scene} scene
20
+ * @param {Object} options
21
+ */
22
+ Widgets.setStatic(function onScene(scene, options) {
23
+ Blast.setImmediate(() => {
24
+ Classes.Alchemy.Element.Widget.WidgetToolbar.show();
25
+ });
26
+ });
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "alchemy-widget",
3
3
  "description": "The widget plugin for the AlchemyMVC",
4
- "version": "0.1.5",
4
+ "version": "0.2.0",
5
5
  "author": "Jelle De Loecker <jelle@elevenways.be>",
6
6
  "keywords": [
7
7
  "alchemy",
@@ -10,11 +10,12 @@
10
10
  "widget"
11
11
  ],
12
12
  "peerDependencies": {
13
- "alchemymvc" : ">=1.1.0"
13
+ "alchemymvc" : ">=1.2.0",
14
+ "alchemy-form": "~0.2.0"
14
15
  },
15
16
  "repository": "11ways/alchemy-widget",
16
17
  "license": "MIT",
17
18
  "engines": {
18
- "node" : ">=12.0.0"
19
+ "node" : ">=14.0.0"
19
20
  }
20
21
  }
@@ -1,9 +1,23 @@
1
- <ol>
2
- {% each self.entries as entry %}
3
- <li>
4
- <a href="#{% entry.id %}">
5
- {{ entry.title }}
6
- </a>
7
- </li>
8
- {% /each %}
9
- </ol>
1
+ {% macro printEntries %}
2
+ <ol>
3
+ {% each entries as entry %}
4
+ {% run printEntry entry=entry %}
5
+
6
+ {% if entry.children %}
7
+ <li>
8
+ {% run printEntries entries=entry.children %}
9
+ </li>
10
+ {% /if %}
11
+ {% /each %}
12
+ </ol>
13
+ {% /macro %}
14
+
15
+ {% macro printEntry %}
16
+ <li>
17
+ <a href="#{% entry.id %}">
18
+ {{ entry.title }}
19
+ </a>
20
+ </li>
21
+ {% /macro %}
22
+
23
+ {% run printEntries entries=self.entries}
@@ -1,6 +1,6 @@
1
- <alchemy-widget
1
+ <al-widget
2
2
  type={% alchemy_field.config.options.type %}
3
3
  #value={% value %}
4
4
  class="alchemy-field-value"
5
5
  editing
6
- ></alchemy-widget>
6
+ ></al-widget>
@@ -1,5 +1,5 @@
1
- <alchemy-widgets
1
+ <al-widgets
2
2
  #value={% value %}
3
3
  class="alchemy-field-value"
4
4
  editing
5
- ></alchemy-widgets>
5
+ ></al-widgets>
@@ -0,0 +1,49 @@
1
+ <al-button class="start-edit" state="ready">
2
+ <al-icon icon-style="duotone" icon-name="pencil"></al-icon>
3
+ {%t "start-editing" %}
4
+ </al-button>
5
+ <al-button class="stop-and-save" state="ready">
6
+
7
+ <al-state state-name="saving">
8
+ <al-icon icon-style="duotone" icon-name="spinner" icon-flags="spin"></al-icon>
9
+ {%t "saving" %}
10
+ </al-state>
11
+
12
+ <al-state state-name="saved">
13
+ <al-icon icon-style="duotone" icon-name="badge-check" icon-flags="beat"></al-icon>
14
+ {%t "saved" %}
15
+ </al-state>
16
+
17
+ <al-state state-name="ready">
18
+ <al-icon icon-style="duotone" icon-name="floppy-disk-circle-arrow-right"></al-icon>
19
+ {%t "save-and-stop-editing" %}
20
+ </al-state>
21
+ </al-button>
22
+ <al-button class="stop-edit" state="ready">
23
+ <al-icon icon-style="duotone" icon-name="pencil-slash"></al-icon>
24
+ {%t "stop-editing" %}
25
+ </al-button>
26
+ <al-button class="save-all" state="ready">
27
+
28
+ <al-state state-name="saving">
29
+ <al-icon icon-style="duotone" icon-name="spinner" icon-flags="spin"></al-icon>
30
+ {%t "saving" %}
31
+ </al-state>
32
+
33
+ <al-state state-name="saved">
34
+ <al-icon icon-style="duotone" icon-name="badge-check" icon-flags="beat"></al-icon>
35
+ {%t "saved" %}
36
+ </al-state>
37
+
38
+ <al-state state-name="ready">
39
+ <al-icon icon-style="duotone" icon-name="floppy-disk"></al-icon>
40
+ {%t "save-all" %}
41
+ </al-state>
42
+ </al-button>
43
+
44
+ {% if Router.routeConfig('Chimera.Editor#index') %}
45
+ <a href="/chimera/" data-he-link="false">
46
+ <al-icon icon-style="duotone" icon-name="display-code"></al-icon>
47
+ {%t "go-to-backend" %}
48
+ </a>
49
+ {% /if %}
@@ -2,17 +2,20 @@
2
2
  <% addClass('widget-config-dialog') %>
3
3
 
4
4
  <div class="widget-config-wrapper js-he-ready-wcd">
5
- <alchemy-form
5
+
6
+ <h2 class="widget-config-title">Editing "{{ title }}" widget</h2>
7
+
8
+ <al-form
6
9
  #document={% widget_settings %}
7
10
  #schema={% schema %}
8
11
  class="main-form"
9
12
  >
10
13
  {% each fields as field %}
11
- <alchemy-field
14
+ <al-field
12
15
  field-name={% field.name %}
13
- ></alchemy-field>
16
+ ></al-field>
14
17
  {% /each %}
15
- </alchemy-form>
18
+ </al-form>
16
19
 
17
20
  <button class="btn btn-apply">
18
21
  Apply
@@ -1,191 +0,0 @@
1
- .gg-math-plus,
2
- .gg-math-plus::after {
3
- display: block;
4
- box-sizing: border-box;
5
- background: currentColor;
6
- border-radius: 10px
7
- }
8
-
9
- .gg-math-plus {
10
- margin-top: -2px;
11
- position: relative;
12
- transform: scale(var(--ggs,1));
13
- width: 16px;
14
- height: 2px
15
- }
16
-
17
- .gg-math-plus::after {
18
- content: "";
19
- position: absolute;
20
- width: 2px;
21
- height: 16px;
22
- top: -7px;
23
- left: 7px
24
- }
25
-
26
- .gg-menu-grid-o {
27
- box-sizing: border-box;
28
- position: relative;
29
- display: block;
30
- transform: scale(var(--ggs,1));
31
- width: 16px;
32
- height: 16px;
33
- }
34
-
35
- .gg-menu-grid-o::before {
36
- content: "";
37
- display: block;
38
- box-sizing: border-box;
39
- position: absolute;
40
- width: 4px;
41
- height: 4px;
42
- background: currentColor;
43
- box-shadow:
44
- 0 6px 0,
45
- 6px 6px 0,
46
- 12px 6px 0,
47
- 6px 12px 0,
48
- 12px 12px 0,
49
- 6px 0 0,
50
- 12px 0 0,
51
- 0 12px 0
52
- ;
53
- border-radius: 22px;
54
- }
55
-
56
- .gg-remove {
57
- box-sizing: border-box;
58
- position: relative;
59
- display: block;
60
- transform: scale(var(--ggs,1));
61
- width: 22px;
62
- height: 22px;
63
- border: 2px solid;
64
- border-radius: 22px
65
- }
66
-
67
- .gg-remove::before {
68
- content: "";
69
- display: block;
70
- box-sizing: border-box;
71
- position: absolute;
72
- width: 10px;
73
- height: 2px;
74
- background: currentColor;
75
- border-radius: 5px;
76
- top: 8px;
77
- left: 4px
78
- }
79
-
80
- .gg-trash {
81
- box-sizing: border-box;
82
- position: relative;
83
- display: block;
84
- transform: scale(var(--ggs,1));
85
- width: 10px;
86
- height: 12px;
87
- border: 2px solid transparent;
88
- box-shadow:
89
- 0 0 0 2px,
90
- inset -2px 0 0,
91
- inset 2px 0 0;
92
- border-bottom-left-radius: 1px;
93
- border-bottom-right-radius: 1px;
94
- margin-top: 4px
95
- }
96
-
97
- .gg-trash::after,
98
- .gg-trash::before {
99
- content: "";
100
- display: block;
101
- box-sizing: border-box;
102
- position: absolute
103
- }
104
-
105
- .gg-trash::after {
106
- background: currentColor;
107
- border-radius: 3px;
108
- width: 16px;
109
- height: 2px;
110
- top: -4px;
111
- left: -5px
112
- }
113
-
114
- .gg-trash::before {
115
- width: 10px;
116
- height: 4px;
117
- border: 2px solid;
118
- border-bottom: transparent;
119
- border-top-left-radius: 2px;
120
- border-top-right-radius: 2px;
121
- top: -7px;
122
- left: -2px
123
- }
124
-
125
- .gg-arrow-left {
126
- box-sizing: border-box;
127
- position: relative;
128
- display: block;
129
- transform: scale(var(--ggs,1));
130
- width: 22px;
131
- height: 22px
132
- }
133
-
134
- .gg-arrow-left::after,
135
- .gg-arrow-left::before {
136
- content: "";
137
- display: block;
138
- box-sizing: border-box;
139
- position: absolute;
140
- left: 3px
141
- }
142
-
143
- .gg-arrow-left::after {
144
- width: 8px;
145
- height: 8px;
146
- border-bottom: 2px solid;
147
- border-left: 2px solid;
148
- transform: rotate(45deg);
149
- bottom: 7px
150
- }
151
-
152
- .gg-arrow-left::before {
153
- width: 16px;
154
- height: 2px;
155
- bottom: 10px;
156
- background: currentColor
157
- }
158
-
159
- .gg-arrow-right {
160
- box-sizing: border-box;
161
- position: relative;
162
- display: block;
163
- transform: scale(var(--ggs,1));
164
- width: 22px;
165
- height: 22px
166
- }
167
-
168
- .gg-arrow-right::after,
169
- .gg-arrow-right::before {
170
- content: "";
171
- display: block;
172
- box-sizing: border-box;
173
- position: absolute;
174
- right: 3px
175
- }
176
-
177
- .gg-arrow-right::after {
178
- width: 8px;
179
- height: 8px;
180
- border-top: 2px solid;
181
- border-right: 2px solid;
182
- transform: rotate(45deg);
183
- bottom: 7px
184
- }
185
-
186
- .gg-arrow-right::before {
187
- width: 16px;
188
- height: 2px;
189
- bottom: 10px;
190
- background: currentColor
191
- }