widebible-embed 1.1.0 → 1.2.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/dist/embed.esm.js +60 -0
- package/dist/embed.min.js +25 -25
- package/package.json +1 -1
package/dist/embed.esm.js
CHANGED
|
@@ -937,6 +937,66 @@ function initSearchWidget(el, config) {
|
|
|
937
937
|
`;
|
|
938
938
|
}
|
|
939
939
|
|
|
940
|
+
// src/web-components.ts
|
|
941
|
+
function makeWidgetElement(widgetType, initFn, domainAttrs) {
|
|
942
|
+
const observed = [...domainAttrs, "theme", "style-variant", "size", "show-original"];
|
|
943
|
+
return class extends HTMLElement {
|
|
944
|
+
static get observedAttributes() {
|
|
945
|
+
return observed;
|
|
946
|
+
}
|
|
947
|
+
connectedCallback() {
|
|
948
|
+
if (this.shadowRoot) return;
|
|
949
|
+
this._syncDataAttrs();
|
|
950
|
+
initFn(this, define_SITE_CONFIG_default);
|
|
951
|
+
}
|
|
952
|
+
attributeChangedCallback(_name, oldVal, newVal) {
|
|
953
|
+
if (oldVal === newVal) return;
|
|
954
|
+
if (!this.shadowRoot) return;
|
|
955
|
+
const shadow = this.shadowRoot;
|
|
956
|
+
while (shadow.firstChild) shadow.firstChild.remove();
|
|
957
|
+
this._syncDataAttrs();
|
|
958
|
+
initFn(this, define_SITE_CONFIG_default);
|
|
959
|
+
}
|
|
960
|
+
/**
|
|
961
|
+
* Bridge element attributes → data-* attributes so the existing widget
|
|
962
|
+
* init functions (which read from dataset) work unchanged.
|
|
963
|
+
*/
|
|
964
|
+
_syncDataAttrs() {
|
|
965
|
+
const attrKey = define_SITE_CONFIG_default.attribute.replace("data-", "");
|
|
966
|
+
this.dataset[attrKey] = widgetType;
|
|
967
|
+
for (const a of domainAttrs) {
|
|
968
|
+
const val = this.getAttribute(a);
|
|
969
|
+
if (val !== null) this.dataset[a] = val;
|
|
970
|
+
}
|
|
971
|
+
const theme = this.getAttribute("theme");
|
|
972
|
+
if (theme !== null) this.dataset.theme = theme;
|
|
973
|
+
const styleVariant = this.getAttribute("style-variant");
|
|
974
|
+
if (styleVariant !== null) this.dataset.style = styleVariant;
|
|
975
|
+
const size = this.getAttribute("size");
|
|
976
|
+
if (size !== null) this.dataset.size = size;
|
|
977
|
+
const showOriginal = this.getAttribute("show-original");
|
|
978
|
+
if (showOriginal !== null) this.dataset.showOriginal = showOriginal;
|
|
979
|
+
}
|
|
980
|
+
};
|
|
981
|
+
}
|
|
982
|
+
function registerWideElements() {
|
|
983
|
+
if (typeof customElements === "undefined") return;
|
|
984
|
+
const definitions = [
|
|
985
|
+
["wide-verse", "verse", initVerseWidget, ["ref", "translation", "show-original"]],
|
|
986
|
+
["wide-chapter", "chapter", initChapterWidget, ["ref"]],
|
|
987
|
+
["wide-person", "person", initPersonWidget, ["slug"]],
|
|
988
|
+
["wide-compare", "compare", initCompareWidget, ["a", "b"]],
|
|
989
|
+
["wide-votd", "votd", initVotdWidget, []],
|
|
990
|
+
["wide-search", "search", initSearchWidget, ["placeholder"]]
|
|
991
|
+
];
|
|
992
|
+
for (const [tagName, widgetType, initFn, attrs] of definitions) {
|
|
993
|
+
if (!customElements.get(tagName)) {
|
|
994
|
+
customElements.define(tagName, makeWidgetElement(widgetType, initFn, attrs));
|
|
995
|
+
}
|
|
996
|
+
}
|
|
997
|
+
}
|
|
998
|
+
registerWideElements();
|
|
999
|
+
|
|
940
1000
|
// src/core.ts
|
|
941
1001
|
function initWidget(el, type, config) {
|
|
942
1002
|
switch (type) {
|
package/dist/embed.min.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/* widebible-embed v1.0.0 | MIT | https://widget.widebible.com */
|
|
2
|
-
"use strict";(()=>{var
|
|
2
|
+
"use strict";(()=>{var u={site:"widebible",name:"WideBible",domain:"widebible.com",apiBase:"https://widebible.com/api/v1/bible",votdEndpoint:"https://widebible.com/api/v1/verse-of-the-day/",searchPath:"/search/",accent:"#4F46E5",attribute:"data-widebible",religion:"christianity",scriptureLabel:"Bible",defaultTranslation:"kjv"};function _(t){return`
|
|
3
3
|
:host {
|
|
4
4
|
display: block;
|
|
5
5
|
font-family: system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;
|
|
@@ -441,19 +441,19 @@
|
|
|
441
441
|
color: var(--muted);
|
|
442
442
|
margin: 2px 0 0 0;
|
|
443
443
|
}
|
|
444
|
-
`}function
|
|
444
|
+
`}function m(t,e){let r=t.attachShadow({mode:"open"}),n=document.createElement("style");return n.textContent=_(e.accent),r.appendChild(n),r}function g(t,e,r){let n=e.dataset.theme||"light",o=e.dataset.size||"default",s=document.createElement("div");return s.className=["wide-widget",r].filter(Boolean).join(" "),s.setAttribute("data-theme",n),s.setAttribute("data-size",o),t.appendChild(s),s}function f(t){t.innerHTML=`
|
|
445
445
|
<div class="wide-loading">
|
|
446
446
|
<span class="wide-spinner"></span>
|
|
447
447
|
Loading\u2026
|
|
448
448
|
</div>
|
|
449
|
-
`}function
|
|
449
|
+
`}function l(t,e,r){t.innerHTML=`
|
|
450
450
|
<div class="wide-error">
|
|
451
451
|
<p>${e}</p>
|
|
452
452
|
<a href="https://${r.domain}" target="_blank" rel="noopener">
|
|
453
453
|
Visit ${r.name}
|
|
454
454
|
</a>
|
|
455
455
|
</div>
|
|
456
|
-
`}var
|
|
456
|
+
`}var w='<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"/><polyline points="15 3 21 3 21 9"/><line x1="10" y1="14" x2="21" y2="3"/></svg>',b='<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/></svg>',W='<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><polyline points="20 6 9 17 4 12"/></svg>',I='<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2"/><circle cx="12" cy="7" r="4"/></svg>';function h(t){return`<span class="wide-powered">Powered by <a href="https://${t.domain}" target="_blank" rel="noopener">${t.name}</a></span>`}function k(t,e){t.addEventListener("click",()=>{var r;(r=navigator.clipboard)==null||r.writeText(e).then(()=>{t.innerHTML=`${W} Copied!`,setTimeout(()=>{t.innerHTML=`${b} Copy`},2e3)}).catch(()=>{let n=document.createElement("textarea");n.value=e,n.style.position="fixed",n.style.opacity="0",document.body.appendChild(n),n.select(),document.execCommand("copy"),document.body.removeChild(n),t.innerHTML=`${W} Copied!`,setTimeout(()=>{t.innerHTML=`${b} Copy`},2e3)})})}function V(t,e,r){if(document.querySelector("script[data-wide-snippet]"))return;let n={"@context":"https://schema.org","@type":"Quotation",text:t.text,spokenByCharacter:t.reference,isPartOf:{"@type":"Book",name:t.book},contributor:{"@type":"Organization",name:r,url:`https://${e}`}},o=document.createElement("script");o.type="application/ld+json",o.setAttribute("data-wide-snippet","true"),o.textContent=JSON.stringify(n),document.head.appendChild(o)}function B(t){let e=t.match(/^(.+?)\s+(\d+):(\d+)$/);if(e)return{book:e[1],chapter:e[2],verse:e[3]};let r=t.match(/^(\d+):(\d+)$/);return r?{book:"",chapter:r[1],verse:r[2]}:null}function O(t,e,r){let n=B(e);if(!n)return"";let o=new URLSearchParams;return n.book&&o.set("book",n.book),o.set("chapter",n.chapter),o.set("verse",n.verse),r&&o.set("translation",r),`${t.apiBase}/verses/?${o.toString()}`}function N(t,e,r,n){let o=r.dataset.size==="compact",s=r.dataset.showOriginal==="true",a=e.reference||r.dataset.ref||"",i=e.translation||n.defaultTranslation,d=e.url||`https://${n.domain}`,c=s&&e.original_text?`<p class="wide-original" lang="${e.original_language||""}">${e.original_text}</p>`:"";t.innerHTML=`
|
|
457
457
|
<div class="wide-ribbon${o?" compact":""}">
|
|
458
458
|
<p class="wide-verse-text${o?" compact":""}">${e.text}</p>
|
|
459
459
|
${c}
|
|
@@ -466,14 +466,14 @@
|
|
|
466
466
|
</div>
|
|
467
467
|
<div class="wide-actions${o?" compact":""}">
|
|
468
468
|
<a class="wide-link" href="${d}" target="_blank" rel="noopener">
|
|
469
|
-
Read on ${n.name} ${
|
|
469
|
+
Read on ${n.name} ${w}
|
|
470
470
|
</a>
|
|
471
471
|
<button class="wide-copy-btn" type="button">
|
|
472
|
-
${
|
|
472
|
+
${b} Copy
|
|
473
473
|
</button>
|
|
474
474
|
</div>
|
|
475
|
-
${
|
|
476
|
-
`;let
|
|
475
|
+
${h(n)}
|
|
476
|
+
`;let p=t.querySelector(".wide-copy-btn");p&&k(p,`${e.text} \u2014 ${a}`)}function T(t,e){let r=m(t,e),n=g(r,t);f(n);let o=t.dataset.ref||"",s=t.dataset.translation||e.defaultTranslation;if(!o){l(n,"Missing data-ref attribute.",e);return}let a=O(e,o,s);if(!a){l(n,`Could not parse reference: "${o}"`,e);return}fetch(a).then(i=>{if(!i.ok)throw new Error(`HTTP ${i.status}`);return i.json()}).then(i=>{let d="results"in i&&Array.isArray(i.results)?i.results[0]:i;if(!d||!d.text)throw new Error("No verse found");if(N(n,d,t,e),t.dataset.noSnippet!=="true"){let c=B(d.reference||o),p=(c==null?void 0:c.book)||d.book||e.scriptureLabel;V({text:d.text,reference:d.reference||o,translation:d.translation||e.defaultTranslation,book:p},e.domain,e.name)}}).catch(()=>{l(n,`Could not load "${o}". Visit ${e.name} to read scripture.`,e)})}function j(t){let e=t.match(/^(.+?)\s+(\d+)$/);if(e)return{book:e[1],chapter:e[2]};let r=t.match(/^(\d+)$/);return r?{book:"",chapter:r[1]}:null}function U(t,e){let r=t.split(/\s+/);return r.length<=e?t:r.slice(0,e).join(" ")+"\u2026"}function C(t,e){let r=m(t,e),n=g(r,t);f(n);let o=t.dataset.ref||"";if(!o){l(n,"Missing data-ref attribute.",e);return}let s=j(o);if(!s){l(n,`Could not parse chapter reference: "${o}"`,e);return}let a=s.book?`${e.apiBase}/chapters/${encodeURIComponent(s.book)}/${s.chapter}/`:`${e.apiBase}/chapters/${s.chapter}/`;fetch(a).then(i=>{if(!i.ok)throw new Error(`HTTP ${i.status}`);return i.json()}).then(i=>{var v;let d=i.title||i.name||o,c=i.book_name||i.book||"",p=i.summary||i.description||"",y=(v=i.verse_count)!=null?v:Array.isArray(i.verses)?i.verses.length:null,$=i.url||`https://${e.domain}`,x=p?U(p,100):"";n.innerHTML=`
|
|
477
477
|
<div class="wide-body">
|
|
478
478
|
<div class="wide-meta">
|
|
479
479
|
${c?`<span class="wide-badge">${c}</span>`:""}
|
|
@@ -484,13 +484,13 @@
|
|
|
484
484
|
</div>
|
|
485
485
|
<div class="wide-actions">
|
|
486
486
|
<a class="wide-link" href="${$}" target="_blank" rel="noopener">
|
|
487
|
-
Read full chapter on ${e.name} ${
|
|
487
|
+
Read full chapter on ${e.name} ${w}
|
|
488
488
|
</a>
|
|
489
489
|
</div>
|
|
490
|
-
${
|
|
491
|
-
`}).catch(()=>{
|
|
490
|
+
${h(e)}
|
|
491
|
+
`}).catch(()=>{l(n,`Could not load chapter "${o}". Visit ${e.name} to read scripture.`,e)})}function F(t,e){let r=t.split(/\s+/);return r.length<=e?t:r.slice(0,e).join(" ")+"\u2026"}function E(t,e){let r=m(t,e),n=g(r,t);f(n);let o=t.dataset.slug||"";if(!o){l(n,"Missing data-slug attribute.",e);return}let s=`${e.apiBase}/people/${encodeURIComponent(o)}/`;fetch(s).then(a=>{if(!a.ok)throw new Error(`HTTP ${a.status}`);return a.json()}).then(a=>{var x,v;let i=a.name||a.full_name||o,d=a.era||a.period||"",c=a.bio||a.description||"",p=(v=(x=a.verse_count)!=null?x:a.mentioned_verses)!=null?v:null,y=a.url||`https://${e.domain}/people/${o}/`,$=c?F(c,150):"";n.innerHTML=`
|
|
492
492
|
<div class="wide-person-header">
|
|
493
|
-
<div class="wide-person-icon">${
|
|
493
|
+
<div class="wide-person-icon">${I}</div>
|
|
494
494
|
<div>
|
|
495
495
|
<p class="wide-person-name">${i}</p>
|
|
496
496
|
${d?`<p class="wide-person-era">${d}</p>`:""}
|
|
@@ -498,17 +498,17 @@
|
|
|
498
498
|
</div>
|
|
499
499
|
<div class="wide-body">
|
|
500
500
|
<div class="wide-meta">
|
|
501
|
-
${
|
|
501
|
+
${p!=null?`<span class="wide-stat">${p} verses</span>`:""}
|
|
502
502
|
</div>
|
|
503
503
|
${$?`<p class="wide-summary">${$}</p>`:""}
|
|
504
504
|
</div>
|
|
505
505
|
<div class="wide-actions">
|
|
506
506
|
<a class="wide-link" href="${y}" target="_blank" rel="noopener">
|
|
507
|
-
Learn more on ${e.name} ${
|
|
507
|
+
Learn more on ${e.name} ${w}
|
|
508
508
|
</a>
|
|
509
509
|
</div>
|
|
510
|
-
${
|
|
511
|
-
`}).catch(()=>{
|
|
510
|
+
${h(e)}
|
|
511
|
+
`}).catch(()=>{l(n,`Could not load "${o}". Visit ${e.name} for biblical figures.`,e)})}function G(t){let e=new URLSearchParams,r=t.match(/^(.+?)\s+(\d+):(\d+)$/);if(r)return e.set("book",r[1]),e.set("chapter",r[2]),e.set("verse",r[3]),e;let n=t.match(/^(\d+):(\d+)$/);return n&&(e.set("chapter",n[1]),e.set("verse",n[2])),e}async function z(t,e){var i,d;let r=G(e),n=`${t.apiBase}/verses/?${r.toString()}`,o=await fetch(n);if(!o.ok)throw new Error(`HTTP ${o.status}`);let s=await o.json(),a=(d=(i=s.results)==null?void 0:i[0])!=null?d:s;if(!(a!=null&&a.text))throw new Error("No verse data");return{text:a.text,reference:a.reference||e,url:a.url}}function L(t,e){let r=m(t,e),n=g(r,t);f(n);let o=t.dataset.a||"",s=t.dataset.b||"";if(!o||!s){l(n,"Missing data-a or data-b attributes.",e);return}Promise.all([z(e,o),z(e,s)]).then(([a,i])=>{let d=`https://${e.domain}/compare/`;n.innerHTML=`
|
|
512
512
|
<div class="wide-compare-grid">
|
|
513
513
|
<div class="wide-compare-col">
|
|
514
514
|
<p class="wide-compare-label">${a.reference}</p>
|
|
@@ -521,11 +521,11 @@
|
|
|
521
521
|
</div>
|
|
522
522
|
<div class="wide-actions">
|
|
523
523
|
<a class="wide-link" href="${d}" target="_blank" rel="noopener">
|
|
524
|
-
Compare on ${e.name} ${
|
|
524
|
+
Compare on ${e.name} ${w}
|
|
525
525
|
</a>
|
|
526
526
|
</div>
|
|
527
|
-
${
|
|
528
|
-
`}).catch(()=>{
|
|
527
|
+
${h(e)}
|
|
528
|
+
`}).catch(()=>{l(n,`Could not load comparison. Visit ${e.name} to compare scripture.`,e)})}var D="wide_votd_";function R(){return new Date().toISOString().slice(0,10)}function q(t){try{let e=`${D}${t}`,r=localStorage.getItem(e);if(!r)return null;let n=JSON.parse(r);return n.date!==R()?(localStorage.removeItem(e),null):n.data}catch(e){return null}}function Q(t,e){try{let r=`${D}${t}`;localStorage.setItem(r,JSON.stringify({date:R(),data:e}))}catch(r){}}function S(t,e){let r=m(t,e),n=g(r,t);f(n);let o=t.dataset.size==="compact";function s(i){let d=i.translation||e.defaultTranslation,c=i.url||`https://${e.domain}`;n.innerHTML=`
|
|
529
529
|
<div class="wide-accent-bar"></div>
|
|
530
530
|
<div class="wide-ribbon${o?" compact":""}">
|
|
531
531
|
<p class="wide-verse-text${o?" compact":""}">${i.text}</p>
|
|
@@ -539,14 +539,14 @@
|
|
|
539
539
|
</div>
|
|
540
540
|
<div class="wide-actions${o?" compact":""}">
|
|
541
541
|
<a class="wide-link" href="${c}" target="_blank" rel="noopener">
|
|
542
|
-
More at ${e.name} ${
|
|
542
|
+
More at ${e.name} ${w}
|
|
543
543
|
</a>
|
|
544
544
|
<button class="wide-copy-btn" type="button">
|
|
545
|
-
${
|
|
545
|
+
${b} Copy
|
|
546
546
|
</button>
|
|
547
547
|
</div>
|
|
548
|
-
${
|
|
549
|
-
`;let
|
|
548
|
+
${h(e)}
|
|
549
|
+
`;let p=n.querySelector(".wide-copy-btn");p&&k(p,`${i.text} \u2014 ${i.reference}`)}let a=q(e.site);if(a){s(a);return}fetch(e.votdEndpoint).then(i=>{if(!i.ok)throw new Error(`HTTP ${i.status}`);return i.json()}).then(i=>{if(!(i!=null&&i.text))throw new Error("No VOTD data");Q(e.site,i),s(i)}).catch(()=>{l(n,`Could not load verse of the day. Visit ${e.name} for daily scripture.`,e)})}function M(t,e){let r=m(t,e),n=g(r,t),o=t.dataset.placeholder||`Search ${e.scriptureLabel}\u2026`;n.innerHTML=`
|
|
550
550
|
<div class="wide-search-wrap">
|
|
551
551
|
<form class="wide-search-form" action="https://${e.domain}${e.searchPath}" method="get" target="_blank">
|
|
552
552
|
<input
|
|
@@ -560,5 +560,5 @@
|
|
|
560
560
|
<button class="wide-search-btn" type="submit">Search</button>
|
|
561
561
|
</form>
|
|
562
562
|
</div>
|
|
563
|
-
${
|
|
564
|
-
`}function T(t,e,r){switch(e){case"verse":
|
|
563
|
+
${h(e)}
|
|
564
|
+
`}function J(t,e,r){let n=[...r,"theme","style-variant","size","show-original"];return class extends HTMLElement{static get observedAttributes(){return n}connectedCallback(){this.shadowRoot||(this._syncDataAttrs(),e(this,u))}attributeChangedCallback(o,s,a){if(s===a||!this.shadowRoot)return;let i=this.shadowRoot;for(;i.firstChild;)i.firstChild.remove();this._syncDataAttrs(),e(this,u)}_syncDataAttrs(){let o=u.attribute.replace("data-","");this.dataset[o]=t;for(let c of r){let p=this.getAttribute(c);p!==null&&(this.dataset[c]=p)}let s=this.getAttribute("theme");s!==null&&(this.dataset.theme=s);let a=this.getAttribute("style-variant");a!==null&&(this.dataset.style=a);let i=this.getAttribute("size");i!==null&&(this.dataset.size=i);let d=this.getAttribute("show-original");d!==null&&(this.dataset.showOriginal=d)}}}function K(){if(typeof customElements=="undefined")return;let t=[["wide-verse","verse",T,["ref","translation","show-original"]],["wide-chapter","chapter",C,["ref"]],["wide-person","person",E,["slug"]],["wide-compare","compare",L,["a","b"]],["wide-votd","votd",S,[]],["wide-search","search",M,["placeholder"]]];for(let[e,r,n,o]of t)customElements.get(e)||customElements.define(e,J(r,n,o))}K();function H(t,e,r){switch(e){case"verse":T(t,r);break;case"chapter":C(t,r);break;case"person":E(t,r);break;case"compare":L(t,r);break;case"votd":S(t,r);break;case"search":M(t,r);break;default:break}}function P(t){document.querySelectorAll(`[${t.attribute}]`).forEach(r=>{if(r.shadowRoot)return;let n=r.dataset[t.attribute.replace("data-","")];n&&H(r,n,t)})}(function(){let e=u;document.readyState==="loading"?document.addEventListener("DOMContentLoaded",()=>P(e)):P(e),new MutationObserver(n=>{n.forEach(o=>{o.addedNodes.forEach(s=>{var i;if(s.nodeType!==Node.ELEMENT_NODE)return;let a=s;if(a.hasAttribute(e.attribute)&&!a.shadowRoot){let d=a.dataset[e.attribute.replace("data-","")];d&&H(a,d,e)}(i=a.querySelectorAll)==null||i.call(a,`[${e.attribute}]`).forEach(d=>{if(!d.shadowRoot){let c=d.dataset[e.attribute.replace("data-","")];c&&H(d,c,e)}})})})}).observe(document.body||document.documentElement,{childList:!0,subtree:!0})})();})();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "widebible-embed",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.2.0",
|
|
4
4
|
"description": "Embed WideBible scripture widgets on any website. Lightweight (~5KB gzipped), zero dependencies, Shadow DOM isolation, 3 themes (light/dark/sepia).",
|
|
5
5
|
"main": "dist/embed.min.js",
|
|
6
6
|
"module": "dist/embed.esm.js",
|