alchemy-widget 0.2.6 → 0.2.8

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 (50) hide show
  1. package/CHANGELOG.md +10 -0
  2. package/README.md +0 -0
  3. package/assets/stylesheets/alchemy_widgets.scss +72 -0
  4. package/bootstrap.js +0 -0
  5. package/controller/alchemy_widgets_controller.js +0 -0
  6. package/element/00-widget_base_element.js +0 -0
  7. package/element/05-widget_element.js +0 -0
  8. package/element/10-container_elements.js +0 -0
  9. package/element/11-alchemy_widgets_list_element.js +0 -0
  10. package/element/20-add_area_element.js +0 -0
  11. package/element/30-base_toolbar_element.js +231 -0
  12. package/element/editor_toolbar_element.js +30 -0
  13. package/element/table_of_contents_element.js +0 -0
  14. package/element/user_avatar_element.js +137 -0
  15. package/element/user_avatar_group_element.js +131 -0
  16. package/element/widget_actionbar_element.js +0 -0
  17. package/element/widget_context_element.js +0 -0
  18. package/element/widget_toolbar_element.js +40 -20
  19. package/helper/document_watcher.js +284 -0
  20. package/helper/editor_toolbar_manager.js +296 -0
  21. package/helper/widget_action.js +0 -0
  22. package/helper/widgets/00-widget.js +3 -3
  23. package/helper/widgets/01-container.js +0 -0
  24. package/helper/widgets/05-column.js +0 -0
  25. package/helper/widgets/05-list.js +0 -0
  26. package/helper/widgets/05-row.js +0 -0
  27. package/helper/widgets/alchemy_field_widget.js +0 -0
  28. package/helper/widgets/alchemy_form_widget.js +0 -0
  29. package/helper/widgets/alchemy_table_widget.js +0 -0
  30. package/helper/widgets/alchemy_tabs_widget.js +0 -0
  31. package/helper/widgets/hawkejs_template.js +0 -0
  32. package/helper/widgets/header.js +0 -0
  33. package/helper/widgets/html.js +0 -0
  34. package/helper/widgets/markdown.js +65 -11
  35. package/helper/widgets/partial.js +0 -0
  36. package/helper/widgets/sourcecode.js +0 -0
  37. package/helper/widgets/table_of_contents.js +0 -0
  38. package/helper/widgets/text.js +0 -0
  39. package/helper/widgets_helper.js +0 -0
  40. package/helper_field/widget.js +0 -0
  41. package/helper_field/widgets.js +0 -0
  42. package/lib/conduit_extras.js +65 -0
  43. package/package.json +3 -3
  44. package/view/elements/table_of_contents.hwk +0 -0
  45. package/view/form/inputs/edit/widget.hwk +0 -0
  46. package/view/form/inputs/edit/widgets.hwk +0 -0
  47. package/view/widget/elements/al_editor_toolbar.hwk +3 -0
  48. package/view/widget/elements/al_user_avatar.hwk +5 -0
  49. package/view/widget/elements/al_widget_toolbar.hwk +7 -1
  50. package/view/widget/widget_config.hwk +0 -0
package/CHANGELOG.md CHANGED
@@ -1,3 +1,13 @@
1
+ ## 0.2.8 (2023-06-17)
2
+
3
+ * Make the widget toolbar render area contents correctly + load scripts & styles
4
+
5
+ ## 0.2.7 (2023-04-20)
6
+
7
+ * Use `Element#hideForEveryone()` when hiding widgets
8
+ * Add the `al-editor-toolbar` and accompanying elements
9
+ * Use the `al-code-input` element again for editing markdown widgets
10
+
1
11
  ## 0.2.6 (2023-02-26)
2
12
 
3
13
  * Replace *EasyMDE* markdown editor with *Toast editor*
package/README.md CHANGED
File without changes
@@ -97,6 +97,36 @@ al-widget-toolbar {
97
97
  background-color: rgb(53, 53, 53);
98
98
  }
99
99
  }
100
+
101
+ .watchers:empty {
102
+ display: none;
103
+ }
104
+
105
+ .watchers {
106
+ margin: 0 4rem;
107
+ }
108
+
109
+ al-user-avatar {
110
+ .bubble-representation {
111
+ width: 4.5rem;
112
+ height: 4.5rem;
113
+ font-size: 3.5rem;
114
+ line-height: 4.5rem;
115
+ }
116
+ }
117
+
118
+ [data-area="buttons"] {
119
+ display: flex;
120
+ gap: 1rem;
121
+
122
+ a {
123
+ text-decoration: none;
124
+
125
+ micro-copy {
126
+ text-decoration: underline;
127
+ }
128
+ }
129
+ }
100
130
  }
