@xiee/utils 1.4.3 → 1.5.0

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/README.md CHANGED
@@ -32,6 +32,11 @@ Then the image will have a tooltip on mouseover.
32
32
  Center `<img>`, `<video>`, and `<object>` on a page if they are the only child
33
33
  of their parent element.
34
34
 
35
+ ## copy-button.js
36
+
37
+ Add a copy button to any element (by default, `<pre>` code blocks) on a page.
38
+ See [this post](https://yihui.org/en/2023/09/copy-button/) for details.
39
+
35
40
  ## external-link.js
36
41
 
37
42
  If a link of `<a>` does not start with `http://` or `https://`, add the
@@ -0,0 +1,21 @@
1
+ .copy-button {
2
+ position: absolute;
3
+ display: none;
4
+ cursor: pointer;
5
+ inset: 5px 5px auto auto;
6
+ width: 1em;
7
+ height: 1em;
8
+ border: 1px solid;
9
+ box-shadow: -3px 3px #999;
10
+ }
11
+ :hover > .copy-button {
12
+ display: inline-block;
13
+ }
14
+ .copy-success {
15
+ box-shadow: none;
16
+ background-color: #999;
17
+ transition: box-shadow 300ms ease-out, background-color 300ms ease-out;
18
+ }
19
+ .copy-fail {
20
+ border-style: dotted;
21
+ }
@@ -0,0 +1 @@
1
+ .copy-button{position:absolute;display:none;cursor:pointer;inset:5px 5px auto auto;width:1em;height:1em;border:1px solid;box-shadow:-3px 3px #999}:hover>.copy-button{display:inline-block}.copy-success{box-shadow:none;background-color:#999;transition:box-shadow .3s ease-out,background-color .3s ease-out}.copy-fail{border-style:dotted}
@@ -0,0 +1,22 @@
1
+ // add a button to elements to copy their content: https://yihui.org/en/2023/09/copy-button/
2
+ (d => {
3
+ const cfg = d.currentScript?.dataset;
4
+ d.querySelectorAll(cfg?.selector || 'pre>code').forEach(el => {
5
+ const btn = d.createElement('span'), cls = btn.classList,
6
+ c1 = 'copy-success', c2 = 'copy-fail';
7
+ btn.className = 'copy-button';
8
+ // temporarily add a class to the button (as a feedback to copy action)
9
+ function feedback(c) {
10
+ cls.add(c); setTimeout(() => cls.remove(c), 1000);
11
+ }
12
+ btn.onclick = () => navigator.clipboard.writeText(el.innerText).then(
13
+ () => feedback(c1), () => feedback(c2)
14
+ );
15
+ // add the button to <pre> for <code> because <code>'s innerHTML' may be
16
+ // changed later, e.g., by syntax highlighting libraries
17
+ const p = (el.tagName === 'CODE' && el?.parentNode.tagName === 'PRE') ? el.parentNode : el;
18
+ // add the button only if it has not been added
19
+ p.querySelector('.copy-button') || p.append(btn);
20
+ getComputedStyle(p).position === 'static' && (p.style.position = 'relative');
21
+ });
22
+ })(document);
@@ -0,0 +1 @@
1
+ (e=>{const t=e.currentScript?.dataset;e.querySelectorAll(t?.selector||"pre>code").forEach((t=>{const o=e.createElement("span"),c=o.classList;function a(e){c.add(e),setTimeout((()=>c.remove(e)),1e3)}o.className="copy-button",o.onclick=()=>navigator.clipboard.writeText(t.innerText).then((()=>a("copy-success")),(()=>a("copy-fail")));const n="CODE"===t.tagName&&"PRE"===t?.parentNode.tagName?t.parentNode:t;n.querySelector(".copy-button")||n.append(o),"static"===getComputedStyle(n).position&&(n.style.position="relative")}))})(document);
@@ -26,7 +26,7 @@
26
26
  btn.onclick = (e) => {
27
27
  status = !status;
28
28
  d.querySelectorAll(`details.${cls}`).forEach(el => {
29
- el.toggleAttribute('open', status);
29
+ el.open = status;
30
30
  });
31
31
  };
32
32
  })(document);
