alchemy-widget 0.1.4 → 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 CHANGED
@@ -1,3 +1,8 @@
1
+ ## 0.1.5 (2022-07-14)
2
+
3
+ * Unselect widgets when stopping the editor
4
+ * Add front-end save ability to widgets
5
+
1
6
  ## 0.1.4 (2022-06-23)
2
7
 
3
8
  * Use `he-context-menu` element to show widgets to add
package/bootstrap.js ADDED
@@ -0,0 +1,6 @@
1
+ Router.add({
2
+ name : 'AlchemyWidgets#save',
3
+ methods : 'post',
4
+ paths : '/api/alchemywidgets/save',
5
+ policy : 'logged_in',
6
+ });
@@ -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
+ });
@@ -83,6 +83,37 @@ Base.setProperty(function previous_container() {
83
83
  return this.getSiblingContainer('previous');
84
84
  });
85
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
+
86
117
  /**
87
118
  * Get a sibling container
88
119
  *
@@ -208,5 +239,57 @@ Base.setMethod(function introduced() {
208
239
  if (this.hasAttribute('editing')) {
209
240
  this.startEditor();
210
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
+ };
211
293
 
294
+ let result = await alchemy.fetch(config);
212
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.0
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.0
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
  });
@@ -83,6 +83,17 @@ AlchemyWidgets.setProperty(function value() {
83
83
  return result;
84
84
 
85
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) {
86
97
 
87
98
  let widgets,
88
99
  config;
@@ -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.0
98
+ * @version 0.1.5
99
99
  */
100
100
  Widget.constitute(function prepareSchema() {
101
101
 
@@ -120,6 +120,17 @@ Widget.constitute(function prepareSchema() {
120
120
  array: true,
121
121
  });
122
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
+
123
134
  // Add the remove action
124
135
  let remove = this.createAction('remove', 'Remove');
125
136
 
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "alchemy-widget",
3
3
  "description": "The widget plugin for the AlchemyMVC",
4
- "version": "0.1.4",
4
+ "version": "0.1.5",
5
5
  "author": "Jelle De Loecker <jelle@elevenways.be>",
6
6
  "keywords": [
7
7
  "alchemy",