@pageboard/html 0.14.8 → 0.14.10

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/ui/select.js CHANGED
@@ -1,15 +1,6 @@
1
1
  class HTMLElementSelect extends Page.Element {
2
2
  #observer;
3
3
 
4
- static defaults = {
5
- placeholder: null,
6
- name: null,
7
- value: null,
8
- multiple: false,
9
- disabled: false,
10
- required: false
11
- };
12
-
13
4
  #child(sel) {
14
5
  return this.children.find(node => node.matches(sel));
15
6
  }
@@ -23,6 +14,49 @@ class HTMLElementSelect extends Page.Element {
23
14
  return this.#child('select');
24
15
  }
25
16
 
17
+ get name() {
18
+ return this.getAttribute('name');
19
+ }
20
+
21
+ get required() {
22
+ return this.hasAttribute('required');
23
+ }
24
+
25
+ get multiple() {
26
+ return this.hasAttribute('multiple');
27
+ }
28
+
29
+ get disabled() {
30
+ return this.hasAttribute('disabled');
31
+ }
32
+
33
+ get value() {
34
+ return this.getAttribute('value');
35
+ }
36
+
37
+ set name(n) {
38
+ this.setAttribute('name', n);
39
+ }
40
+
41
+ set required(b) {
42
+ if (b) this.setAttribute('required', '');
43
+ else this.removeAttribute('required');
44
+ }
45
+
46
+ set multiple(b) {
47
+ if (b) this.setAttribute('multiple', '');
48
+ else this.removeAttribute('multiple');
49
+ }
50
+
51
+ set disabled(b) {
52
+ if (b) this.setAttribute('disabled', '');
53
+ else this.removeAttribute('disabled');
54
+ }
55
+
56
+ set value(v) {
57
+ this.getAttribute('value', v);
58
+ }
59
+
26
60
  handleClick(e, state) {
27
61
  if (state.scope.$write) return;
28
62
  const node = e.target;
@@ -32,7 +66,7 @@ class HTMLElementSelect extends Page.Element {
32
66
  if (opt) {
33
67
  opt.selected = true;
34
68
  state.dispatch(opt, 'change');
35
- this.#toggleMenu(false);
69
+ this.classList.remove('active');
36
70
  }
37
71
  return;
38
72
  }
@@ -45,7 +79,7 @@ class HTMLElementSelect extends Page.Element {
45
79
  }
46
80
  return;
47
81
  }
48
- this.#toggleMenu();
82
+ this.classList.toggle('active');
49
83
  }
50
84
  handleChange(e, state) {
51
85
  const opt = e.target;
@@ -55,17 +89,12 @@ class HTMLElementSelect extends Page.Element {
55
89
  this.#deselectItem(opt);
56
90
  }
57
91
  }
58
- #toggleMenu(show) {
59
- const style = this.#menu.style;
60
- if (show === undefined) show = !style.display;
61
- style.display = show ? "block" : null;
62
- }
63
92
  #selectItem(opt) {
64
93
  const select = this.#select;
65
94
  const val = opt.getAttribute('value');
66
95
  const item = this.#menuOption(val);
67
96
 
