@xiee/utils 1.2.14 → 1.3.1

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.
@@ -0,0 +1,140 @@
1
+ body, blockquote, .side, .menu { background: #fafafa; }
2
+ .article, .body, .appendix { position: relative; }
3
+ .article-list, .body, .single main, .single .appendix, .body ~ .appendix, .frontmatter, .fullwidth, .embed-left, .embed-right {
4
+ margin-top: 2em;
5
+ padding: 1em;
6
+ box-shadow: 0 0 8px #ccc;
7
+ background: #fff;
8
+ }
9
+ .article-meta { background: #f8f8f8; }
10
+ .article-meta .terms, .appendix, .footnotes, main .side > *, .body .side, figcaption, .caption { font-size: .9em; }
11
+ .single .appendix, .body ~ .appendix, .frontmatter { background: none; }
12
+ .appendix h2 { border-bottom: 1px dashed #666; }
13
+ #TOC { top: 0; }
14
+ #TOC ul { list-style-position: inside; }
15
+ #TOC > ul {
16
+ padding: 0;
17
+ margin: 0;
18
+ }
19
+ #TOC li > ul { padding-left: 1em; }
20
+ #TOC .numbered { list-style: none; }
21
+ .bg-number {
22
+ padding: 1px 5px;
23
+ border-radius: 5px;
24
+ background: lightslategray;
25
+ color: #fff;
26
+ }
27
+
28
+ /* left/right elements*/
29
+ .side {
30
+ width: 200px;
31
+ margin: 0 auto;
32
+ }
33
+ .side-left {
34
+ float: left;
35
+ clear: left;
36
+ margin-left: calc(-200px - 2em);
37
+ position: sticky;
38
+ }
39
+ .side-right {
40
+ float: right;
41
+ clear: right;
42
+ margin-right: calc(-200px - 2em);
43
+ }
44
+ .quote-left, .quote-right { width: 45%; }
45
+ .embed-left, .embed-right {
46
+ margin-top: auto;
47
+ padding: 0;
48
+ }
49
+ .quote-left, .embed-left {
50
+ float: left;
51
+ margin-right: 1em;
52
+ }
53
+ .quote-right, .embed-right {
54
+ float: right;
55
+ margin-left: 1em;
56
+ }
57
+ .embed-left { margin-left: calc(-200px - 2em); }
58
+ .embed-right { margin-right: calc(-200px - 2em); }
59
+ .side > :first-child, .embed-left > :first-child, .embed-right > :first-child { margin-top: 0; }
60
+ .embed-left > :last-child, .embed-right > :last-child { margin-bottom: 0; }
61
+ .quote-left > :first-child, .quote-right > :first-child { padding-top: .1px; }
62
+ .quote-left > :last-child, .quote-right > :last-child { padding-bottom: .1px; }
63
+
64
+ /* wide elements */
65
+ .fullwidth, .fullwidth * { margin: auto 0; }
66
+ .fullwidth * { max-width: calc(100vw - 4em); }
67
+ .fullscroll * { max-width: initial; }
68
+ .fullwidth {
69
+ max-width: calc(100vw - 2em);
70
+ margin: 1em 0 1em 50%;
71
+ transform: translateX(-50%);
72
+ float: left;
73
+ min-width: 100%;
74
+ background: #fff;
75
+ }
76
+ .fullscroll, .fullscroll figure, .fullscroll .figure { overflow-x: auto; }
77
+ .fullwidth figcaption, .fullwidth .caption {
78
+ margin-left: calc(50% - 400px);
79
+ width: 800px;
80
+ padding: 1em 1em 0;
81
+ }
82
+
83
+ @media (min-width: 1280px) {
84
+ .note-ref { cursor: pointer; }
85
+ .note-ref:hover ~ .side {
86
+ display: inline-block;
87
+ background-color: #f8f8f8;
88
+ position: absolute;
89
+ margin-left: 1em;
90
+ padding: .5em;
91
+ box-sizing: content-box;
92
+ }
93
+ }
94
+ @media (max-width: 1280px) {
95
+ #TOC {
96
+ border: 1px solid #eee;
97
+ border-radius: 5px;
98
+ padding: 1em;
99
+ position: initial;
100
+ }
101
+ .side { width: 100%; }
102
+ main .side, .body .side {
103
+ padding: 0 2em;
104
+ color: darkslategray;
105
+ }
106
+ .side-left, .side-right {
107
+ clear: both;
108
+ margin: 1em auto;
109
+ background: none;
110
+ }
111
+ .note-ref ~ .side { margin-left: 100vw; }
112
+ .side > :last-child { margin-bottom: 0; }
113
+ .embed-left, .embed-right {
114
+ float: inherit;
115
+ margin: auto;
116
+ padding: 1em;
117
+ }
118
+ }
119
+ @media (max-width: 800px) {
120
+ body { padding: initial; }
121
+ main, .body { padding: 0 .5em 0; }
122
+ .quote-left, .quote-right {
123
+ width: inherit;
124
+ float: inherit;
125
+ margin: auto;
126
+ }
127
+ .fullwidth:not(.fullscroll) * { max-width: 100%; }
128
+ .fullwidth {
129
+ margin: initial;
130
+ transform: initial;
131
+ float: none;
132
+ min-width: initial;
133
+ background: none;
134
+ border: none;
135
+ }
136
+ .fullwidth figcaption, .fullwidth .caption {
137
+ margin: initial;
138
+ padding: initial;
139
+ }
140
+ }
@@ -0,0 +1 @@
1
+ .menu,.side,blockquote,body{background:#fafafa}.appendix,.article,.body{position:relative}.article-list,.body,.body~.appendix,.embed-left,.embed-right,.frontmatter,.fullwidth,.single .appendix,.single main{margin-top:2em;padding:1em;box-shadow:0 0 8px #ccc;background:#fff}.article-meta{background:#f8f8f8}.appendix,.article-meta .terms,.body .side,.caption,.footnotes,figcaption,main .side>*{font-size:.9em}.body~.appendix,.frontmatter,.single .appendix{background:0 0}.appendix h2{border-bottom:1px dashed #666}#TOC{top:0}#TOC ul{list-style-position:inside}#TOC>ul{padding:0;margin:0}#TOC li>ul{padding-left:1em}#TOC .numbered{list-style:none}.bg-number{padding:1px 5px;border-radius:5px;background:#778899;color:#fff}.side{width:200px;margin:0 auto}.side-left{float:left;clear:left;margin-left:calc(-200px - 2em);position:sticky}.side-right{float:right;clear:right;margin-right:calc(-200px - 2em)}.quote-left,.quote-right{width:45%}.embed-left,.embed-right{margin-top:auto;padding:0}.embed-left,.quote-left{float:left;margin-right:1em}.embed-right,.quote-right{float:right;margin-left:1em}.embed-left{margin-left:calc(-200px - 2em)}.embed-right{margin-right:calc(-200px - 2em)}.embed-left>:first-child,.embed-right>:first-child,.side>:first-child{margin-top:0}.embed-left>:last-child,.embed-right>:last-child{margin-bottom:0}.quote-left>:first-child,.quote-right>:first-child{padding-top:.1px}.quote-left>:last-child,.quote-right>:last-child{padding-bottom:.1px}.fullwidth,.fullwidth *{margin:auto 0}.fullwidth *{max-width:calc(100vw - 4em)}.fullscroll *{max-width:initial}.fullwidth{max-width:calc(100vw - 2em);margin:1em 0 1em 50%;transform:translateX(-50%);float:left;min-width:100%;background:#fff}.fullscroll,.fullscroll .figure,.fullscroll figure{overflow-x:auto}.fullwidth .caption,.fullwidth figcaption{margin-left:calc(50% - 400px);width:800px;padding:1em 1em 0}@media (min-width:1280px){.note-ref{cursor:pointer}.note-ref:hover~.side{display:inline-block;background-color:#f8f8f8;position:absolute;margin-left:1em;padding:.5em;box-sizing:content-box}}@media (max-width:1280px){#TOC{border:1px solid #eee;border-radius:5px;padding:1em;position:initial}.side{width:100%}.body .side,main .side{padding:0 2em;color:#2f4f4f}.side-left,.side-right{clear:both;margin:1em auto;background:0 0}.note-ref~.side{margin-left:100vw}.side>:last-child{margin-bottom:0}.embed-left,.embed-right{float:inherit;margin:auto;padding:1em}}@media (max-width:800px){body{padding:initial}.body,main{padding:0 .5em 0}.quote-left,.quote-right{width:inherit;float:inherit;margin:auto}.fullwidth:not(.fullscroll) *{max-width:100%}.fullwidth{margin:initial;transform:initial;float:none;min-width:initial;background:0 0;border:none}.fullwidth .caption,.fullwidth figcaption{margin:initial;padding:initial}}
package/js/appendix.js ADDED
@@ -0,0 +1,15 @@
1
+ // find <h[1-6] class="appendix"> and create a new <div> next to the parent
2
+ // element to hold all appendix elements
3
+ (d => {
4
+ const h = d.querySelector([1, 2, 3, 4, 5, 6].map(i => `h${i}.appendix`).join(','));
5
+ if (!h) return;
6
+ h.classList.remove('appendix');
7
+ const a = d.createElement('div');
8
+ a.className = 'appendix';
9
+ a.append(h.cloneNode(true));
10
+ h.parentNode.after(a);
11
+ while(h.nextSibling) {
12
+ a.append(h.nextSibling);
13
+ }
14
+ h.remove();
15
+ })(document);
@@ -0,0 +1 @@
1
+ (e=>{const n=e.querySelector([1,2,3,4,5,6].map((e=>`h${e}.appendix`)).join(","));if(!n)return;n.classList.remove("appendix");const a=e.createElement("div");for(a.className="appendix",a.append(n.cloneNode(!0)),n.parentNode.after(a);n.nextSibling;)a.append(n.nextSibling);n.remove()})(document);
package/js/key-buttons.js CHANGED
@@ -1,8 +1,8 @@
1
- (function(d) {
1
+ (d => {
2
2
  const a1 = ['Enter', 'Up', 'Down', 'Left', 'Right'];
3
3
  const a2 = ['&crarr;', '&uarr;', '&darr;', '&larr;', '&rarr;'];
4
4
  function drawArrows(x) {
5
- a1.map((v, i) => x = x.replace(new RegExp('>' + v + '<', 'g'), ' title="' + v + (i ? ' Arrow' : '') + '">' + a2[i] + '<'));
5
+ a1.map((v, i) => x = x.replace(new RegExp(`>${v}<`, 'g'), ` title="${v + (i ? ' Arrow' : '')}">${a2[i]}<`));
6
6
  return x;
7
7
  }
8
8
  // 1. individual keys; 2. modifiers; 3. normal keys
@@ -10,14 +10,14 @@
10
10
  Array(12).fill().map((v, i) => 'F' + (i + 1)).concat(a1).join('|'),
11
11
  k2 = 'Ctrl|Control|Shift|Alt|Cmd|Command|fn',
12
12
  k3 = '[a-zA-Z0-9]|Click',
13
- r1 = new RegExp('^(' + k1 + '|' + k2 + ')$'),
14
- r2 = new RegExp('^(' + k2 + ') [/+] '),
15
- r3 = new RegExp('^(' + [k1, k2, k3].join('|') + ')( [/+] )(.*)');
13
+ r1 = new RegExp(`^(${k1}|${k2})$`),
14
+ r2 = new RegExp(`^(${k2}) [/+] `),
15
+ r3 = new RegExp(`^(${k1}|${k2}|${k3})( [/+] )(.*)`);
16
16
  d.querySelectorAll(':not(pre) > code').forEach(el => {
17
17
  if (el.childElementCount > 0) return;
18
18
  let t = el.innerText;
19
19
  if (r1.test(t)) {
20
- el.outerHTML = drawArrows('<kbd>' + t + '</kbd>');
20
+ el.outerHTML = drawArrows(`<kbd>${t}</kbd>`);
21
21
  return;
22
22
  }
23
23
  if (!r2.test(t)) return;
@@ -1 +1 @@
1
- !function(e){const r=["Enter","Up","Down","Left","Right"],t=["&crarr;","&uarr;","&darr;","&larr;","&rarr;"];function n(e){return r.map(((r,n)=>e=e.replace(new RegExp(">"+r+"<","g"),' title="'+r+(n?" Arrow":"")+'">'+t[n]+"<"))),e}const o="Esc|Tab|PageUp|PageDown|Space|Delete|Home|End|PrtScr?|PrintScreen|"+Array(12).fill().map(((e,r)=>"F"+(r+1))).concat(r).join("|"),c="Ctrl|Control|Shift|Alt|Cmd|Command|fn",a=new RegExp("^("+o+"|"+c+")$"),l=new RegExp("^("+c+") [/+] "),i=new RegExp("^("+[o,c,"[a-zA-Z0-9]|Click"].join("|")+")( [/+] )(.*)");e.querySelectorAll(":not(pre) > code").forEach((e=>{if(e.childElementCount>0)return;let r=e.innerText;if(a.test(r))return void(e.outerHTML=n("<kbd>"+r+"</kbd>"));if(!l.test(r))return;let t="";for(r+=" + ";i.test(r);)t+=r.replace(i,"<kbd>$1</kbd>$2"),r=r.replace(i,"$3");""===r&&(e.outerHTML=n(t.replace(/ \+ $/,"")))}))}(document);
1
+ (e=>{const r=["Enter","Up","Down","Left","Right"],t=["&crarr;","&uarr;","&darr;","&larr;","&rarr;"];function n(e){return r.map(((r,n)=>e=e.replace(new RegExp(`>${r}<`,"g"),` title="${r+(n?" Arrow":"")}">${t[n]}<`))),e}const o="Esc|Tab|PageUp|PageDown|Space|Delete|Home|End|PrtScr?|PrintScreen|"+Array(12).fill().map(((e,r)=>"F"+(r+1))).concat(r).join("|"),a="Ctrl|Control|Shift|Alt|Cmd|Command|fn",c=new RegExp(`^(${o}|${a})$`),l=new RegExp(`^(${a}) [/+] `),i=new RegExp(`^(${o}|${a}|[a-zA-Z0-9]|Click)( [/+] )(.*)`);e.querySelectorAll(":not(pre) > code").forEach((e=>{if(e.childElementCount>0)return;let r=e.innerText;if(c.test(r))return void(e.outerHTML=n(`<kbd>${r}</kbd>`));if(!l.test(r))return;let t="";for(r+=" + ";i.test(r);)t+=r.replace(i,"<kbd>$1</kbd>$2"),r=r.replace(i,"$3");""===r&&(e.outerHTML=n(t.replace(/ \+ $/,"")))}))})(document);
@@ -0,0 +1,39 @@
1
+ // add section numbers to headings
2
+ (d => {
3
+ // find the body of the article
4
+ const b = d.querySelector('.article, .body, article, body');
5
+ if (!b) return;
6
+ const hs = b.querySelectorAll('h1, h2, h3, h4, h5, h6');
7
+ if (hs.length === 0) return;
8
+ // normalize Pandoc's .header-section-number class to .section-number
9
+ b.querySelectorAll('span.header-section-number').forEach(el => {
10
+ el.classList.add('section-number');
11
+ });
12
+ // already numbered?
13
+ if (b.querySelector('span.section-number')) {
14
+ // avoid Pandoc's numbering from 0 (e.g., 0.1, 0.1.1, 0.2, ...) when top-level heading is not h1
15
+ b.querySelectorAll('span.section-number').forEach(s => {
16
+ s.innerText = s.innerText.replace(/^(0\.)+/, '');
17
+ });
18
+ return;
19
+ }
20
+ let t0 = 0, t1, dict = [0, 0, 0, 0, 0, 0];
21
+ // generate section numbers x.x.x
22
+ function number_section(i) {
23
+ dict[i]++;
24
+ const n = dict.join('.').replace(/^(0\.)+|(\.0)+$/g, '').replace(/^([0-9]+)$/, '$1.');
25
+ return `<span class="section-number">${n}</span> `;
26
+ };
27
+ hs.forEach(h => {
28
+ // header level: <hN> -> N
29
+ t1 = parseInt(h.tagName.replace(/^h/i, ''));
30
+ // when moving to a higher-level heading, reset lower-level counters to 0
31
+ if (t1 < t0) {
32
+ for (let j = t1; j < dict.length; j++) {
33
+ dict[j] = 0;
34
+ }
35
+ }
36
+ h.insertAdjacentHTML('afterbegin', number_section(t1 - 1));
37
+ t0 = t1;
38
+ });
39
+ })(document);
@@ -0,0 +1 @@
1
+ (e=>{const r=document.querySelector(".article, .body, article, body");if(!r)return;const n=r.querySelectorAll("h1, h2, h3, h4, h5, h6");if(0===n.length)return;if(r.querySelectorAll("span.header-section-number").forEach((e=>{e.classList.add("section-number")})),r.querySelector("span.section-number"))return void r.querySelectorAll("span.section-number").forEach((e=>{e.innerText=e.innerText.replace(/^(0\.)+/,"")}));let t,c=0,a=[0,0,0,0,0,0];n.forEach((e=>{if(t=parseInt(e.tagName.replace(/^h/i,"")),t<c)for(let e=t;e<a.length;e++)a[e]=0;e.insertAdjacentHTML("afterbegin",(a[t-1]++,`<span class="section-number">${a.join(".").replace(/^(0\.)+|(\.0)+$/g,"").replace(/^([0-9]+)$/,"$1.")}</span> `)),c=t}))})();
package/js/right-quote.js CHANGED
@@ -1,5 +1,5 @@
1
1
  // right-align a quote footer if it starts with ---
2
2
  [...document.getElementsByTagName('blockquote')].forEach(quote => {
3
3
  const el = quote.lastElementChild;
4
- if (el?.tagName === 'P' && /^—/.test(el.textContent)) el.style.textAlign = 'right';
4
+ if (el?.tagName === 'P' && /^(—|---)/.test(el.textContent)) el.style.textAlign = 'right';
5
5
  });
@@ -1 +1 @@
1
- [...document.getElementsByTagName("blockquote")].forEach((t=>{const e=t.lastElementChild;"P"===e?.tagName&&/^—/.test(e.textContent)&&(e.style.textAlign="right")}));
1
+ [...document.getElementsByTagName("blockquote")].forEach((t=>{const e=t.lastElementChild;"P"===e?.tagName&&/^(—|---)/.test(e.textContent)&&(e.style.textAlign="right")}));
@@ -0,0 +1,31 @@
1
+ // move footnotes (ids start with fn) and citations (ids start with ref-) to sidenotes
2
+ (d => {
3
+ d.querySelectorAll('.footnotes > ol > li[id^="fn"], #refs > div[id^="ref-"]').forEach(el => {
4
+ // find <a> that points to note id in body
5
+ const h = `a[href="#${el.id}"]`,
6
+ a = d.querySelector(`${h} > sup, sup > ${h}, .citation > ${h}`);
7
+ if (!a) return;
8
+ const a2 = a.parentNode;
9
+ (a.tagName === 'A' ? a : a2).removeAttribute('href');
10
+ const s = d.createElement('div'); // insert a side div next to a2 in body
11
+ s.className = 'side side-right';
12
+ if (/^fn/.test(el.id)) {
13
+ s.innerHTML = el.innerHTML;
14
+ // add footnote number
15
+ s.firstElementChild.insertAdjacentHTML('afterbegin', `<span class="bg-number">${a.innerText}</span> `);
16
+ s.querySelector('a[href^="#fnref"]')?.remove(); // remove backreference
17
+ } else {
18
+ s.innerHTML = el.outerHTML;
19
+ }
20
+ // insert note after the <sup> or <span> that contains a
21
+ a2.after(s);
22
+ a2.classList.add('note-ref');
23
+ el.remove();
24
+ });
25
+ // remove the footnote/citation section if it's empty now
26
+ d.querySelectorAll('.footnotes, #refs').forEach(el => {
27
+ /^\s*$/.test(el.innerText) && el.remove();
28
+ });
29
+ // also add side classes to TOC
30
+ d.getElementById('TOC')?.classList.add('side', 'side-left');
31
+ })(document);
@@ -0,0 +1 @@
1
+ (e=>{e.querySelectorAll('.footnotes > ol > li[id^="fn"], #refs > div[id^="ref-"]').forEach((t=>{const r=`a[href="#${t.id}"]`,n=e.querySelector(`${r} > sup, sup > ${r}, .citation > ${r}`);if(!n)return;const s=n.parentNode;("A"===n.tagName?n:s).removeAttribute("href");const i=e.createElement("div");i.className="side side-right",/^fn/.test(t.id)?(i.innerHTML=t.innerHTML,i.firstElementChild.insertAdjacentHTML("afterbegin",`<span class="bg-number">${n.innerText}</span> `),i.querySelector('a[href^="#fnref"]')?.remove()):i.innerHTML=t.outerHTML,s.after(i),s.classList.add("note-ref"),t.remove()})),e.querySelectorAll(".footnotes, #refs").forEach((e=>{/^\s*$/.test(e.innerText)&&e.remove()})),e.getElementById("TOC")?.classList.add("side","side-left")})(document);
package/js/toc.js ADDED
@@ -0,0 +1,49 @@
1
+ // build TOC using headings
2
+ (d => {
3
+ // find the body of the article
4
+ const b = d.querySelector('.article, .body, article, body');
5
+ if (!b) return;
6
+ const hs = b.querySelectorAll('h1, h2, h3, h4, h5, h6');
7
+ if (hs.length === 0) return;
8
+
9
+ var toc = d.getElementById('TOC');
10
+ toc?.remove(); // delete and rebuild TOC if it has been generated (e.g., by Pandoc)
11
+ toc = d.createElement('div');
12
+ toc.id = 'TOC';
13
+
14
+ let li, ul;
15
+ let p = toc; // the current parent into which we insert child TOC items
16
+ let t1, t0 = 0; // pretend there is a top-level <h0> for the sake of convenience
17
+ hs.forEach(h => {
18
+ t1 = parseInt(h.tagName.replace(/^h/i, ''));
19
+ li = d.createElement('li');
20
+ if (t1 > t0) {
21
+ // lower-level header: create a new ul
22
+ ul = d.createElement('ul');
23
+ ul.appendChild(li);
24
+ p.appendChild(ul);
25
+ } else if (t1 < t0) {
26
+ // higher-level header: go back to upper-level ul
27
+ for (let j = 0; j < t0 - t1; j++) {
28
+ p = p.parentNode.parentNode;
29
+ }
30
+ }
31
+ if (t1 <= t0) p.parentNode.appendChild(li);
32
+ p = li;
33
+ const a = d.createElement('a');
34
+ a.innerHTML = h.innerHTML;
35
+ if (h.id) {
36
+ a.href = '#' + h.id;
37
+ } else {
38
+ // Pandoc's section divs
39
+ const s = h.parentNode;
40
+ if (s.classList.contains('section') && s.id) a.href = '#' + s.id;
41
+ }
42
+ p.appendChild(a);
43
+ t0 = t1;
44
+ });
45
+ b.insertBefore(toc, b.firstChild);
46
+
47
+ // check if headings are numbered
48
+ toc.querySelector('span.section-number') && toc.classList.add('numbered');
49
+ })(document);
package/js/toc.min.js ADDED
@@ -0,0 +1 @@
1
+ (e=>{const t=e.querySelector(".article, .body, article, body");if(!t)return;const r=t.querySelectorAll("h1, h2, h3, h4, h5, h6");if(0===r.length)return;var n=e.getElementById("TOC");let i,l;n?.remove(),(n=e.createElement("div")).id="TOC";let a,d=n,c=0;r.forEach((t=>{if(a=parseInt(t.tagName.replace(/^h/i,"")),i=e.createElement("li"),a>c)l=e.createElement("ul"),l.appendChild(i),d.appendChild(l);else if(a<c)for(let e=0;e<c-a;e++)d=d.parentNode.parentNode;a<=c&&d.parentNode.appendChild(i),d=i;const r=e.createElement("a");if(r.innerHTML=t.innerHTML,t.id)r.href="#"+t.id;else{const e=t.parentNode;e.classList.contains("section")&&e.id&&(r.href="#"+e.id)}d.appendChild(r),c=a})),t.insertBefore(n,t.firstChild),n.querySelector("span.section-number")&&n.classList.add("numbered")})(document);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xiee/utils",
3
- "version": "1.2.14",
3
+ "version": "1.3.1",
4
4
  "description": "Miscellaneous tools and utilities to manipulate HTML pages",
5
5
  "scripts": {
6
6
  "test": "echo \"Error: no test specified\" && exit 1"