@pageboard/html 0.12.5 → 0.12.7

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/elements/embed.js CHANGED
@@ -8,31 +8,49 @@ exports.embed = {
8
8
  description: 'The iframe src URL',
9
9
  nullable: true,
10
10
  type: 'string',
11
- format: 'uri-reference'
12
- // TODO plug embeds to href, but url-inspector makes it difficult for us right now
11
+ format: 'uri-reference',
12
+ $helper: {
13
+ name: 'href',
14
+ filter: {
15
+ type: ["embed"]
16
+ }
17
+ }
13
18
  },
14
- name: {
15
- title: 'Name',
19
+ linkable: {
20
+ title: 'Show hash link',
21
+ type: 'boolean',
22
+ default: false
23
+ },
24
+ id: {
25
+ nullable: true,
16
26
  type: 'string',
17
- format: 'id',
27
+ pattern: /^[a-z0-9-]*$/.source
28
+ },
29
+ query: {
30
+ title: 'Additional query parameters',
31
+ type: 'object',
18
32
  nullable: true
19
33
  }
20
34
  },
21
35
  group: "block",
22
- parse: function(dom) {
36
+ parse: function (dom) {
37
+ if (dom.matches('element-embed')) return;
23
38
  return {
24
- url: dom.dataset.src || dom.getAttribute('src')
39
+ url: dom.getAttribute('src')
25
40
  };
26
41
  },
27
42
  tag: 'iframe,element-embed',
28
- html: `<element-embed class="ui embed" data-src="[url]" id="[name|as:xid]"></element-embed>`,
43
+ html: `<element-embed data-src="[url|meta:source][query|as:query]" id="[id]" title="[url|meta:title]" style="padding-bottom:calc([url|meta:height] / [url|meta:width] * 100%)">
44
+ <a aria-hidden="true" class="linkable" href="[$loc.pathname][$loc.search][id|pre:%23]">[linkable|prune:*]#</a>
45
+ <iframe loading="lazy" allowfullscreen frameborder="0" scrolling="no"></iframe>
46
+ </element-embed>`,
29
47
  scripts: [
30
48
  '../ui/embed.js'
31
49
  ],
32
50
  stylesheets: [
33
51
  '../ui/loading.css',
34
- '../lib/components/embed.css',
35
- '../ui/embed.css'
52
+ '../ui/embed.css',
53
+ '../ui/linkable.css'
36
54
  ]
37
55
  };
38
-
56
+ exports.editor.scripts.push('../ui/embed-helper.js');
@@ -33,7 +33,6 @@ exports.heading = {
33
33
  },
34
34
  linkable: {
35
35
  title: 'Show hash link',
36
- description: 'On hover',
37
36
  type: 'boolean',
38
37
  default: false
39
38
  },
