alchemy-widget 0.1.6 → 0.2.1

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 (37) hide show
  1. package/CHANGELOG.md +29 -0
  2. package/assets/stylesheets/{alchemy-widgets.scss → alchemy_widgets.scss} +169 -54
  3. package/bootstrap.js +101 -2
  4. package/controller/alchemy_widgets_controller.js +64 -0
  5. package/element/00-widget_base_element.js +105 -4
  6. package/element/05-widget_element.js +33 -21
  7. package/element/10-container_elements.js +27 -32
  8. package/element/11-alchemy_widgets_list_element.js +2 -2
  9. package/element/20-add_area_element.js +22 -22
  10. package/element/table_of_contents_element.js +144 -11
  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 +295 -50
  14. package/helper/widget_action.js +10 -10
  15. package/helper/widgets/00-widget.js +244 -27
  16. package/helper/widgets/01-container.js +29 -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 +193 -0
  22. package/helper/widgets/hawkejs_template.js +60 -0
  23. package/helper/widgets/header.js +8 -10
  24. package/helper/widgets/html.js +52 -3
  25. package/helper/widgets/markdown.js +18 -13
  26. package/helper/widgets/partial.js +1 -3
  27. package/helper/widgets/sourcecode.js +5 -7
  28. package/helper/widgets/table_of_contents.js +2 -4
  29. package/helper/widgets/text.js +15 -15
  30. package/helper/widgets_helper.js +26 -0
  31. package/package.json +3 -2
  32. package/view/elements/table_of_contents.hwk +33 -9
  33. package/view/form/inputs/edit/widget.hwk +2 -2
  34. package/view/form/inputs/edit/widgets.hwk +2 -2
  35. package/view/widget/elements/al_widget_toolbar.hwk +49 -0
  36. package/view/widget/widget_config.hwk +7 -4
  37. package/assets/stylesheets/alchemy-widget-symbols.scss +0 -191
@@ -1,92 +1,337 @@
1
1
  /**
2
- * The alchemy-widget-toolbar element
2
+ * The al-widget-toolbar element
3
3
  *
4
4
  * @author Jelle De Loecker <jelle@elevenways.be>
5
- * @since 0.1.0
6
- * @version 0.1.0
5
+ * @since 0.2.0
6
+ * @version 0.2.0
7
7
  */
