From 884330da3b00083cd115810fd44832cfc753dab9 Mon Sep 17 00:00:00 2001 From: squidfunk Date: Thu, 11 Feb 2021 19:41:34 +0100 Subject: [PATCH] Centralized fetch methods --- .../assets/javascripts/bundle.1ed0f3ef.min.js | 2 + .../javascripts/bundle.1ed0f3ef.min.js.map | 1 + .../assets/javascripts/bundle.48bdffa8.min.js | 2 - .../javascripts/bundle.48bdffa8.min.js.map | 1 - material/assets/manifest.json | 4 +- material/base.html | 2 +- src/assets/javascripts/_/index.ts | 18 ++-- .../javascripts/browser/element/_/index.ts | 2 +- src/assets/javascripts/browser/fetch/index.ts | 83 ++++++++++++++ src/assets/javascripts/browser/index.ts | 1 + .../components/header/title/index.ts | 10 +- .../javascripts/components/search/_/index.ts | 22 ++-- .../components/search/result/index.ts | 4 +- .../components/source/facts/github/index.ts | 14 +-- .../components/source/facts/gitlab/index.ts | 16 +-- src/assets/javascripts/index.ts | 4 +- .../integrations/clipboard/index.ts | 40 ++++--- src/assets/javascripts/integrations/index.ts | 1 + .../integrations/instant/.eslintrc | 5 + .../javascripts/integrations/instant/index.ts | 102 ++++++++++++++++++ .../integrations/search/worker/_/index.ts | 10 +- 21 files changed, 269 insertions(+), 75 deletions(-) create mode 100644 material/assets/javascripts/bundle.1ed0f3ef.min.js create mode 100644 material/assets/javascripts/bundle.1ed0f3ef.min.js.map delete mode 100644 material/assets/javascripts/bundle.48bdffa8.min.js delete mode 100644 material/assets/javascripts/bundle.48bdffa8.min.js.map create mode 100644 src/assets/javascripts/browser/fetch/index.ts create mode 100644 src/assets/javascripts/integrations/instant/.eslintrc create mode 100644 src/assets/javascripts/integrations/instant/index.ts diff --git a/material/assets/javascripts/bundle.1ed0f3ef.min.js b/material/assets/javascripts/bundle.1ed0f3ef.min.js new file mode 100644 index 000000000..2e1746ccf --- /dev/null +++ b/material/assets/javascripts/bundle.1ed0f3ef.min.js @@ -0,0 +1,2 @@ +!function(e,t){for(var n in t)e[n]=t[n]}(window,function(e){function t(t){for(var a,o,i=t[0],s=t[1],p=t[2],b=0,l=[];b"focus"===e),Object(h.a)(e===(document.activeElement instanceof HTMLElement?document.activeElement:void 0)))}var j=n(52),m=n(53),g=n(55),v=n(56),w=n(57),$=n(58);const x=new a.a,y=Object(j.a)(()=>Object(m.a)(new ResizeObserver(e=>{for(const t of e)x.next(t)}))).pipe(Object(o.a)(e=>r.a.pipe(Object(h.a)(e)).pipe(Object(g.a)(()=>e.disconnect()))),Object(v.a)(1));function _(e){return{width:e.offsetWidth,height:e.offsetHeight}}function E(e){return y.pipe(Object(w.a)(t=>t.observe(e)),Object(o.a)(t=>x.pipe(Object($.a)(({target:t})=>t===e),Object(g.a)(()=>t.unobserve(e)),Object(d.a)(({contentRect:e})=>({width:e.width,height:e.height})))),Object(h.a)(_(e)))}var A=n(6);new DOMParser;function S(e,t={credentials:"same-origin"}){return Object(A.a)(fetch(e,t)).pipe(Object($.a)(e=>200===e.status),Object(o.a)(e=>e.json()),Object(v.a)(1))}var k=n(40);n(59);function T(){return new URL(location.href)}function R(){return location.hash.substring(1)}function M(e){const t=matchMedia(e);return Object(i.a)(t,"change").pipe(Object(d.a)(e=>e.matches),Object(h.a)(t.matches))}const C={drawer:u("[data-md-toggle=drawer]"),search:u("[data-md-toggle=search]")};var L=n(43),P=n(60);function U(){return{x:Math.max(0,pageXOffset),y:Math.max(0,pageYOffset)}}function z(){return{width:innerWidth,height:innerHeight}}function N(e,{viewport$:t,header$:n}){const a=t.pipe(Object(P.a)("size")),c=Object(L.a)([a,n]).pipe(Object(d.a)(()=>({x:e.offsetLeft,y:e.offsetTop})));return Object(L.a)([n,t,c]).pipe(Object(d.a)(([{height:e},{offset:t,size:n},{x:a,y:c}])=>({offset:{x:t.x-a,y:t.y-c+e},size:n})))}var I=n(61),Y=n(62);var H=n(25),q=n.n(H),F=n(63);function J(e,t){e.setAttribute("data-md-state",t)}function W(e){e.removeAttribute("data-md-state")}function D(e,t){e.classList.toggle("md-nav__link--active",t)}function Q(e){e.classList.remove("md-nav__link--active")}const B=u("#__config"),V=JSON.parse(B.textContent);function X(){return V}function G(e,t){return void 0!==t?V.translations[e].replace("#",t.toString()):V.translations[e]}function K(e,t){e.appendChild(t)}function Z(e){e.removeAttribute("data-md-state")}function ee(e,t){if("string"==typeof t||"number"==typeof t)e.innerHTML+=t.toString();else if(t instanceof Node)e.appendChild(t);else if(Array.isArray(t))for(const n of t)ee(e,n)}function te(e,t,...n){const a=document.createElement(e);if(t)for(const e of Object.keys(t))"boolean"!=typeof t[e]?a.setAttribute(e,t[e]):t[e]&&a.setAttribute(e,"");for(const e of n)ee(a,e);return a}function ne(e){if(e>999){return((e+1e-6)/1e3).toFixed(+((e-950)%1e3>99))+"k"}return e.toString()}var ae;function ce(e,t){const n=t&ae.PARENT,a=t&ae.TEASER,c=Object.keys(e.terms).filter(t=>!e.terms[t]).map(e=>[te("del",null,e)," "]).flat().slice(0,-1);return te("a",{href:e.location,class:"md-search-result__link",tabIndex:-1},te("article",{class:["md-search-result__article",...n?["md-search-result__article--document"]:[]].join(" "),"data-md-score":e.score.toFixed(2)},n>0&&te("div",{class:"md-search-result__icon md-icon"}),te("h1",{class:"md-search-result__title"},e.title),a>0&&e.text.length>0&&te("p",{class:"md-search-result__teaser"},function(e,t){let n=t;if(e.length>n){for(;" "!==e[n]&&--n>0;);return e.substring(0,n)+"..."}return e}(e.text,320)),a>0&&c.length>0&&te("p",{class:"md-search-result__terms"},G("search.result.term.missing"),": ",c)))}function re(e,t=1/0){const n=[...e],a=n.findIndex(e=>!e.location.includes("#")),[c]=n.splice(a,1);let r=n.findIndex(e=>e.scorece(e,ae.TEASER)),...i.length?[te("details",{class:"md-search-result__more"},te("summary",{tabIndex:-1},i.length>0&&1===i.length?G("search.result.more.one"):G("search.result.more.other",i.length)),i.map(e=>ce(e,ae.TEASER)))]:[]];return te("li",{class:"md-search-result__item"},s)}V.base=new URL(V.base,T()).toString().replace(/\/$/,""),function(e){e[e.TEASER=1]="TEASER",e[e.PARENT=2]="PARENT"}(ae||(ae={}));let oe=0;function ie(e,t){const n=new a.a;if(n.pipe(Object(F.a)(M("(hover)"))).subscribe(([{scroll:t},n])=>{t&&n?function(e,t=0){e.setAttribute("tabindex",t.toString())}(e):function(e){e.removeAttribute("tabindex")}(e)}),q.a.isSupported()){const t=e.closest("pre");t.id="__code_"+oe++,t.insertBefore((c=t.id,te("button",{class:"md-clipboard md-icon",title:G("clipboard.copy"),"data-clipboard-target":`#${c} > code`})),e)}var c;return function(e,{viewport$:t}){return t.pipe(Object(P.a)("size"),Object(d.a)(()=>{const t=_(e);return{scroll:function(e){return{width:e.scrollWidth,height:e.scrollHeight}}(e).width>t.width}}),Object(P.a)("scroll"))}(e,t).pipe(Object(w.a)(n),Object(g.a)(()=>n.complete()),Object(d.a)(t=>Object.assign({ref:e},t)))}var se=n(64);function pe(e,t){const n=new a.a;return n.subscribe(()=>{e.setAttribute("open",""),e.scrollIntoView()}),function(e,{target$:t,print$:n}){return t.pipe(Object(d.a)(e=>e.closest("details:not([open])")),Object($.a)(t=>e===t),Object(se.a)(n),Object(s.a)(e))}(e,t).pipe(Object(w.a)(n),Object(g.a)(()=>n.complete()),Object(s.a)({ref:e}))}const ue=l("table");function be(e){return f(e,ue),f(ue,te("div",{class:"md-typeset__scrollwrap"},te("div",{class:"md-typeset__table"},e))),Object(m.a)({ref:e})}var le=n(74),fe=n(73),de=n(65);function he(e,{message$:t}){const n=new a.a;return n.pipe(Object(de.a)(le.a)).subscribe(({message:t,open:n})=>{!function(e,t){e.firstElementChild.innerHTML=t}(e,t),n?function(e,t){e.setAttribute("data-md-state",t)}(e,"open"):function(e){e.removeAttribute("data-md-state")}(e)}),function(e,{message$:t}){return t.pipe(Object(o.a)(e=>Object(c.a)(Object(m.a)(!0),Object(m.a)(!1).pipe(Object(fe.a)(2e3))).pipe(Object(d.a)(t=>({message:e,open:t})))))}(0,{message$:t}).pipe(Object(w.a)(n),Object(g.a)(()=>n.complete()),Object(d.a)(t=>Object.assign({ref:e},t)))}var Oe=n(66),je=n(41);function me(e,t){const n=new a.a;n.pipe(Object(de.a)(le.a)).subscribe(({active:t})=>{t?function(e,t){e.setAttribute("data-md-state",t)}(e,"active"):function(e){e.removeAttribute("data-md-state")}(e)});const c=p("article h1");return void 0===c?r.a:function(e,{viewport$:t,header$:n}){return N(e,{header$:n,viewport$:t}).pipe(Object(d.a)(({offset:{y:t}})=>{const{height:n}=_(e);return{active:t>=n}}),Object(P.a)("active"))}(c,t).pipe(Object(w.a)(n),Object(g.a)(()=>n.complete()),Object(d.a)(t=>Object.assign({ref:e},t)))}var ge=n(69),ve=n(37),we=n(4);var $e;n(42);function xe(e){return e.split(/"([^"]+)"/g).map((e,t)=>1&t?e.replace(/^\b|^(?![^\x00-\x7F]|$)|\s+/g," +"):e).join("").replace(/"|(?:^|\s+)[*+\-:^~]+(?=\s+|$)/g,"").trim()}function ye(e){return e.type===$e.READY}function _e(e){return e.type===$e.QUERY}function Ee(e){return e.type===$e.RESULT}function Ae({config:e,docs:t,index:n}){1===e.lang.length&&"en"===e.lang[0]&&(e.lang=[G("search.config.lang")]),"[\\s\\-]+"===e.separator&&(e.separator=G("search.config.separator"));return{config:e,docs:t,index:n,pipeline:G("search.config.pipeline").split(/\s*,\s*/).filter(Boolean)}}function Se(e,t){const n=X(),c=new Worker(e),r=new a.a,o=function(e,{tx$:t}){const n=Object(i.a)(e,"message").pipe(Object(d.a)(({data:e})=>e));return t.pipe(Object(I.a)(()=>n,{leading:!0,trailing:!0}),Object(w.a)(t=>e.postMessage(t)),Object(Y.a)(n),Object(k.a)())}(c,{tx$:r}).pipe(Object(d.a)(e=>{if(Ee(e))for(const t of e.data)for(const e of t)e.location=`${n.base}/${e.location}`;return e}),Object(k.a)());return Object(A.a)(t).pipe(Object(d.a)(e=>({type:$e.SETUP,data:Ae(e)}))).subscribe(r.next.bind(r)),{tx$:r,rx$:o}}!function(e){e[e.SETUP=0]="SETUP",e[e.READY=1]="READY",e[e.QUERY=2]="QUERY",e[e.RESULT=3]="RESULT"}($e||($e={}));var ke=n(67),Te=n(68);function Re(e,{tx$:t}){const n=new a.a;return n.pipe(Object(P.a)("value"),Object(d.a)(({value:e})=>({type:$e.QUERY,data:e}))).subscribe(t.next.bind(t)),n.pipe(Object(P.a)("focus")).subscribe(({focus:t})=>{var n,a;t?(a=t,C[n="search"].checked!==a&&C[n].click(),function(e,t){e.placeholder=t}(e,"")):function(e){e.placeholder=G("search.placeholder")}(e)}),Object(i.a)(e.form,"reset").pipe(Object(ke.a)(n.pipe(Object(Te.a)(1)))).subscribe(()=>function(e,t=!0){t?e.focus():e.blur()}(e)),function(e){const t=(null===__search||void 0===__search?void 0:__search.transform)||xe,n=O(e),a=Object(c.a)(Object(i.a)(e,"keyup"),Object(i.a)(e,"focus").pipe(Object(fe.a)(1))).pipe(Object(d.a)(()=>t(e.value)),Object(h.a)(t(e.value)),Object(je.a)());return Object(L.a)([a,n]).pipe(Object(d.a)(([e,t])=>({value:e,focus:t})))}(e).pipe(Object(w.a)(n),Object(g.a)(()=>n.complete()),Object(d.a)(t=>Object.assign({ref:e},t)))}function Me(e,{rx$:t},{query$:n}){const c=new a.a,r=u(":scope > :first-child",e);c.pipe(Object(F.a)(n)).subscribe(([{data:e},{value:t}])=>{t?function(e,t){switch(t){case 0:e.textContent=G("search.result.none");break;case 1:e.textContent=G("search.result.one");break;default:e.textContent=G("search.result.other",t)}}(r,e.length):function(e){e.textContent=G("search.result.placeholder")}(r)});const o=u(":scope > :last-child",e);c.subscribe(({data:e})=>{!function(e){e.innerHTML=""}(o);const t=[...e.map(([e])=>e.score),0];for(let n=0;n({data:e})),Object(h.a)({data:[]})).pipe(Object(w.a)(c),Object(g.a)(()=>c.complete()),Object(d.a)(t=>Object.assign({ref:e},t)))}function Ce(e){const t=X(),n=Se(t.search,(a=t.base+"/search/search_index.json",(null===__search||void 0===__search?void 0:__search.index)||S(a)));var a;const{tx$:r,rx$:o}=n;r.pipe(Object($.a)(_e),Object(ge.a)(o.pipe(Object($.a)(ye))),Object(ve.a)(1)).subscribe(r.next.bind(r));const i=Re(u("[data-md-component=search-query]",e),n);return Object(c.a)(i,Me(u("[data-md-component=search-result]",e),n,{query$:i}))}var Le=n(24);function Pe(e,t){var{header$:n}=t,c=Object(Le.c)(t,["header$"]);const r=new a.a;return r.pipe(Object(de.a)(le.a),Object(F.a)(n)).subscribe({next([{height:t},{height:n}]){!function(e,t){const n=e.firstElementChild;n.style.height=t-2*n.offsetTop+"px"}(e,t),function(e,t){e.style.top=t+"px"}(e,n)},complete(){!function(e){e.style.top=""}(e),function(e){e.firstElementChild.style.height=""}(e)}}),function(e,{viewport$:t,main$:n}){const a=e.parentElement.offsetTop-e.parentElement.parentElement.offsetTop;return Object(L.a)([n,t]).pipe(Object(d.a)(([{offset:e,height:t},{offset:{y:n}}])=>({height:t=t+Math.min(a,Math.max(0,n-e))-a,locked:n>=e+a})),Object(je.a)((e,t)=>e.height===t.height&&e.locked===t.locked))}(e,c).pipe(Object(w.a)(r),Object(g.a)(()=>r.complete()),Object(d.a)(t=>Object.assign({ref:e},t)))}var Ue=n(71),ze=n(70);function Ne(e){const[t]=e.match(/(git(?:hub|lab))/i)||[];switch(t.toLowerCase()){case"github":const[,t,n]=e.match(/^.+github\.com\/([^/]+)\/?([^/]+)?/i);return function(e,t){return S(void 0!==t?`https://api.github.com/repos/${e}/${t}`:"https://api.github.com/users/"+e).pipe(Object(d.a)(e=>{if(void 0!==t){const{stargazers_count:t,forks_count:n}=e;return[ne(t)+" Stars",ne(n)+" Forks"]}{const{public_repos:t}=e;return[ne(t)+" Repositories"]}}),Object(ze.a)([]))}(t,n);case"gitlab":const[,a,c]=e.match(/^.+?([^/]*gitlab[^/]+)\/(.+?)\/?$/i);return function(e,t){return S(`https://${e}/api/v4/projects/${encodeURIComponent(t)}`).pipe(Object(d.a)(({star_count:e,forks_count:t})=>[ne(e)+" Stars",ne(t)+" Forks"]),Object(ze.a)([]))}(a,c);default:return r.a}}let Ie;function Ye(e){const t=new a.a;return t.subscribe(({facts:t})=>{!function(e,t){e.lastElementChild.appendChild(t)}(e,function(e){return te("ul",{class:"md-source__facts"},e.map(e=>te("li",{class:"md-source__fact"},e)))}(t)),function(e,t){e.lastElementChild.setAttribute("data-md-state",t)}(e,"done")}),function(e){const t=function(e){let t=0;for(let n=0,a=e.length;n{const n=sessionStorage.getItem(t);if(n)return Object(m.a)(JSON.parse(n));{const n=Ne(e.href);return n.subscribe(e=>{try{sessionStorage.setItem(t,JSON.stringify(e))}catch(e){}}),n}}).pipe(Object(Ue.a)(()=>r.a),Object($.a)(e=>e.length>0),Object(d.a)(e=>({facts:e})),Object(v.a)(1)))}(e).pipe(Object(w.a)(t),Object(g.a)(()=>t.complete()),Object(d.a)(t=>Object.assign({ref:e},t)))}function He(e,t){const n=new a.a;return n.pipe(Object(de.a)(le.a)).subscribe({next({hidden:t}){t?function(e,t){e.setAttribute("data-md-state",t)}(e,"hidden"):Z(e)},complete(){Z(e)}}),function(e,{viewport$:t,header$:n}){return N(e,{header$:n,viewport$:t}).pipe(Object(d.a)(({offset:{y:e}})=>({hidden:e>=10})),Object(P.a)("hidden"))}(e,t).pipe(Object(w.a)(n),Object(g.a)(()=>n.complete()),Object(d.a)(t=>Object.assign({ref:e},t)))}var qe=n(75),Fe=n(72);function Je(e,t){const n=new a.a;n.pipe(Object(de.a)(le.a)).subscribe(({prev:e,next:t})=>{for(const[e]of t)Q(e),W(e);for(const[t,[n]]of e.entries())D(n,t===e.length-1),J(n,"blur")});return function(e,{viewport$:t,header$:n}){const a=new Map;for(const t of e){const e=p(`[id="${decodeURIComponent(t.hash.substring(1))}"]`);void 0!==e&&a.set(t,e)}const c=n.pipe(Object(d.a)(e=>24+e.height));return E(document.body).pipe(Object(P.a)("height"),Object(d.a)(()=>{let e=[];return[...a].reduce((t,[n,c])=>{for(;e.length;){if(!(a.get(e[e.length-1]).tagName>=c.tagName))break;e.pop()}let r=c.offsetTop;for(;!r&&c.parentElement;)r=(c=c.parentElement).offsetTop;return t.set([...e=[...e,n]].reverse(),r)},new Map)}),Object(o.a)(e=>Object(L.a)([c,t]).pipe(Object(qe.a)(([e,t],[n,{offset:{y:a}}])=>{for(;t.length;){const[,c]=t[0];if(!(c-n=a))break;t=[e.pop(),...t]}return[e,t]},[[],[...e]]),Object(je.a)((e,t)=>e[0]===t[0]&&e[1]===t[1])))).pipe(Object(d.a)(([e,t])=>({prev:e.map(([e])=>e),next:t.map(([e])=>e)})),Object(h.a)({prev:[],next:[]}),Object(Fe.a)(2,1),Object(d.a)(([e,t])=>e.prev.lengthn.complete()),Object(d.a)(t=>Object.assign({ref:e},t)))}document.documentElement.classList.remove("no-js"),document.documentElement.classList.add("js");const We=Object(i.a)(window,"hashchange").pipe(Object(d.a)(R),Object(h.a)(R()),Object($.a)(e=>e.length>0),Object(k.a)()).pipe(Object(o.a)(e=>Object(m.a)(p(`[id="${e}"]`)))),De=Object(L.a)([Object(c.a)(Object(i.a)(window,"scroll",{passive:!0}),Object(i.a)(window,"resize",{passive:!0})).pipe(Object(d.a)(U),Object(h.a)(U())),Object(i.a)(window,"resize",{passive:!0}).pipe(Object(d.a)(z),Object(h.a)(z()))]).pipe(Object(d.a)(([e,t])=>({offset:e,size:t})),Object(v.a)(1)),Qe=M("(min-width: 960px)"),Be=M("(min-width: 1220px)"),Ve=Object(c.a)(M("print").pipe(Object($.a)(Boolean)),Object(i.a)(window,"beforeprint")).pipe(Object(s.a)(void 0)),Xe=u("[data-md-component=header]"),Ge=u("[data-md-component=main]"),Ke=(Ze=Xe,Object(j.a)(()=>{const e=getComputedStyle(Ze);return Object(m.a)("sticky"===e.position||"-webkit-sticky"===e.position)}).pipe(Object(Oe.a)(E(Ze)),Object(d.a)(([e,{height:t}])=>({sticky:e,height:e?t:0})),Object(je.a)((e,t)=>e.sticky===t.sticky&&e.height===t.height)));var Ze;const et=function(e,{viewport$:t,header$:n}){const a=n.pipe(Object(d.a)(({height:e})=>e),Object(je.a)()),c=a.pipe(Object(o.a)(()=>E(e).pipe(Object(d.a)(({height:t})=>({top:e.offsetTop,bottom:e.offsetTop+t})),Object(P.a)("bottom"))));return Object(L.a)([a,c,t]).pipe(Object(d.a)(([e,{top:t,bottom:n},{offset:{y:a},size:{height:c}}])=>({offset:t-e,height:c=Math.max(0,c-Math.max(0,t-a,e)-Math.max(0,c+a-n)),active:t-e<=a})),Object(je.a)((e,t)=>e.offset===t.offset&&e.height===t.height&&e.active===t.active),Object(v.a)(1))}(Ge,{header$:Ke,viewport$:De}),tt=new a.a;!function({message$:e}){q.a.isSupported()||new we.a(e=>{new q.a("[data-clipboard-target], [data-clipboard-text]").on("success",t=>e.next(t))}).subscribe(()=>e.next(G("clipboard.copied")))}({message$:tt});function nt(e,t){return e.pipe(Object(o.a)(e=>e?t():r.a))}Object(c.a)(...b("[data-md-component=content]").map(e=>function(e,{target$:t,viewport$:n,print$:a}){return Object(c.a)(...b("pre > code",e).map(e=>ie(e,{viewport$:n})),...b("table:not([class])",e).map(e=>be(e)),...b("details",e).map(e=>pe(e,{target$:t,print$:a})))}(e,{target$:We,viewport$:De,print$:Ve})),...b("[data-md-component=dialog]").map(e=>he(e,{message$:tt})),...b("[data-md-component=header]").map(e=>function(e,{header$:t,main$:n}){const c=new a.a;return c.pipe(Object(P.a)("active"),Object(de.a)(le.a)).subscribe(({active:t})=>{t?function(e,t){e.setAttribute("data-md-state",t)}(e,"shadow"):function(e){e.removeAttribute("data-md-state")}(e)}),n.subscribe(e=>c.next(e)),t.pipe(Object(d.a)(t=>Object.assign({ref:e},t)),Object(v.a)(1))}(e,{viewport$:De,header$:Ke,main$:et})),...b("[data-md-component=header-title]").map(e=>me(e,{viewport$:De,header$:Ke})),...b("[data-md-component=search]").map(e=>Ce(e)),...b("[data-md-component=sidebar]").map(e=>"navigation"===e.getAttribute("data-md-type")?nt(Be,()=>Pe(e,{viewport$:De,header$:Ke,main$:et})):nt(Qe,()=>Pe(e,{viewport$:De,header$:Ke,main$:et}))),...b("[data-md-component=source]").map(e=>Ye(e)),...b("[data-md-component=tabs]").map(e=>He(e,{viewport$:De,header$:Ke})),...b("[data-md-component=toc]").map(e=>Je(e,{viewport$:De,header$:Ke}))).subscribe(console.log)}})); +//# sourceMappingURL=bundle.1ed0f3ef.min.js.map \ No newline at end of file diff --git a/material/assets/javascripts/bundle.1ed0f3ef.min.js.map b/material/assets/javascripts/bundle.1ed0f3ef.min.js.map new file mode 100644 index 000000000..29383a599 --- /dev/null +++ b/material/assets/javascripts/bundle.1ed0f3ef.min.js.map @@ -0,0 +1 @@ +{"version":3,"sources":["webpack:///webpack/bootstrap","webpack:///./src/assets/javascripts/browser/element/_/index.ts","webpack:///./src/assets/javascripts/browser/element/focus/index.ts","webpack:///./src/assets/javascripts/browser/element/size/index.ts","webpack:///./src/assets/javascripts/browser/fetch/index.ts","webpack:///./src/assets/javascripts/browser/location/_/index.ts","webpack:///./src/assets/javascripts/browser/location/hash/index.ts","webpack:///./src/assets/javascripts/browser/media/index.ts","webpack:///./src/assets/javascripts/browser/toggle/index.ts","webpack:///./src/assets/javascripts/browser/viewport/offset/index.ts","webpack:///./src/assets/javascripts/browser/viewport/size/index.ts","webpack:///./src/assets/javascripts/browser/viewport/_/index.ts","webpack:///./src/assets/javascripts/actions/anchor/index.ts","webpack:///./src/assets/javascripts/_/index.ts","webpack:///./src/assets/javascripts/actions/search/result/index.ts","webpack:///./src/assets/javascripts/actions/tabs/index.ts","webpack:///./src/assets/javascripts/utilities/jsx/index.ts","webpack:///./src/assets/javascripts/utilities/string/index.ts","webpack:///./src/assets/javascripts/templates/search/index.tsx","webpack:///./src/assets/javascripts/components/content/code/index.ts","webpack:///./src/assets/javascripts/actions/_/index.ts","webpack:///./src/assets/javascripts/templates/clipboard/index.tsx","webpack:///./src/assets/javascripts/components/content/details/index.ts","webpack:///./src/assets/javascripts/components/content/table/index.ts","webpack:///./src/assets/javascripts/templates/table/index.tsx","webpack:///./src/assets/javascripts/components/dialog/index.ts","webpack:///./src/assets/javascripts/actions/dialog/index.ts","webpack:///./src/assets/javascripts/components/header/title/index.ts","webpack:///./src/assets/javascripts/actions/header/title/index.ts","webpack:///./src/assets/javascripts/integrations/search/worker/message/index.ts","webpack:///./src/assets/javascripts/integrations/search/query/transform/index.ts","webpack:///./src/assets/javascripts/integrations/search/worker/_/index.ts","webpack:///./src/assets/javascripts/browser/worker/index.ts","webpack:///./src/assets/javascripts/components/search/query/index.ts","webpack:///./src/assets/javascripts/actions/search/query/index.ts","webpack:///./src/assets/javascripts/components/search/result/index.ts","webpack:///./src/assets/javascripts/components/search/_/index.ts","webpack:///./src/assets/javascripts/components/sidebar/index.ts","webpack:///./src/assets/javascripts/actions/sidebar/index.ts","webpack:///./src/assets/javascripts/components/source/facts/_/index.ts","webpack:///./src/assets/javascripts/components/source/facts/github/index.ts","webpack:///./src/assets/javascripts/components/source/facts/gitlab/index.ts","webpack:///./src/assets/javascripts/components/source/_/index.ts","webpack:///./src/assets/javascripts/actions/source/index.ts","webpack:///./src/assets/javascripts/templates/source/index.tsx","webpack:///./src/assets/javascripts/components/tabs/index.ts","webpack:///./src/assets/javascripts/components/toc/index.ts","webpack:///./src/assets/javascripts/index.ts","webpack:///./src/assets/javascripts/components/header/_/index.ts","webpack:///./src/assets/javascripts/components/main/index.ts","webpack:///./src/assets/javascripts/integrations/clipboard/index.ts","webpack:///./src/assets/javascripts/components/content/_/index.ts","webpack:///./src/assets/javascripts/actions/header/_/index.ts"],"names":["webpackJsonpCallback","data","moduleId","chunkId","chunkIds","moreModules","executeModules","i","resolves","length","Object","prototype","hasOwnProperty","call","installedChunks","push","modules","parentJsonpFunction","shift","deferredModules","apply","checkDeferredModules","result","deferredModule","fulfilled","j","depId","splice","__webpack_require__","s","installedModules","0","exports","module","l","m","c","d","name","getter","o","defineProperty","enumerable","get","r","Symbol","toStringTag","value","t","mode","__esModule","ns","create","key","bind","n","object","property","p","jsonpArray","window","oldJsonpFunction","slice","getElement","selector","node","document","querySelector","undefined","getElementOrThrow","el","ReferenceError","getElements","Array","from","querySelectorAll","createElement","tagName","replaceElement","source","target","replaceWith","watchElementFocus","merge","fromEvent","pipe","map","type","startWith","activeElement","HTMLElement","entry$","Subject","observer$","defer","of","ResizeObserver","entries","entry","next","switchMap","resize","finalize","disconnect","shareReplay","getElementSize","width","offsetWidth","height","offsetHeight","watchElementSize","tap","observer","observe","filter","unobserve","contentRect","DOMParser","fetchJSON","url","options","credentials","fetch","res","status","json","getLocation","URL","location","href","getLocationHash","hash","substring","watchMedia","query","media","matchMedia","ev","matches","toggles","drawer","search","getViewportOffset","x","Math","max","pageXOffset","y","pageYOffset","getViewportSize","innerWidth","innerHeight","watchViewportAt","viewport$","header$","size$","distinctUntilKeyChanged","offset$","combineLatest","offsetLeft","offsetTop","offset","size","setAnchorState","state","setAttribute","resetAnchorState","removeAttribute","setAnchorActive","classList","toggle","resetAnchorActive","remove","script","JSON","parse","textContent","configuration","translation","translations","replace","toString","addToSearchResultList","child","appendChild","resetTabsState","innerHTML","Node","isArray","h","tag","attributes","children","attr","keys","round","toFixed","Flag","renderSearchDocument","flag","parent","PARENT","teaser","TEASER","missing","terms","flat","class","tabIndex","join","score","title","text","truncate","renderSearchResult","threshold","Infinity","docs","findIndex","doc","includes","article","index","best","more","section","base","mountCodeBlock","internal$","withLatestFrom","subscribe","scroll","hover","setFocusable","resetFocusable","isSupported","closest","id","insertBefore","visible","scrollWidth","scrollHeight","getElementContentSize","watchCodeBlock","complete","ref","mountDetails","scrollIntoView","target$","print$","details","mergeWith","mapTo","watchDetails","sentinel","mountDataTable","mountDialog","message$","observeOn","animationFrame","message","open","firstElementChild","setDialogMessage","setDialogState","resetDialogState","_el","delay","watchDialog","mountHeaderTitle","active","setHeaderTitleState","resetHeaderTitleState","headline","watchHeaderTitle","SearchMessageType","defaultTransform","split","trim","isSearchReadyMessage","READY","isSearchQueryMessage","QUERY","isSearchResultMessage","RESULT","setupSearchIndex","config","lang","separator","pipeline","Boolean","setupSearchWorker","worker","Worker","tx$","rx$","throttle","leading","trailing","postMessage","switchMapTo","share","watchWorker","SETUP","mountSearchQuery","focus","checked","click","placeholder","setSearchQueryPlaceholder","resetSearchQueryPlaceholder","form","takeUntil","takeLast","blur","setElementFocus","fn","__search","transform","focus$","value$","distinctUntilChanged","watchSearchQuery","mountSearchResult","query$","meta","setSearchResultMeta","resetSearchResultMeta","list","resetSearchResultList","thresholds","mountSearch","sample","take","mountSidebar","scrollwrap","style","setSidebarHeight","top","setSidebarOffset","resetSidebarOffset","resetSidebarHeight","main$","adjust","parentElement","min","locked","a","b","watchSidebar","fetchSourceFacts","match","toLowerCase","user","repo","stargazers_count","forks_count","public_repos","defaultIfEmpty","fetchSourceFactsFromGitHub","slug","project","encodeURIComponent","star_count","fetchSourceFactsFromGitLab","fetch$","mountSource","facts","lastElementChild","setSourceFacts","fact","renderSourceFacts","setSourceState","digest","len","charCodeAt","sessionStorage","getItem","setItem","stringify","err","catchError","watchSource","mountTabs","hidden","setTabsState","watchTabs","mountTableOfContents","prev","anchor","anchors","table","Map","decodeURIComponent","set","adjust$","header","body","path","reduce","pop","reverse","scan","bufferCount","watchTableOfContents","documentElement","add","passive","tablet$","screen$","main","styles","getComputedStyle","position","combineLatestWith","sticky","border$","bottom","watchMain","Observable","subscriber","on","setupClipboardJS","at","toggle$","factory","mountContent","setHeaderState","resetHeaderState","mountHeader","getAttribute","console","log"],"mappings":"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","file":"assets/javascripts/bundle.1ed0f3ef.min.js","sourcesContent":[" \t// install a JSONP callback for chunk loading\n \tfunction webpackJsonpCallback(data) {\n \t\tvar chunkIds = data[0];\n \t\tvar moreModules = data[1];\n \t\tvar executeModules = data[2];\n\n \t\t// add \"moreModules\" to the modules object,\n \t\t// then flag all \"chunkIds\" as loaded and fire callback\n \t\tvar moduleId, chunkId, i = 0, resolves = [];\n \t\tfor(;i < chunkIds.length; i++) {\n \t\t\tchunkId = chunkIds[i];\n \t\t\tif(Object.prototype.hasOwnProperty.call(installedChunks, chunkId) && installedChunks[chunkId]) {\n \t\t\t\tresolves.push(installedChunks[chunkId][0]);\n \t\t\t}\n \t\t\tinstalledChunks[chunkId] = 0;\n \t\t}\n \t\tfor(moduleId in moreModules) {\n \t\t\tif(Object.prototype.hasOwnProperty.call(moreModules, moduleId)) {\n \t\t\t\tmodules[moduleId] = moreModules[moduleId];\n \t\t\t}\n \t\t}\n \t\tif(parentJsonpFunction) parentJsonpFunction(data);\n\n \t\twhile(resolves.length) {\n \t\t\tresolves.shift()();\n \t\t}\n\n \t\t// add entry modules from loaded chunk to deferred list\n \t\tdeferredModules.push.apply(deferredModules, executeModules || []);\n\n \t\t// run deferred modules when all chunks ready\n \t\treturn checkDeferredModules();\n \t};\n \tfunction checkDeferredModules() {\n \t\tvar result;\n \t\tfor(var i = 0; i < deferredModules.length; i++) {\n \t\t\tvar deferredModule = deferredModules[i];\n \t\t\tvar fulfilled = true;\n \t\t\tfor(var j = 1; j < deferredModule.length; j++) {\n \t\t\t\tvar depId = deferredModule[j];\n \t\t\t\tif(installedChunks[depId] !== 0) fulfilled = false;\n \t\t\t}\n \t\t\tif(fulfilled) {\n \t\t\t\tdeferredModules.splice(i--, 1);\n \t\t\t\tresult = __webpack_require__(__webpack_require__.s = deferredModule[0]);\n \t\t\t}\n \t\t}\n\n \t\treturn result;\n \t}\n\n \t// The module cache\n \tvar installedModules = {};\n\n \t// object to store loaded and loading chunks\n \t// undefined = chunk not loaded, null = chunk preloaded/prefetched\n \t// Promise = chunk loading, 0 = chunk loaded\n \tvar installedChunks = {\n \t\t0: 0\n \t};\n\n \tvar deferredModules = [];\n\n \t// The require function\n \tfunction __webpack_require__(moduleId) {\n\n \t\t// Check if module is in cache\n \t\tif(installedModules[moduleId]) {\n \t\t\treturn installedModules[moduleId].exports;\n \t\t}\n \t\t// Create a new module (and put it into the cache)\n \t\tvar module = installedModules[moduleId] = {\n \t\t\ti: moduleId,\n \t\t\tl: false,\n \t\t\texports: {}\n \t\t};\n\n \t\t// Execute the module function\n \t\tmodules[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n\n \t\t// Flag the module as loaded\n \t\tmodule.l = true;\n\n \t\t// Return the exports of the module\n \t\treturn module.exports;\n \t}\n\n\n \t// expose the modules object (__webpack_modules__)\n \t__webpack_require__.m = modules;\n\n \t// expose the module cache\n \t__webpack_require__.c = installedModules;\n\n \t// define getter function for harmony exports\n \t__webpack_require__.d = function(exports, name, getter) {\n \t\tif(!__webpack_require__.o(exports, name)) {\n \t\t\tObject.defineProperty(exports, name, { enumerable: true, get: getter });\n \t\t}\n \t};\n\n \t// define __esModule on exports\n \t__webpack_require__.r = function(exports) {\n \t\tif(typeof Symbol !== 'undefined' && Symbol.toStringTag) {\n \t\t\tObject.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });\n \t\t}\n \t\tObject.defineProperty(exports, '__esModule', { value: true });\n \t};\n\n \t// create a fake namespace object\n \t// mode & 1: value is a module id, require it\n \t// mode & 2: merge all properties of value into the ns\n \t// mode & 4: return value when already ns object\n \t// mode & 8|1: behave like require\n \t__webpack_require__.t = function(value, mode) {\n \t\tif(mode & 1) value = __webpack_require__(value);\n \t\tif(mode & 8) return value;\n \t\tif((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;\n \t\tvar ns = Object.create(null);\n \t\t__webpack_require__.r(ns);\n \t\tObject.defineProperty(ns, 'default', { enumerable: true, value: value });\n \t\tif(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key));\n \t\treturn ns;\n \t};\n\n \t// getDefaultExport function for compatibility with non-harmony modules\n \t__webpack_require__.n = function(module) {\n \t\tvar getter = module && module.__esModule ?\n \t\t\tfunction getDefault() { return module['default']; } :\n \t\t\tfunction getModuleExports() { return module; };\n \t\t__webpack_require__.d(getter, 'a', getter);\n \t\treturn getter;\n \t};\n\n \t// Object.prototype.hasOwnProperty.call\n \t__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };\n\n \t// __webpack_public_path__\n \t__webpack_require__.p = \"\";\n\n \tvar jsonpArray = window[\"webpackJsonp\"] = window[\"webpackJsonp\"] || [];\n \tvar oldJsonpFunction = jsonpArray.push.bind(jsonpArray);\n \tjsonpArray.push = webpackJsonpCallback;\n \tjsonpArray = jsonpArray.slice();\n \tfor(var i = 0; i < jsonpArray.length; i++) webpackJsonpCallback(jsonpArray[i]);\n \tvar parentJsonpFunction = oldJsonpFunction;\n\n\n \t// add entry module to deferred list\n \tdeferredModules.push([48,1]);\n \t// run deferred modules when ready\n \treturn checkDeferredModules();\n","/*\n * Copyright (c) 2016-2020 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Retrieve an element matching the query selector\n *\n * @template T - Element type\n *\n * @param selector - Query selector\n * @param node - Node of reference\n *\n * @returns Element or nothing\n */\nexport function getElement(\n selector: T, node?: ParentNode\n): HTMLElementTagNameMap[T]\n\nexport function getElement(\n selector: string, node?: ParentNode\n): T | undefined\n\nexport function getElement(\n selector: string, node: ParentNode = document\n): T | undefined {\n return node.querySelector(selector) || undefined\n}\n\n/**\n * Retrieve an element matching a query selector or throw a reference error\n *\n * @template T - Element type\n *\n * @param selector - Query selector\n * @param node - Node of reference\n *\n * @returns Element\n */\nexport function getElementOrThrow(\n selector: T, node?: ParentNode\n): HTMLElementTagNameMap[T]\n\nexport function getElementOrThrow(\n selector: string, node?: ParentNode\n): T\n\nexport function getElementOrThrow(\n selector: string, node: ParentNode = document\n): T {\n const el = getElement(selector, node)\n if (typeof el === \"undefined\")\n throw new ReferenceError(\n `Missing element: expected \"${selector}\" to be present`\n )\n return el\n}\n\n/**\n * Retrieve the currently active element\n *\n * @returns Element or nothing\n */\nexport function getActiveElement(): HTMLElement | undefined {\n return document.activeElement instanceof HTMLElement\n ? document.activeElement\n : undefined\n}\n\n/**\n * Retrieve all elements matching the query selector\n *\n * @template T - Element type\n *\n * @param selector - Query selector\n * @param node - Node of reference\n *\n * @returns Elements\n */\nexport function getElements(\n selector: T, node?: ParentNode\n): HTMLElementTagNameMap[T][]\n\nexport function getElements(\n selector: string, node?: ParentNode\n): T[]\n\nexport function getElements(\n selector: string, node: ParentNode = document\n): T[] {\n return Array.from(node.querySelectorAll(selector))\n}\n\n/* ------------------------------------------------------------------------- */\n\n/**\n * Create an element\n *\n * @template T - Tag name type\n *\n * @param tagName - Tag name\n *\n * @returns Element\n */\nexport function createElement(\n tagName: T\n): HTMLElementTagNameMap[T] {\n return document.createElement(tagName)\n}\n\n/**\n * Replace an element with another element\n *\n * @param source - Source element\n * @param target - Target element\n */\nexport function replaceElement(\n source: HTMLElement, target: Node\n): void {\n source.replaceWith(target)\n}\n","/*\n * Copyright (c) 2016-2020 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport { Observable, fromEvent, merge } from \"rxjs\"\nimport { map, startWith } from \"rxjs/operators\"\n\nimport { getActiveElement } from \"../_\"\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Set element focus\n *\n * @param el - Element\n * @param value - Whether the element should be focused\n */\nexport function setElementFocus(\n el: HTMLElement, value = true\n): void {\n if (value)\n el.focus()\n else\n el.blur()\n}\n\n/* ------------------------------------------------------------------------- */\n\n/**\n * Watch element focus\n *\n * @param el - Element\n *\n * @returns Element focus observable\n */\nexport function watchElementFocus(\n el: HTMLElement\n): Observable {\n return merge(\n fromEvent(el, \"focus\"),\n fromEvent(el, \"blur\")\n )\n .pipe(\n map(({ type }) => type === \"focus\"),\n startWith(el === getActiveElement())\n )\n}\n","/*\n * Copyright (c) 2016-2020 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport {\n NEVER,\n Observable,\n Subject,\n defer,\n of\n} from \"rxjs\"\nimport {\n filter,\n finalize,\n map,\n shareReplay,\n startWith,\n switchMap,\n tap\n} from \"rxjs/operators\"\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Element offset\n */\nexport interface ElementSize {\n width: number /* Element width */\n height: number /* Element height */\n}\n\n/* ----------------------------------------------------------------------------\n * Data\n * ------------------------------------------------------------------------- */\n\n/**\n * Resize observer entry subject\n */\nconst entry$ = new Subject()\n\n/**\n * Resize observer observable\n *\n * This observable will create a `ResizeObserver` on the first subscription\n * and will automatically terminate it when there are no more subscribers.\n * It's quite important to centralize observation in a single `ResizeObserver`,\n * as the performance difference can be quite dramatic, as the link shows.\n *\n * @see https://bit.ly/3iIYfEm - Google Groups on performance\n */\nconst observer$ = defer(() => of(\n new ResizeObserver(entries => {\n for (const entry of entries)\n entry$.next(entry)\n })\n))\n .pipe(\n switchMap(resize => NEVER.pipe(startWith(resize))\n .pipe(\n finalize(() => resize.disconnect())\n )\n ),\n shareReplay(1)\n )\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Retrieve element size\n *\n * @param el - Element\n *\n * @returns Element size\n */\nexport function getElementSize(el: HTMLElement): ElementSize {\n return {\n width: el.offsetWidth,\n height: el.offsetHeight\n }\n}\n\n/**\n * Retrieve element content size, i.e. including overflowing content\n *\n * @param el - Element\n *\n * @returns Element size\n */\nexport function getElementContentSize(el: HTMLElement): ElementSize {\n return {\n width: el.scrollWidth,\n height: el.scrollHeight\n }\n}\n\n/* ------------------------------------------------------------------------- */\n\n/**\n * Watch element size\n *\n * This function returns an observable that will subscribe to a single internal\n * instance of `ResizeObserver` upon subscription, and emit resize events until\n * termination. Note that this function should not be called with the same\n * element twice, as the first unsubscription will terminate observation.\n *\n * @param el - Element\n *\n * @returns Element size observable\n */\nexport function watchElementSize(\n el: HTMLElement\n): Observable {\n return observer$\n .pipe(\n tap(observer => observer.observe(el)),\n switchMap(observer => entry$\n .pipe(\n filter(({ target }) => target === el),\n finalize(() => observer.unobserve(el)),\n map(({ contentRect }) => ({\n width: contentRect.width,\n height: contentRect.height\n }))\n )\n ),\n startWith(getElementSize(el))\n )\n}\n","/*\n * Copyright (c) 2016-2020 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport { Observable, from } from \"rxjs\"\nimport {\n filter,\n map,\n shareReplay,\n switchMap\n} from \"rxjs/operators\"\n\n/* ----------------------------------------------------------------------------\n * Data\n * ------------------------------------------------------------------------- */\n\n/**\n * XML parser\n */\nconst dom = new DOMParser()\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Fetch given URL as JSON\n *\n * @template T - Data type\n *\n * @param url - Request URL\n * @param options - Request options\n *\n * @returns Data observable\n */\nexport function fetchJSON(\n url: string, options: RequestInit = { credentials: \"same-origin\" }\n): Observable {\n return from(fetch(url, options))\n .pipe(\n filter(res => res.status === 200),\n switchMap(res => res.json()),\n shareReplay(1)\n )\n}\n\n/**\n * Fetch given URL as XML\n *\n * @param url - Request URL\n * @param options - Request options\n *\n * @returns Data observable\n */\nexport function fetchXML(\n url: string, options: RequestInit = { credentials: \"same-origin\" }\n): Observable {\n return from(fetch(url, options))\n .pipe(\n filter(res => res.status === 200),\n switchMap(res => res.json()),\n map(res => dom.parseFromString(res, \"text/xml\")),\n shareReplay(1)\n )\n}\n","/*\n * Copyright (c) 2016-2020 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport { BehaviorSubject, Subject } from \"rxjs\"\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Retrieve location\n *\n * This function will return a `URL` object (and not `Location`) in order to\n * normalize typings across the application. Furthermore, locations need to be\n * tracked without setting them and `Location` is a singleton which represents\n * the current location.\n *\n * @returns URL\n */\nexport function getLocation(): URL {\n return new URL(location.href)\n}\n\n/**\n * Set location\n *\n * @param url - URL to change to\n */\nexport function setLocation(url: URL): void {\n location.href = url.href\n}\n\n/* ------------------------------------------------------------------------- */\n\n/**\n * Watch location\n *\n * @returns Location subject\n */\nexport function watchLocation(): Subject {\n return new BehaviorSubject(getLocation())\n}\n","/*\n * Copyright (c) 2016-2020 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport { Observable, fromEvent, of } from \"rxjs\"\nimport { filter, map, share, startWith, switchMap } from \"rxjs/operators\"\n\nimport { createElement, getElement } from \"~/browser\"\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Retrieve location hash\n *\n * @returns Location hash\n */\nexport function getLocationHash(): string {\n return location.hash.substring(1)\n}\n\n/**\n * Set location hash\n *\n * Setting a new fragment identifier via `location.hash` will have no effect\n * if the value doesn't change. When a new fragment identifier is set, we want\n * the browser to target the respective element at all times, which is why we\n * use this dirty little trick.\n *\n * @param hash - Location hash\n */\nexport function setLocationHash(hash: string): void {\n const el = createElement(\"a\")\n el.href = hash\n el.addEventListener(\"click\", ev => ev.stopPropagation())\n el.click()\n}\n\n/* ------------------------------------------------------------------------- */\n\n/**\n * Watch location hash\n *\n * @returns Location hash observable\n */\nexport function watchLocationHash(): Observable {\n return fromEvent(window, \"hashchange\")\n .pipe(\n map(getLocationHash),\n startWith(getLocationHash()),\n filter(hash => hash.length > 0),\n share()\n )\n}\n\n/**\n * Watch location target\n *\n * @returns Location target observable\n */\nexport function watchLocationTarget(): Observable {\n return watchLocationHash()\n .pipe(\n switchMap(id => of(getElement(`[id=\"${id}\"]`)!))\n )\n}\n","/*\n * Copyright (c) 2016-2020 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport { Observable, fromEvent, merge } from \"rxjs\"\nimport { filter, map, mapTo, startWith } from \"rxjs/operators\"\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Watch media query\n *\n * @param query - Media query\n *\n * @returns Media observable\n */\nexport function watchMedia(query: string): Observable {\n const media = matchMedia(query)\n return fromEvent(media, \"change\")\n .pipe(\n map(ev => ev.matches),\n startWith(media.matches)\n )\n}\n\n/**\n * Watch print mode, cross-browser\n *\n * @returns Print observable\n */\nexport function watchPrint(): Observable {\n return merge(\n watchMedia(\"print\").pipe(filter(Boolean)), /* Webkit */\n fromEvent(window, \"beforeprint\") /* IE, FF */\n )\n .pipe(\n mapTo(undefined)\n )\n}\n","/*\n * Copyright (c) 2016-2020 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport { Observable, fromEvent } from \"rxjs\"\nimport { map, startWith } from \"rxjs/operators\"\n\nimport { getElementOrThrow } from \"../element\"\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Toggle\n */\nexport type Toggle =\n | \"drawer\" /* Toggle for drawer */\n | \"search\" /* Toggle for search */\n\n/* ----------------------------------------------------------------------------\n * Data\n * ------------------------------------------------------------------------- */\n\n/**\n * Toggle map\n */\nconst toggles: Record = {\n drawer: getElementOrThrow(\"[data-md-toggle=drawer]\"),\n search: getElementOrThrow(\"[data-md-toggle=search]\")\n}\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Retrieve the value of a toggle\n *\n * @param name - Toggle\n *\n * @returns Toggle value\n */\nexport function getToggle(name: Toggle): boolean {\n return toggles[name].checked\n}\n\n/**\n * Set toggle\n *\n * Simulating a click event seems to be the most cross-browser compatible way\n * of changing the value while also emitting a `change` event. Before, Material\n * used `CustomEvent` to programmatically change the value of a toggle, but this\n * is a much simpler and cleaner solution which doesn't require a polyfill.\n *\n * @param name - Toggle\n * @param value - Toggle value\n */\nexport function setToggle(name: Toggle, value: boolean): void {\n if (toggles[name].checked !== value)\n toggles[name].click()\n}\n\n/* ------------------------------------------------------------------------- */\n\n/**\n * Watch toggle\n *\n * @param name - Toggle\n *\n * @returns Toggle value observable\n */\nexport function watchToggle(name: Toggle): Observable {\n const el = toggles[name]\n return fromEvent(el, \"change\")\n .pipe(\n map(() => el.checked),\n startWith(el.checked)\n )\n}\n","/*\n * Copyright (c) 2016-2020 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport { Observable, fromEvent, merge } from \"rxjs\"\nimport { map, startWith } from \"rxjs/operators\"\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Viewport offset\n */\nexport interface ViewportOffset {\n x: number /* Horizontal offset */\n y: number /* Vertical offset */\n}\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Retrieve viewport offset\n *\n * On iOS Safari, viewport offset can be negative due to overflow scrolling.\n * As this may induce strange behaviors downstream, we'll just limit it to 0.\n *\n * @returns Viewport offset\n */\nexport function getViewportOffset(): ViewportOffset {\n return {\n x: Math.max(0, pageXOffset),\n y: Math.max(0, pageYOffset)\n }\n}\n\n/**\n * Set viewport offset\n *\n * @param offset - Viewport offset\n */\nexport function setViewportOffset(\n { x, y }: Partial\n): void {\n window.scrollTo(x || 0, y || 0)\n}\n\n/* ------------------------------------------------------------------------- */\n\n/**\n * Watch viewport offset\n *\n * @returns Viewport offset observable\n */\nexport function watchViewportOffset(): Observable {\n return merge(\n fromEvent(window, \"scroll\", { passive: true }),\n fromEvent(window, \"resize\", { passive: true })\n )\n .pipe(\n map(getViewportOffset),\n startWith(getViewportOffset())\n )\n}\n","/*\n * Copyright (c) 2016-2020 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport { Observable, fromEvent } from \"rxjs\"\nimport { map, startWith } from \"rxjs/operators\"\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Viewport size\n */\nexport interface ViewportSize {\n width: number /* Viewport width */\n height: number /* Viewport height */\n}\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Retrieve viewport size\n *\n * @returns Viewport size\n */\nexport function getViewportSize(): ViewportSize {\n return {\n width: innerWidth,\n height: innerHeight\n }\n}\n\n/* ------------------------------------------------------------------------- */\n\n/**\n * Watch viewport size\n *\n * @returns Viewport size observable\n */\nexport function watchViewportSize(): Observable {\n return fromEvent(window, \"resize\", { passive: true })\n .pipe(\n map(getViewportSize),\n startWith(getViewportSize())\n )\n}\n","/*\n * Copyright (c) 2016-2020 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport { Observable, combineLatest } from \"rxjs\"\nimport {\n distinctUntilKeyChanged,\n map,\n shareReplay\n} from \"rxjs/operators\"\n\nimport { Header } from \"~/components\"\n\nimport {\n ViewportOffset,\n watchViewportOffset\n} from \"../offset\"\nimport {\n ViewportSize,\n watchViewportSize\n} from \"../size\"\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Viewport\n */\nexport interface Viewport {\n offset: ViewportOffset /* Viewport offset */\n size: ViewportSize /* Viewport size */\n}\n\n/* ----------------------------------------------------------------------------\n * Helper types\n * ------------------------------------------------------------------------- */\n\n/**\n * Watch at options\n */\ninterface WatchAtOptions {\n viewport$: Observable /* Viewport observable */\n header$: Observable
/* Header observable */\n}\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Watch viewport\n *\n * @returns Viewport observable\n */\nexport function watchViewport(): Observable {\n return combineLatest([\n watchViewportOffset(),\n watchViewportSize()\n ])\n .pipe(\n map(([offset, size]) => ({ offset, size })),\n shareReplay(1)\n )\n}\n\n/**\n * Watch viewport relative to element\n *\n * @param el - Element\n * @param options - Options\n *\n * @returns Viewport observable\n */\nexport function watchViewportAt(\n el: HTMLElement, { viewport$, header$ }: WatchAtOptions\n): Observable {\n const size$ = viewport$\n .pipe(\n distinctUntilKeyChanged(\"size\")\n )\n\n /* Compute element offset */\n const offset$ = combineLatest([size$, header$])\n .pipe(\n map((): ViewportOffset => ({\n x: el.offsetLeft,\n y: el.offsetTop\n }))\n )\n\n /* Compute relative viewport, return hot observable */\n return combineLatest([header$, viewport$, offset$])\n .pipe(\n map(([{ height }, { offset, size }, { x, y }]) => ({\n offset: {\n x: offset.x - x,\n y: offset.y - y + height\n },\n size\n }))\n )\n}\n","/*\n * Copyright (c) 2016-2020 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Set anchor state\n *\n * @param el - Anchor element\n * @param state - Anchor state\n */\nexport function setAnchorState(\n el: HTMLElement, state: \"blur\"\n): void {\n el.setAttribute(\"data-md-state\", state)\n}\n\n/**\n * Reset anchor state\n *\n * @param el - Anchor element\n */\nexport function resetAnchorState(\n el: HTMLElement\n): void {\n el.removeAttribute(\"data-md-state\")\n}\n\n/* ------------------------------------------------------------------------- */\n\n/**\n * Set anchor active\n *\n * @param el - Anchor element\n * @param value - Whether the anchor is active\n */\nexport function setAnchorActive(\n el: HTMLElement, value: boolean\n): void {\n el.classList.toggle(\"md-nav__link--active\", value)\n}\n\n/**\n * Reset anchor active\n *\n * @param el - Anchor element\n */\nexport function resetAnchorActive(\n el: HTMLElement\n): void {\n el.classList.remove(\"md-nav__link--active\")\n}\n","/*\n * Copyright (c) 2016-2020 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport { getElementOrThrow, getLocation } from \"~/browser\"\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Feature flag\n */\nexport type Flag =\n | \"header.autohide\" /* Hide header */\n | \"navigation.tabs\" /* Tabs navigation */\n | \"navigation.instant\" /* Instant loading */\n\n/* ------------------------------------------------------------------------- */\n\n/**\n * Translation\n */\nexport type Translation =\n | \"clipboard.copy\" /* Copy to clipboard */\n | \"clipboard.copied\" /* Copied to clipboard */\n | \"search.config.lang\" /* Search language */\n | \"search.config.pipeline\" /* Search pipeline */\n | \"search.config.separator\" /* Search separator */\n | \"search.placeholder\" /* Search */\n | \"search.result.placeholder\" /* Type to start searching */\n | \"search.result.none\" /* No matching documents */\n | \"search.result.one\" /* 1 matching document */\n | \"search.result.other\" /* # matching documents */\n | \"search.result.more.one\" /* 1 more on this page */\n | \"search.result.more.other\" /* # more on this page */\n | \"search.result.term.missing\" /* Missing */\n\n/**\n * Translations\n */\nexport type Translations = Record\n\n/* ------------------------------------------------------------------------- */\n\n/**\n * Configuration\n */\nexport interface Config {\n base: string /* Base URL */\n features: Flag[] /* Feature flags */\n translations: Translations /* Translations */\n search: string /* Search worker URL */\n}\n\n/* ----------------------------------------------------------------------------\n * Data\n * ------------------------------------------------------------------------- */\n\n/**\n * Retrieve global configuration and make base URL absolute\n */\nconst script = getElementOrThrow(\"#__config\")\nconst config: Config = JSON.parse(script.textContent!)\nconfig.base = new URL(config.base, getLocation())\n .toString()\n .replace(/\\/$/, \"\")\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Retrieve global configuration\n *\n * @returns Global configuration\n */\nexport function configuration(): Config {\n return config\n}\n\n/**\n * Check whether a feature flag is enabled\n *\n * @param flag - Feature flag\n *\n * @returns Test result\n */\nexport function feature(flag: Flag): boolean {\n return config.features.includes(flag)\n}\n\n/**\n * Retrieve the translation for the given key\n *\n * @param key - Key to be translated\n * @param value - Value to be replaced\n *\n * @returns Translation\n */\nexport function translation(\n key: Translation, value?: string | number\n): string {\n return typeof value !== \"undefined\"\n ? config.translations[key].replace(\"#\", value.toString())\n : config.translations[key]\n}\n","/*\n * Copyright (c) 2016-2020 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport { translation } from \"~/_\"\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Set number of search results\n *\n * @param el - Search result metadata element\n * @param value - Number of results\n */\nexport function setSearchResultMeta(\n el: HTMLElement, value: number\n): void {\n switch (value) {\n\n /* No results */\n case 0:\n el.textContent = translation(\"search.result.none\")\n break\n\n /* One result */\n case 1:\n el.textContent = translation(\"search.result.one\")\n break\n\n /* Multiple result */\n default:\n el.textContent = translation(\"search.result.other\", value)\n }\n}\n\n/**\n * Reset number of search results\n *\n * @param el - Search result metadata element\n */\nexport function resetSearchResultMeta(\n el: HTMLElement\n): void {\n el.textContent = translation(\"search.result.placeholder\")\n}\n\n/* ------------------------------------------------------------------------- */\n\n/**\n * Add an element to the search result list\n *\n * @param el - Search result list element\n * @param child - Search result element\n */\nexport function addToSearchResultList(\n el: HTMLElement, child: Element\n): void {\n el.appendChild(child)\n}\n\n/**\n * Reset search result list\n *\n * @param el - Search result list element\n */\nexport function resetSearchResultList(\n el: HTMLElement\n): void {\n el.innerHTML = \"\"\n}\n","/*\n * Copyright (c) 2016-2020 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Set tabs state\n *\n * @param el - Tabs element\n * @param state - Tabs state\n */\nexport function setTabsState(\n el: HTMLElement, state: \"hidden\"\n): void {\n el.setAttribute(\"data-md-state\", state)\n}\n\n/**\n * Reset tabs state\n *\n * @param el - Tabs element\n */\nexport function resetTabsState(\n el: HTMLElement\n): void {\n el.removeAttribute(\"data-md-state\")\n}\n","/*\n * Copyright (c) 2016-2020 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport { JSX as JSXInternal } from \"preact\"\n\n/* ----------------------------------------------------------------------------\n * Helper types\n * ------------------------------------------------------------------------- */\n\n/**\n * HTML attributes\n */\ntype Attributes =\n & JSXInternal.HTMLAttributes\n & JSXInternal.SVGAttributes\n & Record\n\n/**\n * Child element\n */\ntype Child =\n | HTMLElement\n | Text\n | string\n | number\n\n/* ----------------------------------------------------------------------------\n * Helper functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Append a child node to an element\n *\n * @param el - Element\n * @param child - Child node(s)\n */\nfunction appendChild(el: HTMLElement, child: Child | Child[]): void {\n\n /* Handle primitive types (including raw HTML) */\n if (typeof child === \"string\" || typeof child === \"number\") {\n el.innerHTML += child.toString()\n\n /* Handle nodes */\n } else if (child instanceof Node) {\n el.appendChild(child)\n\n /* Handle nested children */\n } else if (Array.isArray(child)) {\n for (const node of child)\n appendChild(el, node)\n }\n}\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * JSX factory\n *\n * @param tag - HTML tag\n * @param attributes - HTML attributes\n * @param children - Child elements\n *\n * @returns Element\n */\nexport function h(\n tag: string, attributes: Attributes | null, ...children: Child[]\n): HTMLElement {\n const el = document.createElement(tag)\n\n /* Set attributes, if any */\n if (attributes)\n for (const attr of Object.keys(attributes))\n if (typeof attributes[attr] !== \"boolean\")\n el.setAttribute(attr, attributes[attr])\n else if (attributes[attr])\n el.setAttribute(attr, \"\")\n\n /* Append child nodes */\n for (const child of children)\n appendChild(el, child)\n\n /* Return element */\n return el\n}\n\n/* ----------------------------------------------------------------------------\n * Namespace\n * ------------------------------------------------------------------------- */\n\nexport declare namespace h {\n namespace JSX {\n type Element = HTMLElement\n type IntrinsicElements = JSXInternal.IntrinsicElements\n }\n}\n","/*\n * Copyright (c) 2016-2020 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Truncate a string after the given number of characters\n *\n * This is not a very reasonable approach, since the summaries kind of suck.\n * It would be better to create something more intelligent, highlighting the\n * search occurrences and making a better summary out of it, but this note was\n * written three years ago, so who knows if we'll ever fix it.\n *\n * @param value - Value to be truncated\n * @param n - Number of characters\n *\n * @returns Truncated value\n */\nexport function truncate(value: string, n: number): string {\n let i = n\n if (value.length > i) {\n while (value[i] !== \" \" && --i > 0) { /* keep eating */ }\n return `${value.substring(0, i)}...`\n }\n return value\n}\n\n/**\n * Round a number for display with repository facts\n *\n * This is a reverse-engineered version of GitHub's weird rounding algorithm\n * for stars, forks and all other numbers. While all numbers below `1,000` are\n * returned as-is, bigger numbers are converted to fixed numbers:\n *\n * - `1,049` => `1k`\n * - `1,050` => `1.1k`\n * - `1,949` => `1.9k`\n * - `1,950` => `2k`\n *\n * @param value - Original value\n *\n * @returns Rounded value\n */\nexport function round(value: number): string {\n if (value > 999) {\n const digits = +((value - 950) % 1000 > 99)\n return `${((value + 0.000001) / 1000).toFixed(digits)}k`\n } else {\n return value.toString()\n }\n}\n\n/**\n * Simple hash function\n *\n * @see https://bit.ly/2wsVjJ4 - Original source\n *\n * @param value - Value to be hashed\n *\n * @returns Hash as 32bit integer\n */\nexport function hash(value: string): number {\n let h = 0\n for (let i = 0, len = value.length; i < len; i++) {\n h = ((h << 5) - h) + value.charCodeAt(i)\n h |= 0 // Convert to 32bit integer\n }\n return h\n}\n","/*\n * Copyright (c) 2016-2020 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport { translation } from \"~/_\"\nimport {\n SearchDocument,\n SearchMetadata,\n SearchResult\n} from \"~/integrations/search\"\nimport { h, truncate } from \"~/utilities\"\n\n/* ----------------------------------------------------------------------------\n * Helper types\n * ------------------------------------------------------------------------- */\n\n/**\n * Render flag\n */\nconst enum Flag {\n TEASER = 1, /* Render teaser */\n PARENT = 2 /* Render as parent */\n}\n\n/* ----------------------------------------------------------------------------\n * Helper function\n * ------------------------------------------------------------------------- */\n\n/**\n * Render a search document\n *\n * @param section - Search document\n * @param flag - Render flags\n *\n * @returns Element\n */\nfunction renderSearchDocument(\n document: SearchDocument & SearchMetadata, flag: Flag\n) {\n const parent = flag & Flag.PARENT\n const teaser = flag & Flag.TEASER\n\n /* Render missing query terms */\n const missing = Object.keys(document.terms)\n .filter(key => !document.terms[key])\n .map(key => [{key}, \" \"])\n .flat()\n .slice(0, -1)\n\n /* Render article or section, depending on flags */\n const url = document.location\n return (\n \n \n {parent > 0 &&
}\n

{document.title}

\n {teaser > 0 && document.text.length > 0 &&\n

\n {truncate(document.text, 320)}\n

\n }\n {teaser > 0 && missing.length > 0 &&\n

\n {translation(\"search.result.term.missing\")}: {...missing}\n

\n }\n \n
\n )\n}\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Render a search result\n *\n * @param result - Search result\n * @param threshold - Score threshold\n *\n * @returns Element\n */\nexport function renderSearchResult(\n result: SearchResult, threshold: number = Infinity\n) {\n const docs = [...result]\n\n /* Find and extract parent article */\n const parent = docs.findIndex(doc => !doc.location.includes(\"#\"))\n const [article] = docs.splice(parent, 1)\n\n /* Determine last index above threshold */\n let index = docs.findIndex(doc => doc.score < threshold)\n if (index === -1)\n index = docs.length\n\n /* Partition sections */\n const best = docs.slice(0, index)\n const more = docs.slice(index)\n\n /* Render children */\n const children = [\n renderSearchDocument(article, Flag.PARENT | +(!parent && index === 0)),\n ...best.map(section => renderSearchDocument(section, Flag.TEASER)),\n ...more.length ? [\n
\n \n {more.length > 0 && more.length === 1\n ? translation(\"search.result.more.one\")\n : translation(\"search.result.more.other\", more.length)\n }\n \n {...more.map(section => renderSearchDocument(section, Flag.TEASER))}\n
\n ] : []\n ]\n\n /* Render search result */\n return (\n
  • \n {children}\n
  • \n )\n}\n","/*\n * Copyright (c) 2016-2020 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport ClipboardJS from \"clipboard\"\nimport { Observable, Subject } from \"rxjs\"\nimport {\n distinctUntilKeyChanged,\n finalize,\n map,\n tap,\n withLatestFrom\n} from \"rxjs/operators\"\n\nimport { resetFocusable, setFocusable } from \"~/actions\"\nimport {\n Viewport,\n getElementContentSize,\n getElementSize,\n watchMedia\n} from \"~/browser\"\nimport { renderClipboardButton } from \"~/templates\"\n\nimport { Component } from \"../../_\"\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Code block\n */\nexport interface CodeBlock {\n scroll: boolean /* Code block overflows */\n}\n\n/* ----------------------------------------------------------------------------\n * Helper types\n * ------------------------------------------------------------------------- */\n\n/**\n * Watch options\n */\ninterface WatchOptions {\n viewport$: Observable /* Viewport observable */\n}\n\n/**\n * Mount options\n */\ninterface MountOptions {\n viewport$: Observable /* Viewport observable */\n}\n\n/* ----------------------------------------------------------------------------\n * Data\n * ------------------------------------------------------------------------- */\n\n/**\n * Global index for Clipboard.js integration\n */\nlet index = 0\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Watch code block\n *\n * @param el - Code block element\n * @param options - Options\n *\n * @returns Code block observable\n */\nexport function watchCodeBlock(\n el: HTMLElement, { viewport$ }: WatchOptions\n): Observable {\n return viewport$\n .pipe(\n distinctUntilKeyChanged(\"size\"),\n map(() => {\n const visible = getElementSize(el)\n const content = getElementContentSize(el)\n return {\n scroll: content.width > visible.width\n }\n }),\n distinctUntilKeyChanged(\"scroll\")\n )\n}\n\n/**\n * Mount code block\n *\n * This function ensures that overflowing code blocks are focusable by keyboard,\n * so they can be scrolled without a mouse to improve on accessibility.\n *\n * @param el - Code block element\n * @param options - Options\n *\n * @returns Code block component observable\n */\nexport function mountCodeBlock(\n el: HTMLElement, options: MountOptions\n): Observable> {\n const internal$ = new Subject()\n internal$\n .pipe(\n withLatestFrom(watchMedia(\"(hover)\"))\n )\n .subscribe(([{ scroll }, hover]) => {\n if (scroll && hover)\n setFocusable(el)\n else\n resetFocusable(el)\n })\n\n /* Inject button for Clipboard.js integration */\n if (ClipboardJS.isSupported()) {\n const parent = el.closest(\"pre\")!\n parent.id = `__code_${index++}`\n parent.insertBefore(\n renderClipboardButton(parent.id),\n el\n )\n }\n\n /* Create and return component */\n return watchCodeBlock(el, options)\n .pipe(\n tap(internal$),\n finalize(() => internal$.complete()),\n map(state => ({ ref: el, ...state }))\n )\n}\n","/*\n * Copyright (c) 2016-2020 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Set focusable property\n *\n * @param el - Element\n * @param value - Tabindex value\n */\nexport function setFocusable(\n el: HTMLElement, value = 0\n): void {\n el.setAttribute(\"tabindex\", value.toString())\n}\n\n/**\n * Reset focusable property\n *\n * @param el - Element\n */\nexport function resetFocusable(\n el: HTMLElement\n): void {\n el.removeAttribute(\"tabindex\")\n}\n","/*\n * Copyright (c) 2016-2020 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport { translation } from \"~/_\"\nimport { h } from \"~/utilities\"\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Render a 'copy-to-clipboard' button\n *\n * @param id - Unique identifier\n *\n * @returns Element\n */\nexport function renderClipboardButton(id: string) {\n return (\n code`}\n >\n )\n}\n","/*\n * Copyright (c) 2016-2020 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport { Observable, Subject } from \"rxjs\"\nimport {\n filter,\n finalize,\n map,\n mapTo,\n mergeWith,\n tap\n} from \"rxjs/operators\"\n\nimport { Component } from \"../../_\"\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Details\n */\nexport interface Details {}\n\n/* ----------------------------------------------------------------------------\n * Helper types\n * ------------------------------------------------------------------------- */\n\n/**\n * Watch options\n */\ninterface WatchOptions {\n target$: Observable /* Location target observable */\n print$: Observable /* Print observable */\n}\n\n/**\n * Mount options\n */\ninterface MountOptions {\n target$: Observable /* Location target observable */\n print$: Observable /* Print observable */\n}\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Watch details\n *\n * @param el - Details element\n * @param options - Options\n *\n * @returns Details observable\n */\nexport function watchDetails(\n el: HTMLDetailsElement, { target$, print$ }: WatchOptions\n): Observable
    {\n return target$\n .pipe(\n map(target => target.closest(\"details:not([open])\")!),\n filter(details => el === details),\n mergeWith(print$),\n mapTo(el)\n )\n}\n\n/**\n * Mount details\n *\n * This function ensures that `details` tags are opened prior to printing, so\n * the whole content of the page is included and on anchor jumps.\n *\n * @param el - Details element\n * @param options - Options\n *\n * @returns Details component observable\n */\nexport function mountDetails(\n el: HTMLDetailsElement, options: MountOptions\n): Observable> {\n const internal$ = new Subject
    ()\n internal$.subscribe(() => {\n el.setAttribute(\"open\", \"\")\n el.scrollIntoView()\n })\n\n /* Create and return component */\n return watchDetails(el, options)\n .pipe(\n tap(internal$),\n finalize(() => internal$.complete()),\n mapTo({ ref: el })\n )\n}\n","/*\n * Copyright (c) 2016-2020 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport { Observable, of } from \"rxjs\"\n\nimport { createElement, replaceElement } from \"~/browser\"\nimport { renderTable } from \"~/templates\"\n\nimport { Component } from \"../../_\"\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Data table\n */\nexport interface DataTable {}\n\n/* ----------------------------------------------------------------------------\n * Data\n * ------------------------------------------------------------------------- */\n\n/**\n * Sentinel for replacement\n */\nconst sentinel = createElement(\"table\")\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Mount data table\n *\n * @param el - Data table element\n *\n * @returns Data table component observable\n */\nexport function mountDataTable(\n el: HTMLElement\n): Observable> {\n replaceElement(el, sentinel)\n replaceElement(sentinel, renderTable(el))\n\n /* Create and return component */\n return of({ ref: el })\n}\n","/*\n * Copyright (c) 2016-2020 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport { h } from \"utilities\"\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Render a table inside a wrapper to improve scrolling on mobile\n *\n * @param table - Table element\n *\n * @returns Element\n */\nexport function renderTable(table: HTMLElement) {\n return (\n
    \n
    \n {table}\n
    \n
    \n )\n}\n","/*\n * Copyright (c) 2016-2020 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport {\n Observable,\n Subject,\n animationFrameScheduler,\n merge,\n of\n} from \"rxjs\"\nimport {\n delay,\n finalize,\n map,\n observeOn,\n switchMap,\n tap\n} from \"rxjs/operators\"\n\nimport {\n resetDialogState,\n setDialogMessage,\n setDialogState\n} from \"~/actions\"\n\nimport { Component } from \"../_\"\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Dialog\n */\nexport interface Dialog {\n message: string /* Dialog message */\n open: boolean /* Dialog is visible */\n}\n\n/* ----------------------------------------------------------------------------\n * Helper types\n * ------------------------------------------------------------------------- */\n\n/**\n * Watch options\n */\ninterface WatchOptions {\n message$: Subject /* Message subject */\n}\n\n/**\n * Mount options\n */\ninterface MountOptions {\n message$: Subject /* Message subject */\n}\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Watch dialog\n *\n * @param _el - Dialog element\n * @param options - Options\n *\n * @returns Dialog observable\n */\nexport function watchDialog(\n _el: HTMLElement, { message$ }: WatchOptions\n): Observable {\n return message$\n .pipe(\n switchMap(message => merge(\n of(true),\n of(false).pipe(delay(2000))\n )\n .pipe(\n map(open => ({ message, open }))\n )\n )\n )\n}\n\n/**\n * Mount dialog\n *\n * @param el - Dialog element\n * @param options - Options\n *\n * @returns Dialog component observable\n */\nexport function mountDialog(\n el: HTMLElement, { message$ }: MountOptions\n): Observable> {\n const internal$ = new Subject()\n internal$\n .pipe(\n observeOn(animationFrameScheduler)\n )\n .subscribe(({ message, open }) => {\n setDialogMessage(el, message)\n if (open)\n setDialogState(el, \"open\")\n else\n resetDialogState(el)\n })\n\n /* Create and return component */\n return watchDialog(el, { message$ })\n .pipe(\n tap(internal$),\n finalize(() => internal$.complete()),\n map(state => ({ ref: el, ...state }))\n )\n}\n","/*\n * Copyright (c) 2016-2020 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Set dialog message\n *\n * @param el - Dialog element\n * @param value - Dialog message\n */\nexport function setDialogMessage(\n el: HTMLElement, value: string\n): void {\n el.firstElementChild!.innerHTML = value\n}\n\n/* ------------------------------------------------------------------------- */\n\n/**\n * Set dialog state\n *\n * @param el - Dialog element\n * @param state - Dialog state\n */\nexport function setDialogState(\n el: HTMLElement, state: \"open\"\n): void {\n el.setAttribute(\"data-md-state\", state)\n}\n\n/**\n * Reset dialog state\n *\n * @param el - Dialog element\n */\nexport function resetDialogState(\n el: HTMLElement\n): void {\n el.removeAttribute(\"data-md-state\")\n}\n","/*\n * Copyright (c) 2016-2020 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport { NEVER, Observable, Subject, animationFrameScheduler } from \"rxjs\"\nimport {\n distinctUntilKeyChanged,\n finalize,\n map,\n observeOn,\n tap\n} from \"rxjs/operators\"\n\nimport {\n resetHeaderTitleState,\n setHeaderTitleState\n} from \"~/actions\"\nimport {\n Viewport,\n getElement,\n getElementSize,\n watchViewportAt\n} from \"~/browser\"\n\nimport { Component } from \"../../_\"\nimport { Header } from \"../_\"\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Header\n */\nexport interface HeaderTitle {\n active: boolean /* User scrolled past first headline */\n}\n\n/* ----------------------------------------------------------------------------\n * Helper types\n * ------------------------------------------------------------------------- */\n\n/**\n * Watch options\n */\ninterface WatchOptions {\n viewport$: Observable /* Viewport observable */\n header$: Observable
    /* Header observable */\n}\n\n/**\n * Mount options\n */\ninterface MountOptions {\n viewport$: Observable /* Viewport observable */\n header$: Observable
    /* Header observable */\n}\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Watch header title\n *\n * @param el - Heading element\n * @param options - Options\n *\n * @returns Header title observable\n */\nexport function watchHeaderTitle(\n el: HTMLHeadingElement, { viewport$, header$ }: WatchOptions\n): Observable {\n return watchViewportAt(el, { header$, viewport$ })\n .pipe(\n map(({ offset: { y } }) => {\n const { height } = getElementSize(el)\n return {\n active: y >= height\n }\n }),\n distinctUntilKeyChanged(\"active\")\n )\n}\n\n/**\n * Mount header title\n *\n * @param el - Header title element\n * @param options - Options\n *\n * @returns Header title component observable\n */\nexport function mountHeaderTitle(\n el: HTMLElement, options: MountOptions\n): Observable> {\n const internal$ = new Subject()\n internal$\n .pipe(\n observeOn(animationFrameScheduler),\n )\n .subscribe(({ active }) => {\n if (active)\n setHeaderTitleState(el, \"active\")\n else\n resetHeaderTitleState(el)\n })\n\n /* Obtain headline, if any */\n const headline = getElement(\"article h1\")\n if (typeof headline === \"undefined\")\n return NEVER\n\n /* Create and return component */\n return watchHeaderTitle(headline, options)\n .pipe(\n tap(internal$),\n finalize(() => internal$.complete()),\n map(state => ({ ref: el, ...state }))\n )\n}\n","/*\n * Copyright (c) 2016-2020 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Set header title state\n *\n * @param el - Header title element\n * @param state - Header title state\n */\nexport function setHeaderTitleState(\n el: HTMLElement, state: \"active\"\n): void {\n el.setAttribute(\"data-md-state\", state)\n}\n\n/**\n * Reset header title state\n *\n * @param el - Header title element\n */\nexport function resetHeaderTitleState(\n el: HTMLElement\n): void {\n el.removeAttribute(\"data-md-state\")\n}\n","/*\n * Copyright (c) 2016-2020 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A RTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport { SearchIndex, SearchResult } from \"../../_\"\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Search message type\n */\nexport const enum SearchMessageType {\n SETUP, /* Search index setup */\n READY, /* Search index ready */\n QUERY, /* Search query */\n RESULT /* Search results */\n}\n\n/* ------------------------------------------------------------------------- */\n\n/**\n * A message containing the data necessary to setup the search index\n */\nexport interface SearchSetupMessage {\n type: SearchMessageType.SETUP /* Message type */\n data: SearchIndex /* Message data */\n}\n\n/**\n * A message indicating the search index is ready\n */\nexport interface SearchReadyMessage {\n type: SearchMessageType.READY /* Message type */\n}\n\n/**\n * A message containing a search query\n */\nexport interface SearchQueryMessage {\n type: SearchMessageType.QUERY /* Message type */\n data: string /* Message data */\n}\n\n/**\n * A message containing results for a search query\n */\nexport interface SearchResultMessage {\n type: SearchMessageType.RESULT /* Message type */\n data: SearchResult[] /* Message data */\n}\n\n/* ------------------------------------------------------------------------- */\n\n/**\n * A message exchanged with the search worker\n */\nexport type SearchMessage =\n | SearchSetupMessage\n | SearchReadyMessage\n | SearchQueryMessage\n | SearchResultMessage\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Type guard for search setup messages\n *\n * @param message - Search worker message\n *\n * @returns Test result\n */\nexport function isSearchSetupMessage(\n message: SearchMessage\n): message is SearchSetupMessage {\n return message.type === SearchMessageType.SETUP\n}\n\n/**\n * Type guard for search ready messages\n *\n * @param message - Search worker message\n *\n * @returns Test result\n */\nexport function isSearchReadyMessage(\n message: SearchMessage\n): message is SearchReadyMessage {\n return message.type === SearchMessageType.READY\n}\n\n/**\n * Type guard for search query messages\n *\n * @param message - Search worker message\n *\n * @returns Test result\n */\nexport function isSearchQueryMessage(\n message: SearchMessage\n): message is SearchQueryMessage {\n return message.type === SearchMessageType.QUERY\n}\n\n/**\n * Type guard for search result messages\n *\n * @param message - Search worker message\n *\n * @returns Test result\n */\nexport function isSearchResultMessage(\n message: SearchMessage\n): message is SearchResultMessage {\n return message.type === SearchMessageType.RESULT\n}\n","/*\n * Copyright (c) 2016-2020 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Search transformation function\n *\n * @param value - Query value\n *\n * @returns Transformed query value\n */\nexport type SearchTransformFn = (value: string) => string\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Default transformation function\n *\n * 1. Search for terms in quotation marks and prepend a `+` modifier to denote\n * that the resulting document must contain all terms, converting the query\n * to an `AND` query (as opposed to the default `OR` behavior). While users\n * may expect terms enclosed in quotation marks to map to span queries, i.e.\n * for which order is important, `lunr` doesn't support them, so the best\n * we can do is to convert the terms to an `AND` query.\n *\n * 2. Replace control characters which are not located at the beginning of the\n * query or preceded by white space, or are not followed by a non-whitespace\n * character or are at the end of the query string. Furthermore, filter\n * unmatched quotation marks.\n *\n * 3. Trim excess whitespace from left and right.\n *\n * @param query - Query value\n *\n * @returns Transformed query value\n */\nexport function defaultTransform(query: string): string {\n return query\n .split(/\"([^\"]+)\"/g) /* => 1 */\n .map((terms, index) => index & 1\n ? terms.replace(/^\\b|^(?![^\\x00-\\x7F]|$)|\\s+/g, \" +\")\n : terms\n )\n .join(\"\")\n .replace(/\"|(?:^|\\s+)[*+\\-:^~]+(?=\\s+|$)/g, \"\") /* => 2 */\n .trim() /* => 3 */\n}\n","/*\n * Copyright (c) 2016-2020 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A RTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport { ObservableInput, Subject, from } from \"rxjs\"\nimport { map, share } from \"rxjs/operators\"\n\nimport { configuration, translation } from \"~/_\"\nimport { WorkerHandler, watchWorker } from \"~/browser\"\n\nimport { SearchIndex, SearchIndexPipeline } from \"../../_\"\nimport {\n SearchMessage,\n SearchMessageType,\n SearchSetupMessage,\n isSearchResultMessage\n} from \"../message\"\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Search worker\n */\nexport type SearchWorker = WorkerHandler\n\n/* ----------------------------------------------------------------------------\n * Helper functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Set up search index\n *\n * @param data - Search index\n *\n * @returns Search index\n */\nfunction setupSearchIndex(\n { config, docs, index }: SearchIndex\n): SearchIndex {\n\n /* Override default language with value from translation */\n if (config.lang.length === 1 && config.lang[0] === \"en\")\n config.lang = [\n translation(\"search.config.lang\")\n ]\n\n /* Override default separator with value from translation */\n if (config.separator === \"[\\\\s\\\\-]+\")\n config.separator = translation(\"search.config.separator\")\n\n /* Set pipeline from translation */\n const pipeline = translation(\"search.config.pipeline\")\n .split(/\\s*,\\s*/)\n .filter(Boolean) as SearchIndexPipeline\n\n /* Return search index after defaulting */\n return { config, docs, index, pipeline }\n}\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Set up search worker\n *\n * This function will create a web worker to set up and query the search index\n * which is done using `lunr`. The index must be passed as an observable to\n * enable hacks like _localsearch_ via search index embedding as JSON.\n *\n * @param url - Worker URL\n * @param index - Search index observable input\n *\n * @returns Search worker\n */\nexport function setupSearchWorker(\n url: string, index: ObservableInput\n): SearchWorker {\n const config = configuration()\n const worker = new Worker(url)\n\n /* Create communication channels and resolve relative links */\n const tx$ = new Subject()\n const rx$ = watchWorker(worker, { tx$ })\n .pipe(\n map(message => {\n if (isSearchResultMessage(message)) {\n for (const result of message.data)\n for (const document of result)\n document.location = `${config.base}/${document.location}`\n }\n return message\n }),\n share()\n )\n\n /* Set up search index */\n from(index)\n .pipe(\n map(data => ({\n type: SearchMessageType.SETUP,\n data: setupSearchIndex(data)\n }))\n )\n .subscribe(tx$.next.bind(tx$))\n\n /* Return search worker */\n return { tx$, rx$ }\n}\n","/*\n * Copyright (c) 2016-2020 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport { Observable, Subject, fromEvent } from \"rxjs\"\nimport {\n map,\n share,\n switchMapTo,\n tap,\n throttle\n} from \"rxjs/operators\"\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Worker message\n */\nexport interface WorkerMessage {\n type: unknown /* Message type */\n data?: unknown /* Message data */\n}\n\n/**\n * Worker handler\n *\n * @template T - Message type\n */\nexport interface WorkerHandler<\n T extends WorkerMessage\n> {\n tx$: Subject /* Message transmission subject */\n rx$: Observable /* Message receive observable */\n}\n\n/* ----------------------------------------------------------------------------\n * Helper types\n * ------------------------------------------------------------------------- */\n\n/**\n * Watch options\n *\n * @template T - Worker message type\n */\ninterface WatchOptions {\n tx$: Observable /* Message transmission observable */\n}\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Watch a web worker\n *\n * This function returns an observable that will send all values emitted by the\n * message observable to the web worker. Web worker communication is expected\n * to be bidirectional (request-response) and synchronous. Messages that are\n * emitted during a pending request are throttled, the last one is emitted.\n *\n * @param worker - Web worker\n * @param options - Options\n *\n * @returns Worker message observable\n */\nexport function watchWorker(\n worker: Worker, { tx$ }: WatchOptions\n): Observable {\n\n /* Intercept messages from worker-like objects */\n const rx$ = fromEvent(worker, \"message\")\n .pipe(\n map(({ data }) => data)\n )\n\n /* Send and receive messages, return hot observable */\n return tx$\n .pipe(\n throttle(() => rx$, { leading: true, trailing: true }),\n tap(message => worker.postMessage(message)),\n switchMapTo(rx$),\n share()\n )\n}\n","/*\n * Copyright (c) 2016-2020 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport {\n Observable,\n Subject,\n combineLatest,\n fromEvent,\n merge\n} from \"rxjs\"\nimport {\n delay,\n distinctUntilChanged,\n distinctUntilKeyChanged,\n finalize,\n map,\n startWith,\n takeLast,\n takeUntil,\n tap\n} from \"rxjs/operators\"\n\nimport {\n resetSearchQueryPlaceholder,\n setSearchQueryPlaceholder\n} from \"~/actions\"\nimport {\n setElementFocus,\n setToggle,\n watchElementFocus\n} from \"~/browser\"\nimport {\n SearchMessageType,\n SearchQueryMessage,\n SearchWorker,\n defaultTransform\n} from \"~/integrations\"\n\nimport { Component } from \"../../_\"\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Search query\n */\nexport interface SearchQuery {\n value: string /* Query value */\n focus: boolean /* Query focus */\n}\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Watch search query\n *\n * Note that the focus event which triggers re-reading the current query value\n * is delayed by `1ms` so the input's empty state is allowed to propagate.\n *\n * @param el - Search query element\n *\n * @returns Search query observable\n */\nexport function watchSearchQuery(\n el: HTMLInputElement\n): Observable {\n const fn = __search?.transform || defaultTransform\n\n /* Intercept focus and input events */\n const focus$ = watchElementFocus(el)\n const value$ = merge(\n fromEvent(el, \"keyup\"),\n fromEvent(el, \"focus\").pipe(delay(1))\n )\n .pipe(\n map(() => fn(el.value)),\n startWith(fn(el.value)),\n distinctUntilChanged()\n )\n\n /* Combine into single observable */\n return combineLatest([value$, focus$])\n .pipe(\n map(([value, focus]) => ({ value, focus }))\n )\n}\n\n/**\n * Mount search query\n *\n * @param el - Search query element\n * @param worker - Search worker\n *\n * @returns Search query component observable\n */\nexport function mountSearchQuery(\n el: HTMLInputElement, { tx$ }: SearchWorker\n): Observable> {\n const internal$ = new Subject()\n\n /* Handle value changes */\n internal$\n .pipe(\n distinctUntilKeyChanged(\"value\"),\n map(({ value }): SearchQueryMessage => ({\n type: SearchMessageType.QUERY,\n data: value\n }))\n )\n .subscribe(tx$.next.bind(tx$))\n\n /* Handle focus changes */\n internal$\n .pipe(\n distinctUntilKeyChanged(\"focus\")\n )\n .subscribe(({ focus }) => {\n if (focus) {\n setToggle(\"search\", focus)\n setSearchQueryPlaceholder(el, \"\")\n } else {\n resetSearchQueryPlaceholder(el)\n }\n })\n\n /* Handle reset */\n fromEvent(el.form!, \"reset\")\n .pipe(\n takeUntil(internal$.pipe(takeLast(1)))\n )\n .subscribe(() => setElementFocus(el))\n\n /* Create and return component */\n return watchSearchQuery(el)\n .pipe(\n tap(internal$),\n finalize(() => internal$.complete()),\n map(state => ({ ref: el, ...state }))\n )\n}\n","/*\n * Copyright (c) 2016-2020 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport { translation } from \"~/_\"\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Set search query placeholder\n *\n * @param el - Search query element\n * @param value - Placeholder\n */\nexport function setSearchQueryPlaceholder(\n el: HTMLInputElement, value: string\n): void {\n el.placeholder = value\n}\n\n/**\n * Reset search query placeholder\n *\n * @param el - Search query element\n */\nexport function resetSearchQueryPlaceholder(\n el: HTMLInputElement\n): void {\n el.placeholder = translation(\"search.placeholder\")\n}\n","/*\n * Copyright (c) 2016-2020 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport { Observable, Subject } from \"rxjs\"\nimport {\n filter,\n finalize,\n map,\n startWith,\n tap,\n withLatestFrom\n} from \"rxjs/operators\"\n\nimport {\n addToSearchResultList,\n resetSearchResultList,\n resetSearchResultMeta,\n setSearchResultMeta\n} from \"~/actions\"\nimport { getElementOrThrow } from \"~/browser\"\nimport {\n SearchResult as SearchResultData,\n SearchWorker,\n isSearchResultMessage\n} from \"~/integrations\"\nimport { renderSearchResult } from \"~/templates\"\n\nimport { Component } from \"../../_\"\nimport { SearchQuery } from \"../query\"\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Search result\n */\nexport interface SearchResult {\n data: SearchResultData[] /* Search result data */\n}\n\n/* ----------------------------------------------------------------------------\n * Helper types\n * ------------------------------------------------------------------------- */\n\n/**\n * Mount options\n */\ninterface MountOptions {\n query$: Observable /* Search query observable */\n}\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Mount search result list\n *\n * @param el - Search result list element\n * @param worker - Search worker\n * @param options - Options\n *\n * @returns Search result list component observable\n */\nexport function mountSearchResult(\n el: HTMLElement, { rx$ }: SearchWorker, { query$ }: MountOptions\n): Observable> {\n const internal$ = new Subject()\n\n /* Update search result metadata */\n const meta = getElementOrThrow(\":scope > :first-child\", el)\n internal$\n .pipe(\n withLatestFrom(query$)\n )\n .subscribe(([{ data }, { value }]) => {\n if (value)\n setSearchResultMeta(meta, data.length)\n else\n resetSearchResultMeta(meta)\n })\n\n /* Update search result list */\n const list = getElementOrThrow(\":scope > :last-child\", el)\n internal$\n .subscribe(({ data }) => {\n resetSearchResultList(list)\n\n /* Compute thresholds and search results */\n const thresholds = [...data.map(([best]) => best.score), 0]\n for (let index = 0; index < data.length; index++)\n addToSearchResultList(list, renderSearchResult(\n data[index++], thresholds[index]\n ))\n })\n\n /* Filter search result list */\n const result$ = rx$\n .pipe(\n filter(isSearchResultMessage),\n map(({ data }) => ({ data })),\n startWith({ data: [] })\n )\n\n /* Create and return component */\n return result$\n .pipe(\n tap(internal$),\n finalize(() => internal$.complete()),\n map(state => ({ ref: el, ...state }))\n )\n}\n","/*\n * Copyright (c) 2016-2020 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport { Observable, merge } from \"rxjs\"\nimport { filter, sample, take } from \"rxjs/operators\"\n\nimport { configuration } from \"~/_\"\nimport { fetchJSON, getElementOrThrow } from \"~/browser\"\nimport {\n SearchIndex,\n isSearchQueryMessage,\n isSearchReadyMessage,\n setupSearchWorker\n} from \"~/integrations\"\n\nimport { Component } from \"../../_\"\nimport { SearchQuery, mountSearchQuery } from \"../query\"\nimport { SearchResult, mountSearchResult } from \"../result\"\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Search\n */\nexport type Search =\n | SearchQuery\n | SearchResult\n\n/* ----------------------------------------------------------------------------\n * Helper functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Fetch search index\n *\n * @param url - Search index URL\n *\n * @returns Promise resolving with search index\n */\nfunction fetchSearchIndex(url: string) {\n return __search?.index || fetchJSON(url)\n}\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Mount search\n *\n * @param el - Search element\n *\n * @returns Search component observable\n */\nexport function mountSearch(\n el: HTMLElement\n): Observable> {\n const config = configuration()\n const worker = setupSearchWorker(config.search, fetchSearchIndex(\n `${config.base}/search/search_index.json`\n ))\n\n /* Re-emit query when search is ready */\n const { tx$, rx$ } = worker\n tx$\n .pipe(\n filter(isSearchQueryMessage),\n sample(rx$.pipe(filter(isSearchReadyMessage))),\n take(1)\n )\n .subscribe(tx$.next.bind(tx$))\n\n /* Mount search query component */\n const query$ = mountSearchQuery(\n getElementOrThrow(\"[data-md-component=search-query]\", el),\n worker\n )\n\n /* Mount search result and return component */\n return merge(\n query$,\n mountSearchResult(\n getElementOrThrow(\"[data-md-component=search-result]\", el),\n worker, { query$ }\n )\n )\n}\n","/*\n * Copyright (c) 2016-2020 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport {\n Observable,\n Subject,\n animationFrameScheduler,\n combineLatest\n} from \"rxjs\"\nimport {\n distinctUntilChanged,\n finalize,\n map,\n observeOn,\n tap,\n withLatestFrom\n} from \"rxjs/operators\"\n\nimport {\n resetSidebarHeight,\n resetSidebarOffset,\n setSidebarHeight,\n setSidebarOffset\n} from \"~/actions\"\nimport { Viewport } from \"~/browser\"\n\nimport { Component } from \"../_\"\nimport { Header } from \"../header\"\nimport { Main } from \"../main\"\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Sidebar\n */\nexport interface Sidebar {\n height: number /* Sidebar height */\n locked: boolean /* User scrolled past header */\n}\n\n/* ----------------------------------------------------------------------------\n * Helper types\n * ------------------------------------------------------------------------- */\n\n/**\n * Watch options\n */\ninterface WatchOptions {\n viewport$: Observable /* Viewport observable */\n main$: Observable
    /* Main area observable */\n}\n\n/**\n * Mount options\n */\ninterface MountOptions {\n viewport$: Observable /* Viewport observable */\n header$: Observable
    /* Header observable */\n main$: Observable
    /* Main area observable */\n}\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Watch sidebar\n *\n * This function returns an observable that computes the visual parameters of\n * the sidebar which depends on the vertical viewport offset, as well as the\n * height of the main area. When the page is scrolled beyond the header, the\n * sidebar is locked and fills the remaining space.\n *\n * @param el - Sidebar element\n * @param options - Options\n *\n * @returns Sidebar observable\n */\nexport function watchSidebar(\n el: HTMLElement, { viewport$, main$ }: WatchOptions\n): Observable {\n const adjust =\n el.parentElement!.offsetTop -\n el.parentElement!.parentElement!.offsetTop\n\n /* Compute the sidebar's available height and if it should be locked */\n return combineLatest([main$, viewport$])\n .pipe(\n map(([{ offset, height }, { offset: { y } }]) => {\n height = height\n + Math.min(adjust, Math.max(0, y - offset))\n - adjust\n return {\n height,\n locked: y >= offset + adjust\n }\n }),\n distinctUntilChanged((a, b) => (\n a.height === b.height &&\n a.locked === b.locked\n ))\n )\n}\n\n/**\n * Mount sidebar\n *\n * @param el - Sidebar element\n * @param options - Options\n *\n * @returns Sidebar component observable\n */\nexport function mountSidebar(\n el: HTMLElement, { header$, ...options }: MountOptions\n): Observable> {\n const internal$ = new Subject()\n internal$\n .pipe(\n observeOn(animationFrameScheduler),\n withLatestFrom(header$)\n )\n .subscribe({\n\n /* Update height and offset */\n next([{ height }, { height: offset }]) {\n setSidebarHeight(el, height)\n setSidebarOffset(el, offset)\n },\n\n /* Reset on complete */\n complete() {\n resetSidebarOffset(el)\n resetSidebarHeight(el)\n }\n })\n\n /* Create and return component */\n return watchSidebar(el, options)\n .pipe(\n tap(internal$),\n finalize(() => internal$.complete()),\n map(state => ({ ref: el, ...state }))\n )\n}\n","/*\n * Copyright (c) 2016-2020 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Set sidebar offset\n *\n * @param el - Sidebar element\n * @param value - Sidebar offset\n */\nexport function setSidebarOffset(\n el: HTMLElement, value: number\n): void {\n el.style.top = `${value}px`\n}\n\n/**\n * Reset sidebar offset\n *\n * @param el - Sidebar element\n */\nexport function resetSidebarOffset(\n el: HTMLElement\n): void {\n el.style.top = \"\"\n}\n\n/* ------------------------------------------------------------------------- */\n\n/**\n * Set sidebar height\n *\n * This function doesn't set the height of the actual sidebar, but of its first\n * child – the `.md-sidebar__scrollwrap` element in order to mitigiate jittery\n * sidebars when the footer is scrolled into view. At some point we switched\n * from `absolute` / `fixed` positioning to `sticky` positioning, significantly\n * reducing jitter in some browsers (respectively Firefox and Safari) when\n * scrolling from the top. However, top-aligned sticky positioning means that\n * the sidebar snaps to the bottom when the end of the container is reached.\n * This is what leads to the mentioned jitter, as the sidebar's height may be\n * updated too slowly.\n *\n * This behaviour can be mitigiated by setting the height of the sidebar to `0`\n * while preserving the padding, and the height on its first element.\n *\n * @param el - Sidebar element\n * @param value - Sidebar height\n */\nexport function setSidebarHeight(\n el: HTMLElement, value: number\n): void {\n const scrollwrap = el.firstElementChild as HTMLElement\n scrollwrap.style.height = `${value - 2 * scrollwrap.offsetTop}px`\n}\n\n/**\n * Reset sidebar height\n *\n * @param el - Sidebar element\n */\nexport function resetSidebarHeight(\n el: HTMLElement\n): void {\n const scrollwrap = el.firstElementChild as HTMLElement\n scrollwrap.style.height = \"\"\n}\n","/*\n * Copyright (c) 2016-2020 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport { NEVER, Observable } from \"rxjs\"\n\nimport { fetchSourceFactsFromGitHub } from \"../github\"\nimport { fetchSourceFactsFromGitLab } from \"../gitlab\"\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Repository facts\n */\nexport type SourceFacts = string[]\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Fetch repository facts\n *\n * @param url - Repository URL\n *\n * @returns Repository facts observable\n */\nexport function fetchSourceFacts(\n url: string\n): Observable {\n const [type] = url.match(/(git(?:hub|lab))/i) || []\n switch (type.toLowerCase()) {\n\n /* GitHub repository */\n case \"github\":\n const [, user, repo] = url.match(/^.+github\\.com\\/([^/]+)\\/?([^/]+)?/i)!\n return fetchSourceFactsFromGitHub(user, repo)\n\n /* GitLab repository */\n case \"gitlab\":\n const [, base, slug] = url.match(/^.+?([^/]*gitlab[^/]+)\\/(.+?)\\/?$/i)!\n return fetchSourceFactsFromGitLab(base, slug)\n\n /* Everything else */\n default:\n return NEVER\n }\n}\n","/*\n * Copyright (c) 2016-2020 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport { Repo, User } from \"github-types\"\nimport { Observable } from \"rxjs\"\nimport { defaultIfEmpty, map } from \"rxjs/operators\"\n\nimport { fetchJSON } from \"~/browser\"\nimport { round } from \"~/utilities\"\n\nimport { SourceFacts } from \"../_\"\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Fetch GitHub repository facts\n *\n * @param user - GitHub user\n * @param repo - GitHub repository\n *\n * @returns Repository facts observable\n */\nexport function fetchSourceFactsFromGitHub(\n user: string, repo?: string\n): Observable {\n const url = typeof repo !== \"undefined\"\n ? `https://api.github.com/repos/${user}/${repo}`\n : `https://api.github.com/users/${user}`\n return fetchJSON(url)\n .pipe(\n map(data => {\n\n /* GitHub repository */\n if (typeof repo !== \"undefined\") {\n const { stargazers_count, forks_count }: Repo = data\n return [\n `${round(stargazers_count!)} Stars`,\n `${round(forks_count!)} Forks`\n ]\n\n /* GitHub user/organization */\n } else {\n const { public_repos }: User = data\n return [\n `${round(public_repos!)} Repositories`\n ]\n }\n }),\n defaultIfEmpty([])\n )\n}\n","/*\n * Copyright (c) 2016-2020 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport { ProjectSchema } from \"gitlab\"\nimport { Observable } from \"rxjs\"\nimport { defaultIfEmpty, map } from \"rxjs/operators\"\n\nimport { fetchJSON } from \"~/browser\"\nimport { round } from \"~/utilities\"\n\nimport { SourceFacts } from \"../_\"\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Fetch GitLab repository facts\n *\n * @param base - GitLab base\n * @param project - GitLab project\n *\n * @returns Repository facts observable\n */\nexport function fetchSourceFactsFromGitLab(\n base: string, project: string\n): Observable {\n const url = `https://${base}/api/v4/projects/${encodeURIComponent(project)}`\n return fetchJSON(url)\n .pipe(\n map(({ star_count, forks_count }) => ([\n `${round(star_count)} Stars`,\n `${round(forks_count)} Forks`\n ])),\n defaultIfEmpty([])\n )\n}\n","/*\n * Copyright (c) 2016-2020 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport { NEVER, Observable, Subject, defer, of } from \"rxjs\"\nimport {\n catchError,\n filter,\n finalize,\n map,\n shareReplay,\n tap\n} from \"rxjs/operators\"\n\nimport { setSourceFacts, setSourceState } from \"~/actions\"\nimport { renderSourceFacts } from \"~/templates\"\nimport { hash } from \"~/utilities\"\n\nimport { Component } from \"../../_\"\nimport { SourceFacts, fetchSourceFacts } from \"../facts\"\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Repository information\n */\nexport interface Source {\n facts: SourceFacts /* Repository facts */\n}\n\n/* ----------------------------------------------------------------------------\n * Data\n * ------------------------------------------------------------------------- */\n\n/**\n * Repository facts observable\n */\nlet fetch$: Observable\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Watch repository information\n *\n * @param el - Repository information element\n *\n * @returns Repository information observable\n */\nexport function watchSource(\n el: HTMLAnchorElement\n): Observable {\n const digest = hash(el.href).toString()\n\n /* Fetch repository facts once */\n return fetch$ ||= defer(() => {\n const data = sessionStorage.getItem(digest)\n if (data) {\n return of(JSON.parse(data))\n } else {\n const value$ = fetchSourceFacts(el.href)\n value$.subscribe(value => {\n try {\n sessionStorage.setItem(digest, JSON.stringify(value))\n } catch (err) {\n /* Uncritical, just swallow */\n }\n })\n\n /* Return value */\n return value$\n }\n })\n .pipe(\n catchError(() => NEVER),\n filter(facts => facts.length > 0),\n map(facts => ({ facts })),\n shareReplay(1)\n )\n}\n\n/**\n * Mount repository information\n *\n * @param el - Repository information element\n *\n * @returns Repository information component observable\n */\nexport function mountSource(\n el: HTMLAnchorElement\n): Observable> {\n const internal$ = new Subject()\n internal$.subscribe(({ facts }) => {\n setSourceFacts(el, renderSourceFacts(facts))\n setSourceState(el, \"done\")\n })\n\n /* Create and return component */\n return watchSource(el)\n .pipe(\n tap(internal$),\n finalize(() => internal$.complete()),\n map(state => ({ ref: el, ...state }))\n )\n}\n","/*\n * Copyright (c) 2016-2020 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Set repository facts\n *\n * @param el - Repository element\n * @param child - Repository facts element\n */\nexport function setSourceFacts(\n el: HTMLElement, child: Element\n): void {\n el.lastElementChild!.appendChild(child)\n}\n\n/**\n * Set repository state\n *\n * @param el - Repository element\n * @param state - Repository state\n */\nexport function setSourceState(\n el: HTMLElement, state: \"done\"\n): void {\n el.lastElementChild!.setAttribute(\"data-md-state\", state)\n}\n","/*\n * Copyright (c) 2016-2020 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport { SourceFacts } from \"~/components\"\nimport { h } from \"~/utilities\"\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Render repository facts\n *\n * @param facts - Repository facts\n *\n * @returns Element\n */\nexport function renderSourceFacts(facts: SourceFacts) {\n return (\n
      \n {facts.map(fact => (\n
    • {fact}
    • \n ))}\n
    \n )\n}\n","/*\n * Copyright (c) 2016-2020 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport { Observable, Subject, animationFrameScheduler } from \"rxjs\"\nimport {\n distinctUntilKeyChanged,\n finalize,\n map,\n observeOn,\n tap\n} from \"rxjs/operators\"\n\nimport { resetTabsState, setTabsState } from \"~/actions\"\nimport { Viewport, watchViewportAt } from \"~/browser\"\n\nimport { Component } from \"../_\"\nimport { Header } from \"../header\"\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Navigation tabs\n */\nexport interface Tabs {\n hidden: boolean /* User scrolled past tabs */\n}\n\n/* ----------------------------------------------------------------------------\n * Helper types\n * ------------------------------------------------------------------------- */\n\n/**\n * Watch options\n */\ninterface WatchOptions {\n viewport$: Observable /* Viewport observable */\n header$: Observable
    /* Header observable */\n}\n\n/**\n * Mount options\n */\ninterface MountOptions {\n viewport$: Observable /* Viewport observable */\n header$: Observable
    /* Header observable */\n}\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Watch navigation tabs\n *\n * @param el - Navigation tabs element\n * @param options - Options\n *\n * @returns Navigation tabs observable\n */\nexport function watchTabs(\n el: HTMLElement, { viewport$, header$ }: WatchOptions\n): Observable {\n return watchViewportAt(el, { header$, viewport$ })\n .pipe(\n map(({ offset: { y } }) => {\n return {\n hidden: y >= 10\n }\n }),\n distinctUntilKeyChanged(\"hidden\")\n )\n}\n\n/**\n * Mount navigation tabs\n *\n * @param el - Navigation tabs element\n * @param options - Options\n *\n * @returns Navigation tabs component observable\n */\nexport function mountTabs(\n el: HTMLElement, options: MountOptions\n): Observable> {\n const internal$ = new Subject()\n internal$\n .pipe(\n observeOn(animationFrameScheduler)\n )\n .subscribe({\n\n /* Update state */\n next({ hidden }) {\n if (hidden)\n setTabsState(el, \"hidden\")\n else\n resetTabsState(el)\n },\n\n /* Reset on complete */\n complete() {\n resetTabsState(el)\n }\n })\n\n /* Create and return component */\n return watchTabs(el, options)\n .pipe(\n tap(internal$),\n finalize(() => internal$.complete()),\n map(state => ({ ref: el, ...state }))\n )\n}\n","/*\n * Copyright (c) 2016-2020 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport {\n Observable,\n Subject,\n animationFrameScheduler,\n combineLatest\n} from \"rxjs\"\nimport {\n bufferCount,\n distinctUntilChanged,\n distinctUntilKeyChanged,\n finalize,\n map,\n observeOn,\n scan,\n startWith,\n switchMap,\n tap\n} from \"rxjs/operators\"\n\nimport {\n resetAnchorActive,\n resetAnchorState,\n setAnchorActive,\n setAnchorState\n} from \"~/actions\"\nimport {\n Viewport,\n getElement,\n getElements,\n watchElementSize\n} from \"~/browser\"\n\nimport { Component } from \"../_\"\nimport { Header } from \"../header\"\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Table of contents\n */\nexport interface TableOfContents {\n prev: HTMLAnchorElement[][] /* Anchors (previous) */\n next: HTMLAnchorElement[][] /* Anchors (next) */\n}\n\n/* ----------------------------------------------------------------------------\n * Helper types\n * ------------------------------------------------------------------------- */\n\n/**\n * Watch options\n */\ninterface WatchOptions {\n viewport$: Observable /* Viewport observable */\n header$: Observable
    /* Header observable */\n}\n\n/**\n * Mount options\n */\ninterface MountOptions {\n viewport$: Observable /* Viewport observable */\n header$: Observable
    /* Header observable */\n}\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Watch table of contents\n *\n * This is effectively a scroll spy implementation which will account for the\n * fixed header and automatically re-calculate anchor offsets when the viewport\n * is resized. The returned observable will only emit if the table of contents\n * needs to be repainted.\n *\n * This implementation tracks an anchor element's entire path starting from its\n * level up to the top-most anchor element, e.g. `[h3, h2, h1]`. Although the\n * Material theme currently doesn't make use of this information, it enables\n * the styling of the entire hierarchy through customization.\n *\n * Note that the current anchor is the last item of the `prev` anchor list.\n *\n * @param anchors - Anchor elements\n * @param options - Options\n *\n * @returns Table of contents observable\n */\nexport function watchTableOfContents(\n anchors: HTMLAnchorElement[], { viewport$, header$ }: WatchOptions\n): Observable {\n const table = new Map()\n for (const anchor of anchors) {\n const id = decodeURIComponent(anchor.hash.substring(1))\n const target = getElement(`[id=\"${id}\"]`)\n if (typeof target !== \"undefined\")\n table.set(anchor, target)\n }\n\n /* Compute necessary adjustment for header */\n const adjust$ = header$\n .pipe(\n map(header => 24 + header.height)\n )\n\n /* Compute partition of previous and next anchors */\n const partition$ = watchElementSize(document.body)\n .pipe(\n distinctUntilKeyChanged(\"height\"),\n\n /* Build index to map anchor paths to vertical offsets */\n map(() => {\n let path: HTMLAnchorElement[] = []\n return [...table].reduce((index, [anchor, target]) => {\n while (path.length) {\n const last = table.get(path[path.length - 1])!\n if (last.tagName >= target.tagName) {\n path.pop()\n } else {\n break\n }\n }\n\n /* If the current anchor is hidden, continue with its parent */\n let offset = target.offsetTop\n while (!offset && target.parentElement) {\n target = target.parentElement\n offset = target.offsetTop\n }\n\n /* Map reversed anchor path to vertical offset */\n return index.set(\n [...path = [...path, anchor]].reverse(),\n offset\n )\n }, new Map())\n }),\n\n /* Re-compute partition when viewport offset changes */\n switchMap(index => combineLatest([adjust$, viewport$])\n .pipe(\n scan(([prev, next], [adjust, { offset: { y } }]) => {\n\n /* Look forward */\n while (next.length) {\n const [, offset] = next[0]\n if (offset - adjust < y) {\n prev = [...prev, next.shift()!]\n } else {\n break\n }\n }\n\n /* Look backward */\n while (prev.length) {\n const [, offset] = prev[prev.length - 1]\n if (offset - adjust >= y) {\n next = [prev.pop()!, ...next]\n } else {\n break\n }\n }\n\n /* Return partition */\n return [prev, next]\n }, [[], [...index]]),\n distinctUntilChanged((a, b) => (\n a[0] === b[0] &&\n a[1] === b[1]\n ))\n )\n )\n )\n\n /* Compute and return anchor list migrations */\n return partition$\n .pipe(\n map(([prev, next]) => ({\n prev: prev.map(([path]) => path),\n next: next.map(([path]) => path)\n })),\n\n /* Extract anchor list migrations */\n startWith({ prev: [], next: [] }),\n bufferCount(2, 1),\n map(([a, b]) => {\n\n /* Moving down */\n if (a.prev.length < b.prev.length) {\n return {\n prev: b.prev.slice(Math.max(0, a.prev.length - 1), b.prev.length),\n next: []\n }\n\n /* Moving up */\n } else {\n return {\n prev: b.prev.slice(-1),\n next: b.next.slice(0, b.next.length - a.next.length)\n }\n }\n })\n )\n}\n\n/* ------------------------------------------------------------------------- */\n\n/**\n * Mount table of contents\n *\n * @param el - Anchor list element\n * @param options - Options\n *\n * @returns Table of contents component observable\n */\nexport function mountTableOfContents(\n el: HTMLElement, options: MountOptions\n): Observable> {\n const internal$ = new Subject()\n internal$\n .pipe(\n observeOn(animationFrameScheduler),\n )\n .subscribe(({ prev, next }) => {\n\n /* Look forward */\n for (const [anchor] of next) {\n resetAnchorActive(anchor)\n resetAnchorState(anchor)\n }\n\n /* Look backward */\n for (const [index, [anchor]] of prev.entries()) {\n setAnchorActive(anchor, index === prev.length - 1)\n setAnchorState(anchor, \"blur\")\n }\n })\n\n /* Create and return component */\n const anchors = getElements(\"[href^=\\\\#]\", el)\n return watchTableOfContents(anchors, options)\n .pipe(\n tap(internal$),\n finalize(() => internal$.complete()),\n map(state => ({ ref: el, ...state }))\n )\n}\n","/*\n * Copyright (c) 2016-2020 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport \"focus-visible\"\nimport { NEVER, Observable, Subject, merge } from \"rxjs\"\nimport { switchMap } from \"rxjs/operators\"\n\nimport {\n getElementOrThrow,\n getElements,\n watchLocationTarget,\n watchMedia,\n watchPrint,\n watchViewport\n} from \"./browser\"\nimport {\n mountContent,\n mountDialog,\n mountHeader,\n mountHeaderTitle,\n mountSearch,\n mountSidebar,\n mountSource,\n mountTableOfContents,\n mountTabs,\n watchHeader,\n watchMain\n} from \"./components\"\nimport {\n setupClipboardJS\n} from \"./integrations\"\n\n/* ----------------------------------------------------------------------------\n * Program\n * ------------------------------------------------------------------------- */\n\n/* Yay, JavaScript is available */\ndocument.documentElement.classList.remove(\"no-js\")\ndocument.documentElement.classList.add(\"js\")\n\n/* Set up subjects */\nconst target$ = watchLocationTarget()\n\n/* Set up user interface observables */\nconst viewport$ = watchViewport()\nconst tablet$ = watchMedia(\"(min-width: 960px)\")\nconst screen$ = watchMedia(\"(min-width: 1220px)\")\nconst print$ = watchPrint()\n\n// these elements MUST be available\nconst header = getElementOrThrow(\"[data-md-component=header]\")\nconst main = getElementOrThrow(\"[data-md-component=main]\")\n\nconst header$ = watchHeader(header)\nconst main$ = watchMain(main, { header$, viewport$ })\n\n/* Setup Clipboard.js integration */\nconst message$ = new Subject()\nsetupClipboardJS({ message$ })\n\n// TODO: watchElements + general mount function that takes a factory...\n// + a toggle function (optionally)\n\n// TODO: catch errors on all components when mounting, so one error doesn't\n// take down the whole site.\n\nconst app$ = merge(\n\n /* Content */\n ...getElements(\"[data-md-component=content]\")\n .map(child => mountContent(child, { target$, viewport$, print$ })),\n\n /* Dialog */\n ...getElements(\"[data-md-component=dialog]\")\n .map(child => mountDialog(child, { message$ })),\n\n /* Header */\n ...getElements(\"[data-md-component=header]\")\n .map(child => mountHeader(child, { viewport$, header$, main$ })),\n\n /* Header title */\n ...getElements(\"[data-md-component=header-title]\")\n .map(child => mountHeaderTitle(child, { viewport$, header$ })),\n\n /* Search */\n ...getElements(\"[data-md-component=search]\")\n .map(child => mountSearch(child)),\n\n /* Sidebar */\n ...getElements(\"[data-md-component=sidebar]\")\n .map(child => child.getAttribute(\"data-md-type\") === \"navigation\"\n ? at(screen$, () => mountSidebar(child, { viewport$, header$, main$ }))\n : at(tablet$, () => mountSidebar(child, { viewport$, header$, main$ }))\n ),\n\n /* Repository information */\n ...getElements(\"[data-md-component=source]\")\n .map(child => mountSource(child as HTMLAnchorElement)),\n\n /* Navigation tabs */\n ...getElements(\"[data-md-component=tabs]\")\n .map(child => mountTabs(child, { viewport$, header$ })),\n\n /* Table of contents */\n ...getElements(\"[data-md-component=toc]\")\n .map(child => mountTableOfContents(child, { viewport$, header$ })),\n)\n\n// eslint-disable-next-line\napp$.subscribe(console.log)\n\n/* ------------------------------------------------------------------------- */\n\n/**\n * Test\n *\n * @param toggle$ - Toggle observable\n * @param factory - Observable factory\n *\n * @returns New observable\n */\nfunction at(\n toggle$: Observable, factory: () => Observable\n) {\n return toggle$\n .pipe(\n switchMap(active => active ? factory() : NEVER),\n )\n}\n","/*\n * Copyright (c) 2016-2020 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport {\n Observable,\n Subject,\n animationFrameScheduler,\n defer,\n of\n} from \"rxjs\"\nimport {\n combineLatestWith,\n distinctUntilChanged,\n distinctUntilKeyChanged,\n map,\n observeOn,\n shareReplay\n} from \"rxjs/operators\"\n\nimport { resetHeaderState, setHeaderState } from \"~/actions\"\nimport { Viewport, watchElementSize } from \"~/browser\"\n\nimport { Component } from \"../../_\"\nimport { Main } from \"../../main\"\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Header\n */\nexport interface Header {\n sticky: boolean /* Header stickyness */\n height: number /* Header visible height */\n}\n\n/* ----------------------------------------------------------------------------\n * Helper types\n * ------------------------------------------------------------------------- */\n\n/**\n * Mount options\n */\ninterface MountOptions {\n viewport$: Observable /* Viewport observable */\n header$: Observable
    /* Header observable */\n main$: Observable
    /* Main area observable */\n}\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Watch header\n *\n * @param el - Header element\n *\n * @returns Header observable\n */\nexport function watchHeader(\n el: HTMLElement\n): Observable
    {\n return defer(() => {\n const styles = getComputedStyle(el)\n return of(\n styles.position === \"sticky\" ||\n styles.position === \"-webkit-sticky\"\n )\n })\n .pipe(\n combineLatestWith(watchElementSize(el)),\n map(([sticky, { height }]) => ({\n sticky,\n height: sticky ? height : 0\n })),\n distinctUntilChanged((a, b) => (\n a.sticky === b.sticky &&\n a.height === b.height\n ))\n )\n}\n\n/**\n * Mount header\n *\n * The header must be connected to the main area observable outside of the\n * operator function, as the header will persist in-between document switches\n * while the main area is replaced. However, the header observable must be\n * passed to this function, so we connect both via a long-living subject.\n *\n * @param el - Header element\n * @param options - Options\n *\n * @returns Header component observable\n */\nexport function mountHeader(\n el: HTMLElement, { header$, main$ }: MountOptions\n): Observable> {\n const internal$ = new Subject
    ()\n internal$\n .pipe(\n distinctUntilKeyChanged(\"active\"),\n observeOn(animationFrameScheduler)\n )\n .subscribe(({ active }) => {\n if (active)\n setHeaderState(el, \"shadow\")\n else\n resetHeaderState(el)\n })\n\n /* Connect to long-living subject and return component */\n main$.subscribe(main => internal$.next(main))\n return header$\n .pipe(\n map(state => ({ ref: el, ...state })),\n shareReplay(1)\n )\n}\n","/*\n * Copyright (c) 2016-2020 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport {\n Observable,\n combineLatest\n} from \"rxjs\"\nimport {\n distinctUntilChanged,\n distinctUntilKeyChanged,\n map,\n shareReplay,\n switchMap\n} from \"rxjs/operators\"\n\nimport { Viewport, watchElementSize } from \"~/browser\"\n\nimport { Header } from \"../header\"\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Main area\n */\nexport interface Main {\n offset: number /* Main area top offset */\n height: number /* Main area visible height */\n active: boolean /* User scrolled past header */\n}\n\n/* ----------------------------------------------------------------------------\n * Helper types\n * ------------------------------------------------------------------------- */\n\n/**\n * Watch options\n */\ninterface WatchOptions {\n viewport$: Observable /* Viewport observable */\n header$: Observable
    /* Header observable */\n}\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Watch main area\n *\n * This function returns an observable that computes the visual parameters of\n * the main area which depends on the viewport vertical offset and height, as\n * well as the height of the header element, if the header is fixed.\n *\n * @param el - Main area element\n * @param options - Options\n *\n * @returns Main area observable\n */\nexport function watchMain(\n el: HTMLElement, { viewport$, header$ }: WatchOptions\n): Observable
    {\n\n /* Compute necessary adjustment for header */\n const adjust$ = header$\n .pipe(\n map(({ height }) => height),\n distinctUntilChanged()\n )\n\n /* Compute the main area's top and bottom borders */\n const border$ = adjust$\n .pipe(\n switchMap(() => watchElementSize(el)\n .pipe(\n map(({ height }) => ({\n top: el.offsetTop,\n bottom: el.offsetTop + height\n })),\n distinctUntilKeyChanged(\"bottom\")\n )\n )\n )\n\n /* Compute the main area's offset, visible height and if we scrolled past */\n return combineLatest([adjust$, border$, viewport$])\n .pipe(\n map(([header, { top, bottom }, { offset: { y }, size: { height } }]) => {\n height = Math.max(0, height\n - Math.max(0, top - y, header)\n - Math.max(0, height + y - bottom)\n )\n return {\n offset: top - header,\n height,\n active: top - header <= y\n }\n }),\n distinctUntilChanged((a, b) => (\n a.offset === b.offset &&\n a.height === b.height &&\n a.active === b.active\n )),\n shareReplay(1)\n )\n}\n","/*\n * Copyright (c) 2016-2020 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport ClipboardJS from \"clipboard\"\nimport { Observable, Subject } from \"rxjs\"\n\nimport { translation } from \"~/_\"\n\n/* ----------------------------------------------------------------------------\n * Helper types\n * ------------------------------------------------------------------------- */\n\n/**\n * Setup options\n */\ninterface SetupOptions {\n message$: Subject /* Message subject */\n}\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Set up Clipboard.js integration\n *\n * @param options - Options\n */\nexport function setupClipboardJS(\n { message$ }: SetupOptions\n): void {\n if (!ClipboardJS.isSupported()) {\n new Observable(subscriber => {\n new ClipboardJS(\"[data-clipboard-target], [data-clipboard-text]\")\n .on(\"success\", ev => subscriber.next(ev))\n })\n .subscribe(() => message$.next(translation(\"clipboard.copied\")))\n }\n}\n","/*\n * Copyright (c) 2016-2020 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport { Observable, merge } from \"rxjs\"\n\nimport { Viewport, getElements } from \"~/browser\"\n\nimport { Component } from \"../../_\"\nimport { CodeBlock, mountCodeBlock } from \"../code\"\nimport { Details, mountDetails } from \"../details\"\nimport { DataTable, mountDataTable } from \"../table\"\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Content\n */\nexport type Content =\n | CodeBlock\n | DataTable\n | Details\n\n/* ----------------------------------------------------------------------------\n * Helper types\n * ------------------------------------------------------------------------- */\n\n/**\n * Mount options\n */\ninterface MountOptions {\n target$: Observable /* Location target observable */\n viewport$: Observable /* Viewport observable */\n print$: Observable /* Print observable */\n}\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Mount content\n *\n * @param el - Content element\n * @param options - Options\n *\n * @returns Content component observable\n */\nexport function mountContent(\n el: HTMLElement, { target$, viewport$, print$ }: MountOptions\n): Observable> {\n return merge(\n\n /* Code blocks */\n ...getElements(\"pre > code\", el)\n .map(child => mountCodeBlock(child, { viewport$ })),\n\n /* Data tables */\n ...getElements(\"table:not([class])\", el)\n .map(child => mountDataTable(child)),\n\n /* Details */\n ...getElements(\"details\", el)\n .map(child => mountDetails(child, { target$, print$ }))\n )\n}\n","/*\n * Copyright (c) 2016-2020 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Set header state\n *\n * @param el - Header element\n * @param state - Header state\n */\nexport function setHeaderState(\n el: HTMLElement, state: \"shadow\" | \"hidden\"\n): void {\n el.setAttribute(\"data-md-state\", state)\n}\n\n/**\n * Reset header state\n *\n * @param el - Header element\n */\nexport function resetHeaderState(\n el: HTMLElement\n): void {\n el.removeAttribute(\"data-md-state\")\n}\n"],"sourceRoot":""} \ No newline at end of file diff --git a/material/assets/javascripts/bundle.48bdffa8.min.js b/material/assets/javascripts/bundle.48bdffa8.min.js deleted file mode 100644 index bf1114727..000000000 --- a/material/assets/javascripts/bundle.48bdffa8.min.js +++ /dev/null @@ -1,2 +0,0 @@ -!function(e,t){for(var n in t)e[n]=t[n]}(window,function(e){function t(t){for(var a,o,i=t[0],s=t[1],p=t[2],b=0,l=[];b"focus"===e),Object(h.a)(e===(document.activeElement instanceof HTMLElement?document.activeElement:void 0)))}var O=n(52),m=n(53),g=n(55),v=n(56),w=n(57),$=n(58);const x=new a.a,y=Object(O.a)(()=>Object(m.a)(new ResizeObserver(e=>{for(const t of e)x.next(t)}))).pipe(Object(o.a)(e=>r.a.pipe(Object(h.a)(e)).pipe(Object(g.a)(()=>e.disconnect()))),Object(v.a)(1));function _(e){return{width:e.offsetWidth,height:e.offsetHeight}}function E(e){return y.pipe(Object(w.a)(t=>t.observe(e)),Object(o.a)(t=>x.pipe(Object($.a)(({target:t})=>t===e),Object(g.a)(()=>t.unobserve(e)),Object(d.a)(({contentRect:e})=>({width:e.width,height:e.height})))),Object(h.a)(_(e)))}var A=n(40);n(59);function S(){return new URL(location.href)}function k(){return location.hash.substring(1)}function T(e){const t=matchMedia(e);return Object(i.a)(t,"change").pipe(Object(d.a)(e=>e.matches),Object(h.a)(t.matches))}const R={drawer:u("[data-md-toggle=drawer]"),search:u("[data-md-toggle=search]")};var M=n(43),C=n(60);function L(){return{x:Math.max(0,pageXOffset),y:Math.max(0,pageYOffset)}}function P(){return{width:innerWidth,height:innerHeight}}function U(e,{viewport$:t,header$:n}){const a=t.pipe(Object(C.a)("size")),c=Object(M.a)([a,n]).pipe(Object(d.a)(()=>({x:e.offsetLeft,y:e.offsetTop})));return Object(M.a)([n,t,c]).pipe(Object(d.a)(([{height:e},{offset:t,size:n},{x:a,y:c}])=>({offset:{x:t.x-a,y:t.y-c+e},size:n})))}var z=n(61),I=n(62);const N=JSON.parse(u("#__config").textContent);function Y(){return N}function H(e,t){if(void 0===N.translations[e])throw new ReferenceError("Invalid translation: "+e);return void 0!==t?N.translations[e].replace("#",t.toString()):N.translations[e]}N.base=new URL(N.base,S()).toString().replace(/\/$/,"");var q,F=n(25),J=n.n(F),W=n(63);function Q(e,t){e.setAttribute("data-md-state",t)}function B(e){e.removeAttribute("data-md-state")}function D(e,t){e.classList.toggle("md-nav__link--active",t)}function V(e){e.classList.remove("md-nav__link--active")}function X(e,t){e.appendChild(t)}function G(e){e.removeAttribute("data-md-state")}function K(e,t){if("string"==typeof t||"number"==typeof t)e.innerHTML+=t.toString();else if(t instanceof Node)e.appendChild(t);else if(Array.isArray(t))for(const n of t)K(e,n)}function Z(e,t,...n){const a=document.createElement(e);if(t)for(const e of Object.keys(t))"boolean"!=typeof t[e]?a.setAttribute(e,t[e]):t[e]&&a.setAttribute(e,"");for(const e of n)K(a,e);return a}function ee(e){if(e>999){return((e+1e-6)/1e3).toFixed(+((e-950)%1e3>99))+"k"}return e.toString()}function te(e,t){const n=t&q.PARENT,a=t&q.TEASER,c=Object.keys(e.terms).filter(t=>!e.terms[t]).map(e=>[Z("del",null,e)," "]).flat().slice(0,-1);return Z("a",{href:e.location,class:"md-search-result__link",tabIndex:-1},Z("article",{class:["md-search-result__article",...n?["md-search-result__article--document"]:[]].join(" "),"data-md-score":e.score.toFixed(2)},n>0&&Z("div",{class:"md-search-result__icon md-icon"}),Z("h1",{class:"md-search-result__title"},e.title),a>0&&e.text.length>0&&Z("p",{class:"md-search-result__teaser"},function(e,t){let n=t;if(e.length>n){for(;" "!==e[n]&&--n>0;);return e.substring(0,n)+"..."}return e}(e.text,320)),a>0&&c.length>0&&Z("p",{class:"md-search-result__terms"},H("search.result.term.missing"),": ",c)))}function ne(e,t=1/0){const n=[...e],a=n.findIndex(e=>!e.location.includes("#")),[c]=n.splice(a,1);let r=n.findIndex(e=>e.scorete(e,q.TEASER)),...i.length?[Z("details",{class:"md-search-result__more"},Z("summary",{tabIndex:-1},i.length>0&&1===i.length?H("search.result.more.one"):H("search.result.more.other",i.length)),i.map(e=>te(e,q.TEASER)))]:[]];return Z("li",{class:"md-search-result__item"},s)}!function(e){e[e.TEASER=1]="TEASER",e[e.PARENT=2]="PARENT"}(q||(q={}));let ae=0;function ce(e,t){const n=new a.a;if(n.pipe(Object(W.a)(T("(hover)"))).subscribe(([{scroll:t},n])=>{t&&n?function(e,t=0){e.setAttribute("tabindex",t.toString())}(e):function(e){e.removeAttribute("tabindex")}(e)}),J.a.isSupported()){const t=e.closest("pre");t.id="__code_"+ae++,t.insertBefore((c=t.id,Z("button",{class:"md-clipboard md-icon",title:H("clipboard.copy"),"data-clipboard-target":`#${c} > code`})),e)}var c;return function(e,{viewport$:t}){return t.pipe(Object(C.a)("size"),Object(d.a)(()=>{const t=_(e);return{scroll:function(e){return{width:e.scrollWidth,height:e.scrollHeight}}(e).width>t.width}}),Object(C.a)("scroll"))}(e,t).pipe(Object(w.a)(n),Object(g.a)(()=>n.complete()),Object(d.a)(t=>Object.assign({ref:e},t)))}var re=n(64);function oe(e,t){const n=new a.a;return n.subscribe(()=>{e.setAttribute("open",""),e.scrollIntoView()}),function(e,{target$:t,print$:n}){return t.pipe(Object(d.a)(e=>e.closest("details:not([open])")),Object($.a)(t=>e===t),Object(re.a)(n),Object(s.a)(e))}(e,t).pipe(Object(w.a)(n),Object(g.a)(()=>n.complete()),Object(s.a)({ref:e}))}const ie=l("table");function se(e){return f(e,ie),f(ie,Z("div",{class:"md-typeset__scrollwrap"},Z("div",{class:"md-typeset__table"},e))),Object(m.a)({ref:e})}var pe=n(74),ue=n(73),be=n(65);function le(e,{message$:t}){const n=new a.a;return n.pipe(Object(be.a)(pe.a)).subscribe(({message:t,open:n})=>{!function(e,t){e.firstElementChild.innerHTML=t}(e,t),n?function(e,t){e.setAttribute("data-md-state",t)}(e,"open"):function(e){e.removeAttribute("data-md-state")}(e)}),function(e,{message$:t}){return t.pipe(Object(o.a)(e=>Object(c.a)(Object(m.a)(!0),Object(m.a)(!1).pipe(Object(ue.a)(2e3))).pipe(Object(d.a)(t=>({message:e,open:t})))))}(0,{message$:t}).pipe(Object(w.a)(n),Object(g.a)(()=>n.complete()),Object(d.a)(t=>Object.assign({ref:e},t)))}var fe=n(66),de=n(41);function he(e,t){const n=new a.a;n.pipe(Object(be.a)(pe.a)).subscribe(({active:t})=>{t?function(e,t){e.setAttribute("data-md-state",t)}(e,"active"):function(e){e.removeAttribute("data-md-state")}(e)});return function(e,{viewport$:t,header$:n}){return U(e,{header$:n,viewport$:t}).pipe(Object(d.a)(({offset:{y:t}})=>{const{height:n}=_(e);return{active:t>=n}}),Object(C.a)("active"))}(u("article h1"),t).pipe(Object(w.a)(n),Object(g.a)(()=>n.complete()),Object(d.a)(t=>Object.assign({ref:e},t)))}var je=n(69),Oe=n(37),me=n(4);n(42);function ge(e){return e.split(/"([^"]+)"/g).map((e,t)=>1&t?e.replace(/^\b|^(?![^\x00-\x7F]|$)|\s+/g," +"):e).join("").replace(/"|(?:^|\s+)[*+\-:^~]+(?=\s+|$)/g,"").trim()}var ve,we=n(6);function $e(e){return e.type===ve.READY}function xe(e){return e.type===ve.QUERY}function ye(e){return e.type===ve.RESULT}function _e({config:e,docs:t,index:n}){1===e.lang.length&&"en"===e.lang[0]&&(e.lang=[H("search.config.lang")]),"[\\s\\-]+"===e.separator&&(e.separator=H("search.config.separator"));return{config:e,docs:t,index:n,pipeline:H("search.config.pipeline").split(/\s*,\s*/).filter(Boolean)}}function Ee(e,t){const n=Y(),c=new Worker(e),r=new a.a,o=function(e,{tx$:t}){const n=Object(i.a)(e,"message").pipe(Object(d.a)(({data:e})=>e));return t.pipe(Object(z.a)(()=>n,{leading:!0,trailing:!0}),Object(w.a)(t=>e.postMessage(t)),Object(I.a)(n),Object(A.a)())}(c,{tx$:r}).pipe(Object(d.a)(e=>{if(ye(e))for(const t of e.data)for(const e of t)e.location=`${n.base}/${e.location}`;return e}),Object(A.a)());return Object(we.a)(t).pipe(Object(d.a)(e=>({type:ve.SETUP,data:_e(e)}))).subscribe(r.next.bind(r)),{tx$:r,rx$:o}}!function(e){e[e.SETUP=0]="SETUP",e[e.READY=1]="READY",e[e.QUERY=2]="QUERY",e[e.RESULT=3]="RESULT"}(ve||(ve={}));var Ae=n(67),Se=n(68);function ke(e,{tx$:t}){const n=new a.a;return n.pipe(Object(C.a)("value"),Object(d.a)(({value:e})=>({type:ve.QUERY,data:e}))).subscribe(t.next.bind(t)),n.pipe(Object(C.a)("focus")).subscribe(({focus:t})=>{var n,a;t?(a=t,R[n="search"].checked!==a&&R[n].click(),function(e,t){e.placeholder=t}(e,"")):function(e){e.placeholder=H("search.placeholder")}(e)}),Object(i.a)(e.form,"reset").pipe(Object(Ae.a)(n.pipe(Object(Se.a)(1)))).subscribe(()=>function(e,t=!0){t?e.focus():e.blur()}(e)),function(e){const t=(null===__search||void 0===__search?void 0:__search.transform)||ge,n=j(e),a=Object(c.a)(Object(i.a)(e,"keyup"),Object(i.a)(e,"focus").pipe(Object(ue.a)(1))).pipe(Object(d.a)(()=>t(e.value)),Object(h.a)(t(e.value)),Object(de.a)());return Object(M.a)([a,n]).pipe(Object(d.a)(([e,t])=>({value:e,focus:t})))}(e).pipe(Object(w.a)(n),Object(g.a)(()=>n.complete()),Object(d.a)(t=>Object.assign({ref:e},t)))}function Te(e,{rx$:t},{query$:n}){const c=new a.a,r=u(":first-child",e);c.pipe(Object(W.a)(n)).subscribe(([{data:e},{value:t}])=>{t?function(e,t){switch(t){case 0:e.textContent=H("search.result.none");break;case 1:e.textContent=H("search.result.one");break;default:e.textContent=H("search.result.other",t)}}(r,e.length):function(e){e.textContent=H("search.result.placeholder")}(r)});const o=u(":last-child",e);c.subscribe(({data:e})=>{!function(e){e.innerHTML=""}(o);const t=[...e.map(([e])=>e.score),0];for(let n=0;n({data:e})),Object(h.a)({data:[]})).pipe(Object(w.a)(c),Object(g.a)(()=>c.complete()),Object(d.a)(t=>Object.assign({ref:e},t)))}function Re(e){const t=Y(),n=Ee(t.search,(a=t.base+"/search/search_index.json",(null===__search||void 0===__search?void 0:__search.index)||fetch(a,{credentials:"same-origin"}).then(e=>e.json())));var a;const{tx$:r,rx$:o}=n;r.pipe(Object($.a)(xe),Object(je.a)(o.pipe(Object($.a)($e))),Object(Oe.a)(1)).subscribe(r.next.bind(r));const i=u("[data-md-component=search-query]",e),s=u("[data-md-component=search-result]",e),p=ke(i,n);return Object(c.a)(p,Te(s,n,{query$:p}))}var Me=n(24);function Ce(e,t){var{header$:n}=t,c=Object(Me.c)(t,["header$"]);const r=new a.a;return r.pipe(Object(be.a)(pe.a),Object(W.a)(n)).subscribe({next([{height:t},{height:n}]){!function(e,t){const n=e.firstElementChild;n.style.height=t-2*n.offsetTop+"px"}(e,t),function(e,t){e.style.top=t+"px"}(e,n)},complete(){!function(e){e.style.top=""}(e),function(e){e.firstElementChild.style.height=""}(e)}}),function(e,{viewport$:t,main$:n}){const a=e.parentElement.offsetTop-e.parentElement.parentElement.offsetTop;return Object(M.a)([n,t]).pipe(Object(d.a)(([{offset:e,height:t},{offset:{y:n}}])=>({height:t=t+Math.min(a,Math.max(0,n-e))-a,locked:n>=e+a})),Object(de.a)((e,t)=>e.height===t.height&&e.locked===t.locked))}(e,c).pipe(Object(w.a)(r),Object(g.a)(()=>r.complete()),Object(d.a)(t=>Object.assign({ref:e},t)))}var Le=n(71),Pe=n(70);function Ue(e){const[t]=e.match(/(git(?:hub|lab))/i)||[];switch(t.toLowerCase()){case"github":const[,t,n]=e.match(/^.+github\.com\/([^/]+)\/?([^/]+)?/i);return function(e,t){const n=void 0!==t?`https://api.github.com/repos/${e}/${t}`:"https://api.github.com/users/"+e;return Object(we.a)(fetch(n)).pipe(Object($.a)(e=>200===e.status),Object(o.a)(e=>e.json()),Object(d.a)(e=>{if(void 0!==t){const{stargazers_count:t,forks_count:n}=e;return[ee(t)+" Stars",ee(n)+" Forks"]}{const{public_repos:t}=e;return[ee(t)+" Repositories"]}}),Object(Pe.a)([]))}(t,n);case"gitlab":const[,a,c]=e.match(/^.+?([^/]*gitlab[^/]+)\/(.+?)\/?$/i);return function(e,t){const n=`https://${e}/api/v4/projects/${encodeURIComponent(t)}`;return Object(we.a)(fetch(n)).pipe(Object($.a)(e=>200===e.status),Object(o.a)(e=>e.json()),Object(d.a)(({star_count:e,forks_count:t})=>[ee(e)+" Stars",ee(t)+" Forks"]),Object(Pe.a)([]))}(a,c);default:return r.a}}let ze;function Ie(e){const t=new a.a;return t.subscribe(({facts:t})=>{!function(e,t){e.lastElementChild.appendChild(t)}(e,function(e){return Z("ul",{class:"md-source__facts"},e.map(e=>Z("li",{class:"md-source__fact"},e)))}(t)),function(e,t){e.lastElementChild.setAttribute("data-md-state",t)}(e,"done")}),function(e){const t=function(e){let t=0;for(let n=0,a=e.length;n{const n=sessionStorage.getItem(t);if(n)return Object(m.a)(JSON.parse(n));{const n=Ue(e.href);return n.subscribe(e=>{try{sessionStorage.setItem(t,JSON.stringify(e))}catch(e){}}),n}}).pipe(Object(Le.a)(()=>r.a),Object($.a)(e=>e.length>0),Object(d.a)(e=>({facts:e})),Object(v.a)(1)))}(e).pipe(Object(w.a)(t),Object(g.a)(()=>t.complete()),Object(d.a)(t=>Object.assign({ref:e},t)))}function Ne(e,t){const n=new a.a;return n.pipe(Object(be.a)(pe.a)).subscribe({next({hidden:t}){t?function(e,t){e.setAttribute("data-md-state",t)}(e,"hidden"):G(e)},complete(){G(e)}}),function(e,{viewport$:t,header$:n}){return U(e,{header$:n,viewport$:t}).pipe(Object(d.a)(({offset:{y:e}})=>({hidden:e>=10})),Object(C.a)("hidden"))}(e,t).pipe(Object(w.a)(n),Object(g.a)(()=>n.complete()),Object(d.a)(t=>Object.assign({ref:e},t)))}var Ye=n(75),He=n(72);function qe(e,t){const n=new a.a;n.pipe(Object(be.a)(pe.a)).subscribe(({prev:e,next:t})=>{for(const[e]of t)V(e),B(e);for(const[t,[n]]of e.entries())D(n,t===e.length-1),Q(n,"blur")});return function(e,{viewport$:t,header$:n}){const a=new Map;for(const t of e){const e=p(`[id="${decodeURIComponent(t.hash.substring(1))}"]`);void 0!==e&&a.set(t,e)}const c=n.pipe(Object(d.a)(e=>24+e.height));return E(document.body).pipe(Object(C.a)("height"),Object(d.a)(()=>{let e=[];return[...a].reduce((t,[n,c])=>{for(;e.length;){if(!(a.get(e[e.length-1]).tagName>=c.tagName))break;e.pop()}let r=c.offsetTop;for(;!r&&c.parentElement;)r=(c=c.parentElement).offsetTop;return t.set([...e=[...e,n]].reverse(),r)},new Map)}),Object(o.a)(e=>Object(M.a)([c,t]).pipe(Object(Ye.a)(([e,t],[n,{offset:{y:a}}])=>{for(;t.length;){const[,c]=t[0];if(!(c-n=a))break;t=[e.pop(),...t]}return[e,t]},[[],[...e]]),Object(de.a)((e,t)=>e[0]===t[0]&&e[1]===t[1])))).pipe(Object(d.a)(([e,t])=>({prev:e.map(([e])=>e),next:t.map(([e])=>e)})),Object(h.a)({prev:[],next:[]}),Object(He.a)(2,1),Object(d.a)(([e,t])=>e.prev.lengthn.complete()),Object(d.a)(t=>Object.assign({ref:e},t)))}document.documentElement.classList.remove("no-js"),document.documentElement.classList.add("js");const Fe=Object(i.a)(window,"hashchange").pipe(Object(d.a)(k),Object(h.a)(k()),Object($.a)(e=>e.length>0),Object(A.a)()).pipe(Object(o.a)(e=>Object(m.a)(p(`[id="${e}"]`)))),Je=Object(M.a)([Object(c.a)(Object(i.a)(window,"scroll",{passive:!0}),Object(i.a)(window,"resize",{passive:!0})).pipe(Object(d.a)(L),Object(h.a)(L())),Object(i.a)(window,"resize",{passive:!0}).pipe(Object(d.a)(P),Object(h.a)(P()))]).pipe(Object(d.a)(([e,t])=>({offset:e,size:t})),Object(v.a)(1)),We=T("(min-width: 960px)"),Qe=T("(min-width: 1220px)"),Be=Object(c.a)(T("print").pipe(Object($.a)(Boolean)),Object(i.a)(window,"beforeprint")).pipe(Object(s.a)(void 0)),De=u("[data-md-component=header]"),Ve=u("[data-md-component=main]"),Xe=(Ge=De,Object(O.a)(()=>{const e=getComputedStyle(Ge);return Object(m.a)("sticky"===e.position||"-webkit-sticky"===e.position)}).pipe(Object(fe.a)(E(Ge)),Object(d.a)(([e,{height:t}])=>({sticky:e,height:e?t:0})),Object(de.a)((e,t)=>e.sticky===t.sticky&&e.height===t.height)));var Ge;const Ke=function(e,{viewport$:t,header$:n}){const a=n.pipe(Object(d.a)(({height:e})=>e),Object(de.a)()),c=a.pipe(Object(o.a)(()=>E(e).pipe(Object(d.a)(({height:t})=>({top:e.offsetTop,bottom:e.offsetTop+t})),Object(C.a)("bottom"))));return Object(M.a)([a,c,t]).pipe(Object(d.a)(([e,{top:t,bottom:n},{offset:{y:a},size:{height:c}}])=>({offset:t-e,height:c=Math.max(0,c-Math.max(0,t-a,e)-Math.max(0,c+a-n)),active:t-e<=a})),Object(de.a)((e,t)=>e.offset===t.offset&&e.height===t.height&&e.active===t.active),Object(v.a)(1))}(Ve,{header$:Xe,viewport$:Je}),Ze=new a.a;(J.a.isSupported()?new me.a(e=>{new J.a("[data-clipboard-target], [data-clipboard-text]").on("success",t=>e.next(t))}).pipe(Object(A.a)()):r.a).subscribe(()=>Ze.next(H("clipboard.copied")));function et(e,t){return e.pipe(Object(o.a)(e=>e?t():r.a))}Object(c.a)(...b("[data-md-component=content]").map(e=>function(e,{target$:t,viewport$:n,print$:a}){return Object(c.a)(...b("pre > code",e).map(e=>ce(e,{viewport$:n})),...b("table:not([class])",e).map(e=>se(e)),...b("details",e).map(e=>oe(e,{target$:t,print$:a})))}(e,{target$:Fe,viewport$:Je,print$:Be})),...b("[data-md-component=dialog]").map(e=>le(e,{message$:Ze})),...b("[data-md-component=header]").map(e=>function(e,{header$:t,main$:n}){const c=new a.a;return c.pipe(Object(C.a)("active"),Object(be.a)(pe.a)).subscribe(({active:t})=>{t?function(e,t){e.setAttribute("data-md-state",t)}(e,"shadow"):function(e){e.removeAttribute("data-md-state")}(e)}),n.subscribe(e=>c.next(e)),t.pipe(Object(d.a)(t=>Object.assign({ref:e},t)),Object(v.a)(1))}(e,{viewport$:Je,header$:Xe,main$:Ke})),...b("[data-md-component=header-title]").map(e=>he(e,{viewport$:Je,header$:Xe})),...b("[data-md-component=search]").map(e=>Re(e)),...b("[data-md-component=sidebar]").map(e=>"navigation"===e.getAttribute("data-md-type")?et(Qe,()=>Ce(e,{viewport$:Je,header$:Xe,main$:Ke})):et(We,()=>Ce(e,{viewport$:Je,header$:Xe,main$:Ke}))),...b("[data-md-component=source]").map(e=>Ie(e)),...b("[data-md-component=tabs]").map(e=>Ne(e,{viewport$:Je,header$:Xe})),...b("[data-md-component=toc]").map(e=>qe(e,{viewport$:Je,header$:Xe}))).subscribe(console.log)}})); -//# sourceMappingURL=bundle.48bdffa8.min.js.map \ No newline at end of file diff --git a/material/assets/javascripts/bundle.48bdffa8.min.js.map b/material/assets/javascripts/bundle.48bdffa8.min.js.map deleted file mode 100644 index 84cda79c4..000000000 --- a/material/assets/javascripts/bundle.48bdffa8.min.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"sources":["webpack:///webpack/bootstrap","webpack:///./src/assets/javascripts/browser/element/_/index.ts","webpack:///./src/assets/javascripts/browser/element/focus/index.ts","webpack:///./src/assets/javascripts/browser/element/size/index.ts","webpack:///./src/assets/javascripts/browser/location/_/index.ts","webpack:///./src/assets/javascripts/browser/location/hash/index.ts","webpack:///./src/assets/javascripts/browser/media/index.ts","webpack:///./src/assets/javascripts/browser/toggle/index.ts","webpack:///./src/assets/javascripts/browser/viewport/offset/index.ts","webpack:///./src/assets/javascripts/browser/viewport/size/index.ts","webpack:///./src/assets/javascripts/browser/viewport/_/index.ts","webpack:///./src/assets/javascripts/_/index.ts","webpack:///./src/assets/javascripts/templates/search/index.tsx","webpack:///./src/assets/javascripts/actions/anchor/index.ts","webpack:///./src/assets/javascripts/actions/search/result/index.ts","webpack:///./src/assets/javascripts/actions/tabs/index.ts","webpack:///./src/assets/javascripts/utilities/jsx/index.ts","webpack:///./src/assets/javascripts/utilities/string/index.ts","webpack:///./src/assets/javascripts/components/content/code/index.ts","webpack:///./src/assets/javascripts/actions/_/index.ts","webpack:///./src/assets/javascripts/templates/clipboard/index.tsx","webpack:///./src/assets/javascripts/components/content/details/index.ts","webpack:///./src/assets/javascripts/components/content/table/index.ts","webpack:///./src/assets/javascripts/templates/table/index.tsx","webpack:///./src/assets/javascripts/components/dialog/index.ts","webpack:///./src/assets/javascripts/actions/dialog/index.ts","webpack:///./src/assets/javascripts/components/header/title/index.ts","webpack:///./src/assets/javascripts/actions/header/title/index.ts","webpack:///./src/assets/javascripts/integrations/search/query/transform/index.ts","webpack:///./src/assets/javascripts/integrations/search/worker/message/index.ts","webpack:///./src/assets/javascripts/integrations/search/worker/_/index.ts","webpack:///./src/assets/javascripts/browser/worker/index.ts","webpack:///./src/assets/javascripts/components/search/query/index.ts","webpack:///./src/assets/javascripts/actions/search/query/index.ts","webpack:///./src/assets/javascripts/components/search/result/index.ts","webpack:///./src/assets/javascripts/components/search/_/index.ts","webpack:///./src/assets/javascripts/components/sidebar/index.ts","webpack:///./src/assets/javascripts/actions/sidebar/index.ts","webpack:///./src/assets/javascripts/components/source/facts/_/index.ts","webpack:///./src/assets/javascripts/components/source/facts/github/index.ts","webpack:///./src/assets/javascripts/components/source/facts/gitlab/index.ts","webpack:///./src/assets/javascripts/components/source/_/index.ts","webpack:///./src/assets/javascripts/actions/source/index.ts","webpack:///./src/assets/javascripts/templates/source/index.tsx","webpack:///./src/assets/javascripts/components/tabs/index.ts","webpack:///./src/assets/javascripts/components/toc/index.ts","webpack:///./src/assets/javascripts/index.ts","webpack:///./src/assets/javascripts/components/header/_/index.ts","webpack:///./src/assets/javascripts/components/main/index.ts","webpack:///./src/assets/javascripts/integrations/clipboard/index.ts","webpack:///./src/assets/javascripts/components/content/_/index.ts","webpack:///./src/assets/javascripts/actions/header/_/index.ts"],"names":["webpackJsonpCallback","data","moduleId","chunkId","chunkIds","moreModules","executeModules","i","resolves","length","Object","prototype","hasOwnProperty","call","installedChunks","push","modules","parentJsonpFunction","shift","deferredModules","apply","checkDeferredModules","result","deferredModule","fulfilled","j","depId","splice","__webpack_require__","s","installedModules","0","exports","module","l","m","c","d","name","getter","o","defineProperty","enumerable","get","r","Symbol","toStringTag","value","t","mode","__esModule","ns","create","key","bind","n","object","property","p","jsonpArray","window","oldJsonpFunction","slice","getElement","selector","node","document","querySelector","undefined","getElementOrThrow","el","ReferenceError","getElements","Array","from","querySelectorAll","createElement","tagName","replaceElement","source","target","replaceWith","watchElementFocus","merge","fromEvent","pipe","map","type","startWith","activeElement","HTMLElement","entry$","Subject","observer$","defer","of","ResizeObserver","entries","entry","next","switchMap","resize","finalize","disconnect","shareReplay","getElementSize","width","offsetWidth","height","offsetHeight","watchElementSize","tap","observer","observe","filter","unobserve","contentRect","getLocation","URL","location","href","getLocationHash","hash","substring","watchMedia","query","media","matchMedia","ev","matches","toggles","drawer","search","getViewportOffset","x","Math","max","pageXOffset","y","pageYOffset","getViewportSize","innerWidth","innerHeight","watchViewportAt","viewport$","header$","size$","distinctUntilKeyChanged","offset$","combineLatest","offsetLeft","offsetTop","offset","size","JSON","parse","textContent","configuration","translation","translations","replace","toString","base","Flag","setAnchorState","state","setAttribute","resetAnchorState","removeAttribute","setAnchorActive","classList","toggle","resetAnchorActive","remove","addToSearchResultList","child","appendChild","resetTabsState","innerHTML","Node","isArray","h","tag","attributes","children","attr","keys","round","toFixed","renderSearchDocument","flag","parent","PARENT","teaser","TEASER","missing","terms","flat","class","tabIndex","join","score","title","text","truncate","renderSearchResult","threshold","Infinity","docs","findIndex","doc","includes","article","index","best","more","section","mountCodeBlock","options","internal$","withLatestFrom","subscribe","scroll","hover","setFocusable","resetFocusable","isSupported","closest","id","insertBefore","visible","scrollWidth","scrollHeight","getElementContentSize","watchCodeBlock","complete","ref","mountDetails","scrollIntoView","target$","print$","details","mergeWith","mapTo","watchDetails","sentinel","mountDataTable","mountDialog","message$","observeOn","animationFrame","message","open","firstElementChild","setDialogMessage","setDialogState","resetDialogState","_el","delay","watchDialog","mountHeaderTitle","active","setHeaderTitleState","resetHeaderTitleState","watchHeaderTitle","defaultTransform","split","trim","SearchMessageType","isSearchReadyMessage","READY","isSearchQueryMessage","QUERY","isSearchResultMessage","RESULT","setupSearchIndex","config","lang","separator","pipeline","Boolean","setupSearchWorker","url","worker","Worker","tx$","rx$","throttle","leading","trailing","postMessage","switchMapTo","share","watchWorker","SETUP","mountSearchQuery","focus","checked","click","placeholder","setSearchQueryPlaceholder","resetSearchQueryPlaceholder","form","takeUntil","takeLast","blur","setElementFocus","fn","__search","transform","focus$","value$","distinctUntilChanged","watchSearchQuery","mountSearchResult","query$","meta","setSearchResultMeta","resetSearchResultMeta","list","resetSearchResultList","thresholds","mountSearch","fetch","credentials","then","res","json","sample","take","mountSidebar","scrollwrap","style","setSidebarHeight","top","setSidebarOffset","resetSidebarOffset","resetSidebarHeight","main$","adjust","parentElement","min","locked","a","b","watchSidebar","fetchSourceFacts","match","toLowerCase","user","repo","status","stargazers_count","forks_count","public_repos","defaultIfEmpty","fetchSourceFactsFromGitHub","slug","project","encodeURIComponent","star_count","fetchSourceFactsFromGitLab","fetch$","mountSource","facts","lastElementChild","setSourceFacts","fact","renderSourceFacts","setSourceState","digest","len","charCodeAt","sessionStorage","getItem","setItem","stringify","err","catchError","watchSource","mountTabs","hidden","setTabsState","watchTabs","mountTableOfContents","prev","anchor","anchors","table","Map","decodeURIComponent","set","adjust$","header","body","path","reduce","pop","reverse","scan","bufferCount","watchTableOfContents","documentElement","add","passive","tablet$","screen$","main","styles","getComputedStyle","position","combineLatestWith","sticky","border$","bottom","watchMain","Observable","subscriber","on","at","toggle$","factory","mountContent","setHeaderState","resetHeaderState","mountHeader","getAttribute","console","log"],"mappings":"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","file":"assets/javascripts/bundle.48bdffa8.min.js","sourcesContent":[" \t// install a JSONP callback for chunk loading\n \tfunction webpackJsonpCallback(data) {\n \t\tvar chunkIds = data[0];\n \t\tvar moreModules = data[1];\n \t\tvar executeModules = data[2];\n\n \t\t// add \"moreModules\" to the modules object,\n \t\t// then flag all \"chunkIds\" as loaded and fire callback\n \t\tvar moduleId, chunkId, i = 0, resolves = [];\n \t\tfor(;i < chunkIds.length; i++) {\n \t\t\tchunkId = chunkIds[i];\n \t\t\tif(Object.prototype.hasOwnProperty.call(installedChunks, chunkId) && installedChunks[chunkId]) {\n \t\t\t\tresolves.push(installedChunks[chunkId][0]);\n \t\t\t}\n \t\t\tinstalledChunks[chunkId] = 0;\n \t\t}\n \t\tfor(moduleId in moreModules) {\n \t\t\tif(Object.prototype.hasOwnProperty.call(moreModules, moduleId)) {\n \t\t\t\tmodules[moduleId] = moreModules[moduleId];\n \t\t\t}\n \t\t}\n \t\tif(parentJsonpFunction) parentJsonpFunction(data);\n\n \t\twhile(resolves.length) {\n \t\t\tresolves.shift()();\n \t\t}\n\n \t\t// add entry modules from loaded chunk to deferred list\n \t\tdeferredModules.push.apply(deferredModules, executeModules || []);\n\n \t\t// run deferred modules when all chunks ready\n \t\treturn checkDeferredModules();\n \t};\n \tfunction checkDeferredModules() {\n \t\tvar result;\n \t\tfor(var i = 0; i < deferredModules.length; i++) {\n \t\t\tvar deferredModule = deferredModules[i];\n \t\t\tvar fulfilled = true;\n \t\t\tfor(var j = 1; j < deferredModule.length; j++) {\n \t\t\t\tvar depId = deferredModule[j];\n \t\t\t\tif(installedChunks[depId] !== 0) fulfilled = false;\n \t\t\t}\n \t\t\tif(fulfilled) {\n \t\t\t\tdeferredModules.splice(i--, 1);\n \t\t\t\tresult = __webpack_require__(__webpack_require__.s = deferredModule[0]);\n \t\t\t}\n \t\t}\n\n \t\treturn result;\n \t}\n\n \t// The module cache\n \tvar installedModules = {};\n\n \t// object to store loaded and loading chunks\n \t// undefined = chunk not loaded, null = chunk preloaded/prefetched\n \t// Promise = chunk loading, 0 = chunk loaded\n \tvar installedChunks = {\n \t\t0: 0\n \t};\n\n \tvar deferredModules = [];\n\n \t// The require function\n \tfunction __webpack_require__(moduleId) {\n\n \t\t// Check if module is in cache\n \t\tif(installedModules[moduleId]) {\n \t\t\treturn installedModules[moduleId].exports;\n \t\t}\n \t\t// Create a new module (and put it into the cache)\n \t\tvar module = installedModules[moduleId] = {\n \t\t\ti: moduleId,\n \t\t\tl: false,\n \t\t\texports: {}\n \t\t};\n\n \t\t// Execute the module function\n \t\tmodules[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n\n \t\t// Flag the module as loaded\n \t\tmodule.l = true;\n\n \t\t// Return the exports of the module\n \t\treturn module.exports;\n \t}\n\n\n \t// expose the modules object (__webpack_modules__)\n \t__webpack_require__.m = modules;\n\n \t// expose the module cache\n \t__webpack_require__.c = installedModules;\n\n \t// define getter function for harmony exports\n \t__webpack_require__.d = function(exports, name, getter) {\n \t\tif(!__webpack_require__.o(exports, name)) {\n \t\t\tObject.defineProperty(exports, name, { enumerable: true, get: getter });\n \t\t}\n \t};\n\n \t// define __esModule on exports\n \t__webpack_require__.r = function(exports) {\n \t\tif(typeof Symbol !== 'undefined' && Symbol.toStringTag) {\n \t\t\tObject.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });\n \t\t}\n \t\tObject.defineProperty(exports, '__esModule', { value: true });\n \t};\n\n \t// create a fake namespace object\n \t// mode & 1: value is a module id, require it\n \t// mode & 2: merge all properties of value into the ns\n \t// mode & 4: return value when already ns object\n \t// mode & 8|1: behave like require\n \t__webpack_require__.t = function(value, mode) {\n \t\tif(mode & 1) value = __webpack_require__(value);\n \t\tif(mode & 8) return value;\n \t\tif((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;\n \t\tvar ns = Object.create(null);\n \t\t__webpack_require__.r(ns);\n \t\tObject.defineProperty(ns, 'default', { enumerable: true, value: value });\n \t\tif(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key));\n \t\treturn ns;\n \t};\n\n \t// getDefaultExport function for compatibility with non-harmony modules\n \t__webpack_require__.n = function(module) {\n \t\tvar getter = module && module.__esModule ?\n \t\t\tfunction getDefault() { return module['default']; } :\n \t\t\tfunction getModuleExports() { return module; };\n \t\t__webpack_require__.d(getter, 'a', getter);\n \t\treturn getter;\n \t};\n\n \t// Object.prototype.hasOwnProperty.call\n \t__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };\n\n \t// __webpack_public_path__\n \t__webpack_require__.p = \"\";\n\n \tvar jsonpArray = window[\"webpackJsonp\"] = window[\"webpackJsonp\"] || [];\n \tvar oldJsonpFunction = jsonpArray.push.bind(jsonpArray);\n \tjsonpArray.push = webpackJsonpCallback;\n \tjsonpArray = jsonpArray.slice();\n \tfor(var i = 0; i < jsonpArray.length; i++) webpackJsonpCallback(jsonpArray[i]);\n \tvar parentJsonpFunction = oldJsonpFunction;\n\n\n \t// add entry module to deferred list\n \tdeferredModules.push([48,1]);\n \t// run deferred modules when ready\n \treturn checkDeferredModules();\n","/*\n * Copyright (c) 2016-2020 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Retrieve an element matching the query selector\n *\n * @template T - Element type\n *\n * @param selector - Query selector\n * @param node - Node of reference\n *\n * @returns Element or nothing\n */\nexport function getElement(\n selector: T, node?: ParentNode\n): HTMLElementTagNameMap[T]\n\nexport function getElement(\n selector: string, node?: ParentNode\n): T\n\nexport function getElement(\n selector: string, node: ParentNode = document\n): T | undefined {\n return node.querySelector(selector) || undefined\n}\n\n/**\n * Retrieve an element matching a query selector or throw a reference error\n *\n * @template T - Element type\n *\n * @param selector - Query selector\n * @param node - Node of reference\n *\n * @returns Element\n */\nexport function getElementOrThrow(\n selector: T, node?: ParentNode\n): HTMLElementTagNameMap[T]\n\nexport function getElementOrThrow(\n selector: string, node?: ParentNode\n): T\n\nexport function getElementOrThrow(\n selector: string, node: ParentNode = document\n): T {\n const el = getElement(selector, node)\n if (typeof el === \"undefined\")\n throw new ReferenceError(\n `Missing element: expected \"${selector}\" to be present`\n )\n return el\n}\n\n/**\n * Retrieve the currently active element\n *\n * @returns Element or nothing\n */\nexport function getActiveElement(): HTMLElement | undefined {\n return document.activeElement instanceof HTMLElement\n ? document.activeElement\n : undefined\n}\n\n/**\n * Retrieve all elements matching the query selector\n *\n * @template T - Element type\n *\n * @param selector - Query selector\n * @param node - Node of reference\n *\n * @returns Elements\n */\nexport function getElements(\n selector: T, node?: ParentNode\n): HTMLElementTagNameMap[T][]\n\nexport function getElements(\n selector: string, node?: ParentNode\n): T[]\n\nexport function getElements(\n selector: string, node: ParentNode = document\n): T[] {\n return Array.from(node.querySelectorAll(selector))\n}\n\n/* ------------------------------------------------------------------------- */\n\n/**\n * Create an element\n *\n * @template T - Tag name type\n *\n * @param tagName - Tag name\n *\n * @returns Element\n */\nexport function createElement(\n tagName: T\n): HTMLElementTagNameMap[T] {\n return document.createElement(tagName)\n}\n\n/**\n * Replace an element with another element\n *\n * @param source - Source element\n * @param target - Target element\n */\nexport function replaceElement(\n source: HTMLElement, target: Node\n): void {\n source.replaceWith(target)\n}\n","/*\n * Copyright (c) 2016-2020 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport { Observable, fromEvent, merge } from \"rxjs\"\nimport { map, startWith } from \"rxjs/operators\"\n\nimport { getActiveElement } from \"../_\"\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Set element focus\n *\n * @param el - Element\n * @param value - Whether the element should be focused\n */\nexport function setElementFocus(\n el: HTMLElement, value = true\n): void {\n if (value)\n el.focus()\n else\n el.blur()\n}\n\n/* ------------------------------------------------------------------------- */\n\n/**\n * Watch element focus\n *\n * @param el - Element\n *\n * @returns Element focus observable\n */\nexport function watchElementFocus(\n el: HTMLElement\n): Observable {\n return merge(\n fromEvent(el, \"focus\"),\n fromEvent(el, \"blur\")\n )\n .pipe(\n map(({ type }) => type === \"focus\"),\n startWith(el === getActiveElement())\n )\n}\n","/*\n * Copyright (c) 2016-2020 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport {\n NEVER,\n Observable,\n Subject,\n defer,\n of\n} from \"rxjs\"\nimport {\n filter,\n finalize,\n map,\n shareReplay,\n startWith,\n switchMap,\n tap\n} from \"rxjs/operators\"\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Element offset\n */\nexport interface ElementSize {\n width: number /* Element width */\n height: number /* Element height */\n}\n\n/* ----------------------------------------------------------------------------\n * Data\n * ------------------------------------------------------------------------- */\n\n/**\n * Resize observer entry subject\n */\nconst entry$ = new Subject()\n\n/**\n * Resize observer observable\n *\n * This observable will create a `ResizeObserver` on the first subscription\n * and will automatically terminate it when there are no more subscribers.\n * It's quite important to centralize observation in a single `ResizeObserver`,\n * as the performance difference can be quite dramatic, as the link shows.\n *\n * @see https://bit.ly/3iIYfEm - Google Groups on performance\n */\nconst observer$ = defer(() => of(\n new ResizeObserver(entries => {\n for (const entry of entries)\n entry$.next(entry)\n })\n))\n .pipe(\n switchMap(resize => NEVER.pipe(startWith(resize))\n .pipe(\n finalize(() => resize.disconnect())\n )\n ),\n shareReplay(1)\n )\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Retrieve element size\n *\n * @param el - Element\n *\n * @returns Element size\n */\nexport function getElementSize(el: HTMLElement): ElementSize {\n return {\n width: el.offsetWidth,\n height: el.offsetHeight\n }\n}\n\n/**\n * Retrieve element content size, i.e. including overflowing content\n *\n * @param el - Element\n *\n * @returns Element size\n */\nexport function getElementContentSize(el: HTMLElement): ElementSize {\n return {\n width: el.scrollWidth,\n height: el.scrollHeight\n }\n}\n\n/* ------------------------------------------------------------------------- */\n\n/**\n * Watch element size\n *\n * This function returns an observable that will subscribe to a single internal\n * instance of `ResizeObserver` upon subscription, and emit resize events until\n * termination. Note that this function should not be called with the same\n * element twice, as the first unsubscription will terminate observation.\n *\n * @param el - Element\n *\n * @returns Element size observable\n */\nexport function watchElementSize(\n el: HTMLElement\n): Observable {\n return observer$\n .pipe(\n tap(observer => observer.observe(el)),\n switchMap(observer => entry$\n .pipe(\n filter(({ target }) => target === el),\n finalize(() => observer.unobserve(el)),\n map(({ contentRect }) => ({\n width: contentRect.width,\n height: contentRect.height\n }))\n )\n ),\n startWith(getElementSize(el))\n )\n}\n","/*\n * Copyright (c) 2016-2020 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport { BehaviorSubject, Subject } from \"rxjs\"\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Retrieve location\n *\n * This function will return a `URL` object (and not `Location`) in order to\n * normalize typings across the application. Furthermore, locations need to be\n * tracked without setting them and `Location` is a singleton which represents\n * the current location.\n *\n * @returns URL\n */\nexport function getLocation(): URL {\n return new URL(location.href)\n}\n\n/**\n * Set location\n *\n * @param url - URL to change to\n */\nexport function setLocation(url: URL): void {\n location.href = url.href\n}\n\n/* ------------------------------------------------------------------------- */\n\n/**\n * Watch location\n *\n * @returns Location subject\n */\nexport function watchLocation(): Subject {\n return new BehaviorSubject(getLocation())\n}\n","/*\n * Copyright (c) 2016-2020 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport { Observable, fromEvent, of } from \"rxjs\"\nimport { filter, map, share, startWith, switchMap } from \"rxjs/operators\"\n\nimport { createElement, getElement } from \"~/browser\"\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Retrieve location hash\n *\n * @returns Location hash\n */\nexport function getLocationHash(): string {\n return location.hash.substring(1)\n}\n\n/**\n * Set location hash\n *\n * Setting a new fragment identifier via `location.hash` will have no effect\n * if the value doesn't change. When a new fragment identifier is set, we want\n * the browser to target the respective element at all times, which is why we\n * use this dirty little trick.\n *\n * @param hash - Location hash\n */\nexport function setLocationHash(hash: string): void {\n const el = createElement(\"a\")\n el.href = hash\n el.addEventListener(\"click\", ev => ev.stopPropagation())\n el.click()\n}\n\n/* ------------------------------------------------------------------------- */\n\n/**\n * Watch location hash\n *\n * @returns Location hash observable\n */\nexport function watchLocationHash(): Observable {\n return fromEvent(window, \"hashchange\")\n .pipe(\n map(getLocationHash),\n startWith(getLocationHash()),\n filter(hash => hash.length > 0),\n share()\n )\n}\n\n/**\n * Watch location target\n *\n * @returns Location target observable\n */\nexport function watchLocationTarget(): Observable {\n return watchLocationHash()\n .pipe(\n switchMap(id => of(getElement(`[id=\"${id}\"]`)!))\n )\n}\n","/*\n * Copyright (c) 2016-2020 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport { Observable, fromEvent, merge } from \"rxjs\"\nimport { filter, map, mapTo, startWith } from \"rxjs/operators\"\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Watch media query\n *\n * @param query - Media query\n *\n * @returns Media observable\n */\nexport function watchMedia(query: string): Observable {\n const media = matchMedia(query)\n return fromEvent(media, \"change\")\n .pipe(\n map(ev => ev.matches),\n startWith(media.matches)\n )\n}\n\n/**\n * Watch print mode, cross-browser\n *\n * @returns Print observable\n */\nexport function watchPrint(): Observable {\n return merge(\n watchMedia(\"print\").pipe(filter(Boolean)), /* Webkit */\n fromEvent(window, \"beforeprint\") /* IE, FF */\n )\n .pipe(\n mapTo(undefined)\n )\n}\n","/*\n * Copyright (c) 2016-2020 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport { Observable, fromEvent } from \"rxjs\"\nimport { map, startWith } from \"rxjs/operators\"\n\nimport { getElementOrThrow } from \"../element\"\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Toggle\n */\nexport type Toggle =\n | \"drawer\" /* Toggle for drawer */\n | \"search\" /* Toggle for search */\n\n/* ----------------------------------------------------------------------------\n * Data\n * ------------------------------------------------------------------------- */\n\n/**\n * Toggle map\n */\nconst toggles: Record = {\n drawer: getElementOrThrow(\"[data-md-toggle=drawer]\"),\n search: getElementOrThrow(\"[data-md-toggle=search]\")\n}\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Retrieve the value of a toggle\n *\n * @param name - Toggle\n *\n * @returns Toggle value\n */\nexport function getToggle(name: Toggle): boolean {\n return toggles[name].checked\n}\n\n/**\n * Set toggle\n *\n * Simulating a click event seems to be the most cross-browser compatible way\n * of changing the value while also emitting a `change` event. Before, Material\n * used `CustomEvent` to programmatically change the value of a toggle, but this\n * is a much simpler and cleaner solution which doesn't require a polyfill.\n *\n * @param name - Toggle\n * @param value - Toggle value\n */\nexport function setToggle(name: Toggle, value: boolean): void {\n if (toggles[name].checked !== value)\n toggles[name].click()\n}\n\n/* ------------------------------------------------------------------------- */\n\n/**\n * Watch toggle\n *\n * @param name - Toggle\n *\n * @returns Toggle value observable\n */\nexport function watchToggle(name: Toggle): Observable {\n const el = toggles[name]\n return fromEvent(el, \"change\")\n .pipe(\n map(() => el.checked),\n startWith(el.checked)\n )\n}\n","/*\n * Copyright (c) 2016-2020 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport { Observable, fromEvent, merge } from \"rxjs\"\nimport { map, startWith } from \"rxjs/operators\"\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Viewport offset\n */\nexport interface ViewportOffset {\n x: number /* Horizontal offset */\n y: number /* Vertical offset */\n}\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Retrieve viewport offset\n *\n * On iOS Safari, viewport offset can be negative due to overflow scrolling.\n * As this may induce strange behaviors downstream, we'll just limit it to 0.\n *\n * @returns Viewport offset\n */\nexport function getViewportOffset(): ViewportOffset {\n return {\n x: Math.max(0, pageXOffset),\n y: Math.max(0, pageYOffset)\n }\n}\n\n/**\n * Set viewport offset\n *\n * @param offset - Viewport offset\n */\nexport function setViewportOffset(\n { x, y }: Partial\n): void {\n window.scrollTo(x || 0, y || 0)\n}\n\n/* ------------------------------------------------------------------------- */\n\n/**\n * Watch viewport offset\n *\n * @returns Viewport offset observable\n */\nexport function watchViewportOffset(): Observable {\n return merge(\n fromEvent(window, \"scroll\", { passive: true }),\n fromEvent(window, \"resize\", { passive: true })\n )\n .pipe(\n map(getViewportOffset),\n startWith(getViewportOffset())\n )\n}\n","/*\n * Copyright (c) 2016-2020 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport { Observable, fromEvent } from \"rxjs\"\nimport { map, startWith } from \"rxjs/operators\"\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Viewport size\n */\nexport interface ViewportSize {\n width: number /* Viewport width */\n height: number /* Viewport height */\n}\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Retrieve viewport size\n *\n * @returns Viewport size\n */\nexport function getViewportSize(): ViewportSize {\n return {\n width: innerWidth,\n height: innerHeight\n }\n}\n\n/* ------------------------------------------------------------------------- */\n\n/**\n * Watch viewport size\n *\n * @returns Viewport size observable\n */\nexport function watchViewportSize(): Observable {\n return fromEvent(window, \"resize\", { passive: true })\n .pipe(\n map(getViewportSize),\n startWith(getViewportSize())\n )\n}\n","/*\n * Copyright (c) 2016-2020 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport { Observable, combineLatest } from \"rxjs\"\nimport {\n distinctUntilKeyChanged,\n map,\n shareReplay\n} from \"rxjs/operators\"\n\nimport { Header } from \"~/components\"\n\nimport {\n ViewportOffset,\n watchViewportOffset\n} from \"../offset\"\nimport {\n ViewportSize,\n watchViewportSize\n} from \"../size\"\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Viewport\n */\nexport interface Viewport {\n offset: ViewportOffset /* Viewport offset */\n size: ViewportSize /* Viewport size */\n}\n\n/* ----------------------------------------------------------------------------\n * Helper types\n * ------------------------------------------------------------------------- */\n\n/**\n * Watch at options\n */\ninterface WatchAtOptions {\n viewport$: Observable /* Viewport observable */\n header$: Observable
    /* Header observable */\n}\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Watch viewport\n *\n * @returns Viewport observable\n */\nexport function watchViewport(): Observable {\n return combineLatest([\n watchViewportOffset(),\n watchViewportSize()\n ])\n .pipe(\n map(([offset, size]) => ({ offset, size })),\n shareReplay(1)\n )\n}\n\n/**\n * Watch viewport relative to element\n *\n * @param el - Element\n * @param options - Options\n *\n * @returns Viewport observable\n */\nexport function watchViewportAt(\n el: HTMLElement, { viewport$, header$ }: WatchAtOptions\n): Observable {\n const size$ = viewport$\n .pipe(\n distinctUntilKeyChanged(\"size\")\n )\n\n /* Compute element offset */\n const offset$ = combineLatest([size$, header$])\n .pipe(\n map((): ViewportOffset => ({\n x: el.offsetLeft,\n y: el.offsetTop\n }))\n )\n\n /* Compute relative viewport, return hot observable */\n return combineLatest([header$, viewport$, offset$])\n .pipe(\n map(([{ height }, { offset, size }, { x, y }]) => ({\n offset: {\n x: offset.x - x,\n y: offset.y - y + height\n },\n size\n }))\n )\n}\n","/*\n * Copyright (c) 2016-2020 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport { getElementOrThrow, getLocation } from \"~/browser\"\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Feature flag\n */\nexport type Feature =\n | \"header.autohide\" /* Hide header */\n | \"navigation.tabs\" /* Tabs navigation */\n | \"navigation.instant\" /* Instant loading */\n\n/* ------------------------------------------------------------------------- */\n\n/**\n * Translation\n */\nexport type Translation =\n | \"clipboard.copy\" /* Copy to clipboard */\n | \"clipboard.copied\" /* Copied to clipboard */\n | \"search.config.lang\" /* Search language */\n | \"search.config.pipeline\" /* Search pipeline */\n | \"search.config.separator\" /* Search separator */\n | \"search.placeholder\" /* Search */\n | \"search.result.placeholder\" /* Type to start searching */\n | \"search.result.none\" /* No matching documents */\n | \"search.result.one\" /* 1 matching document */\n | \"search.result.other\" /* # matching documents */\n | \"search.result.more.one\" /* 1 more on this page */\n | \"search.result.more.other\" /* # more on this page */\n | \"search.result.term.missing\" /* Missing */\n\n/**\n * Translations\n */\nexport type Translations = Record\n\n/* ------------------------------------------------------------------------- */\n\n/**\n * Configuration\n */\nexport interface Config {\n base: string /* Base URL */\n features: Feature[] /* Feature flags */\n translations: Translations /* Translations */\n search: string /* Search worker URL */\n}\n\n/* ----------------------------------------------------------------------------\n * Data\n * ------------------------------------------------------------------------- */\n\n/**\n * Retrieve global configuration and make base URL absolute\n */\nconst config: Config = JSON.parse(getElementOrThrow(\"#__config\").textContent!)\nconfig.base = new URL(config.base, getLocation())\n .toString()\n .replace(/\\/$/, \"\")\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Retrieve global configuration\n *\n * @returns Global configuration\n */\nexport function configuration(): Config {\n return config\n}\n\n/**\n * Check whether a feature is enabled\n *\n * @param feature - Feature\n *\n * @returns Test result\n */\nexport function flag(feature: Feature): boolean {\n return config.features.includes(feature)\n}\n\n/**\n * Retrieve the translation for the given key\n *\n * @param key - Key to be translated\n * @param value - Value to be replaced\n *\n * @returns Translation\n */\nexport function translation(\n key: Translation, value?: string | number\n): string {\n if (typeof config.translations[key] === \"undefined\") {\n throw new ReferenceError(`Invalid translation: ${key}`)\n }\n return typeof value !== \"undefined\"\n ? config.translations[key].replace(\"#\", value.toString())\n : config.translations[key]\n}\n","/*\n * Copyright (c) 2016-2020 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport { translation } from \"~/_\"\nimport {\n SearchDocument,\n SearchMetadata,\n SearchResult\n} from \"~/integrations/search\"\nimport { h, truncate } from \"~/utilities\"\n\n/* ----------------------------------------------------------------------------\n * Helper types\n * ------------------------------------------------------------------------- */\n\n/**\n * Render flag\n */\nconst enum Flag {\n TEASER = 1, /* Render teaser */\n PARENT = 2 /* Render as parent */\n}\n\n/* ----------------------------------------------------------------------------\n * Helper function\n * ------------------------------------------------------------------------- */\n\n/**\n * Render a search document\n *\n * @param section - Search document\n * @param flag - Render flags\n *\n * @returns Element\n */\nfunction renderSearchDocument(\n document: SearchDocument & SearchMetadata, flag: Flag\n) {\n const parent = flag & Flag.PARENT\n const teaser = flag & Flag.TEASER\n\n /* Render missing query terms */\n const missing = Object.keys(document.terms)\n .filter(key => !document.terms[key])\n .map(key => [{key}, \" \"])\n .flat()\n .slice(0, -1)\n\n /* Render article or section, depending on flags */\n const url = document.location\n return (\n \n \n {parent > 0 &&
    }\n

    {document.title}

    \n {teaser > 0 && document.text.length > 0 &&\n

    \n {truncate(document.text, 320)}\n

    \n }\n {teaser > 0 && missing.length > 0 &&\n

    \n {translation(\"search.result.term.missing\")}: {...missing}\n

    \n }\n \n
    \n )\n}\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Render a search result\n *\n * @param result - Search result\n * @param threshold - Score threshold\n *\n * @returns Element\n */\nexport function renderSearchResult(\n result: SearchResult, threshold: number = Infinity\n) {\n const docs = [...result]\n\n /* Find and extract parent article */\n const parent = docs.findIndex(doc => !doc.location.includes(\"#\"))\n const [article] = docs.splice(parent, 1)\n\n /* Determine last index above threshold */\n let index = docs.findIndex(doc => doc.score < threshold)\n if (index === -1)\n index = docs.length\n\n /* Partition sections */\n const best = docs.slice(0, index)\n const more = docs.slice(index)\n\n /* Render children */\n const children = [\n renderSearchDocument(article, Flag.PARENT | +(!parent && index === 0)),\n ...best.map(section => renderSearchDocument(section, Flag.TEASER)),\n ...more.length ? [\n
    \n \n {more.length > 0 && more.length === 1\n ? translation(\"search.result.more.one\")\n : translation(\"search.result.more.other\", more.length)\n }\n \n {...more.map(section => renderSearchDocument(section, Flag.TEASER))}\n
    \n ] : []\n ]\n\n /* Render search result */\n return (\n
  • \n {children}\n
  • \n )\n}\n","/*\n * Copyright (c) 2016-2020 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Set anchor state\n *\n * @param el - Anchor element\n * @param state - Anchor state\n */\nexport function setAnchorState(\n el: HTMLElement, state: \"blur\"\n): void {\n el.setAttribute(\"data-md-state\", state)\n}\n\n/**\n * Reset anchor state\n *\n * @param el - Anchor element\n */\nexport function resetAnchorState(\n el: HTMLElement\n): void {\n el.removeAttribute(\"data-md-state\")\n}\n\n/* ------------------------------------------------------------------------- */\n\n/**\n * Set anchor active\n *\n * @param el - Anchor element\n * @param value - Whether the anchor is active\n */\nexport function setAnchorActive(\n el: HTMLElement, value: boolean\n): void {\n el.classList.toggle(\"md-nav__link--active\", value)\n}\n\n/**\n * Reset anchor active\n *\n * @param el - Anchor element\n */\nexport function resetAnchorActive(\n el: HTMLElement\n): void {\n el.classList.remove(\"md-nav__link--active\")\n}\n","/*\n * Copyright (c) 2016-2020 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport { translation } from \"~/_\"\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Set number of search results\n *\n * @param el - Search result metadata element\n * @param value - Number of results\n */\nexport function setSearchResultMeta(\n el: HTMLElement, value: number\n): void {\n switch (value) {\n\n /* No results */\n case 0:\n el.textContent = translation(\"search.result.none\")\n break\n\n /* One result */\n case 1:\n el.textContent = translation(\"search.result.one\")\n break\n\n /* Multiple result */\n default:\n el.textContent = translation(\"search.result.other\", value)\n }\n}\n\n/**\n * Reset number of search results\n *\n * @param el - Search result metadata element\n */\nexport function resetSearchResultMeta(\n el: HTMLElement\n): void {\n el.textContent = translation(\"search.result.placeholder\")\n}\n\n/* ------------------------------------------------------------------------- */\n\n/**\n * Add an element to the search result list\n *\n * @param el - Search result list element\n * @param child - Search result element\n */\nexport function addToSearchResultList(\n el: HTMLElement, child: Element\n): void {\n el.appendChild(child)\n}\n\n/**\n * Reset search result list\n *\n * @param el - Search result list element\n */\nexport function resetSearchResultList(\n el: HTMLElement\n): void {\n el.innerHTML = \"\"\n}\n","/*\n * Copyright (c) 2016-2020 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Set tabs state\n *\n * @param el - Tabs element\n * @param state - Tabs state\n */\nexport function setTabsState(\n el: HTMLElement, state: \"hidden\"\n): void {\n el.setAttribute(\"data-md-state\", state)\n}\n\n/**\n * Reset tabs state\n *\n * @param el - Tabs element\n */\nexport function resetTabsState(\n el: HTMLElement\n): void {\n el.removeAttribute(\"data-md-state\")\n}\n","/*\n * Copyright (c) 2016-2020 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport { JSX as JSXInternal } from \"preact\"\n\n/* ----------------------------------------------------------------------------\n * Helper types\n * ------------------------------------------------------------------------- */\n\n/**\n * HTML attributes\n */\ntype Attributes =\n & JSXInternal.HTMLAttributes\n & JSXInternal.SVGAttributes\n & Record\n\n/**\n * Child element\n */\ntype Child =\n | HTMLElement\n | Text\n | string\n | number\n\n/* ----------------------------------------------------------------------------\n * Helper functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Append a child node to an element\n *\n * @param el - Element\n * @param child - Child node(s)\n */\nfunction appendChild(el: HTMLElement, child: Child | Child[]): void {\n\n /* Handle primitive types (including raw HTML) */\n if (typeof child === \"string\" || typeof child === \"number\") {\n el.innerHTML += child.toString()\n\n /* Handle nodes */\n } else if (child instanceof Node) {\n el.appendChild(child)\n\n /* Handle nested children */\n } else if (Array.isArray(child)) {\n for (const node of child)\n appendChild(el, node)\n }\n}\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * JSX factory\n *\n * @param tag - HTML tag\n * @param attributes - HTML attributes\n * @param children - Child elements\n *\n * @returns Element\n */\nexport function h(\n tag: string, attributes: Attributes | null, ...children: Child[]\n): HTMLElement {\n const el = document.createElement(tag)\n\n /* Set attributes, if any */\n if (attributes)\n for (const attr of Object.keys(attributes))\n if (typeof attributes[attr] !== \"boolean\")\n el.setAttribute(attr, attributes[attr])\n else if (attributes[attr])\n el.setAttribute(attr, \"\")\n\n /* Append child nodes */\n for (const child of children)\n appendChild(el, child)\n\n /* Return element */\n return el\n}\n\n/* ----------------------------------------------------------------------------\n * Namespace\n * ------------------------------------------------------------------------- */\n\nexport declare namespace h {\n namespace JSX {\n type Element = HTMLElement\n type IntrinsicElements = JSXInternal.IntrinsicElements\n }\n}\n","/*\n * Copyright (c) 2016-2020 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Truncate a string after the given number of characters\n *\n * This is not a very reasonable approach, since the summaries kind of suck.\n * It would be better to create something more intelligent, highlighting the\n * search occurrences and making a better summary out of it, but this note was\n * written three years ago, so who knows if we'll ever fix it.\n *\n * @param value - Value to be truncated\n * @param n - Number of characters\n *\n * @returns Truncated value\n */\nexport function truncate(value: string, n: number): string {\n let i = n\n if (value.length > i) {\n while (value[i] !== \" \" && --i > 0) { /* keep eating */ }\n return `${value.substring(0, i)}...`\n }\n return value\n}\n\n/**\n * Round a number for display with repository facts\n *\n * This is a reverse-engineered version of GitHub's weird rounding algorithm\n * for stars, forks and all other numbers. While all numbers below `1,000` are\n * returned as-is, bigger numbers are converted to fixed numbers:\n *\n * - `1,049` => `1k`\n * - `1,050` => `1.1k`\n * - `1,949` => `1.9k`\n * - `1,950` => `2k`\n *\n * @param value - Original value\n *\n * @returns Rounded value\n */\nexport function round(value: number): string {\n if (value > 999) {\n const digits = +((value - 950) % 1000 > 99)\n return `${((value + 0.000001) / 1000).toFixed(digits)}k`\n } else {\n return value.toString()\n }\n}\n\n/**\n * Simple hash function\n *\n * @see https://bit.ly/2wsVjJ4 - Original source\n *\n * @param value - Value to be hashed\n *\n * @returns Hash as 32bit integer\n */\nexport function hash(value: string): number {\n let h = 0\n for (let i = 0, len = value.length; i < len; i++) {\n h = ((h << 5) - h) + value.charCodeAt(i)\n h |= 0 // Convert to 32bit integer\n }\n return h\n}\n","/*\n * Copyright (c) 2016-2020 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport ClipboardJS from \"clipboard\"\nimport { Observable, Subject } from \"rxjs\"\nimport {\n distinctUntilKeyChanged,\n finalize,\n map,\n tap,\n withLatestFrom\n} from \"rxjs/operators\"\n\nimport { resetFocusable, setFocusable } from \"~/actions\"\nimport {\n Viewport,\n getElementContentSize,\n getElementSize,\n watchMedia\n} from \"~/browser\"\nimport { renderClipboardButton } from \"~/templates\"\n\nimport { Component } from \"../../_\"\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Code block\n */\nexport interface CodeBlock {\n scroll: boolean /* Code block overflows */\n}\n\n/* ----------------------------------------------------------------------------\n * Helper types\n * ------------------------------------------------------------------------- */\n\n/**\n * Watch options\n */\ninterface WatchOptions {\n viewport$: Observable /* Viewport observable */\n}\n\n/**\n * Mount options\n */\ninterface MountOptions {\n viewport$: Observable /* Viewport observable */\n}\n\n/* ----------------------------------------------------------------------------\n * Data\n * ------------------------------------------------------------------------- */\n\n/**\n * Global index for Clipboard.js integration\n */\nlet index = 0\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Watch code block\n *\n * @param el - Code block element\n * @param options - Options\n *\n * @returns Code block observable\n */\nexport function watchCodeBlock(\n el: HTMLElement, { viewport$ }: WatchOptions\n): Observable {\n return viewport$\n .pipe(\n distinctUntilKeyChanged(\"size\"),\n map(() => {\n const visible = getElementSize(el)\n const content = getElementContentSize(el)\n return {\n scroll: content.width > visible.width\n }\n }),\n distinctUntilKeyChanged(\"scroll\")\n )\n}\n\n/**\n * Mount code block\n *\n * This function ensures that overflowing code blocks are focusable by keyboard,\n * so they can be scrolled without a mouse to improve on accessibility.\n *\n * @param el - Code block element\n * @param options - Options\n *\n * @returns Code block component observable\n */\nexport function mountCodeBlock(\n el: HTMLElement, options: MountOptions\n): Observable> {\n const internal$ = new Subject()\n internal$\n .pipe(\n withLatestFrom(watchMedia(\"(hover)\"))\n )\n .subscribe(([{ scroll }, hover]) => {\n if (scroll && hover)\n setFocusable(el)\n else\n resetFocusable(el)\n })\n\n /* Inject button for Clipboard.js integration */\n if (ClipboardJS.isSupported()) {\n const parent = el.closest(\"pre\")!\n parent.id = `__code_${index++}`\n parent.insertBefore(\n renderClipboardButton(parent.id),\n el\n )\n }\n\n /* Create and return component */\n return watchCodeBlock(el, options)\n .pipe(\n tap(internal$),\n finalize(() => internal$.complete()),\n map(state => ({ ref: el, ...state }))\n )\n}\n","/*\n * Copyright (c) 2016-2020 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Set focusable property\n *\n * @param el - Element\n * @param value - Tabindex value\n */\nexport function setFocusable(\n el: HTMLElement, value = 0\n): void {\n el.setAttribute(\"tabindex\", value.toString())\n}\n\n/**\n * Reset focusable property\n *\n * @param el - Element\n */\nexport function resetFocusable(\n el: HTMLElement\n): void {\n el.removeAttribute(\"tabindex\")\n}\n","/*\n * Copyright (c) 2016-2020 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport { translation } from \"~/_\"\nimport { h } from \"~/utilities\"\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Render a 'copy-to-clipboard' button\n *\n * @param id - Unique identifier\n *\n * @returns Element\n */\nexport function renderClipboardButton(id: string) {\n return (\n code`}\n >\n )\n}\n","/*\n * Copyright (c) 2016-2020 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport { Observable, Subject } from \"rxjs\"\nimport {\n filter,\n finalize,\n map,\n mapTo,\n mergeWith,\n tap\n} from \"rxjs/operators\"\n\nimport { Component } from \"../../_\"\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Details\n */\nexport interface Details {}\n\n/* ----------------------------------------------------------------------------\n * Helper types\n * ------------------------------------------------------------------------- */\n\n/**\n * Watch options\n */\ninterface WatchOptions {\n target$: Observable /* Location target observable */\n print$: Observable /* Print observable */\n}\n\n/**\n * Mount options\n */\ninterface MountOptions {\n target$: Observable /* Location target observable */\n print$: Observable /* Print observable */\n}\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Watch details\n *\n * @param el - Details element\n * @param options - Options\n *\n * @returns Details observable\n */\nexport function watchDetails(\n el: HTMLDetailsElement, { target$, print$ }: WatchOptions\n): Observable
    {\n return target$\n .pipe(\n map(target => target.closest(\"details:not([open])\")!),\n filter(details => el === details),\n mergeWith(print$),\n mapTo(el)\n )\n}\n\n/**\n * Mount details\n *\n * This function ensures that `details` tags are opened prior to printing, so\n * the whole content of the page is included and on anchor jumps.\n *\n * @param el - Details element\n * @param options - Options\n *\n * @returns Details component observable\n */\nexport function mountDetails(\n el: HTMLDetailsElement, options: MountOptions\n): Observable> {\n const internal$ = new Subject
    ()\n internal$.subscribe(() => {\n el.setAttribute(\"open\", \"\")\n el.scrollIntoView()\n })\n\n /* Create and return component */\n return watchDetails(el, options)\n .pipe(\n tap(internal$),\n finalize(() => internal$.complete()),\n mapTo({ ref: el })\n )\n}\n","/*\n * Copyright (c) 2016-2020 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport { Observable, of } from \"rxjs\"\n\nimport { createElement, replaceElement } from \"~/browser\"\nimport { renderTable } from \"~/templates\"\n\nimport { Component } from \"../../_\"\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Data table\n */\nexport interface DataTable {}\n\n/* ----------------------------------------------------------------------------\n * Data\n * ------------------------------------------------------------------------- */\n\n/**\n * Sentinel for replacement\n */\nconst sentinel = createElement(\"table\")\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Mount data table\n *\n * @param el - Data table element\n *\n * @returns Data table component observable\n */\nexport function mountDataTable(\n el: HTMLElement\n): Observable> {\n replaceElement(el, sentinel)\n replaceElement(sentinel, renderTable(el))\n\n /* Create and return component */\n return of({ ref: el })\n}\n","/*\n * Copyright (c) 2016-2020 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport { h } from \"utilities\"\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Render a table inside a wrapper to improve scrolling on mobile\n *\n * @param table - Table element\n *\n * @returns Element\n */\nexport function renderTable(table: HTMLElement) {\n return (\n
    \n
    \n {table}\n
    \n
    \n )\n}\n","/*\n * Copyright (c) 2016-2020 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport {\n Observable,\n Subject,\n animationFrameScheduler,\n merge,\n of\n} from \"rxjs\"\nimport {\n delay,\n finalize,\n map,\n observeOn,\n switchMap,\n tap\n} from \"rxjs/operators\"\n\nimport {\n resetDialogState,\n setDialogMessage,\n setDialogState\n} from \"~/actions\"\n\nimport { Component } from \"../_\"\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Dialog\n */\nexport interface Dialog {\n message: string /* Dialog message */\n open: boolean /* Dialog is visible */\n}\n\n/* ----------------------------------------------------------------------------\n * Helper types\n * ------------------------------------------------------------------------- */\n\n/**\n * Watch options\n */\ninterface WatchOptions {\n message$: Subject /* Message subject */\n}\n\n/**\n * Mount options\n */\ninterface MountOptions {\n message$: Subject /* Message subject */\n}\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Watch dialog\n *\n * @param _el - Dialog element\n * @param options - Options\n *\n * @returns Dialog observable\n */\nexport function watchDialog(\n _el: HTMLElement, { message$ }: WatchOptions\n): Observable {\n return message$\n .pipe(\n switchMap(message => merge(\n of(true),\n of(false).pipe(delay(2000))\n )\n .pipe(\n map(open => ({ message, open }))\n )\n )\n )\n}\n\n/**\n * Mount dialog\n *\n * @param el - Dialog element\n * @param options - Options\n *\n * @returns Dialog component observable\n */\nexport function mountDialog(\n el: HTMLElement, { message$ }: MountOptions\n): Observable> {\n const internal$ = new Subject()\n internal$\n .pipe(\n observeOn(animationFrameScheduler)\n )\n .subscribe(({ message, open }) => {\n setDialogMessage(el, message)\n if (open)\n setDialogState(el, \"open\")\n else\n resetDialogState(el)\n })\n\n /* Create and return component */\n return watchDialog(el, { message$ })\n .pipe(\n tap(internal$),\n finalize(() => internal$.complete()),\n map(state => ({ ref: el, ...state }))\n )\n}\n","/*\n * Copyright (c) 2016-2020 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Set dialog message\n *\n * @param el - Dialog element\n * @param value - Dialog message\n */\nexport function setDialogMessage(\n el: HTMLElement, value: string\n): void {\n el.firstElementChild!.innerHTML = value\n}\n\n/* ------------------------------------------------------------------------- */\n\n/**\n * Set dialog state\n *\n * @param el - Dialog element\n * @param state - Dialog state\n */\nexport function setDialogState(\n el: HTMLElement, state: \"open\"\n): void {\n el.setAttribute(\"data-md-state\", state)\n}\n\n/**\n * Reset dialog state\n *\n * @param el - Dialog element\n */\nexport function resetDialogState(\n el: HTMLElement\n): void {\n el.removeAttribute(\"data-md-state\")\n}\n","/*\n * Copyright (c) 2016-2020 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport { Observable, Subject, animationFrameScheduler } from \"rxjs\"\nimport {\n distinctUntilKeyChanged,\n finalize,\n map,\n observeOn,\n tap\n} from \"rxjs/operators\"\n\nimport {\n resetHeaderTitleState,\n setHeaderTitleState\n} from \"~/actions\"\nimport {\n Viewport,\n getElementOrThrow,\n getElementSize,\n watchViewportAt\n} from \"~/browser\"\n\nimport { Component } from \"../../_\"\nimport { Header } from \"../_\"\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Header\n */\nexport interface HeaderTitle {\n active: boolean /* User scrolled past first headline */\n}\n\n/* ----------------------------------------------------------------------------\n * Helper types\n * ------------------------------------------------------------------------- */\n\n/**\n * Watch options\n */\ninterface WatchOptions {\n viewport$: Observable /* Viewport observable */\n header$: Observable
    /* Header observable */\n}\n\n/**\n * Mount options\n */\ninterface MountOptions {\n viewport$: Observable /* Viewport observable */\n header$: Observable
    /* Header observable */\n}\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Watch header title\n *\n * @param el - Heading element\n * @param options - Options\n *\n * @returns Header title observable\n */\nexport function watchHeaderTitle(\n el: HTMLHeadingElement, { viewport$, header$ }: WatchOptions\n): Observable {\n return watchViewportAt(el, { header$, viewport$ })\n .pipe(\n map(({ offset: { y } }) => {\n const { height } = getElementSize(el)\n return {\n active: y >= height\n }\n }),\n distinctUntilKeyChanged(\"active\")\n )\n}\n\n/**\n * Mount header title\n *\n * @param el - Header title element\n * @param options - Options\n *\n * @returns Header title component observable\n */\nexport function mountHeaderTitle(\n el: HTMLElement, options: MountOptions\n): Observable> {\n const internal$ = new Subject()\n internal$\n .pipe(\n observeOn(animationFrameScheduler),\n )\n .subscribe(({ active }) => {\n if (active)\n setHeaderTitleState(el, \"active\")\n else\n resetHeaderTitleState(el)\n })\n\n /* Create and return component */\n const headline = getElementOrThrow(\"article h1\")\n return watchHeaderTitle(headline, options)\n .pipe(\n tap(internal$),\n finalize(() => internal$.complete()),\n map(state => ({ ref: el, ...state }))\n )\n}\n","/*\n * Copyright (c) 2016-2020 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Set header title state\n *\n * @param el - Header title element\n * @param state - Header title state\n */\nexport function setHeaderTitleState(\n el: HTMLElement, state: \"active\"\n): void {\n el.setAttribute(\"data-md-state\", state)\n}\n\n/**\n * Reset header title state\n *\n * @param el - Header title element\n */\nexport function resetHeaderTitleState(\n el: HTMLElement\n): void {\n el.removeAttribute(\"data-md-state\")\n}\n","/*\n * Copyright (c) 2016-2020 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Search transformation function\n *\n * @param value - Query value\n *\n * @returns Transformed query value\n */\nexport type SearchTransformFn = (value: string) => string\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Default transformation function\n *\n * 1. Search for terms in quotation marks and prepend a `+` modifier to denote\n * that the resulting document must contain all terms, converting the query\n * to an `AND` query (as opposed to the default `OR` behavior). While users\n * may expect terms enclosed in quotation marks to map to span queries, i.e.\n * for which order is important, `lunr` doesn't support them, so the best\n * we can do is to convert the terms to an `AND` query.\n *\n * 2. Replace control characters which are not located at the beginning of the\n * query or preceded by white space, or are not followed by a non-whitespace\n * character or are at the end of the query string. Furthermore, filter\n * unmatched quotation marks.\n *\n * 3. Trim excess whitespace from left and right.\n *\n * @param query - Query value\n *\n * @returns Transformed query value\n */\nexport function defaultTransform(query: string): string {\n return query\n .split(/\"([^\"]+)\"/g) /* => 1 */\n .map((terms, index) => index & 1\n ? terms.replace(/^\\b|^(?![^\\x00-\\x7F]|$)|\\s+/g, \" +\")\n : terms\n )\n .join(\"\")\n .replace(/\"|(?:^|\\s+)[*+\\-:^~]+(?=\\s+|$)/g, \"\") /* => 2 */\n .trim() /* => 3 */\n}\n","/*\n * Copyright (c) 2016-2020 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A RTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport { SearchIndex, SearchResult } from \"../../_\"\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Search message type\n */\nexport const enum SearchMessageType {\n SETUP, /* Search index setup */\n READY, /* Search index ready */\n QUERY, /* Search query */\n RESULT /* Search results */\n}\n\n/* ------------------------------------------------------------------------- */\n\n/**\n * A message containing the data necessary to setup the search index\n */\nexport interface SearchSetupMessage {\n type: SearchMessageType.SETUP /* Message type */\n data: SearchIndex /* Message data */\n}\n\n/**\n * A message indicating the search index is ready\n */\nexport interface SearchReadyMessage {\n type: SearchMessageType.READY /* Message type */\n}\n\n/**\n * A message containing a search query\n */\nexport interface SearchQueryMessage {\n type: SearchMessageType.QUERY /* Message type */\n data: string /* Message data */\n}\n\n/**\n * A message containing results for a search query\n */\nexport interface SearchResultMessage {\n type: SearchMessageType.RESULT /* Message type */\n data: SearchResult[] /* Message data */\n}\n\n/* ------------------------------------------------------------------------- */\n\n/**\n * A message exchanged with the search worker\n */\nexport type SearchMessage =\n | SearchSetupMessage\n | SearchReadyMessage\n | SearchQueryMessage\n | SearchResultMessage\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Type guard for search setup messages\n *\n * @param message - Search worker message\n *\n * @returns Test result\n */\nexport function isSearchSetupMessage(\n message: SearchMessage\n): message is SearchSetupMessage {\n return message.type === SearchMessageType.SETUP\n}\n\n/**\n * Type guard for search ready messages\n *\n * @param message - Search worker message\n *\n * @returns Test result\n */\nexport function isSearchReadyMessage(\n message: SearchMessage\n): message is SearchReadyMessage {\n return message.type === SearchMessageType.READY\n}\n\n/**\n * Type guard for search query messages\n *\n * @param message - Search worker message\n *\n * @returns Test result\n */\nexport function isSearchQueryMessage(\n message: SearchMessage\n): message is SearchQueryMessage {\n return message.type === SearchMessageType.QUERY\n}\n\n/**\n * Type guard for search result messages\n *\n * @param message - Search worker message\n *\n * @returns Test result\n */\nexport function isSearchResultMessage(\n message: SearchMessage\n): message is SearchResultMessage {\n return message.type === SearchMessageType.RESULT\n}\n","/*\n * Copyright (c) 2016-2020 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A RTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport { Subject, asyncScheduler, from } from \"rxjs\"\nimport { delay, map, observeOn, share } from \"rxjs/operators\"\n\nimport { configuration, translation } from \"~/_\"\nimport { WorkerHandler, watchWorker } from \"~/browser\"\n\nimport { SearchIndex, SearchIndexPipeline } from \"../../_\"\nimport {\n SearchMessage,\n SearchMessageType,\n SearchSetupMessage,\n isSearchResultMessage\n} from \"../message\"\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Search worker\n */\nexport type SearchWorker = WorkerHandler\n\n/* ----------------------------------------------------------------------------\n * Helper functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Set up search index\n *\n * @param data - Search index\n *\n * @returns Search index\n */\nfunction setupSearchIndex(\n { config, docs, index }: SearchIndex\n): SearchIndex {\n\n /* Override default language with value from translation */\n if (config.lang.length === 1 && config.lang[0] === \"en\")\n config.lang = [\n translation(\"search.config.lang\")\n ]\n\n /* Override default separator with value from translation */\n if (config.separator === \"[\\\\s\\\\-]+\")\n config.separator = translation(\"search.config.separator\")\n\n /* Set pipeline from translation */\n const pipeline = translation(\"search.config.pipeline\")\n .split(/\\s*,\\s*/)\n .filter(Boolean) as SearchIndexPipeline\n\n /* Return search index after defaulting */\n return { config, docs, index, pipeline }\n}\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Set up search web worker\n *\n * This function will create a web worker to set up and query the search index\n * which is done using `lunr`. The index must be passed as an observable to\n * enable hacks like _localsearch_ via search index embedding as JSON.\n *\n * @param url - Worker URL\n * @param index - Promise resolving with search index\n *\n * @returns Search worker\n */\nexport function setupSearchWorker(\n url: string, index: Promise\n): SearchWorker {\n const config = configuration()\n const worker = new Worker(url)\n\n /* Create communication channels and resolve relative links */\n const tx$ = new Subject()\n const rx$ = watchWorker(worker, { tx$ })\n .pipe(\n map(message => {\n if (isSearchResultMessage(message)) {\n for (const result of message.data)\n for (const document of result)\n document.location = `${config.base}/${document.location}`\n }\n return message\n }),\n share()\n )\n\n /* Set up search index */\n from(index)\n .pipe(\n map(data => ({\n type: SearchMessageType.SETUP,\n data: setupSearchIndex(data)\n }))\n )\n .subscribe(tx$.next.bind(tx$))\n\n /* Return search worker */\n return { tx$, rx$ }\n}\n","/*\n * Copyright (c) 2016-2020 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport { Observable, Subject, fromEvent } from \"rxjs\"\nimport {\n map,\n share,\n switchMapTo,\n tap,\n throttle\n} from \"rxjs/operators\"\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Worker message\n */\nexport interface WorkerMessage {\n type: unknown /* Message type */\n data?: unknown /* Message data */\n}\n\n/**\n * Worker handler\n *\n * @template T - Message type\n */\nexport interface WorkerHandler<\n T extends WorkerMessage\n> {\n tx$: Subject /* Message transmission subject */\n rx$: Observable /* Message receive observable */\n}\n\n/* ----------------------------------------------------------------------------\n * Helper types\n * ------------------------------------------------------------------------- */\n\n/**\n * Watch options\n *\n * @template T - Worker message type\n */\ninterface WatchOptions {\n tx$: Observable /* Message transmission observable */\n}\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Watch a web worker\n *\n * This function returns an observable that will send all values emitted by the\n * message observable to the web worker. Web worker communication is expected\n * to be bidirectional (request-response) and synchronous. Messages that are\n * emitted during a pending request are throttled, the last one is emitted.\n *\n * @param worker - Web worker\n * @param options - Options\n *\n * @returns Worker message observable\n */\nexport function watchWorker(\n worker: Worker, { tx$ }: WatchOptions\n): Observable {\n\n /* Intercept messages from worker-like objects */\n const rx$ = fromEvent(worker, \"message\")\n .pipe(\n map(({ data }) => data)\n )\n\n /* Send and receive messages, return hot observable */\n return tx$\n .pipe(\n throttle(() => rx$, { leading: true, trailing: true }),\n tap(message => worker.postMessage(message)),\n switchMapTo(rx$),\n share()\n )\n}\n","/*\n * Copyright (c) 2016-2020 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport {\n Observable,\n Subject,\n combineLatest,\n fromEvent,\n merge\n} from \"rxjs\"\nimport {\n delay,\n distinctUntilChanged,\n distinctUntilKeyChanged,\n finalize,\n map,\n startWith,\n takeLast,\n takeUntil,\n tap\n} from \"rxjs/operators\"\n\nimport {\n resetSearchQueryPlaceholder,\n setSearchQueryPlaceholder\n} from \"~/actions\"\nimport {\n setElementFocus,\n setToggle,\n watchElementFocus\n} from \"~/browser\"\nimport {\n SearchMessageType,\n SearchQueryMessage,\n SearchWorker,\n defaultTransform\n} from \"~/integrations\"\n\nimport { Component } from \"../../_\"\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Search query\n */\nexport interface SearchQuery {\n value: string /* Query value */\n focus: boolean /* Query focus */\n}\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Watch search query\n *\n * Note that the focus event which triggers re-reading the current query value\n * is delayed by `1ms` so the input's empty state is allowed to propagate.\n *\n * @param el - Search query element\n *\n * @returns Search query observable\n */\nexport function watchSearchQuery(\n el: HTMLInputElement\n): Observable {\n const fn = __search?.transform || defaultTransform\n\n /* Intercept focus and input events */\n const focus$ = watchElementFocus(el)\n const value$ = merge(\n fromEvent(el, \"keyup\"),\n fromEvent(el, \"focus\").pipe(delay(1))\n )\n .pipe(\n map(() => fn(el.value)),\n startWith(fn(el.value)),\n distinctUntilChanged()\n )\n\n /* Combine into single observable */\n return combineLatest([value$, focus$])\n .pipe(\n map(([value, focus]) => ({ value, focus }))\n )\n}\n\n/**\n * Mount search query\n *\n * @param el - Search query element\n * @param worker - Search worker\n *\n * @returns Search query component observable\n */\nexport function mountSearchQuery(\n el: HTMLInputElement, { tx$ }: SearchWorker\n): Observable> {\n const internal$ = new Subject()\n\n /* Handle value changes */\n internal$\n .pipe(\n distinctUntilKeyChanged(\"value\"),\n map(({ value }): SearchQueryMessage => ({\n type: SearchMessageType.QUERY,\n data: value\n }))\n )\n .subscribe(tx$.next.bind(tx$))\n\n /* Handle focus changes */\n internal$\n .pipe(\n distinctUntilKeyChanged(\"focus\")\n )\n .subscribe(({ focus }) => {\n if (focus) {\n setToggle(\"search\", focus)\n setSearchQueryPlaceholder(el, \"\")\n } else {\n resetSearchQueryPlaceholder(el)\n }\n })\n\n /* Handle reset */\n fromEvent(el.form!, \"reset\")\n .pipe(\n takeUntil(internal$.pipe(takeLast(1)))\n )\n .subscribe(() => setElementFocus(el))\n\n /* Create and return component */\n return watchSearchQuery(el)\n .pipe(\n tap(internal$),\n finalize(() => internal$.complete()),\n map(state => ({ ref: el, ...state }))\n )\n}\n","/*\n * Copyright (c) 2016-2020 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport { translation } from \"~/_\"\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Set search query placeholder\n *\n * @param el - Search query element\n * @param value - Placeholder\n */\nexport function setSearchQueryPlaceholder(\n el: HTMLInputElement, value: string\n): void {\n el.placeholder = value\n}\n\n/**\n * Reset search query placeholder\n *\n * @param el - Search query element\n */\nexport function resetSearchQueryPlaceholder(\n el: HTMLInputElement\n): void {\n el.placeholder = translation(\"search.placeholder\")\n}\n","/*\n * Copyright (c) 2016-2020 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport { Observable, Subject } from \"rxjs\"\nimport {\n filter,\n finalize,\n map,\n startWith,\n tap,\n withLatestFrom\n} from \"rxjs/operators\"\n\nimport {\n addToSearchResultList,\n resetSearchResultList,\n resetSearchResultMeta,\n setSearchResultMeta\n} from \"~/actions\"\nimport { getElementOrThrow } from \"~/browser\"\nimport {\n SearchResult as SearchResultData,\n SearchWorker,\n isSearchResultMessage\n} from \"~/integrations\"\nimport { renderSearchResult } from \"~/templates\"\n\nimport { Component } from \"../../_\"\nimport { SearchQuery } from \"../query\"\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Search result\n */\nexport interface SearchResult {\n data: SearchResultData[] /* Search result data */\n}\n\n/* ----------------------------------------------------------------------------\n * Helper types\n * ------------------------------------------------------------------------- */\n\n/**\n * Mount options\n */\ninterface MountOptions {\n query$: Observable /* Search query observable */\n}\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Mount search result list\n *\n * @param el - Search result list element\n * @param worker - Search worker\n * @param options - Options\n *\n * @returns Search result list component observable\n */\nexport function mountSearchResult(\n el: HTMLElement, { rx$ }: SearchWorker, { query$ }: MountOptions\n): Observable> {\n const internal$ = new Subject()\n\n /* Update search result metadata */\n const meta = getElementOrThrow(\":first-child\", el)\n internal$\n .pipe(\n withLatestFrom(query$)\n )\n .subscribe(([{ data }, { value }]) => {\n if (value)\n setSearchResultMeta(meta, data.length)\n else\n resetSearchResultMeta(meta)\n })\n\n /* Update search result list */\n const list = getElementOrThrow(\":last-child\", el)\n internal$\n .subscribe(({ data }) => {\n resetSearchResultList(list)\n\n /* Compute thresholds and search results */\n const thresholds = [...data.map(([best]) => best.score), 0]\n for (let index = 0; index < data.length; index++)\n addToSearchResultList(list, renderSearchResult(\n data[index++], thresholds[index]\n ))\n })\n\n /* Filter search result list */\n const result$ = rx$\n .pipe(\n filter(isSearchResultMessage),\n map(({ data }) => ({ data })),\n startWith({ data: [] })\n )\n\n /* Create and return component */\n return result$\n .pipe(\n tap(internal$),\n finalize(() => internal$.complete()),\n map(state => ({ ref: el, ...state }))\n )\n}\n","/*\n * Copyright (c) 2016-2020 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport { Observable, merge } from \"rxjs\"\nimport { filter, sample, take } from \"rxjs/operators\"\n\nimport { configuration } from \"~/_\"\nimport { getElementOrThrow } from \"~/browser\"\nimport {\n isSearchQueryMessage,\n isSearchReadyMessage,\n setupSearchWorker\n} from \"~/integrations\"\n\nimport { Component } from \"../../_\"\nimport { SearchQuery, mountSearchQuery } from \"../query\"\nimport { SearchResult, mountSearchResult } from \"../result\"\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Search\n */\nexport type Search =\n | SearchQuery\n | SearchResult\n\n/* ----------------------------------------------------------------------------\n * Helper functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Fetch search index\n *\n * @param url - Search index URL\n *\n * @returns Promise resolving with search index\n */\nfunction fetchSearchIndex(url: string) {\n return __search?.index || fetch(url, { credentials: \"same-origin\" })\n .then(res => res.json())\n}\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Mount search\n *\n * @param el - Search element\n *\n * @returns Search component observable\n */\nexport function mountSearch(\n el: HTMLElement\n): Observable> {\n const config = configuration()\n const worker = setupSearchWorker(config.search, fetchSearchIndex(\n `${config.base}/search/search_index.json`\n ))\n\n /* Re-emit query when search is ready */\n const { tx$, rx$ } = worker\n tx$\n .pipe(\n filter(isSearchQueryMessage),\n sample(rx$.pipe(filter(isSearchReadyMessage))),\n take(1)\n )\n .subscribe(tx$.next.bind(tx$))\n\n /* Obtain search query and result elements */\n const query = getElementOrThrow(\"[data-md-component=search-query]\", el)\n const result = getElementOrThrow(\"[data-md-component=search-result]\", el)\n\n /* Create and return component */\n const query$ = mountSearchQuery(query as HTMLInputElement, worker)\n return merge(\n query$,\n mountSearchResult(result, worker, { query$ })\n )\n}\n","/*\n * Copyright (c) 2016-2020 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport {\n Observable,\n Subject,\n animationFrameScheduler,\n combineLatest\n} from \"rxjs\"\nimport {\n distinctUntilChanged,\n finalize,\n map,\n observeOn,\n tap,\n withLatestFrom\n} from \"rxjs/operators\"\n\nimport {\n resetSidebarHeight,\n resetSidebarOffset,\n setSidebarHeight,\n setSidebarOffset\n} from \"~/actions\"\nimport { Viewport } from \"~/browser\"\n\nimport { Component } from \"../_\"\nimport { Header } from \"../header\"\nimport { Main } from \"../main\"\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Sidebar\n */\nexport interface Sidebar {\n height: number /* Sidebar height */\n locked: boolean /* User scrolled past header */\n}\n\n/* ----------------------------------------------------------------------------\n * Helper types\n * ------------------------------------------------------------------------- */\n\n/**\n * Watch options\n */\ninterface WatchOptions {\n viewport$: Observable /* Viewport observable */\n main$: Observable
    /* Main area observable */\n}\n\n/**\n * Mount options\n */\ninterface MountOptions {\n viewport$: Observable /* Viewport observable */\n header$: Observable
    /* Header observable */\n main$: Observable
    /* Main area observable */\n}\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Watch sidebar\n *\n * This function returns an observable that computes the visual parameters of\n * the sidebar which depends on the vertical viewport offset, as well as the\n * height of the main area. When the page is scrolled beyond the header, the\n * sidebar is locked and fills the remaining space.\n *\n * @param el - Sidebar element\n * @param options - Options\n *\n * @returns Sidebar observable\n */\nexport function watchSidebar(\n el: HTMLElement, { viewport$, main$ }: WatchOptions\n): Observable {\n const adjust =\n el.parentElement!.offsetTop -\n el.parentElement!.parentElement!.offsetTop\n\n /* Compute the sidebar's available height and if it should be locked */\n return combineLatest([main$, viewport$])\n .pipe(\n map(([{ offset, height }, { offset: { y } }]) => {\n height = height\n + Math.min(adjust, Math.max(0, y - offset))\n - adjust\n return {\n height,\n locked: y >= offset + adjust\n }\n }),\n distinctUntilChanged((a, b) => (\n a.height === b.height &&\n a.locked === b.locked\n ))\n )\n}\n\n/**\n * Mount sidebar\n *\n * @param el - Sidebar element\n * @param options - Options\n *\n * @returns Sidebar component observable\n */\nexport function mountSidebar(\n el: HTMLElement, { header$, ...options }: MountOptions\n): Observable> {\n const internal$ = new Subject()\n internal$\n .pipe(\n observeOn(animationFrameScheduler),\n withLatestFrom(header$)\n )\n .subscribe({\n\n /* Update height and offset */\n next([{ height }, { height: offset }]) {\n setSidebarHeight(el, height)\n setSidebarOffset(el, offset)\n },\n\n /* Reset on complete */\n complete() {\n resetSidebarOffset(el)\n resetSidebarHeight(el)\n }\n })\n\n /* Create and return component */\n return watchSidebar(el, options)\n .pipe(\n tap(internal$),\n finalize(() => internal$.complete()),\n map(state => ({ ref: el, ...state }))\n )\n}\n","/*\n * Copyright (c) 2016-2020 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Set sidebar offset\n *\n * @param el - Sidebar element\n * @param value - Sidebar offset\n */\nexport function setSidebarOffset(\n el: HTMLElement, value: number\n): void {\n el.style.top = `${value}px`\n}\n\n/**\n * Reset sidebar offset\n *\n * @param el - Sidebar element\n */\nexport function resetSidebarOffset(\n el: HTMLElement\n): void {\n el.style.top = \"\"\n}\n\n/* ------------------------------------------------------------------------- */\n\n/**\n * Set sidebar height\n *\n * This function doesn't set the height of the actual sidebar, but of its first\n * child – the `.md-sidebar__scrollwrap` element in order to mitigiate jittery\n * sidebars when the footer is scrolled into view. At some point we switched\n * from `absolute` / `fixed` positioning to `sticky` positioning, significantly\n * reducing jitter in some browsers (respectively Firefox and Safari) when\n * scrolling from the top. However, top-aligned sticky positioning means that\n * the sidebar snaps to the bottom when the end of the container is reached.\n * This is what leads to the mentioned jitter, as the sidebar's height may be\n * updated too slowly.\n *\n * This behaviour can be mitigiated by setting the height of the sidebar to `0`\n * while preserving the padding, and the height on its first element.\n *\n * @param el - Sidebar element\n * @param value - Sidebar height\n */\nexport function setSidebarHeight(\n el: HTMLElement, value: number\n): void {\n const scrollwrap = el.firstElementChild as HTMLElement\n scrollwrap.style.height = `${value - 2 * scrollwrap.offsetTop}px`\n}\n\n/**\n * Reset sidebar height\n *\n * @param el - Sidebar element\n */\nexport function resetSidebarHeight(\n el: HTMLElement\n): void {\n const scrollwrap = el.firstElementChild as HTMLElement\n scrollwrap.style.height = \"\"\n}\n","/*\n * Copyright (c) 2016-2020 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport { NEVER, Observable } from \"rxjs\"\n\nimport { fetchSourceFactsFromGitHub } from \"../github\"\nimport { fetchSourceFactsFromGitLab } from \"../gitlab\"\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Repository facts\n */\nexport type SourceFacts = string[]\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Fetch repository facts\n *\n * @param url - Repository URL\n *\n * @returns Repository facts observable\n */\nexport function fetchSourceFacts(\n url: string\n): Observable {\n const [type] = url.match(/(git(?:hub|lab))/i) || []\n switch (type.toLowerCase()) {\n\n /* GitHub repository */\n case \"github\":\n const [, user, repo] = url.match(/^.+github\\.com\\/([^/]+)\\/?([^/]+)?/i)!\n return fetchSourceFactsFromGitHub(user, repo)\n\n /* GitLab repository */\n case \"gitlab\":\n const [, base, slug] = url.match(/^.+?([^/]*gitlab[^/]+)\\/(.+?)\\/?$/i)!\n return fetchSourceFactsFromGitLab(base, slug)\n\n /* Everything else */\n default:\n return NEVER\n }\n}\n","/*\n * Copyright (c) 2016-2020 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport { Repo, User } from \"github-types\"\nimport { Observable, from } from \"rxjs\"\nimport {\n defaultIfEmpty,\n filter,\n map,\n switchMap\n} from \"rxjs/operators\"\n\nimport { round } from \"~/utilities\"\n\nimport { SourceFacts } from \"../_\"\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Fetch GitHub repository facts\n *\n * @param user - GitHub user\n * @param repo - GitHub repository\n *\n * @returns Repository facts observable\n */\nexport function fetchSourceFactsFromGitHub(\n user: string, repo?: string\n): Observable {\n const url = typeof repo !== \"undefined\"\n ? `https://api.github.com/repos/${user}/${repo}`\n : `https://api.github.com/users/${user}`\n return from(fetch(url))\n .pipe(\n filter(res => res.status === 200),\n switchMap(res => res.json()),\n map(data => {\n\n /* GitHub repository */\n if (typeof repo !== \"undefined\") {\n const { stargazers_count, forks_count }: Repo = data\n return [\n `${round(stargazers_count!)} Stars`,\n `${round(forks_count!)} Forks`\n ]\n\n /* GitHub user/organization */\n } else {\n const { public_repos }: User = data\n return [\n `${round(public_repos!)} Repositories`\n ]\n }\n }),\n defaultIfEmpty([])\n )\n}\n","/*\n * Copyright (c) 2016-2020 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport { ProjectSchema } from \"gitlab\"\nimport { Observable, from } from \"rxjs\"\nimport {\n defaultIfEmpty,\n filter,\n map,\n switchMap\n} from \"rxjs/operators\"\n\nimport { round } from \"~/utilities\"\n\nimport { SourceFacts } from \"../_\"\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Fetch GitLab repository facts\n *\n * @param base - GitLab base\n * @param project - GitLab project\n *\n * @returns Repository facts observable\n */\nexport function fetchSourceFactsFromGitLab(\n base: string, project: string\n): Observable {\n const url = `https://${base}/api/v4/projects/${encodeURIComponent(project)}`\n return from(fetch(url))\n .pipe(\n filter(res => res.status === 200),\n switchMap(res => res.json()),\n map(({ star_count, forks_count }: ProjectSchema) => ([\n `${round(star_count)} Stars`,\n `${round(forks_count)} Forks`\n ])),\n defaultIfEmpty([])\n )\n}\n","/*\n * Copyright (c) 2016-2020 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport { NEVER, Observable, Subject, defer, of } from \"rxjs\"\nimport {\n catchError,\n filter,\n finalize,\n map,\n shareReplay,\n tap\n} from \"rxjs/operators\"\n\nimport { setSourceFacts, setSourceState } from \"~/actions\"\nimport { renderSourceFacts } from \"~/templates\"\nimport { hash } from \"~/utilities\"\n\nimport { Component } from \"../../_\"\nimport { SourceFacts, fetchSourceFacts } from \"../facts\"\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Repository information\n */\nexport interface Source {\n facts: SourceFacts /* Repository facts */\n}\n\n/* ----------------------------------------------------------------------------\n * Data\n * ------------------------------------------------------------------------- */\n\n/**\n * Repository facts observable\n */\nlet fetch$: Observable\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Watch repository information\n *\n * @param el - Repository information element\n *\n * @returns Repository information observable\n */\nexport function watchSource(\n el: HTMLAnchorElement\n): Observable {\n const digest = hash(el.href).toString()\n\n /* Fetch repository facts once */\n return fetch$ ||= defer(() => {\n const data = sessionStorage.getItem(digest)\n if (data) {\n return of(JSON.parse(data))\n } else {\n const value$ = fetchSourceFacts(el.href)\n value$.subscribe(value => {\n try {\n sessionStorage.setItem(digest, JSON.stringify(value))\n } catch (err) {\n /* Uncritical, just swallow */\n }\n })\n\n /* Return value */\n return value$\n }\n })\n .pipe(\n catchError(() => NEVER),\n filter(facts => facts.length > 0),\n map(facts => ({ facts })),\n shareReplay(1)\n )\n}\n\n/**\n * Mount repository information\n *\n * @param el - Repository information element\n *\n * @returns Repository information component observable\n */\nexport function mountSource(\n el: HTMLAnchorElement\n): Observable> {\n const internal$ = new Subject()\n internal$.subscribe(({ facts }) => {\n setSourceFacts(el, renderSourceFacts(facts))\n setSourceState(el, \"done\")\n })\n\n /* Create and return component */\n return watchSource(el)\n .pipe(\n tap(internal$),\n finalize(() => internal$.complete()),\n map(state => ({ ref: el, ...state }))\n )\n}\n","/*\n * Copyright (c) 2016-2020 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Set repository facts\n *\n * @param el - Repository element\n * @param child - Repository facts element\n */\nexport function setSourceFacts(\n el: HTMLElement, child: Element\n): void {\n el.lastElementChild!.appendChild(child)\n}\n\n/**\n * Set repository state\n *\n * @param el - Repository element\n * @param state - Repository state\n */\nexport function setSourceState(\n el: HTMLElement, state: \"done\"\n): void {\n el.lastElementChild!.setAttribute(\"data-md-state\", state)\n}\n","/*\n * Copyright (c) 2016-2020 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport { SourceFacts } from \"~/components\"\nimport { h } from \"~/utilities\"\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Render repository facts\n *\n * @param facts - Repository facts\n *\n * @returns Element\n */\nexport function renderSourceFacts(facts: SourceFacts) {\n return (\n
      \n {facts.map(fact => (\n
    • {fact}
    • \n ))}\n
    \n )\n}\n","/*\n * Copyright (c) 2016-2020 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport { Observable, Subject, animationFrameScheduler } from \"rxjs\"\nimport {\n distinctUntilKeyChanged,\n finalize,\n map,\n observeOn,\n tap\n} from \"rxjs/operators\"\n\nimport { resetTabsState, setTabsState } from \"~/actions\"\nimport { Viewport, watchViewportAt } from \"~/browser\"\n\nimport { Component } from \"../_\"\nimport { Header } from \"../header\"\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Navigation tabs\n */\nexport interface Tabs {\n hidden: boolean /* User scrolled past tabs */\n}\n\n/* ----------------------------------------------------------------------------\n * Helper types\n * ------------------------------------------------------------------------- */\n\n/**\n * Watch options\n */\ninterface WatchOptions {\n viewport$: Observable /* Viewport observable */\n header$: Observable
    /* Header observable */\n}\n\n/**\n * Mount options\n */\ninterface MountOptions {\n viewport$: Observable /* Viewport observable */\n header$: Observable
    /* Header observable */\n}\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Watch navigation tabs\n *\n * @param el - Navigation tabs element\n * @param options - Options\n *\n * @returns Navigation tabs observable\n */\nexport function watchTabs(\n el: HTMLElement, { viewport$, header$ }: WatchOptions\n): Observable {\n return watchViewportAt(el, { header$, viewport$ })\n .pipe(\n map(({ offset: { y } }) => {\n return {\n hidden: y >= 10\n }\n }),\n distinctUntilKeyChanged(\"hidden\")\n )\n}\n\n/**\n * Mount navigation tabs\n *\n * @param el - Navigation tabs element\n * @param options - Options\n *\n * @returns Navigation tabs component observable\n */\nexport function mountTabs(\n el: HTMLElement, options: MountOptions\n): Observable> {\n const internal$ = new Subject()\n internal$\n .pipe(\n observeOn(animationFrameScheduler)\n )\n .subscribe({\n\n /* Update state */\n next({ hidden }) {\n if (hidden)\n setTabsState(el, \"hidden\")\n else\n resetTabsState(el)\n },\n\n /* Reset on complete */\n complete() {\n resetTabsState(el)\n }\n })\n\n /* Create and return component */\n return watchTabs(el, options)\n .pipe(\n tap(internal$),\n finalize(() => internal$.complete()),\n map(state => ({ ref: el, ...state }))\n )\n}\n","/*\n * Copyright (c) 2016-2020 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport {\n Observable,\n Subject,\n animationFrameScheduler,\n combineLatest\n} from \"rxjs\"\nimport {\n bufferCount,\n distinctUntilChanged,\n distinctUntilKeyChanged,\n finalize,\n map,\n observeOn,\n scan,\n startWith,\n switchMap,\n tap\n} from \"rxjs/operators\"\n\nimport {\n resetAnchorActive,\n resetAnchorState,\n setAnchorActive,\n setAnchorState\n} from \"~/actions\"\nimport {\n Viewport,\n getElement,\n getElements,\n watchElementSize\n} from \"~/browser\"\n\nimport { Component } from \"../_\"\nimport { Header } from \"../header\"\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Table of contents\n */\nexport interface TableOfContents {\n prev: HTMLAnchorElement[][] /* Anchors (previous) */\n next: HTMLAnchorElement[][] /* Anchors (next) */\n}\n\n/* ----------------------------------------------------------------------------\n * Helper types\n * ------------------------------------------------------------------------- */\n\n/**\n * Watch options\n */\ninterface WatchOptions {\n viewport$: Observable /* Viewport observable */\n header$: Observable
    /* Header observable */\n}\n\n/**\n * Mount options\n */\ninterface MountOptions {\n viewport$: Observable /* Viewport observable */\n header$: Observable
    /* Header observable */\n}\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Watch table of contents\n *\n * This is effectively a scroll spy implementation which will account for the\n * fixed header and automatically re-calculate anchor offsets when the viewport\n * is resized. The returned observable will only emit if the table of contents\n * needs to be repainted.\n *\n * This implementation tracks an anchor element's entire path starting from its\n * level up to the top-most anchor element, e.g. `[h3, h2, h1]`. Although the\n * Material theme currently doesn't make use of this information, it enables\n * the styling of the entire hierarchy through customization.\n *\n * Note that the current anchor is the last item of the `prev` anchor list.\n *\n * @param anchors - Anchor elements\n * @param options - Options\n *\n * @returns Table of contents observable\n */\nexport function watchTableOfContents(\n anchors: HTMLAnchorElement[], { viewport$, header$ }: WatchOptions\n): Observable {\n const table = new Map()\n for (const anchor of anchors) {\n const id = decodeURIComponent(anchor.hash.substring(1))\n const target = getElement(`[id=\"${id}\"]`)\n if (typeof target !== \"undefined\")\n table.set(anchor, target)\n }\n\n /* Compute necessary adjustment for header */\n const adjust$ = header$\n .pipe(\n map(header => 24 + header.height)\n )\n\n /* Compute partition of previous and next anchors */\n const partition$ = watchElementSize(document.body)\n .pipe(\n distinctUntilKeyChanged(\"height\"),\n\n /* Build index to map anchor paths to vertical offsets */\n map(() => {\n let path: HTMLAnchorElement[] = []\n return [...table].reduce((index, [anchor, target]) => {\n while (path.length) {\n const last = table.get(path[path.length - 1])!\n if (last.tagName >= target.tagName) {\n path.pop()\n } else {\n break\n }\n }\n\n /* If the current anchor is hidden, continue with its parent */\n let offset = target.offsetTop\n while (!offset && target.parentElement) {\n target = target.parentElement\n offset = target.offsetTop\n }\n\n /* Map reversed anchor path to vertical offset */\n return index.set(\n [...path = [...path, anchor]].reverse(),\n offset\n )\n }, new Map())\n }),\n\n /* Re-compute partition when viewport offset changes */\n switchMap(index => combineLatest([adjust$, viewport$])\n .pipe(\n scan(([prev, next], [adjust, { offset: { y } }]) => {\n\n /* Look forward */\n while (next.length) {\n const [, offset] = next[0]\n if (offset - adjust < y) {\n prev = [...prev, next.shift()!]\n } else {\n break\n }\n }\n\n /* Look backward */\n while (prev.length) {\n const [, offset] = prev[prev.length - 1]\n if (offset - adjust >= y) {\n next = [prev.pop()!, ...next]\n } else {\n break\n }\n }\n\n /* Return partition */\n return [prev, next]\n }, [[], [...index]]),\n distinctUntilChanged((a, b) => (\n a[0] === b[0] &&\n a[1] === b[1]\n ))\n )\n )\n )\n\n /* Compute and return anchor list migrations */\n return partition$\n .pipe(\n map(([prev, next]) => ({\n prev: prev.map(([path]) => path),\n next: next.map(([path]) => path)\n })),\n\n /* Extract anchor list migrations */\n startWith({ prev: [], next: [] }),\n bufferCount(2, 1),\n map(([a, b]) => {\n\n /* Moving down */\n if (a.prev.length < b.prev.length) {\n return {\n prev: b.prev.slice(Math.max(0, a.prev.length - 1), b.prev.length),\n next: []\n }\n\n /* Moving up */\n } else {\n return {\n prev: b.prev.slice(-1),\n next: b.next.slice(0, b.next.length - a.next.length)\n }\n }\n })\n )\n}\n\n/* ------------------------------------------------------------------------- */\n\n/**\n * Mount table of contents\n *\n * @param el - Anchor list element\n * @param options - Options\n *\n * @returns Table of contents component observable\n */\nexport function mountTableOfContents(\n el: HTMLElement, options: MountOptions\n): Observable> {\n const internal$ = new Subject()\n internal$\n .pipe(\n observeOn(animationFrameScheduler),\n )\n .subscribe(({ prev, next }) => {\n\n /* Look forward */\n for (const [anchor] of next) {\n resetAnchorActive(anchor)\n resetAnchorState(anchor)\n }\n\n /* Look backward */\n for (const [index, [anchor]] of prev.entries()) {\n setAnchorActive(anchor, index === prev.length - 1)\n setAnchorState(anchor, \"blur\")\n }\n })\n\n /* Create and return component */\n const anchors = getElements(\"[href^=\\\\#]\", el)\n return watchTableOfContents(anchors, options)\n .pipe(\n tap(internal$),\n finalize(() => internal$.complete()),\n map(state => ({ ref: el, ...state }))\n )\n}\n","/*\n * Copyright (c) 2016-2020 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport \"focus-visible\"\nimport { NEVER, Observable, Subject, merge } from \"rxjs\"\nimport { switchMap } from \"rxjs/operators\"\n\nimport { translation } from \"./_\"\nimport {\n getElementOrThrow,\n getElements,\n watchLocationTarget,\n watchMedia,\n watchPrint,\n watchViewport\n} from \"./browser\"\nimport {\n mountContent,\n mountDialog,\n mountHeader,\n mountHeaderTitle,\n mountSearch,\n mountSidebar,\n mountSource,\n mountTableOfContents,\n mountTabs,\n watchHeader,\n watchMain\n} from \"./components\"\nimport {\n setupClipboardJS\n} from \"./integrations\"\n\n/* ----------------------------------------------------------------------------\n * Program\n * ------------------------------------------------------------------------- */\n\n/* Yay, JavaScript is available */\ndocument.documentElement.classList.remove(\"no-js\")\ndocument.documentElement.classList.add(\"js\")\n\n/* Set up subjects */\nconst target$ = watchLocationTarget()\n\n/* Set up user interface observables */\nconst viewport$ = watchViewport()\nconst tablet$ = watchMedia(\"(min-width: 960px)\")\nconst screen$ = watchMedia(\"(min-width: 1220px)\")\nconst print$ = watchPrint()\n\n// these elements MUST be available\nconst header = getElementOrThrow(\"[data-md-component=header]\")\nconst main = getElementOrThrow(\"[data-md-component=main]\")\n\nconst header$ = watchHeader(header)\nconst main$ = watchMain(main, { header$, viewport$ })\n\n/* Setup Clipboard.js integration */\nconst message$ = new Subject()\nsetupClipboardJS()\n .subscribe(() => message$.next(translation(\"clipboard.copied\")))\n\n// TODO: watchElements + general mount function that takes a factory...\n// + a toggle function (optionally)\n\n// TODO: catch errors on all components when mounting, so one error doesn't\n// take down the whole site.\n\nconst app$ = merge(\n\n /* Content */\n ...getElements(\"[data-md-component=content]\")\n .map(child => mountContent(child, { target$, viewport$, print$ })),\n\n /* Dialog */\n ...getElements(\"[data-md-component=dialog]\")\n .map(child => mountDialog(child, { message$ })),\n\n /* Header */\n ...getElements(\"[data-md-component=header]\")\n .map(child => mountHeader(child, { viewport$, header$, main$ })),\n\n /* Header title */\n ...getElements(\"[data-md-component=header-title]\")\n .map(child => mountHeaderTitle(child, { viewport$, header$ })),\n\n /* Search */\n ...getElements(\"[data-md-component=search]\")\n .map(child => mountSearch(child)),\n\n /* Sidebar */\n ...getElements(\"[data-md-component=sidebar]\")\n .map(child => child.getAttribute(\"data-md-type\") === \"navigation\"\n ? at(screen$, () => mountSidebar(child, { viewport$, header$, main$ }))\n : at(tablet$, () => mountSidebar(child, { viewport$, header$, main$ }))\n ),\n\n /* Repository information */\n ...getElements(\"[data-md-component=source]\")\n .map(child => mountSource(child as HTMLAnchorElement)),\n\n /* Navigation tabs */\n ...getElements(\"[data-md-component=tabs]\")\n .map(child => mountTabs(child, { viewport$, header$ })),\n\n /* Table of contents */\n ...getElements(\"[data-md-component=toc]\")\n .map(child => mountTableOfContents(child, { viewport$, header$ })),\n)\n\n// eslint-disable-next-line\napp$.subscribe(console.log)\n\n/* ------------------------------------------------------------------------- */\n\n/**\n * Test\n *\n * @param toggle$ - Toggle observable\n * @param factory - Observable factory\n *\n * @returns New observable\n */\nfunction at(\n toggle$: Observable, factory: () => Observable\n) {\n return toggle$\n .pipe(\n switchMap(active => active ? factory() : NEVER),\n )\n}\n","/*\n * Copyright (c) 2016-2020 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport {\n Observable,\n Subject,\n animationFrameScheduler,\n defer,\n of\n} from \"rxjs\"\nimport {\n combineLatestWith,\n distinctUntilChanged,\n distinctUntilKeyChanged,\n map,\n observeOn,\n shareReplay\n} from \"rxjs/operators\"\n\nimport { resetHeaderState, setHeaderState } from \"~/actions\"\nimport { Viewport, watchElementSize } from \"~/browser\"\n\nimport { Component } from \"../../_\"\nimport { Main } from \"../../main\"\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Header\n */\nexport interface Header {\n sticky: boolean /* Header stickyness */\n height: number /* Header visible height */\n}\n\n/* ----------------------------------------------------------------------------\n * Helper types\n * ------------------------------------------------------------------------- */\n\n/**\n * Mount options\n */\ninterface MountOptions {\n viewport$: Observable /* Viewport observable */\n header$: Observable
    /* Header observable */\n main$: Observable
    /* Main area observable */\n}\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Watch header\n *\n * @param el - Header element\n *\n * @returns Header observable\n */\nexport function watchHeader(\n el: HTMLElement\n): Observable
    {\n return defer(() => {\n const styles = getComputedStyle(el)\n return of(\n styles.position === \"sticky\" ||\n styles.position === \"-webkit-sticky\"\n )\n })\n .pipe(\n combineLatestWith(watchElementSize(el)),\n map(([sticky, { height }]) => ({\n sticky,\n height: sticky ? height : 0\n })),\n distinctUntilChanged((a, b) => (\n a.sticky === b.sticky &&\n a.height === b.height\n ))\n )\n}\n\n/**\n * Mount header\n *\n * The header must be connected to the main area observable outside of the\n * operator function, as the header will persist in-between document switches\n * while the main area is replaced. However, the header observable must be\n * passed to this function, so we connect both via a long-living subject.\n *\n * @param el - Header element\n * @param options - Options\n *\n * @returns Header component observable\n */\nexport function mountHeader(\n el: HTMLElement, { header$, main$ }: MountOptions\n): Observable> {\n const internal$ = new Subject
    ()\n internal$\n .pipe(\n distinctUntilKeyChanged(\"active\"),\n observeOn(animationFrameScheduler)\n )\n .subscribe(({ active }) => {\n if (active)\n setHeaderState(el, \"shadow\")\n else\n resetHeaderState(el)\n })\n\n /* Connect to long-living subject and return component */\n main$.subscribe(main => internal$.next(main))\n return header$\n .pipe(\n map(state => ({ ref: el, ...state })),\n shareReplay(1)\n )\n}\n","/*\n * Copyright (c) 2016-2020 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport {\n Observable,\n combineLatest\n} from \"rxjs\"\nimport {\n distinctUntilChanged,\n distinctUntilKeyChanged,\n map,\n shareReplay,\n switchMap\n} from \"rxjs/operators\"\n\nimport { Viewport, watchElementSize } from \"~/browser\"\n\nimport { Header } from \"../header\"\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Main area\n */\nexport interface Main {\n offset: number /* Main area top offset */\n height: number /* Main area visible height */\n active: boolean /* User scrolled past header */\n}\n\n/* ----------------------------------------------------------------------------\n * Helper types\n * ------------------------------------------------------------------------- */\n\n/**\n * Watch options\n */\ninterface WatchOptions {\n viewport$: Observable /* Viewport observable */\n header$: Observable
    /* Header observable */\n}\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Watch main area\n *\n * This function returns an observable that computes the visual parameters of\n * the main area which depends on the viewport vertical offset and height, as\n * well as the height of the header element, if the header is fixed.\n *\n * @param el - Main area element\n * @param options - Options\n *\n * @returns Main area observable\n */\nexport function watchMain(\n el: HTMLElement, { viewport$, header$ }: WatchOptions\n): Observable
    {\n\n /* Compute necessary adjustment for header */\n const adjust$ = header$\n .pipe(\n map(({ height }) => height),\n distinctUntilChanged()\n )\n\n /* Compute the main area's top and bottom borders */\n const border$ = adjust$\n .pipe(\n switchMap(() => watchElementSize(el)\n .pipe(\n map(({ height }) => ({\n top: el.offsetTop,\n bottom: el.offsetTop + height\n })),\n distinctUntilKeyChanged(\"bottom\")\n )\n )\n )\n\n /* Compute the main area's offset, visible height and if we scrolled past */\n return combineLatest([adjust$, border$, viewport$])\n .pipe(\n map(([header, { top, bottom }, { offset: { y }, size: { height } }]) => {\n height = Math.max(0, height\n - Math.max(0, top - y, header)\n - Math.max(0, height + y - bottom)\n )\n return {\n offset: top - header,\n height,\n active: top - header <= y\n }\n }),\n distinctUntilChanged((a, b) => (\n a.offset === b.offset &&\n a.height === b.height &&\n a.active === b.active\n )),\n shareReplay(1)\n )\n}\n","/*\n * Copyright (c) 2016-2020 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport ClipboardJS from \"clipboard\"\nimport { NEVER, Observable } from \"rxjs\"\nimport { share } from \"rxjs/operators\"\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Set up Clipboard.js integration\n *\n * @returns Clipboard.js event observable\n */\nexport function setupClipboardJS(): Observable {\n if (!ClipboardJS.isSupported())\n return NEVER\n\n /* Initialize Clipboard.js */\n return new Observable(subscriber => {\n new ClipboardJS(\"[data-clipboard-target], [data-clipboard-text]\")\n .on(\"success\", ev => subscriber.next(ev))\n })\n .pipe(\n share()\n )\n}\n","/*\n * Copyright (c) 2016-2020 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport { Observable, merge } from \"rxjs\"\n\nimport { Viewport, getElements } from \"~/browser\"\n\nimport { Component } from \"../../_\"\nimport { CodeBlock, mountCodeBlock } from \"../code\"\nimport { Details, mountDetails } from \"../details\"\nimport { DataTable, mountDataTable } from \"../table\"\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Content\n */\nexport type Content =\n | CodeBlock\n | DataTable\n | Details\n\n/* ----------------------------------------------------------------------------\n * Helper types\n * ------------------------------------------------------------------------- */\n\n/**\n * Mount options\n */\ninterface MountOptions {\n target$: Observable /* Location target observable */\n viewport$: Observable /* Viewport observable */\n print$: Observable /* Print observable */\n}\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Mount content\n *\n * @param el - Content element\n * @param options - Options\n *\n * @returns Content component observable\n */\nexport function mountContent(\n el: HTMLElement, { target$, viewport$, print$ }: MountOptions\n): Observable> {\n return merge(\n\n /* Code blocks */\n ...getElements(\"pre > code\", el)\n .map(child => mountCodeBlock(child, { viewport$ })),\n\n /* Data tables */\n ...getElements(\"table:not([class])\", el)\n .map(child => mountDataTable(child)),\n\n /* Details */\n ...getElements(\"details\", el)\n .map(child => mountDetails(child, { target$, print$ }))\n )\n}\n","/*\n * Copyright (c) 2016-2020 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Set header state\n *\n * @param el - Header element\n * @param state - Header state\n */\nexport function setHeaderState(\n el: HTMLElement, state: \"shadow\" | \"hidden\"\n): void {\n el.setAttribute(\"data-md-state\", state)\n}\n\n/**\n * Reset header state\n *\n * @param el - Header element\n */\nexport function resetHeaderState(\n el: HTMLElement\n): void {\n el.removeAttribute(\"data-md-state\")\n}\n"],"sourceRoot":""} \ No newline at end of file diff --git a/material/assets/manifest.json b/material/assets/manifest.json index 5cca547c3..7357ca61e 100644 --- a/material/assets/manifest.json +++ b/material/assets/manifest.json @@ -1,6 +1,6 @@ { - "assets/javascripts/bundle.js": "assets/javascripts/bundle.48bdffa8.min.js", - "assets/javascripts/bundle.js.map": "assets/javascripts/bundle.48bdffa8.min.js.map", + "assets/javascripts/bundle.js": "assets/javascripts/bundle.1ed0f3ef.min.js", + "assets/javascripts/bundle.js.map": "assets/javascripts/bundle.1ed0f3ef.min.js.map", "assets/javascripts/vendor.js": "assets/javascripts/vendor.250c9a34.min.js", "assets/javascripts/vendor.js.map": "assets/javascripts/vendor.250c9a34.min.js.map", "assets/javascripts/worker/search.js": "assets/javascripts/worker/search.b9424174.min.js", diff --git a/material/base.html b/material/base.html index e129b1b72..30a412e9c 100644 --- a/material/base.html +++ b/material/base.html @@ -217,7 +217,7 @@ {% endblock %} {% block scripts %} - + {% for path in config["extra_javascript"] %} {% endfor %} diff --git a/src/assets/javascripts/_/index.ts b/src/assets/javascripts/_/index.ts index 4fb121d0d..eecaa9202 100644 --- a/src/assets/javascripts/_/index.ts +++ b/src/assets/javascripts/_/index.ts @@ -29,7 +29,7 @@ import { getElementOrThrow, getLocation } from "~/browser" /** * Feature flag */ -export type Feature = +export type Flag = | "header.autohide" /* Hide header */ | "navigation.tabs" /* Tabs navigation */ | "navigation.instant" /* Instant loading */ @@ -66,7 +66,7 @@ export type Translations = Record */ export interface Config { base: string /* Base URL */ - features: Feature[] /* Feature flags */ + features: Flag[] /* Feature flags */ translations: Translations /* Translations */ search: string /* Search worker URL */ } @@ -78,7 +78,8 @@ export interface Config { /** * Retrieve global configuration and make base URL absolute */ -const config: Config = JSON.parse(getElementOrThrow("#__config").textContent!) +const script = getElementOrThrow("#__config") +const config: Config = JSON.parse(script.textContent!) config.base = new URL(config.base, getLocation()) .toString() .replace(/\/$/, "") @@ -97,14 +98,14 @@ export function configuration(): Config { } /** - * Check whether a feature is enabled + * Check whether a feature flag is enabled * - * @param feature - Feature + * @param flag - Feature flag * * @returns Test result */ -export function flag(feature: Feature): boolean { - return config.features.includes(feature) +export function feature(flag: Flag): boolean { + return config.features.includes(flag) } /** @@ -118,9 +119,6 @@ export function flag(feature: Feature): boolean { export function translation( key: Translation, value?: string | number ): string { - if (typeof config.translations[key] === "undefined") { - throw new ReferenceError(`Invalid translation: ${key}`) - } return typeof value !== "undefined" ? config.translations[key].replace("#", value.toString()) : config.translations[key] diff --git a/src/assets/javascripts/browser/element/_/index.ts b/src/assets/javascripts/browser/element/_/index.ts index eb4488e0d..c5604afea 100644 --- a/src/assets/javascripts/browser/element/_/index.ts +++ b/src/assets/javascripts/browser/element/_/index.ts @@ -40,7 +40,7 @@ export function getElement( export function getElement( selector: string, node?: ParentNode -): T +): T | undefined export function getElement( selector: string, node: ParentNode = document diff --git a/src/assets/javascripts/browser/fetch/index.ts b/src/assets/javascripts/browser/fetch/index.ts new file mode 100644 index 000000000..37c9cc658 --- /dev/null +++ b/src/assets/javascripts/browser/fetch/index.ts @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2016-2020 Martin Donath + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +import { Observable, from } from "rxjs" +import { + filter, + map, + shareReplay, + switchMap +} from "rxjs/operators" + +/* ---------------------------------------------------------------------------- + * Data + * ------------------------------------------------------------------------- */ + +/** + * XML parser + */ +const dom = new DOMParser() + +/* ---------------------------------------------------------------------------- + * Functions + * ------------------------------------------------------------------------- */ + +/** + * Fetch given URL as JSON + * + * @template T - Data type + * + * @param url - Request URL + * @param options - Request options + * + * @returns Data observable + */ +export function fetchJSON( + url: string, options: RequestInit = { credentials: "same-origin" } +): Observable { + return from(fetch(url, options)) + .pipe( + filter(res => res.status === 200), + switchMap(res => res.json()), + shareReplay(1) + ) +} + +/** + * Fetch given URL as XML + * + * @param url - Request URL + * @param options - Request options + * + * @returns Data observable + */ +export function fetchXML( + url: string, options: RequestInit = { credentials: "same-origin" } +): Observable { + return from(fetch(url, options)) + .pipe( + filter(res => res.status === 200), + switchMap(res => res.json()), + map(res => dom.parseFromString(res, "text/xml")), + shareReplay(1) + ) +} diff --git a/src/assets/javascripts/browser/index.ts b/src/assets/javascripts/browser/index.ts index b3683101a..70a9679bd 100644 --- a/src/assets/javascripts/browser/index.ts +++ b/src/assets/javascripts/browser/index.ts @@ -22,6 +22,7 @@ export * from "./document" export * from "./element" +export * from "./fetch" export * from "./keyboard" export * from "./location" export * from "./media" diff --git a/src/assets/javascripts/components/header/title/index.ts b/src/assets/javascripts/components/header/title/index.ts index f06061549..0d05cf5ea 100644 --- a/src/assets/javascripts/components/header/title/index.ts +++ b/src/assets/javascripts/components/header/title/index.ts @@ -20,7 +20,7 @@ * IN THE SOFTWARE. */ -import { Observable, Subject, animationFrameScheduler } from "rxjs" +import { NEVER, Observable, Subject, animationFrameScheduler } from "rxjs" import { distinctUntilKeyChanged, finalize, @@ -35,7 +35,7 @@ import { } from "~/actions" import { Viewport, - getElementOrThrow, + getElement, getElementSize, watchViewportAt } from "~/browser" @@ -124,8 +124,12 @@ export function mountHeaderTitle( resetHeaderTitleState(el) }) + /* Obtain headline, if any */ + const headline = getElement("article h1") + if (typeof headline === "undefined") + return NEVER + /* Create and return component */ - const headline = getElementOrThrow("article h1") return watchHeaderTitle(headline, options) .pipe( tap(internal$), diff --git a/src/assets/javascripts/components/search/_/index.ts b/src/assets/javascripts/components/search/_/index.ts index b2ccc889b..6a889cc81 100644 --- a/src/assets/javascripts/components/search/_/index.ts +++ b/src/assets/javascripts/components/search/_/index.ts @@ -24,8 +24,9 @@ import { Observable, merge } from "rxjs" import { filter, sample, take } from "rxjs/operators" import { configuration } from "~/_" -import { getElementOrThrow } from "~/browser" +import { fetchJSON, getElementOrThrow } from "~/browser" import { + SearchIndex, isSearchQueryMessage, isSearchReadyMessage, setupSearchWorker @@ -58,8 +59,7 @@ export type Search = * @returns Promise resolving with search index */ function fetchSearchIndex(url: string) { - return __search?.index || fetch(url, { credentials: "same-origin" }) - .then(res => res.json()) + return __search?.index || fetchJSON(url) } /* ---------------------------------------------------------------------------- @@ -91,14 +91,18 @@ export function mountSearch( ) .subscribe(tx$.next.bind(tx$)) - /* Obtain search query and result elements */ - const query = getElementOrThrow("[data-md-component=search-query]", el) - const result = getElementOrThrow("[data-md-component=search-result]", el) + /* Mount search query component */ + const query$ = mountSearchQuery( + getElementOrThrow("[data-md-component=search-query]", el), + worker + ) - /* Create and return component */ - const query$ = mountSearchQuery(query as HTMLInputElement, worker) + /* Mount search result and return component */ return merge( query$, - mountSearchResult(result, worker, { query$ }) + mountSearchResult( + getElementOrThrow("[data-md-component=search-result]", el), + worker, { query$ } + ) ) } diff --git a/src/assets/javascripts/components/search/result/index.ts b/src/assets/javascripts/components/search/result/index.ts index 9de5b89ad..203af5973 100644 --- a/src/assets/javascripts/components/search/result/index.ts +++ b/src/assets/javascripts/components/search/result/index.ts @@ -88,7 +88,7 @@ export function mountSearchResult( const internal$ = new Subject() /* Update search result metadata */ - const meta = getElementOrThrow(":first-child", el) + const meta = getElementOrThrow(":scope > :first-child", el) internal$ .pipe( withLatestFrom(query$) @@ -101,7 +101,7 @@ export function mountSearchResult( }) /* Update search result list */ - const list = getElementOrThrow(":last-child", el) + const list = getElementOrThrow(":scope > :last-child", el) internal$ .subscribe(({ data }) => { resetSearchResultList(list) diff --git a/src/assets/javascripts/components/source/facts/github/index.ts b/src/assets/javascripts/components/source/facts/github/index.ts index d7eaa587d..600812b6b 100644 --- a/src/assets/javascripts/components/source/facts/github/index.ts +++ b/src/assets/javascripts/components/source/facts/github/index.ts @@ -21,14 +21,10 @@ */ import { Repo, User } from "github-types" -import { Observable, from } from "rxjs" -import { - defaultIfEmpty, - filter, - map, - switchMap -} from "rxjs/operators" +import { Observable } from "rxjs" +import { defaultIfEmpty, map } from "rxjs/operators" +import { fetchJSON } from "~/browser" import { round } from "~/utilities" import { SourceFacts } from "../_" @@ -51,10 +47,8 @@ export function fetchSourceFactsFromGitHub( const url = typeof repo !== "undefined" ? `https://api.github.com/repos/${user}/${repo}` : `https://api.github.com/users/${user}` - return from(fetch(url)) + return fetchJSON(url) .pipe( - filter(res => res.status === 200), - switchMap(res => res.json()), map(data => { /* GitHub repository */ diff --git a/src/assets/javascripts/components/source/facts/gitlab/index.ts b/src/assets/javascripts/components/source/facts/gitlab/index.ts index 464c4b68f..25d0a64ac 100644 --- a/src/assets/javascripts/components/source/facts/gitlab/index.ts +++ b/src/assets/javascripts/components/source/facts/gitlab/index.ts @@ -21,14 +21,10 @@ */ import { ProjectSchema } from "gitlab" -import { Observable, from } from "rxjs" -import { - defaultIfEmpty, - filter, - map, - switchMap -} from "rxjs/operators" +import { Observable } from "rxjs" +import { defaultIfEmpty, map } from "rxjs/operators" +import { fetchJSON } from "~/browser" import { round } from "~/utilities" import { SourceFacts } from "../_" @@ -49,11 +45,9 @@ export function fetchSourceFactsFromGitLab( base: string, project: string ): Observable { const url = `https://${base}/api/v4/projects/${encodeURIComponent(project)}` - return from(fetch(url)) + return fetchJSON(url) .pipe( - filter(res => res.status === 200), - switchMap(res => res.json()), - map(({ star_count, forks_count }: ProjectSchema) => ([ + map(({ star_count, forks_count }) => ([ `${round(star_count)} Stars`, `${round(forks_count)} Forks` ])), diff --git a/src/assets/javascripts/index.ts b/src/assets/javascripts/index.ts index 730691f58..00efff6d3 100644 --- a/src/assets/javascripts/index.ts +++ b/src/assets/javascripts/index.ts @@ -24,7 +24,6 @@ import "focus-visible" import { NEVER, Observable, Subject, merge } from "rxjs" import { switchMap } from "rxjs/operators" -import { translation } from "./_" import { getElementOrThrow, getElements, @@ -76,8 +75,7 @@ const main$ = watchMain(main, { header$, viewport$ }) /* Setup Clipboard.js integration */ const message$ = new Subject() -setupClipboardJS() - .subscribe(() => message$.next(translation("clipboard.copied"))) +setupClipboardJS({ message$ }) // TODO: watchElements + general mount function that takes a factory... // + a toggle function (optionally) diff --git a/src/assets/javascripts/integrations/clipboard/index.ts b/src/assets/javascripts/integrations/clipboard/index.ts index 88b693338..b0602edea 100644 --- a/src/assets/javascripts/integrations/clipboard/index.ts +++ b/src/assets/javascripts/integrations/clipboard/index.ts @@ -21,8 +21,20 @@ */ import ClipboardJS from "clipboard" -import { NEVER, Observable } from "rxjs" -import { share } from "rxjs/operators" +import { Observable, Subject } from "rxjs" + +import { translation } from "~/_" + +/* ---------------------------------------------------------------------------- + * Helper types + * ------------------------------------------------------------------------- */ + +/** + * Setup options + */ +interface SetupOptions { + message$: Subject /* Message subject */ +} /* ---------------------------------------------------------------------------- * Functions @@ -31,18 +43,16 @@ import { share } from "rxjs/operators" /** * Set up Clipboard.js integration * - * @returns Clipboard.js event observable + * @param options - Options */ -export function setupClipboardJS(): Observable { - if (!ClipboardJS.isSupported()) - return NEVER - - /* Initialize Clipboard.js */ - return new Observable(subscriber => { - new ClipboardJS("[data-clipboard-target], [data-clipboard-text]") - .on("success", ev => subscriber.next(ev)) - }) - .pipe( - share() - ) +export function setupClipboardJS( + { message$ }: SetupOptions +): void { + if (!ClipboardJS.isSupported()) { + new Observable(subscriber => { + new ClipboardJS("[data-clipboard-target], [data-clipboard-text]") + .on("success", ev => subscriber.next(ev)) + }) + .subscribe(() => message$.next(translation("clipboard.copied"))) + } } diff --git a/src/assets/javascripts/integrations/index.ts b/src/assets/javascripts/integrations/index.ts index 2ef229cb8..23d0f78e9 100644 --- a/src/assets/javascripts/integrations/index.ts +++ b/src/assets/javascripts/integrations/index.ts @@ -21,4 +21,5 @@ */ export * from "./clipboard" +export * from "./instant" export * from "./search" diff --git a/src/assets/javascripts/integrations/instant/.eslintrc b/src/assets/javascripts/integrations/instant/.eslintrc new file mode 100644 index 000000000..116f46ff3 --- /dev/null +++ b/src/assets/javascripts/integrations/instant/.eslintrc @@ -0,0 +1,5 @@ +{ + "rules": { + "no-self-assign": "off" + } +} diff --git a/src/assets/javascripts/integrations/instant/index.ts b/src/assets/javascripts/integrations/instant/index.ts new file mode 100644 index 000000000..24c86a61b --- /dev/null +++ b/src/assets/javascripts/integrations/instant/index.ts @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2016-2020 Martin Donath + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +import { Observable, Subject, fromEvent } from "rxjs" + +import { Viewport, ViewportOffset, getElement } from "~/browser" + +/* ---------------------------------------------------------------------------- + * Types + * ------------------------------------------------------------------------- */ + +/** + * History state + */ +export interface HistoryState { + url: URL /* State URL */ + offset?: ViewportOffset /* State viewport offset */ +} + +/* ---------------------------------------------------------------------------- + * Helper types + * ------------------------------------------------------------------------- */ + +/** + * Setup options + */ +interface SetupOptions { + document$: Subject /* Document subject */ + location$: Subject /* Location subject */ + viewport$: Observable /* Viewport observable */ +} + +/* ---------------------------------------------------------------------------- + * Functions + * ------------------------------------------------------------------------- */ + +/** + * Set up instant loading + * + * When fetching, theoretically, we could use `responseType: "document"`, but + * since all MkDocs links are relative, we need to make sure that the current + * location matches the document we just loaded. Otherwise any relative links + * in the document could use the old location. + * + * This is the reason why we need to synchronize history events and the process + * of fetching the document for navigation changes (except `popstate` events): + * + * 1. Fetch document via `XMLHTTPRequest` + * 2. Set new location via `history.pushState` + * 3. Parse and emit fetched document + * + * For `popstate` events, we must not use `history.pushState`, or the forward + * history will be irreversibly overwritten. In case the request fails, the + * location change is dispatched regularly. + * + * @param urls - URLs to load with XHR + * @param options - Options + */ +export function setupInstantLoading( + urls: string[], { document$, location$, viewport$ }: SetupOptions +): void { + if (location.protocol === "file:") + return + + /* Disable automatic scroll restoration */ + if ("scrollRestoration" in history) { + history.scrollRestoration = "manual" + + /* Hack: ensure that reloads restore viewport offset */ + fromEvent(window, "beforeunload") + .subscribe(() => { + history.scrollRestoration = "auto" + }) + } + + /* Hack: ensure absolute favicon link to omit 404s when switching */ + const favicon = getElement("link[rel='shortcut icon']") + if (typeof favicon !== "undefined") + favicon.href = favicon.href + + // eslint-disable-next-line + console.log(urls, document$, location$, viewport$) +} diff --git a/src/assets/javascripts/integrations/search/worker/_/index.ts b/src/assets/javascripts/integrations/search/worker/_/index.ts index a0e5ffac0..a226783d5 100644 --- a/src/assets/javascripts/integrations/search/worker/_/index.ts +++ b/src/assets/javascripts/integrations/search/worker/_/index.ts @@ -20,8 +20,8 @@ * IN THE SOFTWARE. */ -import { Subject, asyncScheduler, from } from "rxjs" -import { delay, map, observeOn, share } from "rxjs/operators" +import { ObservableInput, Subject, from } from "rxjs" +import { map, share } from "rxjs/operators" import { configuration, translation } from "~/_" import { WorkerHandler, watchWorker } from "~/browser" @@ -82,19 +82,19 @@ function setupSearchIndex( * ------------------------------------------------------------------------- */ /** - * Set up search web worker + * Set up search worker * * This function will create a web worker to set up and query the search index * which is done using `lunr`. The index must be passed as an observable to * enable hacks like _localsearch_ via search index embedding as JSON. * * @param url - Worker URL - * @param index - Promise resolving with search index + * @param index - Search index observable input * * @returns Search worker */ export function setupSearchWorker( - url: string, index: Promise + url: string, index: ObservableInput ): SearchWorker { const config = configuration() const worker = new Worker(url)