68
- if (this.options.multiple) {
97
+ if (this.multiple) {
69
98
  if (this.#child(`.label[data-value="${val}"]`) == null) {
70
99
  this.#setText("").insertAdjacentHTML(
71
100
  'beforeBegin',
@@ -81,7 +110,7 @@ class HTMLElementSelect extends Page.Element {
81
110
  }
82
111
  #deselectItem(opt) {
83
112
  const val = opt.getAttribute('value');
84
- if (this.options.multiple && val) {
113
+ if (this.multiple && val) {
85
114
  const item = this.#child(`.label[data-value="${val}"]`);
86
115
  if (item) item.remove();
87
116
  }
@@ -95,9 +124,8 @@ class HTMLElementSelect extends Page.Element {
95
124
  text.classList.remove('default');
96
125
  return text;
97
126
  }
98
- #setPlaceholder(str) {
127
+ #setPlaceholder(str = '') {
99
128
  const text = this.#text;
100
- if (!str) str = this.options.placeholder;
101
129
 
102
130
  const defaultOption = this.#select.querySelector('option[value=""]');
103
131
  if (defaultOption) {
@@ -123,57 +151,44 @@ class HTMLElementSelect extends Page.Element {
123
151
  this.#observer = null;
124
152
  }
125
153
  }
126
- #fillSelect(state) {
127
- const select = this.#select;
128
- if (!select) return;
129
- select.insertAdjacentHTML('afterBegin', '<option value="[item.dataset.value]">[children|at:*|repeat:item|.innerText]</option>');
130
- select.fuse(this.#menu, state.scope);
131
- }
132
- setup(state) {
133
- this.#observer = new MutationObserver(mutations => this.#fillSelect(state));
134
- this.#observer.observe(this.#menu, {
135
- childList: true
154
+ fill(values) {
155
+ this.#select.children.forEach(opt => {
156
+ if (opt.value) {
157
+ if (opt.selected) this.#selectItem(opt);
158
+ else this.#deselectItem(opt);
159
+ }
136
160
  });
137
161
  }
138
-
139
- build(state) {
140
- if (state.scope.$write) return;
141
- if (this.children.length == 1) {
142
- this.insertAdjacentHTML(
143
- 'afterBegin',
144
- '<i class="dropdown icon"></i><div class="text"></div><select></select>'
145
- );
146
- }
162
+ prepare(editable) {
147
163
  const select = this.#select;
148
-
149
- select.disabled = this.options.disabled;
150
- select.required = this.options.required;
151
- select.multiple = this.options.multiple;
164
+ select.disabled = this.disabled;
165
+ select.required = this.required;
166
+ select.multiple = this.multiple;
152
167
  if (!select.multiple) {
153
168
  for (const node of this.querySelectorAll('.ui.label')) node.remove();
154
169
  }
155
- select.name = this.options.name;
156
- if (!select.required) {
157
- const menu = this.#menu;
158
- if (!menu.querySelector('element-select-option[data-value=""]')) {
170
+ select.name = this.name;
171
+ const menu = this.#menu;
172
+ const defaultOption = menu.querySelector('element-select-option[data-value=""]');
173
+ if (!select.required && !editable) {
174
+ if (!defaultOption) {
159
175
  menu.insertAdjacentHTML('afterBegin', `<element-select-option data-value="" block-type="input_select_option" class="item">-</element-select-option>`);
160
176
  }
177
+ } else if (defaultOption) {
178
+ defaultOption.remove();
179
+ }
180
+ if (menu.children.length != select.children.length && !editable) {
181
+ // TODO do a better check
182
+ select.textContent = '';
183
+ select.insertAdjacentHTML('afterBegin', '<option value="[item.dataset.value]">[children|at:*|repeat:item|.innerText]</option>');
184
+ select.fuse(this.#menu, {});
161
185
  }
162
- this.#fillSelect(state);
163
186
  }
164
-
165
- patch(state) {
166
- if (state.scope.$write) return;
167
- if (this.children.length == 1) this.build(state);
168
-
169
- state.finish(() => {
170
- // synchronize after form has filled select
171
- this.#select.children.forEach(opt => {
172
- if (opt.value) {
173
- if (opt.selected) this.#selectItem(opt);
174
- else this.#deselectItem(opt);
175
- }
176
- });
187
+ setup() {
188
+ if (this.isContentEditable) return;
189
+ this.#observer = new MutationObserver(mutations => this.prepare());
190
+ this.#observer.observe(this.#menu, {
191
+ childList: true
177
192
  });
178
193
  }
179
194
  }
package/ui/site.css CHANGED
@@ -258,24 +258,3 @@ body .ui.inverted::-webkit-scrollbar-thumb:hover {
258
258
  margin-left: auto !important;
259
259
  margin-right: auto !important;
260
260
  }
261
-
262
- /* for editor only, but semantic-ui dependent */
263
- [contenteditable] .ui.buttons .disabled.button,
264
- [contenteditable] .ui.disabled.button,
265
- [contenteditable] .ui.button:disabled,
266
- [contenteditable] .ui.disabled.button:hover,
267
- [contenteditable] .ui.disabled.active.button {
268
- pointer-events: auto !important;
269
- }
270
-
271
- [contenteditable] .ui.dropdown[block-focused] > .menu {
272
- overflow: visible;
273
- width: auto;
274
- height: auto;
275
- top: 100% !important;
276
- opacity: 1;
277
- }
278
-
279
- [contenteditable] .field[block-focused] .dropdown > .menu {
280
- display: block !important;
281
- }
@@ -1,73 +0,0 @@
1
- class HTMLElementSitepage extends Page.Element {
2
- static defaults = {
3
- url: null,
4
- index: (x) => parseInt(x) || 0
5
- };
6
-
7
- patch(state) {
8
- if (this.isConnected) this.syncBlock(state.scope);
9
- }
10
- setup(state) {
11
- const content = this.querySelector('[block-content="children"]');
12
- if (!content) return;
13
- this.observer = new MutationObserver(mutations => this.updateChildren());
14
- this.observer.observe(content, {
15
- childList: true
16
- });
17
- }
18
-
19
- close(state) {
20
- if (this.observer) this.observer.disconnect();
21
- delete this.observer;
22
- }
23
-
24
- updateChildren() {
25
- if (this.updating) return;
26
- const content = this.querySelector('[block-content="children"]');
27
- if (!content) return;
28
- this.updating = true;
29
- const parentUrl = this.dataset.url || "";
30
- const uniques = {};
31
- Array.prototype.forEach.call(content.children, (child, index) => {
32
- if (!child.matches('element-sitepage')) return; // cursor
33
- const childUrl = child.dataset.url || '';
34
- if (childUrl.startsWith('/.')) return;
35
- const newUrl = parentUrl + "/" + childUrl.split('/').pop();
36
- if (childUrl != newUrl && !uniques[newUrl]) {
37
- child.setAttribute('data-url', newUrl);
38
- }
39
- uniques[newUrl] = true;
40
- const curIndex = parseInt(child.dataset.index);
41
- if (curIndex != index) {
42
- child.setAttribute('data-index', index);
43
- }
44
- });
45
- this.updating = false;
46
- }
47
-
48
- syncBlock(scope) {
49
- if (!this.parentNode || this.matches('element-sitemap')) return;
50
- const editor = scope.editor;
51
- if (!editor || editor.closed) return;
52
- const block = editor.blocks.get(this.getAttribute('block-id'));
53
- if (!block.data) block.data = {};
54
- const data = this.options;
55
- if (Object.keys(data).some(key => data[key] != block.data[key])) {
56
- Object.assign(block.data, data);
57
- editor.dispatch(editor.utils.refreshTr(editor.state.tr, this, block));
58
- this.updateChildren();
59
- } else this.updateChildren();
60
-
61
- }
62
- }
63
-
64
-
65
- Page.define('element-sitepage', HTMLElementSitepage);
66
-
67
- Page.setup(state => {
68
- if (!state.scope.$write) return;
69
- state.finish(() => {
70
- Page.extend('element-sitemap', HTMLElementSitepage);
71
- });
72
- });
73
-
package/ui/sitemap.css DELETED
@@ -1,53 +0,0 @@
1
- [block-type="sitemap"] {
2
- min-height:2em;
3
- position:relative;
4
- display: block;
5
- width: 100%;
6
- }
7
- [block-type="sitemap"] .caret-icon::before {
8
- right:auto;
9
- left:-0.8em;
10
- }
11
- .ui.list[block-type="sitemap"] {
12
- padding:0.5em;
13
- margin:0.5em;
14
- box-shadow: -1px 1px 2px 1px grey;
15
- }
16
-
17
- [block-type="sitemap"] .list > .item > .content {
18
- box-shadow: 0 1px 1px 1px grey;
19
- padding-right: 0.5em;
20
- padding-bottom:1px;
21
- margin-bottom: 0;
22
- min-height:1em;
23
- }
24
-
25
- [block-type="sitemap"] .list.content.active {
26
- margin-top:0;
27
- padding-bottom: 1em !important;
28
- margin-left: 1em;
29
- padding-top: 0 !important;
30
- margin-right: 1em;
31
- }
32
- .ui.accordion[block-type="sitemap"] .title > a,
33
- .ui.accordion[block-type="sitemap"] .accordion .title > a {
34
- padding-left:1.25em;
35
- }
36
- element-sitepage {
37
- display:block;
38
- position: relative;
39
- }
40
- element-sitepage .title.caret-icon.active {
41
- padding-bottom:0 !important;
42
- }
43
- element-sitepage > .title > .label {
44
- float:right;
45
- }
46
-
47
- element-sitepage > .title > a.description {
48
- color: darkgrey;
49
- }
50
- element-sitepage > .title > a.redirection {
51
- color:dodgerblue;
52
- }
53
-
package/ui/sitemap.js DELETED
@@ -1,78 +0,0 @@
1
- class HTMLElementSitemap extends Page.Element {
2
- static makeTree(tree, parent) {
3
- let page = tree._;
4
- if (page) {
5
- if (!parent.children) parent.children = [];
6
- const old = parent.children.find(item => item.id == page.id);
7
- if (!old) parent.children.push(page);
8
- if (parent.content == null) parent.content = {};
9
- if (parent.content.children == null) parent.content.children = "";
10
- if (typeof parent.content.children == "string") {
11
- parent.content.children += `<div block-id="${page.id}" block-type="${page.type}"></div>`;
12
- }
13
- delete tree._;
14
- } else {
15
- page = parent;
16
- }
17
- for (const name of Object.keys(tree).sort((a, b) => {
18
- const pageA = tree[a]._;
19
- const pageB = tree[b]._;
20
- if (!pageA || !pageB) return 0;
21
- let indexA = pageA.data.index;
22
- if (indexA == null) indexA = Infinity;
23
- let indexB = pageB.data.index;
24
- if (indexB == null) indexB = Infinity;
25
- if (indexA == indexB) return 0;
26
- else if (indexA < indexB) return -1;
27
- else if (indexA > indexB) return 1;
28
- })) {
29
- this.makeTree(tree[name], page);
30
- }
31
- return parent;
32
- }
33
-
34
- static transformResponse(res) {
35
- const pages = res.items;
36
- const tree = {};
37
-
38
- for (const page of pages) {
39
- if (!page.data.url) continue;
40
- let branch = tree;
41
- const arr = page.data.url.substring(1).split('/');
42
- arr.forEach((name, i) => {
43
- if (!branch[name]) branch[name] = {};
44
- branch = branch[name];
45
- if (i == arr.length - 1) branch._ = page;
46
- });
47
- }
48
- return this.makeTree(tree, {
49
- type: 'sitemap',
50
- content: { children: '' },
51
- children: []
52
- });
53
- }
54
-
55
- async build(state) {
56
- if (this.firstElementChild.children.length > 0 && state.scope.$write) {
57
- // workaround... build is called a second time with pagecut-placeholder set
58
- return;
59
- }
60
- const res = await state.fetch('get', `/.api/pages`);
61
- const scope = state.scope.copy();
62
- await scope.import(res);
63
- const tree = this.constructor.transformResponse(res);
64
- const node = scope.render({
65
- item: tree
66
- });
67
- // only change block content
68
- const src = node.firstElementChild;
69
- const dst = this.firstElementChild;
70
- dst.textContent = '';
71
- while (src.firstChild) dst.appendChild(src.firstChild);
72
- }
73
- }
74
-
75
-
76
- Page.define('element-sitemap', HTMLElementSitemap);
77
-
78
-