@@ -55,8 +54,8 @@ exports.heading = {
55
54
  group: "block",
56
55
  icon: '<i class="icon header"></i>',
57
56
  tag: 'h1,h2,h3,h4,h5,h6',
58
- html: `<h[level] class="ui [align|or:left] aligned header" is="h[level]-helper" id="[id][linkable|prune:-]" entitled="[entitled]">
59
- <a aria-hidden="true" href="[$loc.pathname][$loc.search][id|pre:%23]">[linkable|prune:*]#</a>
57
+ html: `<h[level] class="ui [align|or:left] aligned header" is="h[level]-helper" id="[id]" entitled="[entitled]">
58
+ <a aria-hidden="true" class="linkable" href="[$loc.pathname][$loc.search][id|pre:%23]">[linkable|prune:*]#</a>
60
59
  <div block-content="text">Heading</div>
61
60
  </hn>`,
62
61
  parse: function (dom) {
@@ -65,7 +64,8 @@ exports.heading = {
65
64
  };
66
65
  },
67
66
  stylesheets: [
68
- '../ui/heading.css'
67
+ '../ui/heading.css',
68
+ '../ui/linkable.css'
69
69
  ],
70
70
  scripts: [
71
71
  '../ui/heading.js'
package/elements/time.js CHANGED
@@ -158,7 +158,7 @@ exports.time = {
158
158
  const format = {};
159
159
  const list = (dom.dataset.format ?? "").split(':');
160
160
  for (const [key, schema] of Object.entries(this.properties.format.properties)) {
161
- for (const tok in list) {
161
+ for (const tok of list) {
162
162
  if (tok) {
163
163
  const item = schema.anyOf.find(item => item.const === tok);
164
164
  if (item) format[key] = item.const;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pageboard/html",
3
- "version": "0.12.5",
3
+ "version": "0.12.7",
4
4
  "description": "",
5
5
  "main": "index.js",
6
6
  "repository": {
@@ -0,0 +1,10 @@
1
+ Page.extend('element-embed', class HTMLElementEmbedHelper {
2
+ patch(state) {
3
+ const { editor } = state.scope;
4
+ if (!editor) return;
5
+ const id = editor.slug(this.title).slice(0, 32);
6
+ if (id != this.id) {
7
+ editor.blocks.mutate(this, { id });
8
+ }
9
+ }
10
+ });
package/ui/embed.css CHANGED
@@ -1,8 +1,24 @@
1
1
  element-embed {
2
2
  display:block;
3
+ position:relative;
4
+ max-width:100%;
3
5
  width:100%;
6
+ background-color:#DDD;
7
+ height:0;
8
+ padding-bottom:56.25%;
4
9
  }
5
10
 
6
11
  [contenteditable] element-embed iframe {
7
12
  pointer-events:none;
8
13
  }
14
+
15
+ element-embed > iframe {
16
+ position: absolute;
17
+ border: none;
18
+ width: 100%;
19
+ height: 100%;
20
+ top: 0px;
21
+ left: 0px;
22
+ margin: 0em;
23
+ padding: 0em;
24
+ }
package/ui/embed.js CHANGED
@@ -4,72 +4,64 @@ class HTMLElementEmbed extends Page.Element {
4
4
  hash: null
5
5
  };
6
6
  static revealRatio = 0.2;
7
- #defer = new Deferred();
8
7
 
9
8
  reveal(state) {
10
9
  this.classList.add('waiting');
11
10
  state.consent(this);
12
- // return this.#defer; // do not hang the chain
11
+ }
12
+ get currentSrc() {
13
+ return this.querySelector('iframe')?.src ?? "about:blank";
13
14
  }
14
15
  consent(state) {
15
16
  const consent = state.scope.$consent;
16
17
  this.classList.toggle('denied', consent == "no");
17
18
  this.classList.toggle('waiting', consent == null);
18
19
 
19
- this.iframe = this.querySelector('iframe');
20
+ const iframe = this.querySelector('iframe');
20
21
  if (consent != "yes") {
21
- if (this.iframe) this.iframe.remove();
22
- this.#defer.resolve();
22
+ iframe.src = "";
23
23
  return;
24
24
  }
25
- if (!this.iframe) {
26
- this.innerHTML = `<iframe width="100%" height="100%" frameborder="0" scrolling="no" allow="autoplay; fullscreen; accelerometer; gyroscope"></iframe>`;
27
- this.iframe = this.firstElementChild;
28
- }
29
- if (!this.iframe.allow) this.iframe.allowFullscreen = true;
25
+ if (!iframe.allow) iframe.allowFullscreen = true;
30
26
 
31
27
  const opts = this.options;
32
- const prev = Page.parse(this.currentSrc || this.iframe.src || "about:blank");
28
+ const prev = Page.parse(this.currentSrc);
33
29
  const cur = Page.parse(opts.src || "about:blank");
34
30
  cur.hash = opts.hash;
35
- this.currentSrc = cur.toString();
31
+ const curSrc = cur.toString();
36
32
 
37
33
  if (cur.samePath(prev) == false) {
38
34
  this.classList.remove('error');
39
35
  this.classList.add('loading');
40
- this.iframe.setAttribute('src', this.currentSrc);
41
- } else {
42
- if (cur.hash != prev.hash) {
43
- try {
44
- this.iframe.contentWindow.location.replace(this.currentSrc);
45
- } catch (err) {
46
- this.iframe.setAttribute('src', this.currentSrc);
47
- }
36
+ if (!state.scope.$write) {
37
+ iframe.allow = "accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture";
38
+ }
39
+ iframe.src = curSrc;
40
+ } else if (cur.hash != prev.hash) {
41
+ try {
42
+ iframe.contentWindow.location.replace(curSrc);
43
+ } catch (err) {
44
+ iframe.src = curSrc;
48
45
  }
49
- this.#defer.resolve();
50
46
  }
51
47
  }
52
48
  captureClick(e, state) {
53
49
  if (this.matches('.denied')) state.reconsent();
54
50
  }
55
51
  captureLoad() {
56
- this.#defer.resolve();
57
52
  this.classList.remove('loading');
58
53
  }
59
54
  captureError() {
60
- this.#defer.resolve();
61
55
  this.classList.add('error');
62
56
  }
63
57
  handleAllMessage(e, state) {
64
- if (!e.origin || !this.options.src) return;
65
- if (this.options.src.startsWith(e.origin) == false) return;
58
+ if (!e.origin || !this.options.source) return;
59
+ if (this.options.source.startsWith(e.origin) == false) return;
66
60
  if (this.receiveMessage) this.receiveMessage(e.data ?? {});
67
61
  }
68
62
  close() {
69
- if (this.iframe) {
70
- this.iframe.remove();
71
- delete this.iframe;
72
- }
63
+ const iframe = this.querySelector('iframe');
64
+ if (iframe) iframe.src = "";
73
65
  }
74
66
  }
75
67
 
@@ -207,7 +207,7 @@ class HTMLElementFieldsetList extends Page.Element {
207
207
 
208
208
  #listToValues(values, list) {
209
209
  for (let i = 0; i < list.length; i++) {
210
- const obj = list[i];
210
+ const obj = list[i] ?? {};
211
211
  for (const [key, val] of Object.entries(obj)) {
212
212
  const parts = this.#prefix.slice();
213
213
  parts.push(i);
package/ui/form.js CHANGED
@@ -364,7 +364,6 @@ class HTMLElementForm extends Page.create(HTMLFormElement) {
364
364
  } else {
365
365
  vary = "patch";
366
366
  }
367
- scope.$vary = vary;
368
367
  }
369
368
  state.push(loc, { vary });
370
369
  }
package/ui/heading.css CHANGED
@@ -1,12 +1,3 @@
1
- [block-type="heading"] > a[aria-hidden="true"] {
2
- display: block;
3
- position: absolute;
4
- visibility:hidden;
5
- left: -1ch;
6
- }
7
- [block-type="heading"]:hover > a[aria-hidden="true"] {
8
- visibility:visible;
9
- }
10
1
  h1,
11
2
  h2,
12
3
  h3,
@@ -0,0 +1,5 @@
1
+ [block-type][id] > a.linkable[aria-hidden="true"] {
2
+ display: block;
3
+ position: absolute;
4
+ left: -2ch;
5
+ }
package/ui/media.js CHANGED
@@ -1,5 +1,4 @@
1
1
  const HTMLElementMediaConstructor = Superclass => class extends Superclass {
2
- #defer = new Deferred();
3
2
 
4
3
  patch(state) {
5
4
  this.classList.remove('error', 'loading');
@@ -15,17 +14,14 @@ const HTMLElementMediaConstructor = Superclass => class extends Superclass {
15
14
  this.setAttribute('src', curSrc);
16
15
  }
17
16
  if (state.scope.$write) this.pause();
18
- // return this.#defer; // do not hang chain
19
17
  }
20
18
  handleClick(e, state) {
21
19
  if (state.scope.$write) e.preventDefault();
22
20
  }
23
21
  captureLoad() {
24
- this.#defer.resolve();
25
22
  this.classList.remove('loading');
26
23
  }
27
24
  captureError() {
28
- this.#defer.resolve();
29
25
  this.classList.remove('loading');
30
26
  this.classList.add('error');
31
27
  }