101
131
 
102
132
  al-widgets,
@@ -444,4 +474,46 @@ al-widget[type="markdown"] {
444
474
  .toastui-editor-toolbar .toastui-editor-md-tab-container .toastui-editor-tabs {
445
475
  display: none;
446
476
  }
477
+ }
478
+
479
+ al-user-avatar-group {
480
+ display: flex;
481
+
482
+ // Let all the al-user-avatar elements overlap a little.
483
+ > * {
484
+ position: relative;
485
+ z-index: 10;
486
+ margin-left: -0.5rem;
487
+ }
488
+
489
+ // The first element should not be overlapped
490
+ > :first-child {
491
+ margin-left: 0;
492
+ }
493
+
494
+ > *:hover {
495
+ z-index: 101;
496
+ }
497
+ }
498
+
499
+ al-user-avatar {
500
+ display: block;
501
+ cursor: default;
502
+ user-select: none;
503
+
504
+ .bubble-representation {
505
+ display: block;
506
+ width: 2rem;
507
+ height: 2rem;
508
+ border-radius: 50%;
509
+ background-color: var(--avatar-bg-color, #388ae5);
510
+ color: white;
511
+ font-size: 1.2rem;
512
+ font-weight: bold;
513
+ text-align: center;
514
+ line-height: 2rem;
515
+
516
+ // Add a shadow
517
+ box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.1), 0 1px 2px rgba(0, 0, 0, 0.2);
518
+ }
447
519
  }