@@ -1 +1 @@
1
- (e=>{const t=e.currentScript?.dataset,a="folder";let r=!!t?.open;if(e.querySelectorAll(t?.selector||"pre>code[class],pre[class]").forEach((l=>{const n=e.createElement("details"),o=e.createElement("summary");n.className=a,n.open=r,o.innerText=(t?.label||"Details")+(t?.tagName?` <${l.tagName}>`:""),"CODE"===l.tagName&&"PRE"===l.parentNode.tagName&&(l=l.parentNode),n.append(o),l.before(n),n.append(l)})),!t?.hasOwnProperty("button"))return;const l=e.querySelector(t.parent);let n=e.querySelector(t.button);(n||l)&&(n||(n=e.createElement("button"),n.id="toggle-all",n.innerText=t.buttonLabel||"Toggle Details",l.insertAdjacentElement(t.position||"afterbegin",n)),n.onclick=t=>{r=!r,e.querySelectorAll(`details.${a}`).forEach((e=>{e.toggleAttribute("open",r)}))})})(document);
1
+ (e=>{const t=e.currentScript?.dataset,a="folder";let r=!!t?.open;if(e.querySelectorAll(t?.selector||"pre>code[class],pre[class]").forEach((n=>{const l=e.createElement("details"),o=e.createElement("summary");l.className=a,l.open=r,o.innerText=(t?.label||"Details")+(t?.tagName?` <${n.tagName}>`:""),"CODE"===n.tagName&&"PRE"===n.parentNode.tagName&&(n=n.parentNode),l.append(o),n.before(l),l.append(n)})),!t?.hasOwnProperty("button"))return;const n=e.querySelector(t.parent);let l=e.querySelector(t.button);(l||n)&&(l||(l=e.createElement("button"),l.id="toggle-all",l.innerText=t.buttonLabel||"Toggle Details",n.insertAdjacentElement(t.position||"afterbegin",l)),l.onclick=t=>{r=!r,e.querySelectorAll(`details.${a}`).forEach((e=>{e.open=r}))})})(document);
package/js/fullwidth.js CHANGED
@@ -6,7 +6,7 @@ document.querySelectorAll('pre,table,#TableOfContents').forEach(node => {
6
6
  switch (node.tagName) {
7
7
  case 'PRE':
8
8
  const el = node.firstElementChild;
9
- el?.tagName === 'CODE' && el.scrollWidth > el.offsetWidth && fullwidth(el);
9
+ el?.tagName === 'CODE' && el.scrollWidth > el.offsetWidth && fullwidth(el.parentNode);
10
10
  break;
11
11
  case 'TABLE':
12
12
  const p = node.parentElement;
@@ -1 +1 @@
1
- document.querySelectorAll("pre,table,#TableOfContents").forEach((t=>{function e(t){t.classList.add("fullwidth")}switch(t.tagName){case"PRE":const l=t.firstElementChild;"CODE"===l?.tagName&&l.scrollWidth>l.offsetWidth&&e(l);break;case"TABLE":const a=t.parentElement;a&&a.offsetWidth<t.offsetWidth&&e(t);break;default:t.querySelectorAll("a").forEach((l=>{!t.classList.contains("fullwidth")&&l.getClientRects().length>1&&e(t)}))}}));
1
+ document.querySelectorAll("pre,table,#TableOfContents").forEach((t=>{function e(t){t.classList.add("fullwidth")}switch(t.tagName){case"PRE":const l=t.firstElementChild;"CODE"===l?.tagName&&l.scrollWidth>l.offsetWidth&&e(l.parentNode);break;case"TABLE":const a=t.parentElement;a&&a.offsetWidth<t.offsetWidth&&e(t);break;default:t.querySelectorAll("a").forEach((l=>{!t.classList.contains("fullwidth")&&l.getClientRects().length>1&&e(t)}))}}));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xiee/utils",
3
- "version": "1.4.3",
3
+ "version": "1.5.0",
4
4
  "description": "Miscellaneous tools and utilities to manipulate HTML pages",
5
5
  "scripts": {
6
6
  "test": "echo \"Error: no test specified\" && exit 1"