Files
sm-seo-plugin/assets/dist/seo.js
Jakub Zych 51413fbda4 feat: robots.txt editor and tester screen
- golem15.seo.robots singleton (UI-SPEC C10): staging callout and the
  served file (P4); the plugin's own extension adds the editor, the
  tester and the AI bots tab, saved to the robots row with history
- field type robotstxt (E4, live lint, size meter; Decode refuses over
  500 KB) and widget golem15-seo-robotstester (E5) on robots_test, which
  tests the unsaved text and switches through grobotstxt
- saving rules that block a noindex address answers robots.blocks_noindex
2026-10-27 11:51:41 +01:00

2 lines
37 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
const H={count:":chars characters · :px / :max px",good:"Good length",emptyTitle:"Empty: the title template is used",emptyDescription:"Empty: the template or the excerpt is used",shortTitle:"Short: aim for 30–60 characters",shortDescription:"Short: aim for 120–160 characters",longTitle:"Too long: Google cuts titles after about 580 px",longDescription:"Too long: Google cuts descriptions after about 920 px on desktop and 680 px on mobile",indexing:"Indexing",links:"Links",inherit:"Inherit",siteDefault:"Site default",index:"Index",noindex:"Noindex",follow:"Follow",nofollow:"Nofollow",advanced:"Advanced directives",advancedSet:{one:":count set",other:":count set"},maxSnippet:"Maximum snippet length (characters)",maxSnippetHint:"Empty: no limit. 0: no snippet. -1: no limit.",maxImagePreview:"Image preview size",notSet:"Not set",none:"None",standard:"Standard",large:"Large",maxVideoPreview:"Maximum video preview (seconds)",noarchive:"Do not show a cached copy (noarchive)",nosnippet:"Do not show a snippet (nosnippet)",noimageindex:"Do not index images (noimageindex)",unavailableAfter:"Remove from results after",invalidNumber:"Enter a whole number, -1 or more.",desktop:"Desktop",mobile:"Mobile",device:"Preview device",language:"Language: :locale",fromTemplate:"Title from the template “:template”",fromContent:"Description from the content excerpt",noDescription:"No description: Google picks text from the page.",noUrl:"The address appears after the first save.",savedNote:"The address and the H1 come from the saved record. Save to refresh them.",checking:"Checking for duplicates…",dupTitle:{one:"Same title as :count other page: :list",other:"Same title as :count other pages: :list"},dupDescription:{one:"Same description as :count other page: :list",other:"Same description as :count other pages: :list"},andMore:"and :count more",keyphrase:"Focus keyphrase “:phrase”",kpTitle:"In the SEO title",kpTitleNo:"Not in the SEO title",kpH1:"In the H1",kpH1No:"Not in the H1",kpDesc:"In the meta description",kpDescNo:"Not in the meta description",kpUrl:"In the address",kpUrlNo:"Not in the address",kpLength:"Text length: :count words",kpLengthNo:"Text length: :count words, aim for at least 300",contextFailed:"The preview data could not be loaded.",imageUpload:"Upload image",imageReplace:"Replace image",imageRemove:"Remove",imageUploading:"Uploading…",imageFailed:"The image could not be uploaded.",imageAlt:"Social image preview",size:":size of 500 KB",clean:"No problems found.",unknown:"Line :line: “:word” is not a robots.txt directive.",unknownSuggest:"Line :line: “:word” is not a robots.txt directive. Did you mean “:suggestion”?",noGroup:"Line :line: this rule has no User-agent line above it, so crawlers ignore it.",badPath:"Line :line: a path must start with / or *.",noColon:"Line :line: write the directive as “Name: value”.",ownSitemap:"Line :line: Sitemap lines are added automatically. This one is kept as written.",crawlDelay:"Line :line: Google ignores Crawl-delay. Bing and Yandex use it.",moreFindings:"and :count more",tooLarge:"Over 500 KB: the file cannot be saved.",url:"Address",urlPlaceholder:"/konto/ustawienia",agent:"Crawler",allowedRule:"Allowed for :agent. Rule: line :line “:rule”.",allowedNone:"Allowed for :agent: no rule matches this address.",blocked:"Blocked for :agent by line :line “:rule”.",blockedBot:"Blocked for :agent by its switch on the AI bots tab.",unsaved:"Tests the text in the editor and the AI bot switches, including unsaved changes.",stagingNote:"On this environment every address is blocked. The result shows the production behaviour.",urlRequired:"Enter an address starting with /."},Y={count:"Znaki: :chars · :px / :max px",good:"Dobra długość",emptyTitle:"Puste: używany jest szablon tytułu",emptyDescription:"Puste: używany jest szablon lub zajawka",shortTitle:"Krótki: celuj w 30–60 znaków",shortDescription:"Krótki: celuj w 120–160 znaków",longTitle:"Za długi: Google ucina tytuły po ok. 580 px",longDescription:"Za długi: Google ucina opisy po ok. 920 px na komputerze i 680 px na telefonie",indexing:"Indeksowanie",links:"Linki",inherit:"Dziedzicz",siteDefault:"Domyślne",index:"Indeksuj",noindex:"Nie indeksuj",follow:"Śledź",nofollow:"Nie śledź",advanced:"Dyrektywy zaawansowane",advancedSet:{one:"ustawiona :count",few:"ustawione :count",many:"ustawionych :count",other:"ustawione :count"},maxSnippet:"Maksymalna długość fragmentu (znaki)",maxSnippetHint:"Puste: bez limitu. 0: bez fragmentu. -1: bez limitu.",maxImagePreview:"Rozmiar podglądu obrazu",notSet:"Nie ustawiono",none:"Brak",standard:"Standardowy",large:"Duży",maxVideoPreview:"Maksymalny podgląd wideo (sekundy)",noarchive:"Nie pokazuj kopii (noarchive)",nosnippet:"Nie pokazuj fragmentu (nosnippet)",noimageindex:"Nie indeksuj obrazów (noimageindex)",unavailableAfter:"Usuń z wyników po dniu",invalidNumber:"Wpisz liczbę całkowitą, -1 lub większą.",desktop:"Komputer",mobile:"Telefon",device:"Urządzenie podglądu",language:"Język: :locale",fromTemplate:"Tytuł z szablonu „:template”",fromContent:"Opis z zajawki treści",noDescription:"Brak opisu: Google wybierze tekst ze strony.",noUrl:"Adres pojawi się po pierwszym zapisie.",savedNote:"Adres i H1 pochodzą z zapisanego rekordu. Zapisz, aby je odświeżyć.",checking:"Sprawdzanie duplikatów…",dupTitle:{one:"Ten sam tytuł co :count inna strona: :list",few:"Ten sam tytuł co :count inne strony: :list",many:"Ten sam tytuł co :count innych stron: :list",other:"Ten sam tytuł co :count innej strony: :list"},dupDescription:{one:"Ten sam opis co :count inna strona: :list",few:"Ten sam opis co :count inne strony: :list",many:"Ten sam opis co :count innych stron: :list",other:"Ten sam opis co :count innej strony: :list"},andMore:"i :count więcej",keyphrase:"Fraza kluczowa „:phrase”",kpTitle:"W tytule SEO",kpTitleNo:"Brak w tytule SEO",kpH1:"W nagłówku H1",kpH1No:"Brak w nagłówku H1",kpDesc:"W opisie meta",kpDescNo:"Brak w opisie meta",kpUrl:"W adresie",kpUrlNo:"Brak w adresie",kpLength:"Długość tekstu: :count słów",kpLengthNo:"Długość tekstu: :count słów, celuj w co najmniej 300",contextFailed:"Nie udało się wczytać danych podglądu.",imageUpload:"Wgraj obraz",imageReplace:"Zmień obraz",imageRemove:"Usuń",imageUploading:"Wgrywanie…",imageFailed:"Nie udało się wgrać obrazu.",imageAlt:"Podgląd obrazu w mediach społecznościowych",size:":size z 500 KB",clean:"Nie znaleziono problemów.",unknown:"Wiersz :line: „:word” nie jest dyrektywą robots.txt.",unknownSuggest:"Wiersz :line: „:word” nie jest dyrektywą robots.txt. Czy chodziło o „:suggestion”?",noGroup:"Wiersz :line: nad tą regułą nie ma wiersza User-agent, więc roboty ją ignorują.",badPath:"Wiersz :line: ścieżka musi zaczynać się od / lub *.",noColon:"Wiersz :line: zapisz dyrektywę jako „Nazwa: wartość”.",ownSitemap:"Wiersz :line: wiersze Sitemap są dodawane automatycznie. Ten zostaje bez zmian.",crawlDelay:"Wiersz :line: Google ignoruje Crawl-delay. Bing i Yandex go stosują.",moreFindings:"i :count więcej",tooLarge:"Ponad 500 KB: nie można zapisać pliku.",url:"Adres",urlPlaceholder:"/konto/ustawienia",agent:"Robot",allowedRule:"Dozwolone dla :agent. Reguła: wiersz :line „:rule”.",allowedNone:"Dozwolone dla :agent: żadna reguła nie pasuje do tego adresu.",blocked:"Zablokowane dla :agent przez wiersz :line „:rule”.",blockedBot:"Zablokowane dla :agent przełącznikiem w zakładce Boty AI.",unsaved:"Sprawdza tekst w edytorze i przełączniki botów AI, także niezapisane zmiany.",stagingNote:"W tym środowisku każdy adres jest zablokowany. Wynik pokazuje zachowanie na produkcji.",urlRequired:"Wpisz adres zaczynający się od /."},J={en:H,pl:Y};function k(n){return(n.getAttribute("ui-locale")||document.documentElement.lang||"en").toLowerCase().split(/[-_]/)[0]||"en"}function C(n){return J[n]??H}function g(n,e={}){const t=Object.keys(e).sort((i,o)=>o.length-i.length);let s=n;for(const i of t)s=s.split(":"+i).join(String(e[i]));return s}function q(n,e,t,s={}){let i="other";try{i=new Intl.PluralRules(t).select(e)}catch{i=e===1?"one":"other"}const o=i==="one"&&n.one||i==="few"&&n.few||i==="many"&&n.many||n.other;return g(o,{...s,count:new Intl.NumberFormat(t).format(e)})}function I(n,e){try{return new Intl.NumberFormat(e).format(n)}catch{return String(n)}}const O="http://www.w3.org/2000/svg",Q={info:["M12 22a10 10 0 1 0 0-20 10 10 0 0 0 0 20z","M12 16v-4","M12 8h.01"],"triangle-alert":["m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3","M12 9v4","M12 17h.01"],"circle-check":["M12 22a10 10 0 1 0 0-20 10 10 0 0 0 0 20z","m9 12 2 2 4-4"],"circle-alert":["M12 22a10 10 0 1 0 0-20 10 10 0 0 0 0 20z","M12 8v4","M12 16h.01"],"chevron-down":["m6 9 6 6 6-6"]};function z(n,e=14){const t=document.createElementNS(O,"svg");t.setAttribute("width",String(e)),t.setAttribute("height",String(e)),t.setAttribute("viewBox","0 0 24 24"),t.setAttribute("fill","none"),t.setAttribute("stroke","currentColor"),t.setAttribute("stroke-width","2"),t.setAttribute("stroke-linecap","round"),t.setAttribute("stroke-linejoin","round"),t.setAttribute("aria-hidden","true"),t.setAttribute("class","seo-icon seo-icon--"+n);for(const s of Q[n]??[]){const i=document.createElementNS(O,"path");i.setAttribute("d",s),t.appendChild(i)}return t}function r(n,e="",t){const s=document.createElement(n);return e&&(s.className=e),t!==void 0&&(s.textContent=t),s}function D(n,e,t){const s=n.getAttribute(e);if(s===null||s==="")return t;try{return JSON.parse(s)}catch{return t}}function T(n,e,t){n.dispatchEvent(new CustomEvent(e,{detail:t,bubbles:!0,composed:!0}))}let U=0;function S(n){return U+=1,`${n}-${U}`}const ee="golem15-seo-image";function te(n){return/^\/(?!\/)/.test(n)||/^https?:\/\//i.test(n)}class se extends HTMLElement{static observedAttributes=["disabled","invalid","ui-locale"];current="";pending="";error="";onUploadResult=e=>{const t=e.detail;!t||t.id!==this.pending||(this.pending="",typeof t.url=="string"&&t.url!==""?(this.current=t.url,this.error="",T(this,"summer-change",{value:this.current})):this.error=t.error||this.labels().imageFailed,this.render())};get value(){return this.current}set value(e){this.current=typeof e=="string"?e:"",this.render()}connectedCallback(){this.addEventListener("summer-upload-result",this.onUploadResult),this.render()}disconnectedCallback(){this.removeEventListener("summer-upload-result",this.onUploadResult)}attributeChangedCallback(){this.isConnected&&this.render()}labels(){return C(k(this))}render(){const e=this.labels(),t=this.hasAttribute("disabled"),s=[];if(this.current&&te(this.current)){const o=r("div","seo-image__preview"),a=r("img","seo-image__img");a.src=this.current,a.alt=e.imageAlt,a.width=240,a.height=126,o.append(a),s.push(o)}if(!t){const o=r("div","seo-image__actions"),a=S("seo-image-file"),l=r("input","seo-visually-hidden");l.type="file",l.accept="image/jpeg,image/png,image/gif,image/webp",l.id=a,l.addEventListener("change",()=>{const u=l.files?.[0];u&&(this.pending=S("seo-image-upload"),this.error="",this.render(),T(this,"summer-upload",{id:this.pending,file:u}))});const c=r("label","seo-image__button",this.current?e.imageReplace:e.imageUpload);if(c.htmlFor=a,o.append(l,c),this.current){const u=r("button","seo-image__button seo-image__button--secondary",e.imageRemove);u.type="button",u.addEventListener("click",()=>{this.current="",this.error="",T(this,"summer-change",{value:""}),this.render()}),o.append(u)}s.push(o)}const i=r("div","seo-image__status"+(this.error?" seo-image__status--error":""));i.setAttribute("role","status"),i.textContent=this.pending?e.imageUploading:this.error,s.push(i),this.classList.toggle("seo-image--invalid",this.hasAttribute("invalid")),this.replaceChildren(...s)}}const ne="golem15-seo-robots";function P(){return{index:"",follow:"",noarchive:!1,nosnippet:!1,noimageindex:!1,maxSnippet:null,maxImagePreview:"",maxVideoPreview:null,unavailableAfter:""}}function ie(n){const e=P(),t=n.trim();if(t==="")return e;const s=new Set;for(const i of t.split(",")){const o=i.trim().toLowerCase();if(o==="")return null;const a=o.indexOf(":"),l=(a<0?o:o.slice(0,a)).trim(),c=a<0?null:o.slice(a+1).trim(),u=l==="noindex"?"index":l==="nofollow"?"follow":l;if(s.has(u))return null;switch(s.add(u),l){case"index":case"noindex":if(c!==null)return null;e.index=l;break;case"follow":case"nofollow":if(c!==null)return null;e.follow=l;break;case"noarchive":case"nosnippet":case"noimageindex":if(c!==null)return null;e[l]=!0;break;case"max-snippet":case"max-video-preview":{if(c===null||!/^-?\d+$/.test(c))return null;const d=Number.parseInt(c,10);if(d<-1)return null;l==="max-snippet"?e.maxSnippet=d:e.maxVideoPreview=d;break}case"max-image-preview":if(c!=="none"&&c!=="standard"&&c!=="large")return null;e.maxImagePreview=c;break;case"unavailable_after":if(c===null||!/^\d{4}-\d{2}-\d{2}$/.test(c)||Number.isNaN(Date.parse(c+"T00:00:00Z")))return null;e.unavailableAfter=c;break;default:return null}}return e}function oe(n){const e=[];return n.index&&e.push(n.index),n.follow&&e.push(n.follow),n.noarchive&&e.push("noarchive"),n.nosnippet&&e.push("nosnippet"),n.noimageindex&&e.push("noimageindex"),n.maxSnippet!==null&&e.push("max-snippet:"+n.maxSnippet),n.maxImagePreview&&e.push("max-image-preview:"+n.maxImagePreview),n.maxVideoPreview!==null&&e.push("max-video-preview:"+n.maxVideoPreview),n.unavailableAfter&&e.push("unavailable_after:"+n.unavailableAfter),e.join(",")}function R(n){return[n.noarchive,n.nosnippet,n.noimageindex,n.maxSnippet!==null,n.maxImagePreview!=="",n.maxVideoPreview!==null,n.unavailableAfter!==""].filter(Boolean).length}class re extends HTMLElement{static observedAttributes=["options","disabled","invalid","ui-locale","locale"];current="";model=P();open=!1;get value(){return this.current}set value(e){const t=typeof e=="string"?e:e==null?"":String(e);t===this.current&&this.childElementCount>0||(this.current=t,this.model=ie(t)??P(),this.open=this.open||R(this.model)>0,this.render())}connectedCallback(){this.open=R(this.model)>0,this.render()}attributeChangedCallback(){this.isConnected&&this.render()}labels(){return C(k(this))}commit(){this.current=oe(this.model),T(this,"summer-change",{value:this.current}),this.render()}render(){const e=this.labels(),t=this.hasAttribute("disabled"),i=D(this,"options",{}).scope==="type"?e.siteDefault:e.inherit;this.classList.toggle("seo-robots--invalid",this.hasAttribute("invalid"));const o=document.activeElement&&this.contains(document.activeElement)?document.activeElement.dataset.focusKey:void 0,a=r("div","seo-robots__groups");a.append(this.radioGroup(e.indexing,"index",[["",i,"inherit"],["index",e.index,"ok"],["noindex",e.noindex,"danger"]],t),this.radioGroup(e.links,"follow",[["",i,"inherit"],["follow",e.follow,"ok"],["nofollow",e.nofollow,"danger"]],t));const l=S("seo-robots-advanced"),c=r("button","seo-robots__toggle");c.type="button",c.setAttribute("aria-expanded",this.open?"true":"false"),c.setAttribute("aria-controls",l),c.dataset.focusKey="toggle",c.append(r("span","",e.advanced),z("chevron-down")),c.addEventListener("click",()=>{this.open=!this.open,this.render()});const u=r("div","seo-robots__advanced-row");u.append(c);const d=R(this.model);d>0&&u.append(r("span","seo-robots__summary",q(e.advancedSet,d,k(this))));const p=r("div","seo-robots__panel");p.id=l,p.hidden=!this.open,p.append(this.numberField(e.maxSnippet,e.maxSnippetHint,"maxSnippet",t,e),this.selectField(e,t),this.numberField(e.maxVideoPreview,"","maxVideoPreview",t,e),this.dateField(e,t));const f=r("div","seo-robots__checks");for(const b of["noarchive","nosnippet","noimageindex"]){const h=r("label","seo-robots__check"),m=r("input");m.type="checkbox",m.checked=this.model[b],m.disabled=t,m.dataset.focusKey=b,m.addEventListener("change",()=>{this.model[b]=m.checked,this.commit()}),h.append(m,r("span","",e[b])),f.append(h)}p.append(f),this.replaceChildren(a,u,p),o&&this.querySelector(`[data-focus-key="${o}"]`)?.focus()}radioGroup(e,t,s,i){const o=r("div","seo-robots__group"),a=S("seo-robots-caption"),l=r("span","seo-robots__caption",e);l.id=a;const c=r("div","seo-robots__track");c.setAttribute("role","radiogroup"),c.setAttribute("aria-labelledby",a);const u=this.model[t];return s.forEach(([d,p,f],b)=>{const h=r("button","seo-robots__segment seo-robots__segment--"+f,p);h.type="button",h.setAttribute("role","radio");const m=u===d;h.setAttribute("aria-checked",m?"true":"false"),h.tabIndex=m?0:-1,h.disabled=i,h.dataset.focusKey=t+"-"+b,h.addEventListener("click",()=>this.choose(t,d)),h.addEventListener("keydown",v=>{const _=v.key==="ArrowRight"||v.key==="ArrowDown"?1:v.key==="ArrowLeft"||v.key==="ArrowUp"?-1:0;if(_===0||i)return;v.preventDefault();const w=(b+_+s.length)%s.length;this.choose(t,s[w][0]),this.querySelector(`[data-focus-key="${t}-${w}"]`)?.focus()}),c.append(h)}),o.append(l,c),o}choose(e,t){this.hasAttribute("disabled")||(e==="index"?this.model.index=t:this.model.follow=t,this.commit())}numberField(e,t,s,i,o){const a=r("label","seo-robots__field");a.append(r("span","seo-robots__label",e));const l=r("input","seo-robots__input");l.type="number",l.min="-1",l.step="1",l.disabled=i,l.dataset.focusKey=s;const c=this.model[s];l.value=c===null?"":String(c);const u=r("span","seo-robots__error");return u.setAttribute("role","status"),l.addEventListener("change",()=>{const d=l.value.trim();if(d===""){this.model[s]=null,this.commit();return}if(!/^-?\d+$/.test(d)||Number.parseInt(d,10)<-1){u.textContent=o.invalidNumber;return}this.model[s]=Number.parseInt(d,10),this.commit()}),a.append(l),t&&a.append(r("span","seo-robots__hint",t)),a.append(u),a}selectField(e,t){const s=r("label","seo-robots__field");s.append(r("span","seo-robots__label",e.maxImagePreview));const i=r("select","seo-robots__input");i.disabled=t,i.dataset.focusKey="maxImagePreview";for(const[o,a]of[["",e.notSet],["none",e.none],["standard",e.standard],["large",e.large]]){const l=r("option","",a);l.value=o,l.selected=this.model.maxImagePreview===o,i.append(l)}return i.addEventListener("change",()=>{this.model.maxImagePreview=i.value,this.commit()}),s.append(i),s}dateField(e,t){const s=r("label","seo-robots__field");s.append(r("span","seo-robots__label",e.unavailableAfter));const i=r("input","seo-robots__input");return i.type="date",i.disabled=t,i.dataset.focusKey="unavailableAfter",i.value=this.model.unavailableAfter,i.addEventListener("change",()=>{this.model.unavailableAfter=/^\d{4}-\d{2}-\d{2}$/.test(i.value)?i.value:"",this.commit()}),s.append(i),s}}const ae="golem15-seo-robotstester",B=["Googlebot","Googlebot-Image","Bingbot","*"];function le(n,e){const t={agent:e.agent,line:e.line,rule:e.rule};return e.allowed?e.line>0?g(n.allowedRule,t):g(n.allowedNone,t):e.bot?g(n.blockedBot,t):g(n.blocked,t)}class ce extends HTMLElement{static observedAttributes=["busy","state","ui-locale","disabled","label","busy-label"];context=null;result=null;error="";inflight=null;queued=null;connected=!1;input=null;select=null;button=null;line=null;notes=null;builtFor="";onResult=e=>{const s=e.detail?.data;this.inflight=null,s&&s.op==="context"?(this.context=s,this.build(!0)):s&&s.op==="test"&&(this.result=s,this.error="",this.renderResult()),this.flush()};connectedCallback(){this.connected=!0,this.addEventListener("summer-result",this.onResult),this.build(!1),this.request({op:"context"})}disconnectedCallback(){this.connected=!1,this.removeEventListener("summer-result",this.onResult)}attributeChangedCallback(e,t,s){if(this.connected){if(e==="busy"&&s===null&&this.flush(),e==="state"&&s==="error"&&(this.inflight=null),e==="ui-locale"){this.build(!0);return}this.syncControls()}}labels(){return C(k(this))}request(e){if(this.hasAttribute("busy")||this.inflight){this.queued=e;return}this.inflight=e,T(this,"summer-action",{payload:e})}flush(){if(this.hasAttribute("busy")||this.inflight||!this.queued)return;const e=this.queued;this.queued=null,this.request(e)}build(e){const t=k(this)+"|"+(this.context?.agents??B).join(",");if(!e&&this.builtFor===t&&this.input){this.syncControls();return}this.builtFor=t;const s=this.labels(),i=this.input?.value??"",o=this.select?.value??"Googlebot";this.replaceChildren();const a=r("div","seo-robotstester__row"),l=S("seo-robotstester-url"),c=r("div","seo-robotstester__field seo-robotstester__field--url"),u=r("label","seo-robotstester__label",s.url);u.htmlFor=l;const d=r("input","seo-robotstester__input");d.id=l,d.type="text",d.placeholder=s.urlPlaceholder,d.value=i,d.addEventListener("keydown",w=>{w.key==="Enter"&&(w.preventDefault(),this.test())}),c.append(u,d);const p=S("seo-robotstester-agent"),f=r("div","seo-robotstester__field seo-robotstester__field--agent"),b=r("label","seo-robotstester__label",s.agent);b.htmlFor=p;const h=r("select","seo-robotstester__select");h.id=p;for(const w of this.context?.agents??B){const L=r("option","",w);L.value=w,h.append(L)}h.value=o,h.value!==o&&(h.value="Googlebot"),f.append(b,h);const m=r("button","seo-robotstester__button");m.type="button",m.addEventListener("click",()=>this.test()),a.append(c,f,m);const v=r("div","seo-robotstester__result");v.setAttribute("role","status");const _=r("div","seo-robotstester__notes");this.input=d,this.select=h,this.button=m,this.line=v,this.notes=_,this.append(a,v,_),this.syncControls(),this.renderResult()}syncControls(){if(!this.button||!this.input||!this.select)return;const e=this.hasAttribute("disabled"),t=this.hasAttribute("busy");this.input.readOnly=e,this.select.disabled=e,this.button.hidden=e,this.button.disabled=t,this.button.textContent=t?this.getAttribute("busy-label")||this.getAttribute("label")||"":this.getAttribute("label")||""}test(){if(this.hasAttribute("disabled")||!this.input||!this.select)return;const e=this.input.value.trim();if(!e.startsWith("/")){this.error=this.labels().urlRequired,this.result=null,this.renderResult();return}this.error="",this.request({op:"test",url:e,agent:this.select.value})}renderResult(){if(!this.line||!this.notes)return;const e=this.labels();if(this.line.className="seo-robotstester__result",this.error)this.line.classList.add("seo-robotstester__result--error"),this.line.replaceChildren(r("span","",this.error));else if(this.result){const s=this.result.allowed;this.line.classList.add(s?"seo-robotstester__result--allowed":"seo-robotstester__result--blocked"),this.line.replaceChildren(z(s?"circle-check":"triangle-alert"),r("span","",le(e,this.result)))}else this.line.replaceChildren();const t=[];(this.context?.staging||D(this,"data",{}).staging)&&t.push(r("p","seo-robotstester__note",e.stagingNote)),t.push(r("p","seo-robotstester__note",e.unsaved)),this.notes.replaceChildren(...t)}}const ue="golem15-seo-robotstxt",de=500*1024,j=10,he=["User-agent","Allow","Disallow","Sitemap","Crawl-delay","Host","Clean-param"];function pe(n,e){const t=Array.from({length:e.length+1},(s,i)=>i);for(let s=1;s<=n.length;s++){let i=t[0];t[0]=s;for(let o=1;o<=e.length;o++){const a=t[o];t[o]=Math.min(t[o]+1,t[o-1]+1,i+(n[s-1]===e[o-1]?0:1)),i=a}}return t[e.length]}function me(n){const e=n.toLowerCase();let t="",s=3;for(const i of he){const o=pe(e,i.toLowerCase());o<s&&(t=i,s=o)}return t}function fe(n){const e=[];let t=!1;return n.split(/\r?\n/).forEach((s,i)=>{const o=i+1,a=s.indexOf("#"),l=(a>=0?s.slice(0,a):s).trim();if(l==="")return;const c=l.indexOf(":");if(c<0){e.push({kind:"noColon",line:o});return}const u=l.slice(0,c).trim(),d=l.slice(c+1).trim();switch(u.toLowerCase()){case"user-agent":t=!0;return;case"allow":case"disallow":t?d!==""&&!d.startsWith("/")&&!d.startsWith("*")&&e.push({kind:"badPath",line:o}):e.push({kind:"noGroup",line:o});return;case"sitemap":e.push({kind:"ownSitemap",line:o});return;case"crawl-delay":e.push({kind:"crawlDelay",line:o});return;case"host":case"clean-param":return}const p=me(u);e.push(p?{kind:"unknownSuggest",line:o,word:u,suggestion:p}:{kind:"unknown",line:o,word:u})}),e}function be(n){return new TextEncoder().encode(n).length}function ge(n,e){return g(n[e.kind],{line:e.line,word:e.word??"",suggestion:e.suggestion??""})}class ve extends HTMLElement{static observedAttributes=["disabled","invalid","ui-locale"];current="";control=null;panel=null;meter=null;builtFor="";get value(){return this.current}set value(e){this.current=typeof e=="string"?e:e==null?"":String(e),this.control&&this.control.value!==this.current&&(this.control.value=this.current),this.update()}connectedCallback(){this.build()}attributeChangedCallback(e){if(this.isConnected){if(e==="ui-locale"){this.build();return}this.sync()}}labels(){return C(k(this))}build(){const e=k(this);if(this.builtFor===e&&this.control){this.sync();return}this.builtFor=e,this.replaceChildren();const t=S("seo-robotstxt-lint"),s=r("textarea","seo-robotstxt__control");s.spellcheck=!1,s.setAttribute("wrap","off"),s.value=this.current,s.setAttribute("aria-describedby",t);const i=this.getAttribute("field-name");i&&s.setAttribute("aria-label",i),s.addEventListener("input",()=>{this.hasAttribute("disabled")||(this.current=s.value,this.update(),T(this,"summer-change",{value:this.current}))});const o=r("div","seo-robotstxt__lint");o.id=t,o.setAttribute("role","status");const a=r("div","seo-robotstxt__size");this.control=s,this.panel=o,this.meter=a,this.append(s,o,a),this.sync()}sync(){this.control&&(this.control.readOnly=this.hasAttribute("disabled"),this.classList.toggle("seo-robotstxt--invalid",this.hasAttribute("invalid")),this.control.setAttribute("aria-invalid",this.hasAttribute("invalid")?"true":"false"),this.update())}update(){if(!this.panel||!this.meter)return;const e=this.labels(),t=k(this),s=fe(this.current),i=[];if(s.length===0){const c=r("div","seo-robotstxt__finding seo-robotstxt__finding--clean");c.append(z("circle-check"),r("span","",e.clean)),i.push(c)}else{for(const c of s.slice(0,j)){const u=r("div","seo-robotstxt__finding");u.append(z("triangle-alert"),r("span","",ge(e,c))),i.push(u)}s.length>j&&i.push(r("div","seo-robotstxt__more",g(e.moreFindings,{count:I(s.length-j,t)})))}this.panel.replaceChildren(...i);const o=be(this.current),a=new Intl.NumberFormat(t,{maximumFractionDigits:1}).format(o/1024)+" KB";this.meter.replaceChildren(r("span","",g(e.size,{size:a})));const l=o>de;this.classList.toggle("seo-robotstxt--over",l),l&&this.meter.append(r("span","seo-robotstxt__over",e.tooLarge))}}const K="20px Arial, sans-serif",V="14px Arial, sans-serif",X=580,$=920,we=680,xe=30,ke=120;let N;function _e(){if(N!==void 0)return N;try{const e=document.createElement("canvas").getContext("2d");N=e&&typeof e.measureText=="function"?e:null}catch{N=null}return N}function ye(n,e){let t=0;for(const s of n)/[ilIj.,:;'!|]/.test(s)?t+=.28:/[mwMW@]/.test(s)?t+=.85:/[A-Z]/.test(s)?t+=.67:s===" "?t+=.28:t+=.53;return t*e}function M(n,e){const t=_e();if(t){t.font=e;const i=t.measureText(n).width;if(Number.isFinite(i)&&(i>0||n===""))return i}const s=Number.parseFloat(e)||14;return ye(n,s)}function W(n,e,t){if(M(n,e)<=t)return n;const s=Array.from(n);let i=0,o=s.length;for(;i<o;){const a=Math.ceil((i+o)/2);M(s.slice(0,a).join("").trimEnd()+"…",e)<=t?i=a:o=a-1}return s.slice(0,i).join("").trimEnd()+"…"}function Ae(n){return n==="title"?{font:K,maxPx:X,shortChars:xe}:{font:V,maxPx:$,shortChars:ke}}function Te(n,e){const{font:t,maxPx:s,shortChars:i}=Ae(e),o=n.trim(),a=Array.from(o).length,l=Math.round(M(o,t));let c="good";return o===""?c="empty":l>s?c="long":a<i&&(c="short"),{status:c,chars:a,px:l,maxPx:s}}const ze="golem15-seo-serp",Se=800,F=3,Ce=300;function Le(n,e){return n.trim()===""?"":n.split("%title%").join(e.title).split("%description%").join(e.description??"").split("%site%").join(e.site).split(/\s+/).filter(Boolean).join(" ").replace(/^[\s|\-–—·:,]+|[\s|\-–—·:,]+$/gu,"")}function Ne(n){return n.toLowerCase().replace(/ł/g,"l").normalize("NFD").replace(/\p{M}/gu,"")}function G(n){return Ne(n).split(/[^\p{L}\p{N}]+/u).filter(Boolean)}function Ee(n,e){if(n===e)return!0;const t=Array.from(n),s=Array.from(e);if(t.length<5||s.length<5)return!1;const i=Math.max(5,Math.min(t.length,s.length)-3);let o=0;for(;o<t.length&&o<s.length&&t[o]===s[o];)o++;return o>=i}function E(n,e){const t=G(n);if(t.length===0)return!1;const s=G(e);for(let i=0;i+t.length<=s.length;i++){let o=!0;for(let a=0;a<t.length;a++)if(!Ee(t[a],s[i+a])){o=!1;break}if(o)return!0}return!1}function y(n,e,t){const s=n[e];if(typeof s=="string")return s;if(s&&typeof s=="object"){const i=s[t];return typeof i=="string"?i:""}return""}class Ie extends HTMLElement{static observedAttributes=["fill-values","busy","state","record-id","ui-locale","locale","disabled"];context=null;contextFailed=!1;device="desktop";shownLocale="";inflight=null;queued=null;duplicates=new Map;checking=!1;timer;lastChecked="";connected=!1;onResult=e=>{const s=e.detail?.data;this.inflight=null,s&&s.op==="context"?(this.context=s,this.contextFailed=!1,this.render(),this.scheduleDuplicates(!0)):s&&s.op==="duplicates"&&(this.duplicates.set(s.locale,s),this.checking=!1,this.render()),this.flush()};onLocale=e=>{const t=e.detail;typeof t=="string"&&t!==""&&t!==this.shownLocale&&(this.shownLocale=t,this.render(),this.scheduleDuplicates(!1))};connectedCallback(){this.connected=!0,this.addEventListener("summer-result",this.onResult),window.addEventListener("summer:ml-locale",this.onLocale),this.render(),this.request({op:"context"})}disconnectedCallback(){this.connected=!1,this.removeEventListener("summer-result",this.onResult),window.removeEventListener("summer:ml-locale",this.onLocale),clearTimeout(this.timer)}attributeChangedCallback(e,t,s){if(this.connected){if(e==="busy"&&s===null){this.flush();return}if(e==="state"&&s==="error"){this.inflight?.op==="context"&&(this.contextFailed=!0),this.checking=!1,this.inflight=null,this.render();return}if(e==="fill-values"){this.render(),this.scheduleDuplicates(!1);return}this.render()}}labels(){return C(k(this))}request(e){if(this.hasAttribute("busy")||this.inflight){this.queued=e;return}this.inflight=e,T(this,"summer-action",{payload:e})}flush(){if(this.hasAttribute("busy")||this.inflight||!this.queued)return;const e=this.queued;this.queued=null,this.request(e)}fill(){return D(this,"fill-values",{})}locale(){const e=this.context?.locales??[];return e.length===0?null:e.find(t=>t.locale===this.shownLocale)??e[0]}scheduleDuplicates(e){const t=this.locale();if(!t)return;const s=this.fill(),i=y(s,"seo_title",t.locale)||y(s,"title",t.locale),o=y(s,"seo_description",t.locale)||y(s,"description",t.locale),a=JSON.stringify([t.locale,i,o]);if(a===this.lastChecked)return;clearTimeout(this.timer);const l=()=>{this.lastChecked=a,this.checking=!0,this.render(),this.request({op:"duplicates",locale:t.locale,title:i,description:o})};e?l():this.timer=setTimeout(l,Se)}render(){const e=this.labels(),t=k(this);if(!this.context&&!this.contextFailed){this.setAttribute("aria-busy","true"),this.replaceChildren(r("div","seo-serp__skeleton"));return}this.removeAttribute("aria-busy");const s=this.locale(),i=s?.locale??this.shownLocale,o=this.fill(),a=(y(o,"seo_title",i)||y(o,"title",i)).trim(),l=(y(o,"seo_description",i)||y(o,"description",i)).trim(),c=y(o,"seo_keyphrase",i).trim(),u=s?.siteName??"",d=a||Le(s?.titleTemplate??"",{title:s?.defaultTitle??"",site:u})||s?.defaultTitle||"",p=l||s?.defaultDescription||"",f=r("div","seo-serp__header"),b=r("div","seo-serp__track");b.setAttribute("role","radiogroup"),b.setAttribute("aria-label",e.device);for(const x of["desktop","mobile"]){const A=r("button","seo-serp__segment",e[x]);A.type="button",A.setAttribute("role","radio"),A.setAttribute("aria-checked",this.device===x?"true":"false"),A.addEventListener("click",()=>{this.device=x,this.render()}),b.append(A)}f.append(b),i&&f.append(r("span","seo-serp__language",g(e.language,{locale:i.toUpperCase()})));const h=r("div","serp-card"+(this.device==="mobile"?" serp-card--mobile":"")),m=r("div","serp-card__site");m.append(r("span","serp-card__favicon",Array.from(u||this.context?.host||"?")[0]?.toUpperCase()??"?"));const v=r("div","serp-card__names");if(v.append(r("span","serp-card__sitename",u||this.context?.host||"")),v.append(r("span","serp-card__crumbs",De(this.context?.host??"",s?.url??null))),m.append(v),h.append(m),h.append(r("div","serp-card__title",W(d,K,X))),p){const x=this.device==="mobile"?we:$;h.append(r("div","serp-card__description",W(p,V,x)))}else h.append(r("div","serp-card__description serp-card__description--missing",e.noDescription));const _=r("div","seo-serp__notes");if(this.contextFailed){const x=r("div","seo-serp__error");x.setAttribute("role","status"),x.append(z("circle-alert"),r("span","",e.contextFailed)),_.append(x)}!a&&s?.titleTemplate&&_.append(r("div","",g(e.fromTemplate,{template:s.titleTemplate}))),!l&&s?.defaultDescription&&s.descriptionSource==="content"&&_.append(r("div","",e.fromContent)),s&&s.url===null&&_.append(r("div","",e.noUrl)),(this.getAttribute("record-id")??"")!==""&&s&&_.append(r("div","",e.savedNote));const w=r("div","seo-serp__checks");if(w.setAttribute("role","status"),this.checking)w.append(r("div","seo-serp__checking",e.checking));else{const x=this.duplicates.get(i);if(x)for(const[A,Z]of[[x.title,e.dupTitle],[x.description,e.dupDescription]])A.length>0&&w.append(Re(A,Z,e,t))}const L=[f,h,_,w];c&&s&&L.push(je(c,{title:d,description:p,h1:s.h1,url:s.url,bodyWords:s.bodyWords},e,t)),this.replaceChildren(...L)}}function De(n,e){const t=(e??"").split("?")[0].split("/").filter(Boolean).map(s=>{try{return decodeURIComponent(s)}catch{return s}});return[n,...t].filter(Boolean).join(" › ")}function Re(n,e,t,s){const i=r("div","seo-serp__check seo-serp__check--warn");i.append(z("triangle-alert"));const o=r("span"),a="\0list\0",l=q(e,n.length,s,{list:a}),[c,u]=l.split(a);return o.append(document.createTextNode(c??"")),n.slice(0,F).forEach((d,p)=>{if(p>0&&o.append(document.createTextNode(", ")),d.url.startsWith("/")&&!d.url.startsWith("//")){const f=r("a","seo-serp__link",d.label);f.href=d.url,f.target="_blank",f.rel="noopener",o.append(f)}else o.append(document.createTextNode(d.label))}),n.length>F&&o.append(document.createTextNode(" "+g(t.andMore,{count:n.length-F}))),o.append(document.createTextNode(u??"")),i.append(o),i}function je(n,e,t,s){const i=r("div","seo-serp__keyphrase");i.append(r("div","seo-serp__keyphrase-title",g(t.keyphrase,{phrase:n})));const o=(a,l,c)=>{const u=r("div","seo-serp__check "+(a?"seo-serp__check--ok":"seo-serp__check--warn"));u.append(z(a?"circle-check":"triangle-alert"),r("span","",a?l:c)),i.append(u)};if(o(E(n,e.title),t.kpTitle,t.kpTitleNo),e.h1!==null&&o(E(n,e.h1),t.kpH1,t.kpH1No),o(E(n,e.description),t.kpDesc,t.kpDescNo),e.url!==null&&o(E(n,e.url.replace(/[-_/]+/g," ")),t.kpUrl,t.kpUrlNo),e.bodyWords!==null){const a=new Intl.NumberFormat(s).format(e.bodyWords);o(e.bodyWords>=Ce,g(t.kpLength,{count:a}),g(t.kpLengthNo,{count:a}))}return i}const Fe="golem15-seo-text",Pe={empty:"info",short:"triangle-alert",long:"triangle-alert",good:"circle-check"};class Me extends HTMLElement{static observedAttributes=["options","disabled","invalid","ui-locale","locale"];current="";control=null;statusIcon=null;statusText=null;countText=null;live=null;lastStatus=null;builtFor="";get value(){return this.current}set value(e){this.current=typeof e=="string"?e:e==null?"":String(e),this.control&&this.control.value!==this.current&&(this.control.value=this.current),this.update(!1)}connectedCallback(){this.build()}attributeChangedCallback(e){if(this.isConnected){if(e==="options"||e==="ui-locale"){this.build();return}this.sync()}}measure(){return D(this,"options",{}).measure==="description"?"description":"title"}labels(){return C(k(this))}build(){const e=this.measure()+"|"+k(this);if(this.builtFor===e&&this.control){this.sync();return}this.builtFor=e,this.replaceChildren();const t=S("seo-text-counter"),i=this.measure()==="description"?r("textarea","seo-text__control seo-text__control--area"):r("input","seo-text__control");i instanceof HTMLTextAreaElement?i.rows=3:i.type="text",i.value=this.current,i.setAttribute("aria-describedby",t);const o=this.getAttribute("field-name");o&&i.setAttribute("aria-label",o),i.addEventListener("input",()=>{this.hasAttribute("disabled")||(this.current=i.value.replace(/\s+$/u,""),this.update(!0),T(this,"summer-change",{value:this.current}))});const a=r("div","seo-text__counter");a.id=t;const l=r("span","seo-text__status");this.statusIcon=r("span","seo-text__icon"),this.statusText=r("span","seo-text__status-text"),l.append(this.statusIcon,this.statusText),this.countText=r("span","seo-text__count"),a.append(l,this.countText),this.live=r("span","seo-visually-hidden"),this.live.setAttribute("aria-live","polite"),this.live.setAttribute("role","status"),this.control=i,this.lastStatus=null,this.append(i,a,this.live),this.sync()}sync(){if(!this.control)return;const e=this.hasAttribute("disabled");this.control.readOnly=e,this.classList.toggle("seo-text--invalid",this.hasAttribute("invalid")),this.control.setAttribute("aria-invalid",this.hasAttribute("invalid")?"true":"false"),this.update(!1)}update(e){if(!this.statusText||!this.countText||!this.statusIcon)return;const t=this.labels(),s=k(this),i=this.measure(),o=Te(this.current,i),a=Oe(t,o.status,i);this.statusIcon.replaceChildren(z(Pe[o.status])),this.statusText.textContent=a,this.dataset.status=o.status,this.countText.textContent=g(t.count,{chars:I(o.chars,s),px:I(o.px,s),max:I(o.maxPx,s)}),e&&this.live&&o.status!==this.lastStatus&&(this.live.textContent=a),this.lastStatus=o.status}}function Oe(n,e,t){switch(e){case"empty":return t==="title"?n.emptyTitle:n.emptyDescription;case"short":return t==="title"?n.shortTitle:n.shortDescription;case"long":return t==="title"?n.longTitle:n.longDescription;default:return n.good}}const Ue=[[Fe,Me],[ne,re],[ze,Ie],[ee,se],[ue,ve],[ae,ce]];for(const[n,e]of Ue)customElements.get(n)||customElements.define(n,e);export{ee as IMAGE_TAG,ae as ROBOTSTESTER_TAG,ue as ROBOTSTXT_TAG,ne as ROBOTS_TAG,ze as SERP_TAG,se as SeoImageElement,re as SeoRobotsElement,ce as SeoRobotsTesterElement,ve as SeoRobotsTxtElement,Ie as SeoSerpElement,Me as SeoTextElement,Fe as TEXT_TAG};