alchemy-widget 0.1.2 → 0.1.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 +14 -0
- package/assets/stylesheets/alchemy-widgets.scss +4 -4
- package/bootstrap.js +6 -0
- package/controller/alchemy_widgets_controller.js +111 -0
- package/element/00-widget_base_element.js +165 -2
- package/element/05-widget_element.js +60 -2
- package/element/10-container_elements.js +33 -5
- package/element/20-add_area_element.js +14 -22
- package/element/table_of_contents_element.js +192 -192
- package/element/widget_toolbar_element.js +1 -0
- package/helper/widgets/00-widget.js +60 -4
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,17 @@
|
|
|
1
|
+
## 0.1.5 (2022-07-14)
|
|
2
|
+
|
|
3
|
+
* Unselect widgets when stopping the editor
|
|
4
|
+
* Add front-end save ability to widgets
|
|
5
|
+
|
|
6
|
+
## 0.1.4 (2022-06-23)
|
|
7
|
+
|
|
8
|
+
* Use `he-context-menu` element to show widgets to add
|
|
9
|
+
* Add widget actions to move across container boundaries
|
|
10
|
+
|
|
11
|
+
## 0.1.3 (2022-03-21)
|
|
12
|
+
|
|
13
|
+
* Catch and print errors when appending a widget to a container
|
|
14
|
+
|
|
1
15
|
## 0.1.2 (2022-02-20)
|
|
2
16
|
|
|
3
17
|
* Add `table-of-contents` element and widget
|
|
@@ -11,7 +11,7 @@ alchemy-widgets-column {
|
|
|
11
11
|
}
|
|
12
12
|
|
|
13
13
|
> * {
|
|
14
|
-
flex:
|
|
14
|
+
flex: 10;
|
|
15
15
|
}
|
|
16
16
|
}
|
|
17
17
|
|
|
@@ -53,7 +53,7 @@ alchemy-widgets {
|
|
|
53
53
|
|
|
54
54
|
alchemy-widgets-row {
|
|
55
55
|
flex-flow: row;
|
|
56
|
-
flex:
|
|
56
|
+
flex: 10 10 auto;
|
|
57
57
|
|
|
58
58
|
&.aw-editing {
|
|
59
59
|
padding-right: 5rem;
|
|
@@ -91,7 +91,7 @@ alchemy-widgets-column > alchemy-widgets-column,
|
|
|
91
91
|
}
|
|
92
92
|
|
|
93
93
|
alchemy-widgets-column {
|
|
94
|
-
flex:
|
|
94
|
+
flex: 10 10 auto;
|
|
95
95
|
}
|
|
96
96
|
|
|
97
97
|
alchemy-widgets-column,
|
|
@@ -149,8 +149,8 @@ alchemy-widget-add-area {
|
|
|
149
149
|
display: flex;
|
|
150
150
|
align-content: center;
|
|
151
151
|
min-height: 26px;
|
|
152
|
-
min-width: 26px;
|
|
153
152
|
align-items: center;
|
|
153
|
+
text-transform: uppercase;
|
|
154
154
|
|
|
155
155
|
&:hover {
|
|
156
156
|
color: #388ae5;
|
package/bootstrap.js
ADDED
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The Alchemy Widgets Controller class
|
|
3
|
+
*
|
|
4
|
+
* @author Jelle De Loecker <jelle@elevenways.be>
|
|
5
|
+
* @since 0.1.5
|
|
6
|
+
* @version 0.1.5
|
|
7
|
+
*/
|
|
8
|
+
const AlchemyWidgets = Function.inherits('Alchemy.Controller', 'AlchemyWidgets');
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Aggregate all the records to save
|
|
12
|
+
*
|
|
13
|
+
* @author Jelle De Loecker <jelle@elevenways.be>
|
|
14
|
+
* @since 0.1.5
|
|
15
|
+
* @version 0.1.5
|
|
16
|
+
*
|
|
17
|
+
* @param {Object[]} fields
|
|
18
|
+
*
|
|
19
|
+
* @return {Document[]}
|
|
20
|
+
*/
|
|
21
|
+
AlchemyWidgets.setMethod(async function aggregate(widgets) {
|
|
22
|
+
|
|
23
|
+
let result = {};
|
|
24
|
+
|
|
25
|
+
for (let widget of widgets) {
|
|
26
|
+
|
|
27
|
+
if (!widget || !widget.model || !widget.field) {
|
|
28
|
+
throw new Error('Unable to save Widget: no model or field was given');
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const model = alchemy.getModel(widget.model);
|
|
32
|
+
|
|
33
|
+
if (!model) {
|
|
34
|
+
throw new Error('Unable to save Widget: model "' + widget.model + '" not found');
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
let field = model.getField(widget.field);
|
|
38
|
+
|
|
39
|
+
if (!field) {
|
|
40
|
+
throw new Error('Unable to save Widget: field "' + widget.field + '" does not exist inside model "' + widget.model + '"');
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
let record;
|
|
44
|
+
|
|
45
|
+
if (widget.pk) {
|
|
46
|
+
|
|
47
|
+
if (result[widget.pk]) {
|
|
48
|
+
record = result[widget.pk];
|
|
49
|
+
} else {
|
|
50
|
+
record = await model.findByPk(widget.pk);
|
|
51
|
+
result[widget.pk] = record;
|
|
52
|
+
}
|
|
53
|
+
} else {
|
|
54
|
+
|
|
55
|
+
if (result[model.name]) {
|
|
56
|
+
record = result[model.name];
|
|
57
|
+
} else {
|
|
58
|
+
record = model.createDocument();
|
|
59
|
+
result[model.name] = record;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
let field_language = widget.field_languages?.[widget.field];
|
|
64
|
+
|
|
65
|
+
if (field_language) {
|
|
66
|
+
if (!record[widget.field]) {
|
|
67
|
+
record[widget.field] = {};
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
record[widget.field][field_language] = widget.value;
|
|
71
|
+
} else {
|
|
72
|
+
record[widget.field] = widget.value;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
return Object.values(result);
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* The save action
|
|
81
|
+
*
|
|
82
|
+
* @author Jelle De Loecker <jelle@elevenways.be>
|
|
83
|
+
* @since 0.1.5
|
|
84
|
+
* @version 0.1.5
|
|
85
|
+
*
|
|
86
|
+
* @param {Conduit} conduit
|
|
87
|
+
*/
|
|
88
|
+
AlchemyWidgets.setAction(async function save(conduit) {
|
|
89
|
+
|
|
90
|
+
const body = conduit.body;
|
|
91
|
+
|
|
92
|
+
if (!body || !body.widgets?.length) {
|
|
93
|
+
return conduit.error('Unable to save Widgets: no widgets were given');
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
let records = await this.aggregate(body.widgets);
|
|
97
|
+
|
|
98
|
+
let saved_pks = [];
|
|
99
|
+
|
|
100
|
+
for (let record of records) {
|
|
101
|
+
await record.save();
|
|
102
|
+
saved_pks.push(record.$pk);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
let result = {
|
|
106
|
+
saved_pks,
|
|
107
|
+
saved : true,
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
conduit.end(result);
|
|
111
|
+
});
|
|
@@ -42,9 +42,120 @@ Base.setAssignedProperty('instance');
|
|
|
42
42
|
*
|
|
43
43
|
* @author Jelle De Loecker <jelle@elevenways.be>
|
|
44
44
|
* @since 0.1.0
|
|
45
|
-
* @version 0.1.
|
|
45
|
+
* @version 0.1.4
|
|
46
46
|
*/
|
|
47
|
-
Base.setProperty(
|
|
47
|
+
Base.setProperty(function parent_container() {
|
|
48
|
+
|
|
49
|
+
let container,
|
|
50
|
+
current = this.parentElement;
|
|
51
|
+
|
|
52
|
+
while (current) {
|
|
53
|
+
if (current.is_container) {
|
|
54
|
+
container = current;
|
|
55
|
+
break;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
current = current.parentElement;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
return container;
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* The next container across container boundaries
|
|
66
|
+
*
|
|
67
|
+
* @author Jelle De Loecker <jelle@elevenways.be>
|
|
68
|
+
* @since 0.1.4
|
|
69
|
+
* @version 0.1.4
|
|
70
|
+
*/
|
|
71
|
+
Base.setProperty(function next_container() {
|
|
72
|
+
return this.getSiblingContainer('next');
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* The previous container across container boundaries
|
|
77
|
+
*
|
|
78
|
+
* @author Jelle De Loecker <jelle@elevenways.be>
|
|
79
|
+
* @since 0.1.4
|
|
80
|
+
* @version 0.1.4
|
|
81
|
+
*/
|
|
82
|
+
Base.setProperty(function previous_container() {
|
|
83
|
+
return this.getSiblingContainer('previous');
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Is this the root element?
|
|
88
|
+
*
|
|
89
|
+
* @author Jelle De Loecker <jelle@elevenways.be>
|
|
90
|
+
* @since 0.1.5
|
|
91
|
+
* @version 0.1.5
|
|
92
|
+
*/
|
|
93
|
+
Base.setProperty(function is_root_widget() {
|
|
94
|
+
return !this.parent_container;
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Can this widget be saved?
|
|
99
|
+
*
|
|
100
|
+
* @author Jelle De Loecker <jelle@elevenways.be>
|
|
101
|
+
* @since 0.1.5
|
|
102
|
+
* @version 0.1.5
|
|
103
|
+
*/
|
|
104
|
+
Base.setProperty(function can_be_saved() {
|
|
105
|
+
|
|
106
|
+
if (!this.is_root_widget) {
|
|
107
|
+
return false;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
if (!this.record || !this.field) {
|
|
111
|
+
return false;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
return true;
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Get a sibling container
|
|
119
|
+
*
|
|
120
|
+
* @author Jelle De Loecker <jelle@elevenways.be>
|
|
121
|
+
* @since 0.1.4
|
|
122
|
+
* @version 0.1.4
|
|
123
|
+
*/
|
|
124
|
+
Base.setMethod(function getSiblingContainer(type) {
|
|
125
|
+
let property;
|
|
126
|
+
|
|
127
|
+
if (type == 'next') {
|
|
128
|
+
property = 'nextElementSibling';
|
|
129
|
+
} else if (type == 'previous') {
|
|
130
|
+
property = 'previousElementSibling';
|
|
131
|
+
} else {
|
|
132
|
+
return false;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
if (!this[property] && !this.parent_container) {
|
|
136
|
+
return;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
let next = this[property];
|
|
140
|
+
|
|
141
|
+
if (next) {
|
|
142
|
+
if (next.is_container) {
|
|
143
|
+
return next;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
if (next.tagName != 'ALCHEMY-WIDGET-ADD-AREA') {
|
|
147
|
+
return false;
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
next = this.parent_container[property];
|
|
152
|
+
|
|
153
|
+
if (next && next.is_container) {
|
|
154
|
+
return next;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
return false;
|
|
158
|
+
});
|
|
48
159
|
|
|
49
160
|
/**
|
|
50
161
|
* Look for a context variable
|
|
@@ -128,5 +239,57 @@ Base.setMethod(function introduced() {
|
|
|
128
239
|
if (this.hasAttribute('editing')) {
|
|
129
240
|
this.startEditor();
|
|
130
241
|
}
|
|
242
|
+
});
|
|
243
|
+
|
|
244
|
+
/**
|
|
245
|
+
* Get the configuration used to save data
|
|
246
|
+
*
|
|
247
|
+
* @author Jelle De Loecker <jelle@elevenways.be>
|
|
248
|
+
* @since 0.1.5
|
|
249
|
+
* @version 0.1.5
|
|
250
|
+
*/
|
|
251
|
+
Base.setMethod(function gatherSaveData() {
|
|
252
|
+
|
|
253
|
+
if (!this.is_root_widget) {
|
|
254
|
+
return;
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
if (!this.record || !this.field) {
|
|
258
|
+
return;
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
let result = {
|
|
262
|
+
model : this.record.$model_name,
|
|
263
|
+
pk : this.record.$pk,
|
|
264
|
+
field : this.field,
|
|
265
|
+
value : this.value,
|
|
266
|
+
field_languages : this.record.$hold.translated_fields,
|
|
267
|
+
};
|
|
268
|
+
|
|
269
|
+
return result;
|
|
270
|
+
});
|
|
271
|
+
|
|
272
|
+
/**
|
|
273
|
+
* Save the current configuration
|
|
274
|
+
*
|
|
275
|
+
* @author Jelle De Loecker <jelle@elevenways.be>
|
|
276
|
+
* @since 0.1.5
|
|
277
|
+
* @version 0.1.5
|
|
278
|
+
*/
|
|
279
|
+
Base.setMethod(async function save() {
|
|
280
|
+
|
|
281
|
+
let data = this.gatherSaveData();
|
|
282
|
+
|
|
283
|
+
if (!data) {
|
|
284
|
+
return;
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
let config = {
|
|
288
|
+
href : alchemy.routeUrl('AlchemyWidgets#save'),
|
|
289
|
+
post : {
|
|
290
|
+
widgets: [data]
|
|
291
|
+
}
|
|
292
|
+
};
|
|
131
293
|
|
|
294
|
+
let result = await alchemy.fetch(config);
|
|
132
295
|
});
|
|
@@ -34,6 +34,24 @@ Widget.setAttribute('type');
|
|
|
34
34
|
*/
|
|
35
35
|
Widget.setProperty('is_alchemy_widget', true);
|
|
36
36
|
|
|
37
|
+
/**
|
|
38
|
+
* The database record to work with
|
|
39
|
+
*
|
|
40
|
+
* @author Jelle De Loecker <jelle@elevenways.be>
|
|
41
|
+
* @since 0.1.5
|
|
42
|
+
* @version 0.1.5
|
|
43
|
+
*/
|
|
44
|
+
Widget.setAssignedProperty('record');
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* The fieldname in the record to work with
|
|
48
|
+
*
|
|
49
|
+
* @author Jelle De Loecker <jelle@elevenways.be>
|
|
50
|
+
* @since 0.1.5
|
|
51
|
+
* @version 0.1.5
|
|
52
|
+
*/
|
|
53
|
+
Widget.setAssignedProperty('field');
|
|
54
|
+
|
|
37
55
|
/**
|
|
38
56
|
* Is this widget being edited?
|
|
39
57
|
*
|
|
@@ -55,7 +73,7 @@ Widget.setProperty(function editing() {
|
|
|
55
73
|
*
|
|
56
74
|
* @author Jelle De Loecker <jelle@elevenways.be>
|
|
57
75
|
* @since 0.1.0
|
|
58
|
-
* @version 0.1.
|
|
76
|
+
* @version 0.1.5
|
|
59
77
|
*/
|
|
60
78
|
Widget.setProperty(function value() {
|
|
61
79
|
return {
|
|
@@ -63,6 +81,45 @@ Widget.setProperty(function value() {
|
|
|
63
81
|
config : this.instance.syncConfig(),
|
|
64
82
|
}
|
|
65
83
|
}, function setValue(value) {
|
|
84
|
+
this.applyValue(value);
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Received a new record
|
|
89
|
+
*
|
|
90
|
+
* @author Jelle De Loecker <jelle@elevenways.be>
|
|
91
|
+
* @since 0.1.5
|
|
92
|
+
* @version 0.1.5
|
|
93
|
+
*/
|
|
94
|
+
Widget.setMethod(function onRecordAssignment(new_record, old_val) {
|
|
95
|
+
if (new_record && this.field) {
|
|
96
|
+
let value = new_record[this.field];
|
|
97
|
+
this.applyValue(value);
|
|
98
|
+
}
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Received a new field name
|
|
103
|
+
*
|
|
104
|
+
* @author Jelle De Loecker <jelle@elevenways.be>
|
|
105
|
+
* @since 0.1.5
|
|
106
|
+
* @version 0.1.5
|
|
107
|
+
*/
|
|
108
|
+
Widget.setMethod(function onFieldAssignment(new_field, old_val) {
|
|
109
|
+
if (new_field && this.record) {
|
|
110
|
+
let value = this.record[new_field];
|
|
111
|
+
this.applyValue(value);
|
|
112
|
+
}
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Apply the given value
|
|
117
|
+
*
|
|
118
|
+
* @author Jelle De Loecker <jelle@elevenways.be>
|
|
119
|
+
* @since 0.1.5
|
|
120
|
+
* @version 0.1.5
|
|
121
|
+
*/
|
|
122
|
+
Widget.setMethod(function applyValue(value) {
|
|
66
123
|
|
|
67
124
|
let config,
|
|
68
125
|
type;
|
|
@@ -136,7 +193,7 @@ Widget.setMethod(function startEditor() {
|
|
|
136
193
|
*
|
|
137
194
|
* @author Jelle De Loecker <jelle@elevenways.be>
|
|
138
195
|
* @since 0.1.0
|
|
139
|
-
* @version 0.1.
|
|
196
|
+
* @version 0.1.5
|
|
140
197
|
*/
|
|
141
198
|
Widget.setMethod(function stopEditor() {
|
|
142
199
|
|
|
@@ -144,6 +201,7 @@ Widget.setMethod(function stopEditor() {
|
|
|
144
201
|
throw new Error('Unable to stop the editor: this widget element has no accompanying instance');
|
|
145
202
|
}
|
|
146
203
|
|
|
204
|
+
this.unselectWidget();
|
|
147
205
|
this.instance.stopEditor();
|
|
148
206
|
this.removeEditEventListeners();
|
|
149
207
|
});
|
|
@@ -32,6 +32,15 @@ AlchemyWidgets.setStatic('custom_element_prefix', 'alchemy-widgets');
|
|
|
32
32
|
*/
|
|
33
33
|
AlchemyWidgets.setProperty('add_edit_event_listeners', false);
|
|
34
34
|
|
|
35
|
+
/**
|
|
36
|
+
* Indicate this is a container
|
|
37
|
+
*
|
|
38
|
+
* @author Jelle De Loecker <jelle@elevenways.be>
|
|
39
|
+
* @since 0.1.4
|
|
40
|
+
* @version 0.1.4
|
|
41
|
+
*/
|
|
42
|
+
AlchemyWidgets.setProperty('is_container', true);
|
|
43
|
+
|
|
35
44
|
/**
|
|
36
45
|
* Context variables
|
|
37
46
|
*
|
|
@@ -74,6 +83,17 @@ AlchemyWidgets.setProperty(function value() {
|
|
|
74
83
|
return result;
|
|
75
84
|
|
|
76
85
|
}, function setValue(value) {
|
|
86
|
+
this.applyValue(value);
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Apply the given value
|
|
91
|
+
*
|
|
92
|
+
* @author Jelle De Loecker <jelle@elevenways.be>
|
|
93
|
+
* @since 0.1.5
|
|
94
|
+
* @version 0.1.5
|
|
95
|
+
*/
|
|
96
|
+
AlchemyWidgets.setMethod(function applyValue(value) {
|
|
77
97
|
|
|
78
98
|
let widgets,
|
|
79
99
|
config;
|
|
@@ -179,15 +199,26 @@ AlchemyWidgets.setMethod(function clear() {
|
|
|
179
199
|
*
|
|
180
200
|
* @author Jelle De Loecker <jelle@elevenways.be>
|
|
181
201
|
* @since 0.1.0
|
|
182
|
-
* @version 0.1.
|
|
202
|
+
* @version 0.1.3
|
|
183
203
|
*
|
|
184
204
|
* @param {String} type
|
|
185
205
|
* @param {Object} config
|
|
186
206
|
*/
|
|
187
207
|
AlchemyWidgets.setMethod(function addWidget(type, config) {
|
|
188
208
|
|
|
209
|
+
let instance;
|
|
210
|
+
|
|
189
211
|
// Create the instance of the widget
|
|
190
|
-
|
|
212
|
+
try {
|
|
213
|
+
instance = this.instance.createChildWidget(type, config);
|
|
214
|
+
} catch (err) {
|
|
215
|
+
config = {
|
|
216
|
+
original_config : config,
|
|
217
|
+
html : '<pre>' + err.message + '\n' + err.stack + '</pre>',
|
|
218
|
+
};
|
|
219
|
+
|
|
220
|
+
instance = this.instance.createChildWidget('html', config);
|
|
221
|
+
}
|
|
191
222
|
|
|
192
223
|
// Attach the renderer
|
|
193
224
|
instance.hawkejs_renderer = this.hawkejs_renderer;
|
|
@@ -195,9 +226,6 @@ AlchemyWidgets.setMethod(function addWidget(type, config) {
|
|
|
195
226
|
// Get the actual widget HTML element
|
|
196
227
|
let element = instance.element;
|
|
197
228
|
|
|
198
|
-
// Make the element know what its parent container is
|
|
199
|
-
element.parent_container = this;
|
|
200
|
-
|
|
201
229
|
this._appendWidgetElement(element);
|
|
202
230
|
|
|
203
231
|
element.value = config;
|
|
@@ -26,11 +26,9 @@ let AddArea = Function.inherits('Alchemy.Element.Widget.Base', function AlchemyW
|
|
|
26
26
|
* @since 0.1.0
|
|
27
27
|
* @version 0.1.0
|
|
28
28
|
*/
|
|
29
|
-
AddArea.setMethod(function showTypes() {
|
|
29
|
+
AddArea.setMethod(function showTypes(event) {
|
|
30
30
|
|
|
31
|
-
let that = this
|
|
32
|
-
types_element = this.querySelector('.widget-types'),
|
|
33
|
-
widgets = alchemy.getClassGroup('widgets');
|
|
31
|
+
let that = this;
|
|
34
32
|
|
|
35
33
|
let context_button = document.querySelector('alchemy-widget-context');
|
|
36
34
|
|
|
@@ -38,31 +36,25 @@ AddArea.setMethod(function showTypes() {
|
|
|
38
36
|
context_button.unselectedWidget();
|
|
39
37
|
}
|
|
40
38
|
|
|
41
|
-
this.
|
|
39
|
+
let context = this.createElement('he-context-menu');
|
|
42
40
|
|
|
43
|
-
|
|
41
|
+
let widgets = Object.values(alchemy.getClassGroup('widgets')).sortByPath(1, 'title');
|
|
44
42
|
|
|
45
|
-
for (let
|
|
43
|
+
for (let widget of widgets) {
|
|
46
44
|
|
|
47
|
-
if (
|
|
45
|
+
if (widget.type_name == 'container') {
|
|
48
46
|
continue;
|
|
49
47
|
}
|
|
50
48
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
button.addEventListener('click', function onClick(e) {
|
|
58
|
-
e.preventDefault();
|
|
59
|
-
that.classList.remove('show-types');
|
|
60
|
-
|
|
61
|
-
that.parentElement.addWidget(key);
|
|
49
|
+
context.addEntry({
|
|
50
|
+
title : widget.title,
|
|
51
|
+
icon : null,
|
|
52
|
+
}, e => {
|
|
53
|
+
that.parentElement.addWidget(widget.type_name);
|
|
62
54
|
});
|
|
63
|
-
|
|
64
|
-
types_element.append(button);
|
|
65
55
|
}
|
|
56
|
+
|
|
57
|
+
context.show(event);
|
|
66
58
|
});
|
|
67
59
|
|
|
68
60
|
/**
|
|
@@ -107,7 +99,7 @@ AddArea.setMethod(function introduced() {
|
|
|
107
99
|
|
|
108
100
|
add_button.addEventListener('click', function onClick(e) {
|
|
109
101
|
e.preventDefault();
|
|
110
|
-
that.showTypes();
|
|
102
|
+
that.showTypes(e);
|
|
111
103
|
});
|
|
112
104
|
|
|
113
105
|
let context_button = this.querySelector('.menu-button');
|
|
@@ -1,193 +1,193 @@
|
|
|
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 content
|
|
21
|
-
*
|
|
22
|
-
* @author Jelle De Loecker <jelle@elevenways.be>
|
|
23
|
-
* @since 0.1.2
|
|
24
|
-
* @version 0.1.2
|
|
25
|
-
*/
|
|
26
|
-
TableOfContents.setAssignedProperty('content');
|
|
27
|
-
|
|
28
|
-
/**
|
|
29
|
-
* The role of this element
|
|
30
|
-
*
|
|
31
|
-
* @author Jelle De Loecker <jelle@elevenways.be>
|
|
32
|
-
* @since 0.1.2
|
|
33
|
-
* @version 0.1.2
|
|
34
|
-
*/
|
|
35
|
-
TableOfContents.setRole('navigation');
|
|
36
|
-
|
|
37
|
-
/**
|
|
38
|
-
* The parent query
|
|
39
|
-
*
|
|
40
|
-
* @author Jelle De Loecker <jelle@elevenways.be>
|
|
41
|
-
* @since 0.1.2
|
|
42
|
-
* @version 0.1.2
|
|
43
|
-
*/
|
|
44
|
-
TableOfContents.setAttribute('parent-selector');
|
|
45
|
-
|
|
46
|
-
/**
|
|
47
|
-
* The children query
|
|
48
|
-
*
|
|
49
|
-
* @author Jelle De Loecker <jelle@elevenways.be>
|
|
50
|
-
* @since 0.1.2
|
|
51
|
-
* @version 0.1.2
|
|
52
|
-
*/
|
|
53
|
-
TableOfContents.setAttribute('children-selector');
|
|
54
|
-
|
|
55
|
-
/**
|
|
56
|
-
* The elements query
|
|
57
|
-
*
|
|
58
|
-
* @author Jelle De Loecker <jelle@elevenways.be>
|
|
59
|
-
* @since 0.1.2
|
|
60
|
-
* @version 0.1.2
|
|
61
|
-
*/
|
|
62
|
-
TableOfContents.setAttribute('elements-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('title-selector');
|
|
72
|
-
|
|
73
|
-
/**
|
|
74
|
-
* The class to add when intersecting (visible)
|
|
75
|
-
*
|
|
76
|
-
* @author Jelle De Loecker <jelle@elevenways.be>
|
|
77
|
-
* @since 0.1.2
|
|
78
|
-
* @version 0.1.2
|
|
79
|
-
*/
|
|
80
|
-
TableOfContents.setAttribute('intersection-class');
|
|
81
|
-
|
|
82
|
-
/**
|
|
83
|
-
* Get the entries
|
|
84
|
-
*
|
|
85
|
-
* @author Jelle De Loecker <jelle@elevenways.be>
|
|
86
|
-
* @since 0.1.2
|
|
87
|
-
* @version 0.1.2
|
|
88
|
-
*/
|
|
89
|
-
TableOfContents.setProperty(function entries() {
|
|
90
|
-
|
|
91
|
-
let result = [],
|
|
92
|
-
parent = this.parentElement,
|
|
93
|
-
wrapper;
|
|
94
|
-
|
|
95
|
-
if (this.parent_selector) {
|
|
96
|
-
parent = this.queryParents(this.parent_selector);
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
if (parent) {
|
|
100
|
-
wrapper = parent;
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
if (wrapper && this.children_selector) {
|
|
104
|
-
wrapper = wrapper.querySelector(this.children_selector);
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
if (wrapper) {
|
|
108
|
-
let elements = wrapper.querySelectorAll(this.elements_selector || 'h1,h2'),
|
|
109
|
-
element,
|
|
110
|
-
title,
|
|
111
|
-
i;
|
|
112
|
-
|
|
113
|
-
for (i = 0; i < elements.length; i++) {
|
|
114
|
-
element = elements[i];
|
|
115
|
-
|
|
116
|
-
if (!element.id) {
|
|
117
|
-
|
|
118
|
-
if (element.hawkejs_id) {
|
|
119
|
-
element.id = element.hawkejs_id;
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
if (!element.id) {
|
|
123
|
-
continue;
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
let title_element;
|
|
128
|
-
|
|
129
|
-
if (this.title_selector) {
|
|
130
|
-
title_element = element.querySelector(this.title_selector);
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
if (!title_element) {
|
|
134
|
-
title_element = element;
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
title = (title_element.toc_title || title_element.textContent || '').trim();
|
|
138
|
-
|
|
139
|
-
title = title.truncate(30);
|
|
140
|
-
|
|
141
|
-
// Don't add empty titles
|
|
142
|
-
if (!title) {
|
|
143
|
-
continue;
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
result.push({
|
|
147
|
-
id : element.id,
|
|
148
|
-
title : title,
|
|
149
|
-
element : element,
|
|
150
|
-
});
|
|
151
|
-
}
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
return result;
|
|
155
|
-
});
|
|
156
|
-
|
|
157
|
-
/**
|
|
158
|
-
* Added to the dom for the first time
|
|
159
|
-
*
|
|
160
|
-
* @author Jelle De Loecker <jelle@elevenways.be>
|
|
161
|
-
* @since 0.1.2
|
|
162
|
-
* @version 0.1.2
|
|
163
|
-
*/
|
|
164
|
-
TableOfContents.setMethod(async function introduced() {
|
|
165
|
-
|
|
166
|
-
await this.rerender();
|
|
167
|
-
|
|
168
|
-
const observer = new IntersectionObserver(entries => {
|
|
169
|
-
|
|
170
|
-
let class_name = this.intersection_class || 'visible';
|
|
171
|
-
|
|
172
|
-
for (let entry of entries) {
|
|
173
|
-
const id = entry.target.getAttribute('id');
|
|
174
|
-
|
|
175
|
-
let query = `a[href="#${id}"]`,
|
|
176
|
-
element = this.querySelector(query);
|
|
177
|
-
|
|
178
|
-
if (!element) {
|
|
179
|
-
return;
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
if (entry.intersectionRatio > 0) {
|
|
183
|
-
element.classList.add(class_name);
|
|
184
|
-
} else {
|
|
185
|
-
element.classList.remove(class_name);
|
|
186
|
-
}
|
|
187
|
-
};
|
|
188
|
-
});
|
|
189
|
-
|
|
190
|
-
for (let entry of this.entries) {
|
|
191
|
-
observer.observe(entry.element);
|
|
192
|
-
}
|
|
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 content
|
|
21
|
+
*
|
|
22
|
+
* @author Jelle De Loecker <jelle@elevenways.be>
|
|
23
|
+
* @since 0.1.2
|
|
24
|
+
* @version 0.1.2
|
|
25
|
+
*/
|
|
26
|
+
TableOfContents.setAssignedProperty('content');
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* The role of this element
|
|
30
|
+
*
|
|
31
|
+
* @author Jelle De Loecker <jelle@elevenways.be>
|
|
32
|
+
* @since 0.1.2
|
|
33
|
+
* @version 0.1.2
|
|
34
|
+
*/
|
|
35
|
+
TableOfContents.setRole('navigation');
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* The parent query
|
|
39
|
+
*
|
|
40
|
+
* @author Jelle De Loecker <jelle@elevenways.be>
|
|
41
|
+
* @since 0.1.2
|
|
42
|
+
* @version 0.1.2
|
|
43
|
+
*/
|
|
44
|
+
TableOfContents.setAttribute('parent-selector');
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* The children query
|
|
48
|
+
*
|
|
49
|
+
* @author Jelle De Loecker <jelle@elevenways.be>
|
|
50
|
+
* @since 0.1.2
|
|
51
|
+
* @version 0.1.2
|
|
52
|
+
*/
|
|
53
|
+
TableOfContents.setAttribute('children-selector');
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* The elements query
|
|
57
|
+
*
|
|
58
|
+
* @author Jelle De Loecker <jelle@elevenways.be>
|
|
59
|
+
* @since 0.1.2
|
|
60
|
+
* @version 0.1.2
|
|
61
|
+
*/
|
|
62
|
+
TableOfContents.setAttribute('elements-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('title-selector');
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* The class to add when intersecting (visible)
|
|
75
|
+
*
|
|
76
|
+
* @author Jelle De Loecker <jelle@elevenways.be>
|
|
77
|
+
* @since 0.1.2
|
|
78
|
+
* @version 0.1.2
|
|
79
|
+
*/
|
|
80
|
+
TableOfContents.setAttribute('intersection-class');
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Get the entries
|
|
84
|
+
*
|
|
85
|
+
* @author Jelle De Loecker <jelle@elevenways.be>
|
|
86
|
+
* @since 0.1.2
|
|
87
|
+
* @version 0.1.2
|
|
88
|
+
*/
|
|
89
|
+
TableOfContents.setProperty(function entries() {
|
|
90
|
+
|
|
91
|
+
let result = [],
|
|
92
|
+
parent = this.parentElement,
|
|
93
|
+
wrapper;
|
|
94
|
+
|
|
95
|
+
if (this.parent_selector) {
|
|
96
|
+
parent = this.queryParents(this.parent_selector);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
if (parent) {
|
|
100
|
+
wrapper = parent;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
if (wrapper && this.children_selector) {
|
|
104
|
+
wrapper = wrapper.querySelector(this.children_selector);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
if (wrapper) {
|
|
108
|
+
let elements = wrapper.querySelectorAll(this.elements_selector || 'h1,h2'),
|
|
109
|
+
element,
|
|
110
|
+
title,
|
|
111
|
+
i;
|
|
112
|
+
|
|
113
|
+
for (i = 0; i < elements.length; i++) {
|
|
114
|
+
element = elements[i];
|
|
115
|
+
|
|
116
|
+
if (!element.id) {
|
|
117
|
+
|
|
118
|
+
if (element.hawkejs_id) {
|
|
119
|
+
element.id = element.hawkejs_id;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
if (!element.id) {
|
|
123
|
+
continue;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
let title_element;
|
|
128
|
+
|
|
129
|
+
if (this.title_selector) {
|
|
130
|
+
title_element = element.querySelector(this.title_selector);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
if (!title_element) {
|
|
134
|
+
title_element = element;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
title = (title_element.toc_title || title_element.textContent || '').trim();
|
|
138
|
+
|
|
139
|
+
title = title.truncate(30);
|
|
140
|
+
|
|
141
|
+
// Don't add empty titles
|
|
142
|
+
if (!title) {
|
|
143
|
+
continue;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
result.push({
|
|
147
|
+
id : element.id,
|
|
148
|
+
title : title,
|
|
149
|
+
element : element,
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
return result;
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* Added to the dom for the first time
|
|
159
|
+
*
|
|
160
|
+
* @author Jelle De Loecker <jelle@elevenways.be>
|
|
161
|
+
* @since 0.1.2
|
|
162
|
+
* @version 0.1.2
|
|
163
|
+
*/
|
|
164
|
+
TableOfContents.setMethod(async function introduced() {
|
|
165
|
+
|
|
166
|
+
await this.rerender();
|
|
167
|
+
|
|
168
|
+
const observer = new IntersectionObserver(entries => {
|
|
169
|
+
|
|
170
|
+
let class_name = this.intersection_class || 'visible';
|
|
171
|
+
|
|
172
|
+
for (let entry of entries) {
|
|
173
|
+
const id = entry.target.getAttribute('id');
|
|
174
|
+
|
|
175
|
+
let query = `a[href="#${id}"]`,
|
|
176
|
+
element = this.querySelector(query);
|
|
177
|
+
|
|
178
|
+
if (!element) {
|
|
179
|
+
return;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
if (entry.intersectionRatio > 0) {
|
|
183
|
+
element.classList.add(class_name);
|
|
184
|
+
} else {
|
|
185
|
+
element.classList.remove(class_name);
|
|
186
|
+
}
|
|
187
|
+
};
|
|
188
|
+
});
|
|
189
|
+
|
|
190
|
+
for (let entry of this.entries) {
|
|
191
|
+
observer.observe(entry.element);
|
|
192
|
+
}
|
|
193
193
|
});
|
|
@@ -95,7 +95,7 @@ Widget.enforceProperty(function hawkejs_renderer(new_value) {
|
|
|
95
95
|
*
|
|
96
96
|
* @author Jelle De Loecker <jelle@elevenways.be>
|
|
97
97
|
* @since 0.1.0
|
|
98
|
-
* @version 0.1.
|
|
98
|
+
* @version 0.1.5
|
|
99
99
|
*/
|
|
100
100
|
Widget.constitute(function prepareSchema() {
|
|
101
101
|
|
|
@@ -107,15 +107,30 @@ Widget.constitute(function prepareSchema() {
|
|
|
107
107
|
|
|
108
108
|
// Extra classnames for the wrapper
|
|
109
109
|
this.schema.addField('wrapper_class_names', 'String', {
|
|
110
|
+
title : 'Wrapper CSS classes',
|
|
111
|
+
description : 'Configure extra CSS classes to the wrapper `alchemy-widget` element',
|
|
110
112
|
array: true,
|
|
111
113
|
widget_config_editable: true,
|
|
112
114
|
});
|
|
113
115
|
|
|
114
116
|
// Classnames for the inserted element (if any)
|
|
115
117
|
this.schema.addField('main_class_names', 'String', {
|
|
118
|
+
title : 'Main CSS classes',
|
|
119
|
+
description : 'Configure extra CSS classes for the main inserted element',
|
|
116
120
|
array: true,
|
|
117
121
|
});
|
|
118
122
|
|
|
123
|
+
// Add the "save" action
|
|
124
|
+
let save = this.createAction('save', 'Save');
|
|
125
|
+
|
|
126
|
+
save.setHandler(function removeAction(widget_el, handle) {
|
|
127
|
+
return widget_el.save();
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
save.setTester(function saveAction(widget_el, handle) {
|
|
131
|
+
return widget_el.can_be_saved;
|
|
132
|
+
});
|
|
133
|
+
|
|
119
134
|
// Add the remove action
|
|
120
135
|
let remove = this.createAction('remove', 'Remove');
|
|
121
136
|
|
|
@@ -179,6 +194,47 @@ Widget.constitute(function prepareSchema() {
|
|
|
179
194
|
|
|
180
195
|
move_right.setIcon('gg-arrow-right');
|
|
181
196
|
|
|
197
|
+
// The move-in-left action
|
|
198
|
+
let move_in_left = this.createAction('move-in-left', 'Move in left');
|
|
199
|
+
|
|
200
|
+
move_in_left.close_toolbar = true;
|
|
201
|
+
|
|
202
|
+
move_in_left.setHandler(function moveLeftAction(widget_el, handle) {
|
|
203
|
+
// Hawkejs custom element method!
|
|
204
|
+
let container = handle.previous_container;
|
|
205
|
+
|
|
206
|
+
if (container) {
|
|
207
|
+
container.append(handle);
|
|
208
|
+
}
|
|
209
|
+
});
|
|
210
|
+
|
|
211
|
+
move_in_left.setTester(function moveLeftTest(widget_el, handle) {
|
|
212
|
+
return !!handle.previous_container;
|
|
213
|
+
});
|
|
214
|
+
|
|
215
|
+
move_in_left.setIcon('gg-arrow-left');
|
|
216
|
+
|
|
217
|
+
// The move-in-right action
|
|
218
|
+
let move_in_right = this.createAction('move-in-right', 'Move in right');
|
|
219
|
+
|
|
220
|
+
move_in_right.close_toolbar = true;
|
|
221
|
+
|
|
222
|
+
move_in_right.setHandler(function moveRightAction(widget_el, handle) {
|
|
223
|
+
// Hawkejs custom element method!
|
|
224
|
+
let container = handle.next_container;
|
|
225
|
+
|
|
226
|
+
if (container) {
|
|
227
|
+
container.prepend(handle);
|
|
228
|
+
}
|
|
229
|
+
});
|
|
230
|
+
|
|
231
|
+
move_in_right.setTester(function moveRightTest(widget_el, handle) {
|
|
232
|
+
console.log('Right test of:', handle)
|
|
233
|
+
return !!handle.next_container;
|
|
234
|
+
});
|
|
235
|
+
|
|
236
|
+
move_in_right.setIcon('gg-arrow-right');
|
|
237
|
+
|
|
182
238
|
let css_class = this.createAction('css-class', 'CSS Class');
|
|
183
239
|
|
|
184
240
|
css_class.setHandler(function setCssClass(widget_el, handle) {
|
|
@@ -212,11 +268,11 @@ Widget.setStatic(function createSchema() {
|
|
|
212
268
|
*
|
|
213
269
|
* @author Jelle De Loecker <jelle@elevenways.be>
|
|
214
270
|
* @since 0.1.0
|
|
215
|
-
* @version 0.1.
|
|
271
|
+
* @version 0.1.4
|
|
216
272
|
*/
|
|
217
|
-
Widget.setStatic(function createAction(name) {
|
|
273
|
+
Widget.setStatic(function createAction(name, title) {
|
|
218
274
|
|
|
219
|
-
let action = new Classes.Alchemy.Widget.Action(name);
|
|
275
|
+
let action = new Classes.Alchemy.Widget.Action(name, title || name.titleize());
|
|
220
276
|
|
|
221
277
|
this.actions.set(name, action);
|
|
222
278
|
|