8
- let Toolbar = Function.inherits('Alchemy.Element.Widget.Base', function AlchemyWidgetToolbar() {
9
- AlchemyWidgetToolbar.super.call(this);
10
- this.hidden = true;
8
+ let Toolbar = Function.inherits('Alchemy.Element.Form.Stateful', 'Alchemy.Element.Widget', 'WidgetToolbar');
9
+
10
+ /**
11
+ * The stylesheet to load for this element
12
+ *
13
+ * @author Jelle De Loecker <jelle@elevenways.be>
14
+ * @since 0.2.0
15
+ * @version 0.2.0
16
+ */
17
+ Toolbar.setStylesheetFile('alchemy_widgets');
18
+
19
+ /**
20
+ * Set the custom element prefix
21
+ *
22
+ * @author Jelle De Loecker <jelle@elevenways.be>
23
+ * @since 0.2.0
24
+ * @version 0.2.0
25
+ */
26
+ Toolbar.setStatic('custom_element_prefix', 'al');
27
+
28
+ /**
29
+ * The template to use for the content of this element
30
+ *
31
+ * @author Jelle De Loecker <jelle@elevenways.be>
32
+ * @since 0.2.0
33
+ * @version 0.2.0
34
+ */
35
+ Toolbar.setTemplateFile('widget/elements/al_widget_toolbar');
36
+
37
+ /**
38
+ * The start-edit button
39
+ *
40
+ * @author Jelle De Loecker <jelle@elevenways.be>
41
+ * @since 0.2.0
42
+ * @version 0.2.0
43
+ */
44
+ Toolbar.addElementGetter('button_start', 'al-button.start-edit');
45
+
46
+ /**
47
+ * The stop-edit button
48
+ *
49
+ * @author Jelle De Loecker <jelle@elevenways.be>
50
+ * @since 0.2.0
51
+ * @version 0.2.0
52
+ */
53
+ Toolbar.addElementGetter('button_stop', 'al-button.stop-edit');
54
+
55
+ /**
56
+ * The stop-and-save button
57
+ *
58
+ * @author Jelle De Loecker <jelle@elevenways.be>
59
+ * @since 0.2.0
60
+ * @version 0.2.0
61
+ */
62
+ Toolbar.addElementGetter('button_stop_and_save', 'al-button.stop-and-save');
63
+
64
+ /**
65
+ * The save-all button
66
+ *
67
+ * @author Jelle De Loecker <jelle@elevenways.be>
68
+ * @since 0.2.0
69
+ * @version 0.2.0
70
+ */
71
+ Toolbar.addElementGetter('button_save_all', 'al-button.save-all');
72
+
73
+ /**
74
+ * Make sure the toolbar is visible
75
+ *
76
+ * @author Jelle De Loecker <jelle@elevenways.be>
77
+ * @since 0.2.0
78
+ * @version 0.2.0
79
+ */
80
+ Toolbar.setStatic(function show() {
81
+
82
+ if (!alchemy.hasPermission('alchemy.widgets.toolbar')) {
83
+ return;
84
+ }
85
+
86
+ let toolbar = document.querySelector('al-widget-toolbar');
87
+
88
+ if (toolbar) {
89
+ return;
90
+ }
91
+
92
+ toolbar = hawkejs.createElement('al-widget-toolbar');
93
+
94
+ hawkejs.scene.bottom_element.append(toolbar);
11
95
  });
12
96
 
13
97
  /**
14
- * Show the actions for the given widget
98
+ * Get all the root widgets
15
99
  *
16
100
  * @author Jelle De Loecker <jelle@elevenways.be>
17
- * @since 0.1.0
18
- * @version 0.1.6
101
+ * @since 0.2.0
102
+ * @version 0.2.0
103
+ */
104
+ Toolbar.setMethod(function getAllRootWidgets() {
105
+
106
+ let elements = document.body.queryAllNotNested('al-widgets'),
107
+ result = [],
108
+ i;
109
+
110
+ for (i = 0; i < elements.length; i++) {
111
+ result.push(elements[i]);
112
+ }
113
+
114
+ elements = document.body.queryAllNotNested('al-widget');
115
+
116
+ for (i = 0; i < elements.length; i++) {
117
+
118
+ if (elements[i].is_root_widget) {
119
+ result.push(elements[i]);
120
+ }
121
+ }
122
+
123
+ return result;
124
+ });
125
+
126
+ /**
127
+ * Start editing all the widgets
19
128
  *
20
- * @param {HTMLElement} widget
129
+ * @author Jelle De Loecker <jelle@elevenways.be>
130
+ * @since 0.2.0
131
+ * @version 0.2.0
21
132
  */
22
- Toolbar.setMethod(function showWidgetActions(widget) {
133
+ Toolbar.setMethod(function startEditing() {
23
134
 
24
- if (!widget || !widget.instance) {
135
+ let i;
136
+
137
+ Blast.editing = true;
138
+ document.body.classList.add('editing-blocks');
139
+
140
+ let elements = this.getAllRootWidgets();
141
+
142
+ for (i = 0; i < elements.length; i++) {
143
+ elements[i].startEditor();
144
+ }
145
+
146
+ this.setState('editing');
147
+ });
148
+
149
+ /**
150
+ * Stop editing all the widgets
151
+ *
152
+ * @author Jelle De Loecker <jelle@elevenways.be>
153
+ * @since 0.2.0
154
+ * @version 0.2.0
155
+ */
156
+ Toolbar.setMethod(function stopEditing() {
157
+
158
+ if (!Blast.editing) {
25
159
  return;
26
160
  }
27
161
 
28
- const that = this;
162
+ let i;
29
163
 
30
- let actions = widget.instance.getToolbarActions();
164
+ Blast.editing = false;
165
+ document.body.classList.remove('editing-blocks');
31
166
 
32
- // Clear all the old buttons
33
- Hawkejs.removeChildren(this);
167
+ let elements = this.getAllRootWidgets();
34
168
 
35
- for (let action of actions) {
169
+ for (i = 0; i < elements.length; i++) {
170
+ elements[i].stopEditor();
171
+ }
36
172
 
37
- let button = this.createElement('button');
38
- button.classList.add('aw-toolbar-button');
173
+ this.setState('ready');
174
+ });
39
175
 
40
- let content = action.getButtonContent();
176
+ /**
177
+ * Save all the widgets
178
+ *
179
+ * @author Jelle De Loecker <jelle@elevenways.be>
180
+ * @since 0.2.0
181
+ * @version 0.2.0
182
+ */
183
+ Toolbar.setMethod(async function saveAll() {
41
184
 
42
- if (!content) {
43
- content = action.title;
185
+ if (this._saving) {
186
+ try {
187
+ await this._saving;
188
+ } catch (err) {
189
+ // Ignore;
44
190
  }
191
+ }
45
192
 
46
- if (typeof content == 'string') {
47
- button.innerText = content;
48
- } else if (content) {
49
- if (Array.isArray(content)) {
50
- for (let entry of content) {
51
- button.append(entry);
52
- }
53
- } else {
54
- button.append(content);
55
- }
193
+ this._saving = null;
194
+
195
+ let elements = this.getAllRootWidgets();
196
+ let widget_data = [];
197
+ let pledge;
198
+
199
+ for (let element of elements) {
200
+ let entry = element.gatherSaveData();
201
+
202
+ if (entry) {
203
+ widget_data.push(entry);
56
204
  }
205
+ }
57
206
 
58
- button.setAttribute('title', action.title);
207
+ if (widget_data.length) {
208
+ let config = {
209
+ href : alchemy.routeUrl('AlchemyWidgets#save'),
210
+ post : {
211
+ widgets: widget_data
212
+ }
213
+ };
214
+
215
+ pledge = alchemy.fetch(config);
216
+ this._saving = pledge;
217
+ }
59
218
 
60
- let is_selected = action.isAlreadySelected(widget);
219
+ return pledge;
220
+ });
61
221
 
62
- if (is_selected) {
63
- button.classList.add('aw-button-selected');
222
+ /**
223
+ * Save all and update the states
224
+ *
225
+ * @author Jelle De Loecker <jelle@elevenways.be>
226
+ * @since 0.2.0
227
+ * @version 0.2.0
228
+ *
229
+ * @param {Boolean} before_stop
230
+ */
231
+ Toolbar.setMethod(async function saveAllAndUpdateButtonStates(before_stop) {
232
+
233
+ let state = 'saving',
234
+ button;
235
+
236
+ if (before_stop) {
237
+ button = this.button_stop_and_save;
238
+ state += '-before-stop';
239
+ } else {
240
+ button = this.button_save_all;
241
+ }
242
+
243
+ this.setState(state);
244
+ button.setState(state);
245
+
246
+ let save_error = null;
247
+
248
+ let restore_toolbar_state = this.wrapForCurrentState(() => {
249
+ if (save_error) {
250
+ this.setState('error');
251
+ } else {
252
+ this.setState('editing')
64
253
  }
254
+ });
65
255
 
66
- button.addEventListener('click', function onClick(e) {
256
+ let restore_button_state = button.wrapForCurrentState(() => {
67
257
 
68
- e.preventDefault();
258
+ if (save_error) {
259
+ button.setState('error');
260
+ } else {
261
+ button.setState('saved', 2500, 'ready');
262
+ }
263
+ });
264
+
265
+ try {
266
+ await this.saveAll();
267
+ } catch (err) {
268
+ save_error = err;
269
+ }
69
270
 
70
- action.applyOnWidget(widget, that);
71
- });
271
+ restore_toolbar_state();
272
+ restore_button_state();
72
273
 
73
- this.append(button);
274
+ if (save_error) {
275
+ return false;
74
276
  }
277
+
278
+ return true;
75
279
  });
76
280
 
77
281
  /**
78
- * Close the toolbar
282
+ * This element has been added to the DOM for the first time
79
283
  *
80
284
  * @author Jelle De Loecker <jelle@elevenways.be>
81
- * @since 0.1.0
82
- * @version 0.1.0
285
+ * @since 0.2.0
286
+ * @version 0.2.0
83
287
  */
84
- Toolbar.setMethod(function close() {
85
- this.hidden = true;
288
+ Toolbar.setMethod(function introduced() {
86
289
 
87
- if (this.context_element && this.context_element.active_widget) {
88
- this.context_element.active_widget.selectWidget();
89
- }
290
+ this.button_start.addEventListener('activate', async e => {
291
+ this.startEditing();
292
+ });
293
+
294
+ this.button_stop.addEventListener('activate', async e => {
295
+ this.stopEditing();
296
+ });
297
+
298
+ this.button_save_all.addEventListener('activate', e => {
299
+ this.saveAllAndUpdateButtonStates(false);
300
+ });
90
301
 
91
- this.context_element = null;
302
+ this.button_stop_and_save.addEventListener('activate', async e => {
303
+ let saved = await this.saveAllAndUpdateButtonStates(true);
304
+
305
+ if (saved) {
306
+ this.stopEditing();
307
+ }
308
+ });
309
+
310
+ hawkejs.scene.on('opening_url', e => {
311
+ this.stopEditing();
312
+ });
313
+ });
314
+
315
+ /**
316
+ * The element has been added to the dom
317
+ *
318
+ * @author Jelle De Loecker <jelle@elevenways.be>
319
+ * @since 0.2.0
320
+ * @version 0.2.0
321
+ */
322
+ Toolbar.setMethod(function connected() {
323
+ let html = document.querySelector('html');
324
+ html.classList.add('with-al-widget-toolbar');
325
+ });
326
+
327
+ /**
328
+ * The element has been removed from the dom
329
+ *
330
+ * @author Jelle De Loecker <jelle@elevenways.be>
331
+ * @since 0.2.0
332
+ * @version 0.2.0
333
+ */
334
+ Toolbar.setMethod(function disconnected() {
335
+ let html = document.querySelector('html');
336
+ html.classList.remove('with-al-widget-toolbar');
92
337
  });
@@ -5,7 +5,7 @@
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.0
9
9
  *
10
10
  * @param {String} name
11
11
  */
@@ -29,8 +29,8 @@ const Action = Function.inherits('Alchemy.Base', 'Alchemy.Widget', function Acti
29
29
  // The icon to use for this action
30
30
  this.icon = null;
31
31
 
32
- // Close the toolbar after clicking?
33
- this.close_toolbar = false;
32
+ // Close the actionbar after clicking?
33
+ this.close_actionbar = false;
34
34
  });
35
35
 
36
36
  /**
@@ -90,11 +90,11 @@ Action.setMethod(function setIcon(icon) {
90
90
  *
91
91
  * @author Jelle De Loecker <jelle@elevenways.be>
92
92
  * @since 0.1.0
93
- * @version 0.1.0
93
+ * @version 0.2.0
94
94
  *
95
95
  * @param {HTMLElement} widget
96
96
  */
97
- Action.setMethod(function applyOnWidget(widget, toolbar) {
97
+ Action.setMethod(function applyOnWidget(widget, actionbar) {
98
98
 
99
99
  if (!this.handler) {
100
100
  throw new Error('Failed to apply action "' + this.name + '" on widget, no handler found');
@@ -103,10 +103,10 @@ Action.setMethod(function applyOnWidget(widget, toolbar) {
103
103
  let instance = widget.instance,
104
104
  handle = instance.getHandle();
105
105
 
106
- this.handler(widget, handle, toolbar);
106
+ this.handler(widget, handle, actionbar);
107
107
 
108
- if (this.close_toolbar) {
109
- toolbar.close();
108
+ if (this.close_actionbar) {
109
+ actionbar.close();
110
110
  }
111
111
  });
112
112
 
@@ -119,7 +119,7 @@ Action.setMethod(function applyOnWidget(widget, toolbar) {
119
119
  *
120
120
  * @param {HTMLElement} widget
121
121
  *
122
- * @return {Boolean}
122
+ * @return {Boolean|Promise}
123
123
  */
124
124
  Action.setMethod(function test(widget) {
125
125
 
@@ -154,7 +154,7 @@ Action.setMethod(function getButtonContent() {
154
154
  let icon = this.icon;
155
155
 
156
156
  if (typeof icon == 'string') {
157
- result = Blast.Classes.Hawkejs.Hawkejs.createElement('al-ico');
157
+ result = Blast.Classes.Hawkejs.Hawkejs.createElement('al-icon');
158
158
  result.setIcon(icon);
159
159
  } else if (icon.html) {
160
160
  result = Blast.Classes.Hawkejs.parseHTML(icon.html);