package/bootstrap.js CHANGED
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
@@ -0,0 +1,231 @@
1
+ const PREPARED = Symbol('prepared');
2
+
3
+ /**
4
+ * The base toolbar element
5
+ *
6
+ * @author Jelle De Loecker <jelle@elevenways.be>
7
+ * @since 0.2.7
8
+ * @version 0.2.7
9
+ */
10
+ let Toolbar = Function.inherits('Alchemy.Element.Form.Stateful', 'Alchemy.Element.Widget', 'BaseToolbar');
11
+
12
+ /**
13
+ * Don't register this as a custom element
14
+ * The `false` argument makes sure child classes don't also set this property
15
+ *
16
+ * @author Jelle De Loecker <jelle@elevenways.be>
17
+ * @since 0.2.7
18
+ * @version 0.2.7
19
+ */
20
+ Toolbar.makeAbstractClass();
21
+
22
+ /**
23
+ * Set the custom element prefix
24
+ *
25
+ * @author Jelle De Loecker <jelle@elevenways.be>
26
+ * @since 0.2.7
27
+ * @version 0.2.7
28
+ */
29
+ Toolbar.setStatic('custom_element_prefix', 'al');
30
+
31
+ /**
32
+ * The stylesheet to load for this element
33
+ *
34
+ * @author Jelle De Loecker <jelle@elevenways.be>
35
+ * @since 0.2.7
36
+ * @version 0.2.7
37
+ */
38
+ Toolbar.setStylesheetFile('alchemy_widgets');
39
+
40
+ /**
41
+ * The toolbar manager
42
+ *
43
+ * @author Jelle De Loecker <jelle@elevenways.be>
44
+ * @since 0.2.7
45
+ * @version 0.2.7
46
+ */
47
+ Toolbar.setAssignedProperty('toolbar_manager');
48
+
49
+ /**
50
+ * The optional watchers element
51
+ *
52
+ * @author Jelle De Loecker <jelle@elevenways.be>
53
+ * @since 0.2.7
54
+ * @version 0.2.7
55
+ */
56
+ Toolbar.addElementGetter('watchers_element', '.watchers');
57
+
58
+ /**
59
+ * A new toolbar manager was assigned
60
+ *
61
+ * @author Jelle De Loecker <jelle@elevenways.be>
62
+ * @since 0.2.7
63
+ * @version 0.2.7
64
+ */
65
+ Toolbar.setMethod(function onToolbarManagerAssignment(manager, old_manager) {
66
+ if (manager != old_manager) {
67
+ this.prepareToolbarManager(manager, old_manager);
68
+ }
69
+ });
70
+
71
+ /**
72
+ * Prepare the toolbar manager
73
+ *
74
+ * @author Jelle De Loecker <jelle@elevenways.be>
75
+ * @since 0.2.7
76
+ * @version 0.2.8
77
+ */
78
+ Toolbar.setMethod(function prepareToolbarManager(manager, old_manager) {
79
+
80
+ if (this.toolbar_manager != manager) {
81
+ this.toolbar_manager = manager;
82
+ }
83
+
84
+ if (manager && manager[PREPARED]) {
85
+ return;
86
+ }
87
+
88
+ if (manager) {
89
+ manager[PREPARED] = true;
90
+ }
91
+
92
+ if (old_manager) {
93
+ old_manager.release();
94
+ }
95
+
96
+ if (!manager) {
97
+ return;
98
+ }
99
+
100
+ let clear_counts = {};
101
+
102
+ manager.watchProperty('document_watcher', watcher => {
103
+ this.attachDocumentWatcher(watcher);
104
+ });
105
+
106
+ let elements = this.querySelectorAll('[data-toolbar]');
107
+
108
+ for (let i = 0; i < elements.length; i++) {
109
+ let element = elements[i],
110
+ name = element.dataset.toolbar;
111
+
112
+ if (name) {
113
+ manager.watchProperty(name, value => {
114
+ element.textContent = value;
115
+ });
116
+ }
117
+ }
118
+
119
+ manager.watchQueue('render_template', (area, template, variables) => {
120
+
121
+ let current_clear_count = clear_counts[area];
122
+
123
+ let area_element = this.getAreaElement(area);
124
+
125
+ if (area_element) {
126
+ let renderer = hawkejs.renderToElements(template, variables, (err, elements) => {
127
+
128
+ if (current_clear_count != clear_counts[area]) {
129
+ // The area has been cleared in the meantime
130
+ return;
131
+ }
132
+
133
+ if (err) {
134
+ console.error('Error rendering template', err);
135
+ return;
136
+ }
137
+
138
+ for (let i = 0; i < elements.length; i++) {
139
+ area_element.appendChild(elements[i]);
140
+ }
141
+
142
+ hawkejs.scene.handleRendererScripts(renderer);
143
+ hawkejs.scene.handleRendererStyles(renderer);
144
+ });
145
+ }
146
+ });
147
+
148
+ manager.watchQueue('clear_area', area => {
149
+
150
+ if (!clear_counts[area]) {
151
+ clear_counts[area] = 0;
152
+ }
153
+
154
+ let area_element = this.getAreaElement(area);
155
+
156
+ clear_counts[area]++;
157
+
158
+ if (area_element) {
159
+ area_element.innerHTML = '';
160
+ }
161
+ });
162
+
163
+ });
164
+
165
+ /**
166
+ * Attach to the given watcher
167
+ *
168
+ * @author Jelle De Loecker <jelle@elevenways.be>
169
+ * @since 0.2.7
170
+ * @version 0.2.7
171
+ */
172
+ Toolbar.setMethod(function attachDocumentWatcher(watcher) {
173
+
174
+ let old_watcher = this.current_watcher;
175
+ let watchers_element = this.watchers_element;
176
+ this.current_watcher = watcher;
177
+
178
+ if (old_watcher && old_watcher != watcher) {
179
+ old_watcher.release();
180
+ }
181
+
182
+ if (watchers_element) {
183
+ if (watcher) {
184
+
185
+ watcher.watchProperty('viewers', async (viewers) => {
186
+
187
+ let users = [];
188
+
189
+ if (viewers) {
190
+ let viewer,
191
+ i;
192
+
193
+ for (i = 0; i < viewers.length; i++) {
194
+ viewer = viewers[i];
195
+
196
+ if (!viewer.info) {
197
+ // The info isn't always set due to race conditions
198
+ viewer.info = await watcher.getUserInfo(viewer.user_id);
199
+ }
200
+
201
+ users.push(viewer.info);
202
+ }
203
+ }
204
+
205
+ watchers_element.setUsers(users);
206
+ });
207
+ } else {
208
+ watchers_element.clear();
209
+ }
210
+ }
211
+
212
+ if (!watcher) {
213
+ return;
214
+ }
215
+ });
216
+
217
+ /**
218
+ * Get an area element
219
+ *
220
+ * @author Jelle De Loecker <jelle@elevenways.be>
221
+ * @since 0.2.7
222
+ * @version 0.2.7
223
+ */
224
+ Toolbar.setMethod(function getAreaElement(area) {
225
+
226
+ if (!area) {
227
+ return;
228
+ }
229
+
230
+ return this.querySelector('[data-area="' + area + '"]');
231
+ });
@@ -0,0 +1,30 @@
1
+ /**
2
+ * The al-editor-toolbar element
3
+ *
4
+ * @author Jelle De Loecker <jelle@elevenways.be>
5
+ * @since 0.2.7
6
+ * @version 0.2.7
7
+ */
8
+ let Toolbar = Function.inherits('Alchemy.Element.Widget.BaseToolbar', 'EditorToolbar');
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.2.7
15
+ * @version 0.2.7
16
+ */
17
+ Toolbar.setTemplateFile('widget/elements/al_editor_toolbar');
18
+
19
+ /**
20
+ * Added to the dom for the first time
21
+ *
22
+ * @author Jelle De Loecker <jelle@elevenways.be>
23
+ * @since 0.2.7
24
+ * @version 0.2.7
25
+ */
26
+ Toolbar.setMethod(async function introduced() {
27
+
28
+ this.prepareToolbarManager(this.toolbar_manager);
29
+
30
+ });
File without changes
@@ -0,0 +1,137 @@
1
+ /**
2
+ * The al-symbol-group element
3
+ *
4
+ * @author Jelle De Loecker <jelle@elevenways.be>
5
+ * @since 0.2.7
6
+ * @version 0.2.7
7
+ */
8
+ let UserAvatar = Function.inherits('Alchemy.Element.App', 'Alchemy.Element.Widget', 'UserAvatar');
9
+
10
+ /**
11
+ * The stylesheet to load for this element
12
+ *
13
+ * @author Jelle De Loecker <jelle@elevenways.be>
14
+ * @since 0.2.7
15
+ * @version 0.2.7
16
+ */
17
+ UserAvatar.setStylesheetFile('alchemy_widgets');
18
+
19
+ /**
20
+ * Set the custom element prefix
21
+ *
22
+ * @author Jelle De Loecker <jelle@elevenways.be>
23
+ * @since 0.2.7
24
+ * @version 0.2.7
25
+ */
26
+ UserAvatar.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.7
33
+ * @version 0.2.7
34
+ */
35
+ UserAvatar.setTemplateFile('widget/elements/al_user_avatar');
36
+
37
+ /**
38
+ * The user data
39
+ *
40
+ * @author Jelle De Loecker <jelle@elevenways.be>
41
+ * @since 0.2.7
42
+ * @version 0.2.7
43
+ */
44
+ UserAvatar.setAssignedProperty('user');
45
+
46
+ /**
47
+ * Get the pk of the user
48
+ *
49
+ * @author Jelle De Loecker <jelle@elevenways.be>
50
+ * @since 0.2.7
51
+ * @version 0.2.7
52
+ */
53
+ UserAvatar.setProperty(function pk() {
54
+
55
+ let result = '';
56
+
57
+ if (this.user) {
58
+ result = this.user.$pk || this.user.pk || this.user.id || '';
59
+ }
60
+
61
+ return String(result);
62
+ });
63
+
64
+ /**
65
+ * Get the first name of the user
66
+ *
67
+ * @author Jelle De Loecker <jelle@elevenways.be>
68
+ * @since 0.2.7
69
+ * @version 0.2.7
70
+ */
71
+ UserAvatar.setProperty(function first_name() {
72
+
73
+ let result = '';
74
+
75
+ if (this.user) {
76
+ result = this.user.firstname || this.user.first_name || this.user.username || '';
77
+ }
78
+
79
+ return result;
80
+ });
81
+
82
+ /**
83
+ * Get the first letter for the user
84
+ *
85
+ * @author Jelle De Loecker <jelle@elevenways.be>
86
+ * @since 0.2.7
87
+ * @version 0.2.7
88
+ */
89
+ UserAvatar.setProperty(function first_letter() {
90
+
91
+ let result = this.first_name;
92
+
93
+ if (result) {
94
+ result = result[0].toUpperCase();
95
+ } else {
96
+ result = '?';
97
+ }
98
+
99
+ return result;
100
+ });
101
+
102
+ /**
103
+ * Set (new) user info
104
+ *
105
+ * @author Jelle De Loecker <jelle@elevenways.be>
106
+ * @since 0.2.7
107
+ * @version 0.2.7
108
+ */
109
+ UserAvatar.setMethod(function setUserInfo(user) {
110
+ this.user = user;
111
+ });
112
+
113
+ /**
114
+ * Received user info
115
+ *
116
+ * @author Jelle De Loecker <jelle@elevenways.be>
117
+ * @since 0.2.7
118
+ * @version 0.2.7
119
+ */
120
+ UserAvatar.setMethod(function onUserAssignment(user) {
121
+
122
+ let bg_color;
123
+
124
+ if (user) {
125
+ bg_color = user.color;
126
+ }
127
+
128
+ if (!bg_color) {
129
+ this.style.removeProperty('--avatar-bg-color');
130
+ } else {
131
+ this.style.setProperty('--avatar-bg-color', bg_color);
132
+ }
133
+
134
+ let first_name = this.first_name;
135
+
136
+ this.setAttribute('title', first_name);
137
+ });
@@ -0,0 +1,131 @@
1
+ /**
2
+ * The al-user-avatar-group element
3
+ *
4
+ * @author Jelle De Loecker <jelle@elevenways.be>
5
+ * @since 0.2.7
6
+ * @version 0.2.7
7
+ */
8
+ let UserAvatarGroup = Function.inherits('Alchemy.Element.App', 'Alchemy.Element.Widget', 'UserAvatarGroup');
9
+
10
+ /**
11
+ * The stylesheet to load for this element
12
+ *
13
+ * @author Jelle De Loecker <jelle@elevenways.be>
14
+ * @since 0.2.7
15
+ * @version 0.2.7
16
+ */
17
+ UserAvatarGroup.setStylesheetFile('alchemy_widgets');
18
+
19
+ /**
20
+ * Set the custom element prefix
21
+ *
22
+ * @author Jelle De Loecker <jelle@elevenways.be>
23
+ * @since 0.2.7
24
+ * @version 0.2.7
25
+ */
26
+ UserAvatarGroup.setStatic('custom_element_prefix', 'al');
27
+
28
+ /**
29
+ * Clear all the avatars
30
+ *
31
+ * @author Jelle De Loecker <jelle@elevenways.be>
32
+ * @since 0.2.7
33
+ * @version 0.2.7
34
+ */
35
+ UserAvatarGroup.setMethod(function clear() {
36
+
37
+ let existing_avatars = this.querySelectorAll('al-user-avatar'),
38
+ avatar;
39
+
40
+ for (let i = 0; i < existing_avatars.length; i++) {
41
+ avatar = existing_avatars[i];
42
+ avatar.remove();
43
+ }
44
+ });
45
+
46
+ /**
47
+ * Set all the users to show
48
+ *
49
+ * @author Jelle De Loecker <jelle@elevenways.be>
50
+ * @since 0.2.7
51
+ * @version 0.2.7
52
+ *
53
+ * @param {Object[]} users
54
+ */
55
+ UserAvatarGroup.setMethod(function setUsers(users) {
56
+
57
+ if (!users || !users.length) {
58
+ this.clear();
59
+ return;
60
+ }
61
+
62
+ let existing_avatars = this.querySelectorAll('al-user-avatar'),
63
+ keep_avatars = [],
64
+ updated,
65
+ avatar,
66
+ user;
67
+
68
+ users = [...users];
69
+
70
+ for (let i = 0; i < users.length; i++) {
71
+ user = users[i];
72
+
73
+ updated = false;
74
+
75
+ for (let j = 0; j < existing_avatars.length; j++) {
76
+ avatar = existing_avatars[j];
77
+
78
+ if (avatar.pk == user.pk) {
79
+ keep_avatars.push(avatar);
80
+ avatar.setUserInfo(user);
81
+ updated = true;
82
+ break;
83
+ }
84
+ }
85
+
86
+ if (updated) {
87
+ continue;
88
+ }
89
+
90
+ avatar = this.createElement('al-user-avatar');
91
+ avatar.setUserInfo(user);
92
+ this.appendChild(avatar);
93
+ keep_avatars.push(avatar);
94
+ }
95
+
96
+ for (let i = 0; i < existing_avatars.length; i++) {
97
+ avatar = existing_avatars[i];
98
+
99
+ if (keep_avatars.indexOf(avatar) == -1) {
100
+ avatar.remove();
101
+ }
102
+ }
103
+ });
104
+
105
+ /**
106
+ * Add a user to the group
107
+ *
108
+ * @author Jelle De Loecker <jelle@elevenways.be>
109
+ * @since 0.2.7
110
+ * @version 0.2.7
111
+ *
112
+ * @param {Object} user
113
+ */
114
+ UserAvatarGroup.setMethod(function addUser(user) {
115
+
116
+ let existing_avatars = this.querySelectorAll('al-user-avatar'),
117
+ avatar;
118
+
119
+ for (let i = 0; i < existing_avatars.length; i++) {
120
+ avatar = existing_avatars[i];
121
+
122
+ if (avatar.pk == user.pk) {
123
+ avatar.setUserInfo(user);
124
+ return;
125
+ }
126
+ }
127
+
128
+ avatar = this.createElement('al-user-avatar');
129
+ avatar.setUserInfo(user);
130
+ this.appendChild(avatar);
131
+ });
File without changes
File without changes