alchemy-widget 0.1.6 → 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 (32) hide show
  1. package/CHANGELOG.md +9 -0
  2. package/assets/stylesheets/{alchemy-widgets.scss → alchemy_widgets.scss} +158 -48
  3. package/bootstrap.js +4 -2
  4. package/element/00-widget_base_element.js +96 -4
  5. package/element/05-widget_element.js +4 -13
  6. package/element/10-container_elements.js +15 -15
  7. package/element/11-alchemy_widgets_list_element.js +2 -2
  8. package/element/20-add_area_element.js +22 -22
  9. package/element/table_of_contents_element.js +104 -8
  10. package/element/widget_actionbar_element.js +92 -0
  11. package/element/widget_context_element.js +39 -23
  12. package/element/widget_toolbar_element.js +295 -50
  13. package/helper/widget_action.js +10 -10
  14. package/helper/widgets/00-widget.js +54 -18
  15. package/helper/widgets/01-container.js +7 -7
  16. package/helper/widgets/05-list.js +1 -1
  17. package/helper/widgets/alchemy_field_widget.js +112 -0
  18. package/helper/widgets/alchemy_form_widget.js +183 -0
  19. package/helper/widgets/alchemy_table_widget.js +71 -0
  20. package/helper/widgets/alchemy_tabs_widget.js +195 -0
  21. package/helper/widgets/header.js +3 -3
  22. package/helper/widgets/markdown.js +17 -10
  23. package/helper/widgets/sourcecode.js +4 -4
  24. package/helper/widgets/table_of_contents.js +2 -2
  25. package/helper/widgets_helper.js +26 -0
  26. package/package.json +3 -2
  27. package/view/elements/table_of_contents.hwk +23 -9
  28. package/view/form/inputs/edit/widget.hwk +2 -2
  29. package/view/form/inputs/edit/widgets.hwk +2 -2
  30. package/view/widget/elements/al_widget_toolbar.hwk +49 -0
  31. package/view/widget/widget_config.hwk +7 -4
  32. package/assets/stylesheets/alchemy-widget-symbols.scss +0 -191
package/CHANGELOG.md CHANGED
@@ -1,3 +1,12 @@
1
+ ## 0.2.0 (2022-11-02)
2
+
3
+ * Use `al-` prefix for all custom elements
4
+ * Update to `alchemy-form` v0.2.0
5
+ * Add copy & paste actions
6
+ * Add nesting levels to `al-toc`
7
+ * Add `al-widget-toolbar` element
8
+ * Use `easymde` markdown editor for markdown widgets
9
+
1
10
  ## 0.1.6 (2022-10-12)
2
11
 
3
12
  * Allow hiding widgets from the add-menu
@@ -1,15 +1,110 @@
1
- @import "alchemy-widget-symbols.scss";
1
+ :root {
2
+ al-widget-toolbar {
3
+ display: none;
4
+ }
5
+ }
6
+
7
+ html.logged-in {
8
+ al-widget-toolbar {
9
+ font-size: 15px;
10
+
11
+ display: flex;
12
+ z-index: 9999;
13
+ background: rgba(200, 200, 200, 0.5);
14
+ box-shadow: 0 5px 10px 0 rgba(0, 0, 0, 0.15);
15
+ bottom: 3em; left: 3em;
16
+ border-radius: 24px;
17
+ height: 5.25em;
18
+ padding: 1em;
19
+ border: 1px solid #aaa;
20
+ display: flex;
21
+ gap: 1em;
22
+ backdrop-filter: blur(10px);
23
+
24
+ position: fixed;
25
+ bottom: 16px;
26
+ left: 16px;
27
+ right: 16px;
28
+ }
29
+ }
30
+
31
+ al-widget-toolbar {
32
+
33
+ &[state="editing"] {
34
+ .start-edit {
35
+ display: none;
36
+ }
37
+ }
38
+
39
+ &[state="default"],
40
+ &[state="ready"] {
41
+ .stop-and-save,
42
+ .stop-edit,
43
+ .save-all {
44
+ display: none;
45
+ }
46
+ }
47
+
48
+ &[state="saving"],
49
+ &[state="saving-before-stop"] {
50
+ .start-edit,
51
+ .stop-edit {
52
+ display: none;
53
+ }
54
+ }
55
+
56
+ &[state="saving"] {
57
+ .stop-and-save {
58
+ display: none;
59
+ }
60
+ }
61
+
62
+ &[state="saving-before-stop"] {
63
+ .save-all {
64
+ display: none;
65
+ }
66
+ }
67
+
68
+ .stop-and-save,
69
+ .save-all {
70
+ --al-button-bg-color: green;
71
+ --al-button-bg-color-hover: rgb(55, 155, 55);
72
+ }
73
+
74
+ a,
75
+ al-button {
76
+ --al-button-font-size: 1.3em;
77
+ border-radius: 1em;
78
+ }
79
+
80
+ a {
81
+ background-color: black;
82
+ color: white;
83
+ padding: 0.5em 1em;
84
+ display: inline-flex;
85
+ align-items: center;
86
+ gap: 0.5em;
87
+
88
+ al-icon {
89
+ font-size: 2em;
90
+ }
91
+
92
+ &:hover {
93
+ background-color: rgb(53, 53, 53);
94
+ }
95
+ }
96
+ }
2
97
 
