alchemy-widget 0.2.3 → 0.2.5

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.
package/CHANGELOG.md CHANGED
@@ -1,3 +1,16 @@
1
+ ## 0.2.5 (2023-02-11)
2
+
3
+ * Add `code_type` field to the `Sourcecode` widget
4
+ * Allow setting the source of an `HTML` widget via its config dialog
5
+ * Make `paste` widget action only append copied widgets to a container
6
+ * Add `replace` widget action to replace a widget with anything in the current clipboard
7
+
8
+ ## 0.2.4 (2023-01-30)
9
+
10
+ * Fix the tree structure generation of the `al-toc` element
11
+ * Make `TableOfContents#entries` return a flat list and `TableOfContents#tree` a tree structure
12
+ * Also take siblings of heading elements into account for the `TableOfContents` scrollspy
13
+
1
14
  ## 0.2.3 (2023-01-23)
2
15
 
3
16
  * Fix `List` widgets not having their content saved
@@ -364,7 +364,7 @@ Base.setMethod(async function save() {
364
364
  *
365
365
  * @author Jelle De Loecker <jelle@elevenways.be>
366
366
  * @since 0.2.0
367
- * @version 0.2.1
367
+ * @version 0.2.5
368
368
  */
369
369
  Base.setMethod(async function copyConfigToClipboard() {
370
370
 
@@ -375,7 +375,10 @@ Base.setMethod(async function copyConfigToClipboard() {
375
375
  }
376
376
 
377
377
  value._altype = 'widget';
378
- value.type = this.type;
378
+
379
+ if (this.type) {
380
+ value.type = this.type;
381
+ }
379
382
 
380
383
  let dried = JSON.dry(value, null, '\t');
381
384
 
@@ -389,11 +392,11 @@ Base.setMethod(async function copyConfigToClipboard() {
389
392
  });
390
393
 
391
394
  /**
392
- * Get configuration from the clipboard and return it if it's valid
395
+ * Get any current configuration from the clipboard
393
396
  *
394
397
  * @author Jelle De Loecker <jelle@elevenways.be>
395
398
  * @since 0.2.0
396
- * @version 0.2.1
399
+ * @version 0.2.5
397
400
  */
398
401
  Base.setMethod(async function getConfigFromClipboard() {
399
402
 
@@ -428,7 +431,35 @@ Base.setMethod(async function getConfigFromClipboard() {
428
431
  return false;
429
432
  }
430
433
 
431
- if (result.type != this.type && !this.can_be_removed) {
434
+ return result;
435
+ });
436
+
437
+ /**
438
+ * Get configuration from the clipboard and return it if it's valid
439
+ *
440
+ * @author Jelle De Loecker <jelle@elevenways.be>
441
+ * @since 0.2.5
442
+ * @version 0.2.5
443
+ */
444
+ Base.setMethod(async function getReplaceableConfigFromClipboard() {
445
+
446
+ let result = await this.getConfigFromClipboard();
447
+
448
+ if (result.type == this.type) {
449
+ return result;
450
+ }
451
+
452
+ if (result.type == 'container') {
453
+ return false;
454
+ }
455
+
456
+ if (!this.can_be_removed) {
457
+ return false;
458
+ }
459
+
460
+ let parent_widget = this.parent_container;
461
+
462
+ if (!parent_widget || !parent_widget.editing || !parent_widget.addWidget) {
432
463
  return false;
433
464
  }
434
465
 
@@ -440,13 +471,46 @@ Base.setMethod(async function getConfigFromClipboard() {
440
471
  *
441
472
  * @author Jelle De Loecker <jelle@elevenways.be>
442
473
  * @since 0.2.0
443
- * @version 0.2.0
474
+ * @version 0.2.5
444
475
  */
445
476
  Base.setMethod(async function pasteConfigFromClipboard() {
446
477
 
447
- let result = await this.getConfigFromClipboard();
478
+ let result = await this.getReplaceableConfigFromClipboard();
448
479
 
449
480
  if (result) {
450
- this.value = result;
481
+ this.replaceWithConfig(config);
482
+ }
483
+ });
484
+
485
+ /**
486
+ * Apply the given config
487
+ *
488
+ * @author Jelle De Loecker <jelle@elevenways.be>
489
+ * @since 0.2.0
490
+ * @version 0.2.5
491
+ */
492
+ Base.setMethod(async function replaceWithConfig(config) {
493
+
494
+ if (!config?.type) {
495
+ throw new Error('Unable to replace, config type is empty');
496
+ }
497
+
498
+ if (this.type == config.type) {
499
+ this.value = config;
500
+ return true;
501
+ }
502
+
503
+ let parent_widget = this.parent_container;
504
+
505
+ // If this isn't in an editable widget, it can't be replaced.
506
+ // (Might be a hard-coded widget type)
507
+ if (!parent_widget || !parent_widget.editing || !parent_widget.addWidget) {
508
+ return false;
509
+ }
510
+
511
+ let new_widget = parent_widget.addWidget(config.type, config.config);
512
+
513
+ if (new_widget) {
514
+ this.replaceWith(new_widget);
451
515
  }
452
516
  });
@@ -12,9 +12,16 @@ let Widget = Function.inherits('Alchemy.Element.Widget.Base', 'Widget');
12
12
  *
13
13
  * @author Jelle De Loecker <jelle@elevenways.be>
14
14
  * @since 0.1.0
15
- * @version 0.1.0
15
+ * @version 0.2.5
16
16
  */
17
- Widget.setAttribute('type');
17
+ Widget.setAttribute('type', function getType(type) {
18
+
19
+ if (!type) {
20
+ type = this.instance.constructor.type_name;
21
+ }
22
+
23
+ return type;
24
+ });
18
25
 
19
26
  /**
20
27
  * Mark this as a widget
@@ -199,6 +199,8 @@ AlchemyWidgets.setMethod(function clear() {
199
199
  *
200
200
  * @param {String} type
201
201
  * @param {Object} config
202
+ *
203
+ * @return {HTMLElement}
202
204
  */
203
205
  AlchemyWidgets.setMethod(function addWidget(type, config) {
204
206
 
@@ -229,6 +231,8 @@ AlchemyWidgets.setMethod(function addWidget(type, config) {
229
231
  if (this.editing) {
230
232
  element.startEditor();
231
233
  }
234
+
235
+ return element;
232
236
  });
233
237
 
234
238
  /**
@@ -1,326 +1,315 @@
1
- /**
2
- * The table-of-contents element
3
- *
4
- * @author Jelle De Loecker <jelle@elevenways.be>
5
- * @since 0.1.2
6
- * @version 0.1.2
7
- */
8
- const TableOfContents = Function.inherits('Alchemy.Element.App', 'TableOfContents');
9
-
10
- /**
11
- * The template to use for the content of this element
12
- *
13
- * @author Jelle De Loecker <jelle@elevenways.be>
14
- * @since 0.1.2
15
- * @version 0.1.2
16
- */
17
- TableOfContents.setTemplateFile('elements/table_of_contents');
18
-
19
- /**
20
- * Set the actual tag name
21
- *
22
- * @author Jelle De Loecker <jelle@elevenways.be>
23
- * @since 0.2.0
24
- * @version 0.2.0
25
- */
26
- TableOfContents.setTagName('AL-TOC');
27
-
28
- /**
29
- * Set the content
30
- *
31
- * @author Jelle De Loecker <jelle@elevenways.be>
32
- * @since 0.1.2
33
- * @version 0.1.2
34
- */
35
- TableOfContents.setAssignedProperty('content');
36
-
37
- /**
38
- * The role of this element
39
- *
40
- * @author Jelle De Loecker <jelle@elevenways.be>
41
- * @since 0.1.2
42
- * @version 0.1.2
43
- */
44
- TableOfContents.setRole('navigation');
45
-
46
- /**
47
- * The parent query
48
- *
49
- * @author Jelle De Loecker <jelle@elevenways.be>
50
- * @since 0.1.2
51
- * @version 0.1.2
52
- */
53
- TableOfContents.setAttribute('parent-selector');
54
-
55
- /**
56
- * The children query
57
- *
58
- * @author Jelle De Loecker <jelle@elevenways.be>
59
- * @since 0.1.2
60
- * @version 0.1.2
61
- */
62
- TableOfContents.setAttribute('children-selector');
63
-
64
- /**
65
- * The elements query
66
- *
67
- * @author Jelle De Loecker <jelle@elevenways.be>
68
- * @since 0.1.2
69
- * @version 0.1.2
70
- */
71
- TableOfContents.setAttribute('elements-selector');
72
-
73
- /**
74
- * The elements query
75
- *
76
- * @author Jelle De Loecker <jelle@elevenways.be>
77
- * @since 0.1.2
78
- * @version 0.1.2
79
- */
80
- TableOfContents.setAttribute('title-selector');
81
-
82
- /**
83
- * The class to add when intersecting (visible)
84
- *
85
- * @author Jelle De Loecker <jelle@elevenways.be>
86
- * @since 0.1.2
87
- * @version 0.1.2
88
- */
89
- TableOfContents.setAttribute('intersection-class');
90
-
91
- /**
92
- * Should titles be truncated?
93
- *
94
- * @author Jelle De Loecker <jelle@elevenways.be>
95
- * @since 0.2.1
96
- * @version 0.2.1
97
- */
98
- TableOfContents.setAttribute('truncate-length', {type: 'number'});
99
-
100
- /**
101
- * Get the entries
102
- *
103
- * @author Jelle De Loecker <jelle@elevenways.be>
104
- * @since 0.1.2
105
- * @version 0.2.1
106
- */
107
- TableOfContents.setProperty(function entries() {
108
-
109
- let result = [],
110
- parent = this.parentElement,
111
- wrapper;
112
-
113
- if (this.parent_selector) {
114
- parent = this.queryParents(this.parent_selector);
115
- }
116
-
117
- if (parent) {
118
- wrapper = parent;
119
- }
120
-
121
- if (wrapper && this.children_selector) {
122
- wrapper = wrapper.querySelector(this.children_selector);
123
- }
124
-
125
- if (wrapper) {
126
-
127
- let current_level = null,
128
- last_entry,
129
- elements = wrapper.querySelectorAll(this.elements_selector || 'h1,h2'),
130
- element,
131
- title,
132
- i;
133
-
134
- for (i = 0; i < elements.length; i++) {
135
- element = elements[i];
136
-
137
- if (!element.id) {
138
-
139
- if (element.hawkejs_id) {
140
- element.id = element.hawkejs_id;
141
- }
142
-
143
- if (!element.id) {
144
- continue;
145
- }
146
- }
147
-
148
- let title_element,
149
- starts_level,
150
- ends_level;
151
-
152
- if (this.title_selector) {
153
- title_element = element.querySelector(this.title_selector);
154
- }
155
-
156
- if (!title_element) {
157
- title_element = element;
158
- }
159
-
160
- if (element.nodeName[0] == 'H' && isFinite(element.nodeName[1])) {
161
- let heading_level = +element.nodeName[1];
162
-
163
- if (current_level == null) {
164
- current_level = heading_level;
165
- } else if (heading_level > current_level) {
166
- current_level++;
167
-
168
- if (last_entry) {
169
- last_entry.starts_level = true;
170
- }
171
- } else if (heading_level == current_level && last_entry) {
172
- last_entry.starts_level = false;
173
- } else if (heading_level < current_level) {
174
- current_level--;
175
-
176
- if (last_entry) {
177
- last_entry.ends_level = true;
178
- }
179
- }
180
- }
181
-
182
- title = (title_element.toc_title || title_element.textContent || '').trim();
183
-
184
- if (this.truncate_length) {
185
- title = title.truncate(this.truncate_length);
186
- }
187
-
188
- // Don't add empty titles
189
- if (!title) {
190
- continue;
191
- }
192
-
193
- last_entry = {
194
- id : element.id,
195
- level : current_level,
196
- title : title,
197
- element : element,
198
- starts_level : starts_level,
199
- ends_level : ends_level,
200
- };
201
-
202
- result.push(last_entry);
203
- }
204
-
205
- let ended_level = false,
206
- entries = result,
207
- current_branch,
208
- current_nodes = [];
209
-
210
- result = current_nodes;
211
- last_entry = null;
212
-
213
- for (let entry of entries) {
214
-
215
- if (ended_level) {
216
-
217
- while (entry.level >= current_branch.level) {
218
- current_branch = current_branch.parent;
219
- current_nodes = current_branch?.children || result;
220
-
221
- if (!current_branch) {
222
- current_branch = result[result.length - 1];
223
- break;
224
- }
225
- }
226
-
227
- ended_level = false;
228
- }
229
-
230
- if (!current_branch) {
231
- current_branch = entry;
232
- } else {
233
- entry.parent = current_branch;
234
- }
235
-
236
- if (entry.starts_level) {
237
-
238
- current_branch = last_entry;
239
-
240
- if (!current_branch.children) {
241
- current_branch.children = [];
242
- }
243
-
244
- current_nodes = current_branch.children;
245
- }
246
-
247
- current_nodes.push(entry);
248
-
249
- if (entry.ends_level) {
250
- ended_level = true;
251
- current_branch = entry.parent;
252
- current_nodes = current_branch.children || result;
253
-
254
- if (!current_branch) {
255
- current_branch = result[result.length - 1];
256
- break;
257
- }
258
- }
259
-
260
- last_entry = entry;
261
- }
262
- }
263
-
264
- return result;
265
- });
266
-
267
- /**
268
- * Added to the dom for the first time
269
- *
270
- * @author Jelle De Loecker <jelle@elevenways.be>
271
- * @since 0.1.2
272
- * @version 0.2.1
273
- */
274
- TableOfContents.setMethod(async function introduced() {
275
-
276
- await this.rerender();
277
-
278
- const observer = new IntersectionObserver(entries => {
279
-
280
- let class_name = this.intersection_class || 'visible',
281
- first_name = class_name + '-first';
282
-
283
- for (let entry of entries) {
284
- const id = entry.target.getAttribute('id');
285
-
286
- let query = `a[href="#${id}"]`,
287
- element = this.querySelector(query);
288
-
289
- if (!element) {
290
- return;
291
- }
292
-
293
- if (entry.intersectionRatio > 0) {
294
- element.classList.add(class_name);
295
- } else {
296
- element.classList.remove(class_name);
297
- }
298
- };
299
-
300
- let is_visible,
301
- all_marked = this.querySelectorAll('.' + class_name + ', .' + first_name),
302
- element,
303
- seen = 0,
304
- i;
305
-
306
- for (i = 0; i < all_marked.length; i++) {
307
- element = all_marked[i];
308
- is_visible = element.classList.contains(class_name);
309
-
310
- if (is_visible && seen == 0) {
311
- element.classList.add(first_name);
312
- } else {
313
- element.classList.remove(first_name);
314
- }
315
-
316
- if (is_visible) {
317
- seen++;
318
- }
319
- }
320
-
321
- });
322
-
323
- for (let entry of this.entries) {
324
- observer.observe(entry.element);
325
- }
1
+ const RELATED_HEADING = Symbol('related_heading'),
2
+ RELATED_SIBLINGS = Symbol('related_siblings');
3
+
4
+ /**
5
+ * The table-of-contents element
6
+ *
7
+ * @author Jelle De Loecker <jelle@elevenways.be>
8
+ * @since 0.1.2
9
+ * @version 0.1.2
10
+ */
11
+ const TableOfContents = Function.inherits('Alchemy.Element.App', 'TableOfContents');
12
+
13
+ /**
14
+ * The template to use for the content of this element
15
+ *
16
+ * @author Jelle De Loecker <jelle@elevenways.be>
17
+ * @since 0.1.2
18
+ * @version 0.1.2
19
+ */
20
+ TableOfContents.setTemplateFile('elements/table_of_contents');
21
+
22
+ /**
23
+ * Set the actual tag name
24
+ *
25
+ * @author Jelle De Loecker <jelle@elevenways.be>
26
+ * @since 0.2.0
27
+ * @version 0.2.0
28
+ */
29
+ TableOfContents.setTagName('AL-TOC');
30
+
31
+ /**
32
+ * Set the content
33
+ *
34
+ * @author Jelle De Loecker <jelle@elevenways.be>
35
+ * @since 0.1.2
36
+ * @version 0.1.2
37
+ */
38
+ TableOfContents.setAssignedProperty('content');
39
+
40
+ /**
41
+ * The role of this element
42
+ *
43
+ * @author Jelle De Loecker <jelle@elevenways.be>
44
+ * @since 0.1.2
45
+ * @version 0.1.2
46
+ */
47
+ TableOfContents.setRole('navigation');
48
+
49
+ /**
50
+ * The parent query
51
+ *
52
+ * @author Jelle De Loecker <jelle@elevenways.be>
53
+ * @since 0.1.2
54
+ * @version 0.1.2
55
+ */
56
+ TableOfContents.setAttribute('parent-selector');
57
+
58
+ /**
59
+ * The children query
60
+ *
61
+ * @author Jelle De Loecker <jelle@elevenways.be>
62
+ * @since 0.1.2
63
+ * @version 0.1.2
64
+ */
65
+ TableOfContents.setAttribute('children-selector');
66
+
67
+ /**
68
+ * The elements query
69
+ *
70
+ * @author Jelle De Loecker <jelle@elevenways.be>
71
+ * @since 0.1.2
72
+ * @version 0.1.2
73
+ */
74
+ TableOfContents.setAttribute('elements-selector');
75
+
76
+ /**
77
+ * The elements query
78
+ *
79
+ * @author Jelle De Loecker <jelle@elevenways.be>
80
+ * @since 0.1.2
81
+ * @version 0.1.2
82
+ */
83
+ TableOfContents.setAttribute('title-selector');
84
+
85
+ /**
86
+ * The class to add when intersecting (visible)
87
+ *
88
+ * @author Jelle De Loecker <jelle@elevenways.be>
89
+ * @since 0.1.2
90
+ * @version 0.1.2
91
+ */
92
+ TableOfContents.setAttribute('intersection-class');
93
+
94
+ /**
95
+ * Should titles be truncated?
96
+ *
97
+ * @author Jelle De Loecker <jelle@elevenways.be>
98
+ * @since 0.2.1
99
+ * @version 0.2.1
100
+ */
101
+ TableOfContents.setAttribute('truncate-length', {type: 'number'});
102
+
103
+ /**
104
+ * Get the entries
105
+ *
106
+ * @author Jelle De Loecker <jelle@elevenways.be>
107
+ * @since 0.1.2
108
+ * @version 0.2.4
109
+ */
110
+ TableOfContents.setProperty(function entries() {
111
+
112
+ let result = [],
113
+ parent = this.parentElement,
114
+ wrapper;
115
+
116
+ if (this.parent_selector) {
117
+ parent = this.queryParents(this.parent_selector);
118
+ }
119
+
120
+ if (parent) {
121
+ wrapper = parent;
122
+ }
123
+
124
+ if (wrapper && this.children_selector) {
125
+ wrapper = wrapper.querySelector(this.children_selector);
126
+ }
127
+
128
+ if (wrapper) {
129
+
130
+ let heading_level = 0,
131
+ heading,
132
+ i;
133
+
134
+ let headings = wrapper.querySelectorAll(this.elements_selector || 'h1, h2, h3, h4, h5, h6'),
135
+ nodes = [];
136
+
137
+ for (i = 0; i < headings.length; i++) {
138
+ heading = headings[i];
139
+
140
+ if (!heading.id) {
141
+
142
+ if (heading.hawkejs_id) {
143
+ heading.id = heading.hawkejs_id;
144
+ }
145
+
146
+ if (!heading.id) {
147
+ continue;
148
+ }
149
+ }
150
+
151
+ let title_element,
152
+ title;
153
+
154
+ if (this.title_selector) {
155
+ title_element = heading.querySelector(this.title_selector);
156
+ }
157
+
158
+ if (!title_element) {
159
+ title_element = heading;
160
+ }
161
+
162
+ if (title_element.nodeName[0] == 'H' && isFinite(title_element.nodeName[1])) {
163
+ heading_level = +title_element.nodeName[1];
164
+ } else if (!heading_level) {
165
+ heading_level = 1;
166
+ }
167
+
168
+ title = (title_element.toc_title || title_element.textContent || '').trim();
169
+
170
+ if (this.truncate_length) {
171
+ title = title.truncate(this.truncate_length);
172
+ }
173
+
174
+ // Don't add empty titles
175
+ if (!title) {
176
+ continue;
177
+ }
178
+
179
+ let node = {
180
+ id : heading.id,
181
+ level : heading_level,
182
+ title : title,
183
+ element : heading,
184
+ };
185
+
186
+ nodes.push(node);
187
+ }
188
+
189
+ result = nodes;
190
+ }
191
+
192
+ return result;
193
+ });
194
+
195
+ /**
196
+ * Get the entries tree
197
+ *
198
+ * @author Jelle De Loecker <jelle@elevenways.be>
199
+ * @since 0.2.4
200
+ * @version 0.2.4
201
+ */
202
+ TableOfContents.setProperty(function tree() {
203
+ return Blast.listToTree(this.entries);
204
+ });
205
+
206
+ /**
207
+ * Added to the dom for the first time
208
+ *
209
+ * @author Jelle De Loecker <jelle@elevenways.be>
210
+ * @since 0.1.2
211
+ * @version 0.2.4
212
+ */
213
+ TableOfContents.setMethod(async function introduced() {
214
+
215
+ await this.rerender();
216
+
217
+ const observer = new IntersectionObserver(entries => {
218
+
219
+ let class_name = this.intersection_class || 'visible',
220
+ first_name = class_name + '-first';
221
+
222
+ let intersect_map = new Map();
223
+
224
+ for (let entry of entries) {
225
+ const heading = entry.target[RELATED_HEADING] || entry.target;
226
+ const id = heading.getAttribute('id');
227
+
228
+ if (!id) {
229
+ continue;
230
+ }
231
+
232
+ let query = `a[href="#${id}"]`,
233
+ element = this.querySelector(query);
234
+
235
+ if (!element) {
236
+ continue;
237
+ }
238
+
239
+ let value = intersect_map.get(element) || 0;
240
+
241
+ if (entry.intersectionRatio > 0) {
242
+ value++;
243
+ } else {
244
+ let siblings = heading[RELATED_SIBLINGS];
245
+
246
+ if (siblings?.length) {
247
+ for (let sibling of siblings) {
248
+ if (sibling.isVisible(-150)) {
249
+ value++;
250
+ break;
251
+ }
252
+ }
253
+ }
254
+ }
255
+
256
+ intersect_map.set(element, value);
257
+ };
258
+
259
+ for (let [element, value] of intersect_map) {
260
+
261
+ if (value > 0) {
262
+ element.classList.add(class_name);
263
+ } else {
264
+ element.classList.remove(class_name);
265
+ }
266
+ }
267
+
268
+ let is_visible,
269
+ all_marked = this.querySelectorAll('.' + class_name + ', .' + first_name),
270
+ element,
271
+ seen = 0,
272
+ i;
273
+
274
+ for (i = 0; i < all_marked.length; i++) {
275
+ element = all_marked[i];
276
+ is_visible = element.classList.contains(class_name);
277
+
278
+ if (is_visible && seen == 0) {
279
+ element.classList.add(first_name);
280
+ } else {
281
+ element.classList.remove(first_name);
282
+ }
283
+
284
+ if (is_visible) {
285
+ seen++;
286
+ }
287
+ }
288
+ });
289
+
290
+ let entries = this.entries,
291
+ elements = [];
292
+
293
+ for (let entry of entries) {
294
+ observer.observe(entry.element);
295
+ elements.push(entry.element);
296
+ }
297
+
298
+ for (let element of elements) {
299
+
300
+ element[RELATED_SIBLINGS] = [];
301
+ let sibling = element.nextElementSibling;
302
+
303
+ while (sibling) {
304
+
305
+ if (elements.includes(sibling)) {
306
+ break;
307
+ }
308
+
309
+ element[RELATED_SIBLINGS].push(sibling);
310
+ sibling[RELATED_HEADING] = element;
311
+ observer.observe(sibling);
312
+ sibling = sibling.nextElementSibling;
313
+ }
314
+ }
326
315
  });
@@ -148,7 +148,7 @@ Widget.enforceProperty(function is_hidden(new_value) {
148
148
  *
149
149
  * @author Jelle De Loecker <jelle@elevenways.be>
150
150
  * @since 0.1.0
151
- * @version 0.2.1
151
+ * @version 0.2.5
152
152
  */
153
153
  Widget.constitute(function prepareSchema() {
154
154
 
@@ -197,18 +197,57 @@ Widget.constitute(function prepareSchema() {
197
197
  return true;
198
198
  });
199
199
 
200
- copy.setIcon('clipboard');
200
+ copy.setIcon('copy');
201
201
  copy.close_actionbar = true;
202
202
 
203
+ // Add the "replace from clipboard" action
204
+ let replace = this.createAction('replace', 'Replace from clipboard');
205
+
206
+ replace.setHandler(async function replaceAction(widget_el, handle) {
207
+
208
+ let config = await widget_el.getReplaceableConfigFromClipboard();
209
+
210
+ if (!config) {
211
+ return false;
212
+ }
213
+
214
+ widget_el.replaceWithConfig(config);
215
+ });
216
+
217
+ replace.setTester(function replaceActionTester(widget_el, handle) {
218
+ return widget_el.getReplaceableConfigFromClipboard();
219
+ });
220
+
221
+ replace.setIcon('repeat');
222
+ replace.close_actionbar = true;
223
+
203
224
  // Add the "paste from clipboard" action
204
- let paste = this.createAction('paste', 'Replace from clipboard');
225
+ let paste = this.createAction('paste', 'Paste from clipboard');
226
+
227
+ paste.setHandler(async function pasteAction(widget_el, handle) {
205
228
 
206
- paste.setHandler(function pasteAction(widget_el, handle) {
207
- return widget_el.pasteConfigFromClipboard();
229
+ let config = await widget_el.getConfigFromClipboard();
230
+
231
+ if (!config) {
232
+ return false;
233
+ }
234
+
235
+ widget_el.addWidget(config.type, config.config);
208
236
  });
209
237
 
210
- paste.setTester(function pasteAction(widget_el, handle) {
211
- return widget_el.getConfigFromClipboard();
238
+ paste.setTester(async function pasteActionTester(widget_el, handle) {
239
+
240
+ if (!widget_el.addWidget) {
241
+ return false;
242
+ }
243
+
244
+ let config = await widget_el.getConfigFromClipboard();
245
+
246
+ if (!config || config.type == 'container') {
247
+ return false;
248
+ }
249
+
250
+ return true;
212
251
  });
213
252
 
214
253
  paste.setIcon('paste');
@@ -17,11 +17,15 @@ const Html = Function.inherits('Alchemy.Widget', 'Html');
17
17
  *
18
18
  * @author Jelle De Loecker <jelle@elevenways.be>
19
19
  * @since 0.1.0
20
- * @version 0.1.0
20
+ * @version 0.2.5
21
21
  */
22
22
  Html.constitute(function prepareSchema() {
23
23
  // The actual HTML contents
24
- this.schema.addField('html', 'Html');
24
+ this.schema.addField('html', 'Html', {
25
+ title : 'HTML',
26
+ description : 'The HTML sourcecode',
27
+ widget_config_editable : true,
28
+ });
25
29
  });
26
30
 
27
31
  /**
@@ -79,12 +83,24 @@ Html.setMethod(function _stopEditor() {
79
83
  *
80
84
  * @author Jelle De Loecker <jelle@elevenways.be>
81
85
  * @since 0.1.0
82
- * @version 0.2.1
86
+ * @version 0.2.5
83
87
  *
84
88
  * @param {HTMLElement} widget
85
89
  */
86
90
  Html.setMethod(function populateWidget() {
87
- this.widget.innerHTML = this.config.html;
91
+
92
+ let html = this.config.html;
93
+
94
+ if (html == null) {
95
+ html = '';
96
+ }
97
+
98
+ if (this.ckeditor) {
99
+
100
+ this.ckeditor.setData(html);
101
+ } else {
102
+ this.widget.innerHTML = html;
103
+ }
88
104
  });
89
105
 
90
106
  /**
@@ -16,11 +16,18 @@ const Sourcecode = Function.inherits('Alchemy.Widget', 'Sourcecode');
16
16
  *
17
17
  * @author Jelle De Loecker <jelle@elevenways.be>
18
18
  * @since 0.1.0
19
- * @version 0.1.0
19
+ * @version 0.2.5
20
20
  */
21
21
  Sourcecode.constitute(function prepareSchema() {
22
22
  // The actual sourcecode contents
23
23
  this.schema.addField('sourcecode', 'Text');
24
+
25
+ // The type of sourcecode
26
+ this.schema.addField('code_type', 'String', {
27
+ title : 'Code type',
28
+ description : 'The type of sourcecode',
29
+ widget_config_editable : true,
30
+ });
24
31
  });
25
32
 
26
33
  /**
@@ -37,7 +44,7 @@ Sourcecode.setProperty('sourcecode_field', 'sourcecode');
37
44
  *
38
45
  * @author Jelle De Loecker <jelle@elevenways.be>
39
46
  * @since 0.1.0
40
- * @version 0.2.1
47
+ * @version 0.2.5
41
48
  *
42
49
  * @param {HTMLElement} widget
43
50
  */
@@ -53,7 +60,12 @@ Sourcecode.setMethod(function populateWidget() {
53
60
  pre = this.createElement('pre');
54
61
 
55
62
  pre.append(code);
56
- code.innerText = source;
63
+ code.textContent = source;
64
+
65
+ if (this.config.code_type) {
66
+ code.classList.add('language-' + this.config.code_type);
67
+ pre.classList.add('language-' + this.config.code_type);
68
+ }
57
69
 
58
70
  this.widget.append(pre);
59
71
  });
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.2.3",
4
+ "version": "0.2.5",
5
5
  "author": "Jelle De Loecker <jelle@elevenways.be>",
6
6
  "keywords": [
7
7
  "alchemy",
@@ -1,4 +1,4 @@
1
- <% all_entries = self.entries %>
1
+ <% all_entries = self.tree %>
2
2
 
3
3
  {% macro printEntries %}
4
4
  <ol>