3
- alchemy-widgets,
4
- alchemy-widgets-row,
5
- alchemy-widgets-column,
6
- alchemy-widget {
98
+ al-widgets,
99
+ al-widgets-row,
100
+ al-widgets-column,
101
+ al-widget {
7
102
 
8
103
  }
9
104
 
10
- alchemy-widgets,
11
- alchemy-widgets-row,
12
- alchemy-widgets-column {
105
+ al-widgets,
106
+ al-widgets-row,
107
+ al-widgets-column {
13
108
  display: flex;
14
109
 
15
110
  &.aw-editing {
@@ -22,15 +117,24 @@ alchemy-widgets-column {
22
117
  }
23
118
  }
24
119
 
25
- alchemy-widget {
120
+ al-widgets,
121
+ al-widget {
26
122
  &.aw-editing {
27
- outline: 2px dashed rgba(0, 0, 0, 0.3);
28
- outline-offset: -2px;
123
+ &:before {
124
+ content: "";
125
+ position: absolute;
126
+ inset: -2px;
127
+ background: white;
128
+ border: 2px dashed rgba(0, 0, 0, 0.4);
129
+ pointer-events: none;
130
+ backdrop-filter: invert(80%);
131
+ clip-path: polygon(0% 0%, 0% 100%, 2px 100%, 2px 2px, calc(100% - 2px) 2px, calc(100% - 2px) calc(100% - 2px), 0 calc(100% - 2px), 0 100%, 100% 100%, 100% 0)
132
+ }
29
133
  }
30
134
  }
31
135
 
32
- alchemy-widgets-row,
33
- alchemy-widgets-column {
136
+ al-widgets-row,
137
+ al-widgets-column {
34
138
 
35
139
  &.aw-editing {
36
140
  &:hover {
@@ -39,15 +143,15 @@ alchemy-widgets-column {
39
143
  }
40
144
  }
41
145
 
42
- alchemy-widgets,
43
- alchemy-widgets-column {
146
+ al-widgets,
147
+ al-widgets-column {
44
148
  flex-flow: column;
45
149
 
46
150
  &.aw-editing {
47
151
  padding-bottom: 5rem;
48
152
  }
49
153
 
50
- > alchemy-widget-add-area {
154
+ > al-widget-add-area {
51
155
  position: absolute;
52
156
  bottom: 0.2rem;
53
157
  left: 50%;
@@ -55,17 +159,12 @@ alchemy-widgets-column {
55
159
  }
56
160
  }
57
161
 
58
- alchemy-widgets {
162
+ al-widgets {
59
163
  min-width: 10rem;
60
164
  min-height: 10rem;
61
-
62
- &.aw-editing {
63
- outline: 2px dashed rgba(0, 0, 0, 0.3);
64
- outline-offset: -2px;
65
- }
66
165
  }
67
166
 
68
- alchemy-widgets-row {
167
+ al-widgets-row {
69
168
  flex-flow: row;
70
169
  flex: 10 10 auto;
71
170
 
@@ -73,7 +172,7 @@ alchemy-widgets-row {
73
172
  padding-right: 5rem;
74
173
  }
75
174
 
76
- > alchemy-widget-add-area {
175
+ > al-widget-add-area {
77
176
  position: absolute;
78
177
  right: 0.5rem;
79
178
  top: 50%;
@@ -81,7 +180,7 @@ alchemy-widgets-row {
81
180
  }
82
181
  }
83
182
 
84
- alchemy-widget-add-area {
183
+ al-widget-add-area {
85
184
  background: rgba(255,255,255,0.5);
86
185
  padding: 0.5rem 2rem;
87
186
  border-radius: 2rem;
@@ -93,10 +192,10 @@ alchemy-widget-add-area {
93
192
  }
94
193
  }
95
194
 
96
- alchemy-widgets-row,
97
- alchemy-widgets > alchemy-widgets-column,
98
- alchemy-widgets-column > alchemy-widgets-column,
99
- .alchemy-widgets-container > alchemy-widgets-column {
195
+ al-widgets-row,
196
+ al-widgets > al-widgets-column,
197
+ al-widgets-column > al-widgets-column,
198
+ .alchemy-widgets-container > al-widgets-column {
100
199
  &.aw-editing {
101
200
 
102
201
  &::after {
@@ -116,13 +215,13 @@ alchemy-widgets-column > alchemy-widgets-column,
116
215
  }
117
216
  }
118
217
 
119
- alchemy-widgets-column {
218
+ al-widgets-column {
120
219
  flex: 10 10 auto;
121
220
  }
122
221
 
123
- alchemy-widgets-column,
124
- alchemy-widgets-row > alchemy-widgets-row,
125
- .alchemy-widgets-container > alchemy-widgets-row {
222
+ al-widgets-column,
223
+ al-widgets-row > al-widgets-row,
224
+ .alchemy-widgets-container > al-widgets-row {
126
225
  &.aw-editing {
127
226
  &::after {
128
227
  content: "";
@@ -141,7 +240,7 @@ alchemy-widgets-row > alchemy-widgets-row,
141
240
  }
142
241
  }
143
242
 
144
- alchemy-widget-add-area {
243
+ al-widget-add-area {
145
244
  display: flex;
146
245
  justify-content: center;
147
246
  align-items: center;
@@ -165,7 +264,7 @@ alchemy-widget-add-area {
165
264
  }
166
265
  }
167
266
 
168
- .aw-toolbar-button,
267
+ .aw-actionbar-button,
169
268
  .widget-button {
170
269
  color: #707684;
171
270
  cursor: pointer;
@@ -183,7 +282,7 @@ alchemy-widget-add-area {
183
282
  }
184
283
  }
185
284
 
186
- alchemy-widget {
285
+ al-widget {
187
286
  display: block;
188
287
 
189
288
  &.aw-editing {
@@ -199,12 +298,17 @@ alchemy-widget {
199
298
 
200
299
  &.aw-selected {
201
300
  background-color: #7979f347;
202
- outline: 1px dashed #7979f399;
301
+ position: relative;
302
+ outline: none;
303
+
304
+ &:before {
305
+ background-color: yellow;
306
+ }
203
307
  }
204
308
  }
205
309
 
206
- alchemy-widget-context,
207
- alchemy-widget-toolbar {
310
+ al-widget-context,
311
+ al-widget-actionbar {
208
312
  display: block;
209
313
  padding: 0.4rem;
210
314
  background-color: white;
@@ -217,11 +321,11 @@ alchemy-widget-toolbar {
217
321
  }
218
322
  }
219
323
 
220
- alchemy-widget-context {
324
+ al-widget-context {
221
325
  position: fixed;
222
326
  z-index: 99999;
223
327
 
224
- alchemy-widget-toolbar {
328
+ al-widget-actionbar {
225
329
  position: absolute;
226
330
  top: calc(100% + 5px);
227
331
  right: 0;
@@ -229,7 +333,7 @@ alchemy-widget-context {
229
333
  }
230
334
  }
231
335
 
232
- alchemy-widget-toolbar {
336
+ al-widget-actionbar {
233
337
  min-height: 2.5rem;
234
338
  min-width: 2.5rem;
235
339
  display: flex;
@@ -238,7 +342,7 @@ alchemy-widget-toolbar {
238
342
  margin-right: 5px;
239
343
  }
240
344
 
241
- .aw-toolbar-button {
345
+ .aw-actionbar-button {
242
346
  font-size: 2.5rem;
243
347
  border-radius: 4px;
244
348
  padding: 0.6rem;
@@ -254,7 +358,7 @@ alchemy-widget-toolbar {
254
358
  }
255
359
  }
256
360
 
257
- alchemy-widget[type="header"] {
361
+ al-widget[type="header"] {
258
362
 
259
363
  h1, h2, h3, h4, h5, h6 {
260
364
  padding: 1em 0;
@@ -272,7 +376,7 @@ alchemy-widget[type="header"] {
272
376
  }
273
377
  }
274
378
 
275
- alchemy-widget[type="text"] {
379
+ al-widget[type="text"] {
276
380
 
277
381
  &.aw-editing {
278
382
  &,
@@ -288,7 +392,7 @@ alchemy-widget[type="text"] {
288
392
  }
289
393
  }
290
394
 
291
- .aw-toolbar-button {
395
+ .aw-actionbar-button {
292
396
 
293
397
  .aw-header-h {
294
398
  font-weight: bold;
@@ -301,12 +405,18 @@ alchemy-widget[type="text"] {
301
405
  }
302
406
  }
303
407
 
304
- table-of-contents {
408
+ al-toc {
305
409
  display: block;
306
410
  }
307
411
 
308
412
  [data-he-template="widget/widget_config"] {
309
- alchemy-label {
413
+
414
+ .widget-config-title {
415
+ margin-bottom: 1rem;
416
+ color: black;
417
+ }
418
+
419
+ al-label {
310
420
  padding: 0.5rem;
311
421
 
312
422
  [data-he-name="field-title"] {
package/bootstrap.js CHANGED
@@ -1,5 +1,7 @@
1
- if (alchemy.plugins.form) {
2
- throw new Error('The alchemy-form plugin has to be loaded AFTER alchemy-widget');
1
+ alchemy.requirePlugin('form', false);
2
+
3
+ if (!alchemy.plugins.form) {
4
+ throw new Error('The alchemy-form plugin has to be loaded BEFORE alchemy-widget');
3
5
  }
4
6
 
5
7
  Router.add({
@@ -14,7 +14,16 @@ let Base = Function.inherits('Alchemy.Element', 'Alchemy.Element.Widget', 'Base'
14
14
  * @since 0.1.0
15
15
  * @version 0.1.0
16
16
  */
17
- Base.setStylesheetFile('alchemy-widgets');
17
+ Base.setStylesheetFile('alchemy_widgets');
18
+
19
+ /**
20
+ * Set the custom element prefix
21
+ *
22
+ * @author Jelle De Loecker <jelle@elevenways.be>
23
+ * @since 0.1.0
24
+ * @version 0.2.0
25
+ */
26
+ Base.setStatic('custom_element_prefix', 'al');
18
27
 
19
28
  /**
20
29
  * Don't register this as a custom element
@@ -22,9 +31,9 @@ Base.setStylesheetFile('alchemy-widgets');
22
31
  *
23
32
  * @author Jelle De Loecker <jelle@elevenways.be>
24
33
  * @since 0.1.0
25
- * @version 0.1.0
34
+ * @version 0.2.0
26
35
  */
27
- Base.setStatic('is_abstract_class', true, false);
36
+ Base.makeAbstractClass();
28
37
 
29
38
  /**
30
39
  * The Widget class instance belonging to this element
@@ -183,7 +192,7 @@ Base.setMethod(function getSiblingContainer(type) {
183
192
  return next;
184
193
  }
185
194
 
186
- if (next.tagName != 'ALCHEMY-WIDGET-ADD-AREA') {
195
+ if (next.tagName != 'AL-WIDGET-ADD-AREA') {
187
196
  return false;
188
197
  }
189
198
  }
@@ -348,4 +357,87 @@ Base.setMethod(async function save() {
348
357
  };
349
358
 
350
359
  let result = await alchemy.fetch(config);
360
+ });
361
+
362
+ /**
363
+ * Copy this widget's configuration to the clipboard
364
+ *
365
+ * @author Jelle De Loecker <jelle@elevenways.be>
366
+ * @since 0.2.0
367
+ * @version 0.2.0
368
+ */
369
+ Base.setMethod(async function copyConfigToClipboard() {
370
+
371
+ let value = this.value;
372
+
373
+ if (!value) {
374
+ return;
375
+ }
376
+
377
+ value._altype = 'widget';
378
+ value.type = this.type;
379
+
380
+ try {
381
+ await navigator.clipboard.writeText(JSON.dry(value, null, '\t'));
382
+ } catch (err) {
383
+ console.error('Failed to copy:', err);
384
+ }
385
+ });
386
+
387
+ /**
388
+ * Get configuration from the clipboard and return it if it's valid
389
+ *
390
+ * @author Jelle De Loecker <jelle@elevenways.be>
391
+ * @since 0.2.0
392
+ * @version 0.2.0
393
+ */
394
+ Base.setMethod(async function getConfigFromClipboard() {
395
+
396
+ let result;
397
+
398
+ try {
399
+ result = await navigator.clipboard.readText();
400
+ } catch (err) {
401
+ return false;
402
+ }
403
+
404
+ if (result) {
405
+ result = result.trim();
406
+ }
407
+
408
+ if (!result || result[0] != '{') {
409
+ return false;
410
+ }
411
+
412
+ try {
413
+ result = JSON.undry(result);
414
+ } catch (err) {
415
+ return false;
416
+ }
417
+
418
+ if (result._altype != 'widget') {
419
+ return false;
420
+ }
421
+
422
+ if (result.type != this.type && !this.can_be_removed) {
423
+ return false;
424
+ }
425
+
426
+ return result;
427
+ });
428
+
429
+ /**
430
+ * Read the configuration from the clipboard & apply
431
+ *
432
+ * @author Jelle De Loecker <jelle@elevenways.be>
433
+ * @since 0.2.0
434
+ * @version 0.2.0
435
+ */
436
+ Base.setMethod(async function pasteConfigFromClipboard() {
437
+
438
+ let result = await this.getConfigFromClipboard();
439
+
440
+ if (result) {
441
+ this.value = result;
442
+ }
351
443
  });
@@ -1,5 +1,5 @@
1
1
  /**
2
- * The alchemy-widget element
2
+ * The al-widget element
3
3
  *
4
4
  * @author Jelle De Loecker <jelle@elevenways.be>
5
5
  * @since 0.1.0
@@ -7,15 +7,6 @@
7
7
  */
8
8
  let Widget = Function.inherits('Alchemy.Element.Widget.Base', 'Widget');
9
9
 
10
- /**
11
- * Set the custom element prefix
12
- *
13
- * @author Jelle De Loecker <jelle@elevenways.be>
14
- * @since 0.1.0
15
- * @version 0.1.0
16
- */
17
- Widget.setStatic('custom_element_prefix', 'alchemy');
18
-
19
10
  /**
20
11
  * The type of widget
21
12
  *
@@ -363,14 +354,14 @@ Widget.setMethod(function removeEditEventListeners() {
363
354
  *
364
355
  * @author Jelle De Loecker <jelle@elevenways.be>
365
356
  * @since 0.1.0
366
- * @version 0.1.0
357
+ * @version 0.2.0
367
358
  */
368
359
  Widget.setMethod(function getContextButton() {
369
360
 
370
- let button = document.querySelector('alchemy-widget-context');
361
+ let button = document.querySelector('al-widget-context');
371
362
 
372
363
  if (!button) {
373
- button = this.createElement('alchemy-widget-context');
364
+ button = this.createElement('al-widget-context');
374
365
  document.body.append(button);
375
366
  }
376
367
 
@@ -1,13 +1,13 @@
1
1
  /**
2
- * The alchemy-widgets element is the base "container" for all other widgets.
2
+ * The al-widgets element is the base "container" for all other widgets.
3
3
  * It should never be nested, though
4
4
  *
5
5
  * @author Jelle De Loecker <jelle@elevenways.be>
6
6
  * @since 0.1.0
7
7
  * @version 0.1.0
8
8
  */
9
- let AlchemyWidgets = Function.inherits('Alchemy.Element.Widget', function AlchemyWidgets() {
10
- AlchemyWidgets.super.call(this);
9
+ let AlchemyWidgets = Function.inherits('Alchemy.Element.Widget', function AlWidgets() {
10
+ AlWidgets.super.call(this);
11
11
 
12
12
  // Always create this dummy instance just in case?
13
13
  this.instance = new Classes.Alchemy.Widget.Container();
@@ -19,9 +19,9 @@ let AlchemyWidgets = Function.inherits('Alchemy.Element.Widget', function Alchem
19
19
  *
20
20
  * @author Jelle De Loecker <jelle@elevenways.be>
21
21
  * @since 0.1.0
22
- * @version 0.1.0
22
+ * @version 0.2.0
23
23
  */
24
- AlchemyWidgets.setStatic('custom_element_prefix', 'alchemy-widgets');
24
+ AlchemyWidgets.setStatic('custom_element_prefix', 'al-widgets');
25
25
 
26
26
  /**
27
27
  * Don't add the edit event listeners
@@ -69,7 +69,7 @@ AlchemyWidgets.setProperty(function value() {
69
69
  let widgets = this.getWidgetsConfig(),
70
70
  result;
71
71
 
72
- if (this.nodeName == 'ALCHEMY-WIDGETS') {
72
+ if (this.nodeName == 'AL-WIDGETS') {
73
73
  result = {widgets};
74
74
  } else {
75
75
  result = {
@@ -186,7 +186,7 @@ AlchemyWidgets.setMethod(function clear() {
186
186
  for (i = 0; i < children.length; i++) {
187
187
  child = children[i];
188
188
 
189
- if (child.nodeName == 'ALCHEMY-WIDGET-ADD-AREA') {
189
+ if (child.nodeName == 'AL-WIDGET-ADD-AREA') {
190
190
  continue;
191
191
  }
192
192
 
@@ -240,7 +240,7 @@ AlchemyWidgets.setMethod(function addWidget(type, config) {
240
240
  *
241
241
  * @author Jelle De Loecker <jelle@elevenways.be>
242
242
  * @since 0.1.0
243
- * @version 0.1.0
243
+ * @version 0.2.0
244
244
  *
245
245
  * @param {Element} element
246
246
  */
@@ -249,7 +249,7 @@ AlchemyWidgets.setMethod(function _appendWidgetElement(element) {
249
249
  let add_area;
250
250
 
251
251
  if (this.editing) {
252
- add_area = this.querySelector(':scope > alchemy-widget-add-area');
252
+ add_area = this.querySelector(':scope > al-widget-add-area');
253
253
  }
254
254
 
255
255
  if (add_area) {
@@ -270,19 +270,19 @@ AlchemyWidgets.setMethod(function _appendWidgetElement(element) {
270
270
  AlchemyWidgets.setMethod(function initEventListeners() {});
271
271
 
272
272
  /**
273
- * The alchemy-widgets-column element
273
+ * The al-widgets-column element
274
274
  *
275
275
  * @author Jelle De Loecker <jelle@elevenways.be>
276
276
  * @since 0.1.0
277
- * @version 0.1.0
277
+ * @version 0.2.0
278
278
  */
279
- Function.inherits('Alchemy.Element.Widget.AlchemyWidgets', 'Column');
279
+ Function.inherits('Alchemy.Element.Widget.AlWidgets', 'Column');
280
280
 
281
281
  /**
282
- * The alchemy-widgets-row element
282
+ * The al-widgets-row element
283
283
  *
284
284
  * @author Jelle De Loecker <jelle@elevenways.be>
285
285
  * @since 0.1.0
286
- * @version 0.1.0
286
+ * @version 0.2.0
287
287
  */
288
- Function.inherits('Alchemy.Element.Widget.AlchemyWidgets', 'Row');
288
+ Function.inherits('Alchemy.Element.Widget.AlWidgets', 'Row');
@@ -1,11 +1,11 @@
1
1
  /**
2
- * The alchemy-widgets-list element
2
+ * The al-widgets-list element
3
3
  *
4
4
  * @author Jelle De Loecker <jelle@elevenways.be>
5
5
  * @since 0.1.0
6
6
  * @version 0.1.0
7
7
  */
8
- const List = Function.inherits('Alchemy.Element.Widget.AlchemyWidgets', 'List');
8
+ const List = Function.inherits('Alchemy.Element.Widget.AlWidgets', 'List');
9
9
 
10
10
  /**
11
11
  * Get the list element