jotterjs 0.5.0 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,5 +1,5 @@
1
- var JotterJS=(()=>{var C=Object.defineProperty;var x=Object.getOwnPropertyDescriptor;var T=Object.getOwnPropertyNames;var L=Object.prototype.hasOwnProperty;var w=(m,t)=>{for(var e in t)C(m,e,{get:t[e],enumerable:!0})},M=(m,t,e,o)=>{if(t&&typeof t=="object"||typeof t=="function")for(let i of T(t))!L.call(m,i)&&i!==e&&C(m,i,{get:()=>t[i],enumerable:!(o=x(t,i))||o.enumerable});return m};var j=m=>M(C({},"__esModule",{value:!0}),m);var q={};w(q,{JotterJS:()=>h,default:()=>P});var f={source:{custom:"toggleSource",label:"Source",title:"Edit HTML Source"},sep:{type:"sep"},blockformat:{type:"blockformat"},fontfamily:{type:"fontfamily"},fontsize:{type:"fontsize"},theme:{type:"theme"},undo:{cmd:"undo",icon:"undo",title:"Undo (Ctrl+Z)"},redo:{cmd:"redo",icon:"redo",title:"Redo (Ctrl+Y)"},bold:{cmd:"bold",icon:"format_bold",title:"Bold (Ctrl+B)"},italic:{cmd:"italic",icon:"format_italic",title:"Italic (Ctrl+I)"},underline:{cmd:"underline",icon:"format_underlined",title:"Underline (Ctrl+U)"},strike:{cmd:"strikeThrough",icon:"strikethrough_s",title:"Strikethrough"},subscript:{cmd:"subscript",icon:"subscript",title:"Subscript"},superscript:{cmd:"superscript",icon:"superscript",title:"Superscript"},code:{custom:"code",icon:"code",title:"Inline Code"},copy:{cmd:"copy",icon:"content_copy",title:"Copy"},cut:{cmd:"cut",icon:"content_cut",title:"Cut"},paste:{cmd:"paste",icon:"content_paste",title:"Paste"},clearFormat:{cmd:"removeFormat",icon:"format_clear",title:"Clear Formatting"},alignLeft:{cmd:"justifyLeft",icon:"format_align_left",title:"Align Left"},alignCenter:{cmd:"justifyCenter",icon:"format_align_center",title:"Align Center"},alignRight:{cmd:"justifyRight",icon:"format_align_right",title:"Align Right"},bullets:{cmd:"insertUnorderedList",icon:"format_list_bulleted",title:"Bullet List"},numbered:{cmd:"insertOrderedList",icon:"format_list_numbered",title:"Numbered List"},link:{type:"popup",id:"link",icon:"insert_link",title:"Insert Link"},unlink:{cmd:"unlink",icon:"link_off",title:"Remove Link"},foreColor:{type:"color",cmd:"foreColor",icon:"format_color_text",title:"Text Color"},hiliteColor:{type:"color",cmd:"hiliteColor",icon:"format_color_fill",title:"Background Color"},image:{type:"popup",id:"image",icon:"image",title:"Insert Image"},video:{type:"popup",id:"video",icon:"smart_display",title:"Insert YouTube Video"},table:{type:"popup",id:"table",icon:"table_chart",title:"Insert Table"},embed:{type:"popup",id:"embed",icon:"html",title:"Insert Embed"},symbol:{type:"popup",id:"symbol",icon:"emoji_symbols",title:"Insert Symbol"},specialChar:{type:"popup",id:"specialchar",icon:"format_shapes",title:"Special Characters"},lorem:{type:"popup",id:"lorem",icon:"history_edu",title:"Insert Lorem Ipsum"}};Object.values(f).forEach(Object.freeze);Object.freeze(f);var s=f,_={minimal:[s.source,s.sep,s.bold,s.italic,s.underline,s.sep,s.link,s.unlink],writing:[s.source,s.sep,s.undo,s.redo,s.sep,s.blockformat,s.sep,s.bold,s.italic,s.underline,s.strike,s.sep,s.bullets,s.numbered,s.sep,s.link,s.unlink,s.sep,s.image],full:[s.source,s.sep,s.undo,s.redo,s.sep,s.copy,s.cut,s.paste,s.sep,s.clearFormat,s.sep,s.blockformat,s.fontfamily,s.fontsize,s.sep,s.bold,s.italic,s.underline,s.strike,s.subscript,s.superscript,s.code,s.sep,s.foreColor,s.hiliteColor,s.sep,s.alignLeft,s.alignCenter,s.alignRight,s.sep,s.bullets,s.numbered,s.sep,s.link,s.unlink,s.sep,s.image,s.video,s.table,s.embed,s.symbol,s.specialChar,s.lorem,s.sep,s.theme]};Object.values(_).forEach(Object.freeze);Object.freeze(_);var N=_.full,A={image:"onRequestImage",link:"onRequestLink",video:"onRequestVideo",embed:"onRequestEmbed"},v=[{label:"Paragraph",tag:"p"},{label:"Heading 1",tag:"h1"},{label:"Heading 2",tag:"h2"},{label:"Heading 3",tag:"h3"},{label:"Heading 4",tag:"h4"},{label:"Pre / Code",tag:"pre"},{label:"Blockquote",tag:"blockquote"}],I=["Arial","Arial Black","Comic Sans MS","Courier New","Georgia","Impact","Lucida Console","Palatino Linotype","Tahoma","Times New Roman","Trebuchet MS","Verdana"],B=[8,9,10,11,12,14,16,18,20,24,28,32,36,48,72],H=["\u2190","\u2192","\u2191","\u2193","\u2194","\u2195","\u21D0","\u21D2","\u21D1","\u21D3","\u21D4","\u2022","\xB7","\u25E6","\u25CB","\u25CF","\u25A1","\u25A0","\u25C6","\u25C7","\u25B2","\u25BC","\u2605","\u2606","\u2660","\u2663","\u2665","\u2666","\u2713","\u2717","\u2715","\u2718","\u2248","\u2260","\u2261","\u2264","\u2265","\xF7","\xD7","\xB1","\u221E","\u221A","\u2211","\u220F","\u222B","\u2202","\u2206","\u2207","\u03C0","\u03A9","\u03BC","\u03B1","\u03B2","\u03B3","\xA9","\xAE","\u2122","\xA7","\xB6","\u2020","\u2021","\xB0","\u2032","\u2033","\u2030","\u201C","\u201D","\u2018","\u2019","\xAB","\xBB","\u2039","\u203A","\u2014","\u2013","\u2026","\xBF","\xA1","\u20AC","\xA3","\xA5","\xA2","\u20B9","\u20BD","\u20BF"],R=["\xC0","\xC1","\xC2","\xC3","\xC4","\xC5","\xC6","\xC7","\xC8","\xC9","\xCA","\xCB","\xCC","\xCD","\xCE","\xCF","\xD0","\xD1","\xD2","\xD3","\xD4","\xD5","\xD6","\xD8","\xD9","\xDA","\xDB","\xDC","\xDD","\xDE","\xDF","\xE0","\xE1","\xE2","\xE3","\xE4","\xE5","\xE6","\xE7","\xE8","\xE9","\xEA","\xEB","\xEC","\xED","\xEE","\xEF","\xF0","\xF1","\xF2","\xF3","\xF4","\xF5","\xF6","\xF8","\xF9","\xFA","\xFB","\xFC","\xFD","\xFE","\xFF","\u0152","\u0153","\u0160","\u0161","\u0178","\u017D","\u017E"],E=[{id:"default",label:"Default"},{id:"warm",label:"Warm"},{id:"ink",label:"Ink / Navy"},{id:"forest",label:"Forest"}],F=[{label:"Short \u2014 1 sentence",text:"Lorem ipsum dolor sit amet, consectetur adipiscing elit."},{label:"Medium \u2014 1 paragraph",text:"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat."},{label:"Long \u2014 3 paragraphs",isHTML:!0,text:"<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris.</p><p>Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p><p>Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo.</p>"}],h=class{constructor(t,e={}){if(this._target=typeof t=="string"?document.querySelector(t):t,!this._target)throw new Error("[JotterJS] Target element not found.");this._options=Object.assign({placeholder:"Start typing\u2026",height:"320px",theme:"default",onChange:null,onFocus:null,onBlur:null,onRequestImage:null,onRequestLink:null,onRequestVideo:null,onRequestEmbed:null},e),this._listeners={},this._bookmarks=new Map,this._bmSeq=0,this._savedBookmark=null,this._externalBookmark=null,this._externalDepth=0,this._changeCount=0,this._destroyed=!1,this._lastForeColor="#e8e4d8",this._lastHiliteColor="#c8a96e",this._init()}_init(){let t=this._target.innerHTML||"";this._target.innerHTML="",this._target.classList.add("jotter-host"),this._root=document.createElement("div"),this._root.className="htmled",this._toolbar=this._buildToolbar(),this._editorWrap=document.createElement("div"),this._editorWrap.className="jotter-editor-wrap",this._editor=document.createElement("div"),this._editor.className="jotter-editor",this._editor.contentEditable="true",this._editor.setAttribute("data-placeholder",this._options.placeholder),this._editor.style.minHeight=this._options.height,this._editor.innerHTML=this._sanitize(t),this._editor.spellcheck=!0,document.execCommand("defaultParagraphSeparator",!1,"p"),this._source=document.createElement("textarea"),this._source.className="jotter-source",this._source.setAttribute("aria-label","HTML source"),this._source.setAttribute("spellcheck","false"),this._source.style.minHeight=this._options.height,this._sourceMode=!1,this._statusBar=this._buildStatusBar(),this._editorWrap.appendChild(this._editor),this._editorWrap.appendChild(this._source),this._root.appendChild(this._toolbar),this._root.appendChild(this._editorWrap),this._root.appendChild(this._statusBar),this._target.appendChild(this._root),this._popup=this._buildPopupContainer(),document.body.appendChild(this._popup),this._bindEvents(),this._updateToolbarState(),this._updateStatus(),this.setTheme(this._options.theme)}_buildToolbar(){let t=document.createElement("div");return t.className="jotter-toolbar",this._toolbarEl=t,(this._options.toolbar||N).forEach(e=>{let o=this._buildAction(e);o&&t.appendChild(o)}),t}_buildAction(t){if(typeof t.onClick=="function")return this._buildBtn(t);switch(t.type){case"sep":return this._makeSep();case"blockformat":return this._buildBlockFormatSelect();case"fontfamily":return this._buildFontFamilySelect();case"fontsize":return this._buildFontSizeSelect();case"color":return this._buildColorBtn(t);case"popup":return this._buildPopupBtn(t);case"theme":return this._buildThemeSelect();default:return this._buildBtn(t)}}_makeSep(){let t=document.createElement("span");return t.className="jotter-sep",t}_bindActivation(t,e){t.addEventListener("mousedown",o=>{o.preventDefault(),e(!1)}),t.addEventListener("keydown",o=>{o.key!=="Enter"&&o.key!==" "&&o.key!=="Spacebar"||o.repeat||(o.preventDefault(),e(!0))})}_returnFocus(t,e){e&&this._isInternalTarget(document.activeElement)&&t.focus()}_buildBtn(t){let e=document.createElement("button");if(e.type="button",e.className="jotter-btn",t.cmd&&(e.dataset.cmd=t.cmd),t.custom&&(e.dataset.custom=t.custom),e.title=t.title,e.setAttribute("aria-label",t.title),t.label)e.classList.add("jotter-btn--text"),e.appendChild(document.createTextNode(t.label));else{let o=document.createElement("span");o.className="material-icons",o.textContent=t.icon,e.appendChild(o)}return this._bindActivation(e,o=>{this._editor.focus(),this._applyEdit(()=>{if(t.onClick)t.onClick(this);else if(t.custom==="toggleSource")this._toggleSourceMode();else if(t.custom==="code")this._toggleInlineCode();else if(t.cmd==="copy")document.execCommand("copy");else if(t.cmd==="cut")document.execCommand("cut");else if(t.cmd==="paste")this._pasteFromClipboard();else if(t.prompt){let i=window.prompt(t.prompt);i&&document.execCommand(t.cmd,!1,i)}else document.execCommand(t.cmd,!1,null)}),this._updateToolbarState(),this._returnFocus(e,o)}),e}_bindSelectCaret(t){let e={viaKeyboard:!1};return t.addEventListener("mousedown",()=>{e.viaKeyboard=!1,this._saveBookmark()}),t.addEventListener("keydown",o=>{o.key==="Tab"||o.key==="Escape"||(e.viaKeyboard=!0,this._savedBookmark==null&&this._saveBookmark())}),e}_buildBlockFormatSelect(){let t=document.createElement("select");t.className="jotter-select",t.title="Block format",t.dataset.id="blockformat",v.forEach(({label:o,tag:i})=>{let n=document.createElement("option");n.value=i,n.textContent=o,t.appendChild(n)});let e=this._bindSelectCaret(t);return t.addEventListener("change",()=>{this._restoreSavedBookmark(),this._applyEdit(()=>document.execCommand("formatBlock",!1,t.value)),this._returnFocus(t,e.viaKeyboard)}),t}_buildFontFamilySelect(){let t=document.createElement("select");t.className="jotter-select jotter-select--font",t.title="Font family",t.dataset.id="fontfamily";let e=document.createElement("option");e.value="",e.textContent="Font",t.appendChild(e),I.forEach(i=>{let n=document.createElement("option");n.value=i,n.textContent=i,n.style.fontFamily=i,t.appendChild(n)});let o=this._bindSelectCaret(t);return t.addEventListener("change",()=>{t.value&&(this._restoreSavedBookmark(),this._applyEdit(()=>document.execCommand("fontName",!1,t.value)),this._returnFocus(t,o.viaKeyboard))}),t}_buildFontSizeSelect(){let t=document.createElement("select");t.className="jotter-select jotter-select--size",t.title="Font size",t.dataset.id="fontsize";let e=document.createElement("option");e.value="",e.textContent="Size",t.appendChild(e),B.forEach(i=>{let n=document.createElement("option");n.value=i,n.textContent=`${i}px`,t.appendChild(n)});let o=this._bindSelectCaret(t);return t.addEventListener("change",()=>{t.value&&(this._restoreSavedBookmark(),this._applyEdit(()=>this._applyFontSize(t.value)),this._returnFocus(t,o.viaKeyboard))}),t}_buildThemeSelect(){let t=document.createElement("select");return t.className="jotter-select jotter-select--theme",t.title="Editor theme",t.dataset.id="theme",E.forEach(({id:e,label:o})=>{let i=document.createElement("option");i.value=e,i.textContent=o,t.appendChild(i)}),t.value=this._options.theme,t.addEventListener("change",()=>this.setTheme(t.value)),this._themeSelect=t,t}_buildColorBtn(t){let e=document.createElement("span");e.className="jotter-color-wrap";let o=document.createElement("button");o.type="button",o.className="jotter-btn jotter-color-btn",o.dataset.cmd=t.cmd,o.title=t.title,o.setAttribute("aria-label",t.title);let i=document.createElement("span");i.className="material-icons",i.textContent=t.icon,o.appendChild(i);let n=document.createElement("span");n.className="jotter-color-swatch";let r=t.cmd==="foreColor"?this._lastForeColor:this._lastHiliteColor;n.style.background=r,o.appendChild(n);let a=document.createElement("input");a.type="color",a.className="jotter-color-input",a.value=r,a.tabIndex=-1;let u=!1;return a.addEventListener("change",()=>{let p=a.value;n.style.background=p,t.cmd==="foreColor"?this._lastForeColor=p:this._lastHiliteColor=p,this._restoreSavedBookmark(),this._applyEdit(()=>document.execCommand(t.cmd,!1,p)),this._returnFocus(o,u)}),this._bindActivation(o,p=>{u=p,this._saveBookmark(),a.click()}),e.appendChild(o),e.appendChild(a),e}_buildPopupBtn(t){let e=document.createElement("button");e.type="button",e.className="jotter-btn",e.title=t.title,e.setAttribute("aria-label",t.title);let o=document.createElement("span");return o.className="material-icons",o.textContent=t.icon,e.appendChild(o),this._bindActivation(e,i=>{let n=this._resolverFor(t.id);if(n){this._hidePopup(),this._runResolver(t.id,n);return}if(this._saveBookmark(),this._popupVisible()&&this._popup.dataset.popupId===t.id){this._hidePopup();return}this._showPopup(e,this._buildPopupContent(t.id),t.id),i&&this._focusPopup()}),e}_focusPopup(){let t=this._popup.querySelector('input, textarea, select, button, [tabindex]:not([tabindex="-1"])');t&&t.focus()}_buildPopupContainer(){let t=document.createElement("div");return t.className="jotter-popup",t.setAttribute("role","dialog"),t}_showPopup(t,e,o){this._popup.innerHTML="",this._popup.appendChild(e),this._popup.dataset.popupId=o,this._popup.classList.add("jotter-popup--visible");let i=t.getBoundingClientRect();this._popup.style.top=i.bottom+6+"px",this._popup.style.left=i.left+"px",this._popup.style.right="auto",requestAnimationFrame(()=>{let n=this._popup.getBoundingClientRect();n.right>window.innerWidth-8&&(this._popup.style.left=Math.max(8,i.left-(n.right-window.innerWidth+8))+"px")})}_popupVisible(){return this._popup.classList.contains("jotter-popup--visible")}_hidePopup(){this._popup.classList.remove("jotter-popup--visible"),this._popup.dataset.popupId="",this._releaseSavedBookmark()}_buildPopupContent(t){switch(t){case"link":return this._popupLink();case"table":return this._popupTable();case"image":return this._popupImage();case"video":return this._popupVideo();case"embed":return this._popupEmbed();case"symbol":return this._popupSymbol();case"specialchar":return this._popupSpecialChar();case"lorem":return this._popupLorem();default:{let e=document.createElement("div");return e.className="jotter-popup-inner",e.textContent="Unknown: "+t,e}}}_popupTable(){let t=document.createElement("div");t.className="jotter-popup-inner";let e=this._popupTitle("Insert Table");t.appendChild(e);let o=10,i=8,n=document.createElement("div");n.className="jotter-table-grid",n.style.gridTemplateColumns=`repeat(${o}, 1fr)`,n.setAttribute("role","grid"),n.setAttribute("aria-label","Table size");let r=document.createElement("div");r.className="jotter-popup-hint",r.textContent="Hover or arrow to select size";let a=[],u=(c,l)=>{r.textContent=`${c+1} \xD7 ${l+1} table`,a.forEach(d=>{d.classList.toggle("jotter-table-cell--active",+d.dataset.r<=c&&+d.dataset.c<=l)})};for(let c=0;c<i;c++)for(let l=0;l<o;l++){let d=document.createElement("span");d.className="jotter-table-cell",d.dataset.r=c,d.dataset.c=l,d.setAttribute("role","gridcell"),d.setAttribute("aria-label",`${c+1} by ${l+1} table`),d.tabIndex=c===0&&l===0?0:-1,d.addEventListener("mouseenter",()=>u(c,l)),d.addEventListener("focus",()=>u(c,l)),d.addEventListener("click",()=>this._insertTable(c+1,l+1)),a.push(d),n.appendChild(d)}let p={ArrowRight:[0,1],ArrowLeft:[0,-1],ArrowDown:[1,0],ArrowUp:[-1,0]};return n.addEventListener("keydown",c=>{let l=a.indexOf(document.activeElement)===-1?null:document.activeElement;if(!l)return;let d=+l.dataset.r,k=+l.dataset.c;if(c.key==="Enter"||c.key===" "||c.key==="Spacebar"){c.preventDefault(),this._insertTable(d+1,k+1);return}let b=p[c.key];if(!b)return;c.preventDefault();let y=Math.min(i-1,Math.max(0,d+b[0])),S=Math.min(o-1,Math.max(0,k+b[1])),g=a[y*o+S];g!==l&&(l.tabIndex=-1,g.tabIndex=0,g.focus())}),t.appendChild(n),t.appendChild(r),t}_commitPopup(t){this._restoreSavedBookmark(),this._hidePopup(),this._applyEdit(t)}_insertTable(t,e){let o="<table><tbody>";for(let i=0;i<t;i++){o+="<tr>";for(let n=0;n<e;n++)o+=i===0?"<th><br></th>":"<td><br></td>";o+="</tr>"}o+="</tbody></table><p><br></p>",this._commitPopup(()=>document.execCommand("insertHTML",!1,o))}_popupLink(){let t=document.createElement("div");t.className="jotter-popup-inner jotter-popup-form",t.appendChild(this._popupTitle("Insert Link"));let e=this._anchorInSelection(),o=this._selectedText(),i=this._makeField(t,"URL","url","https://"),n=this._makeField(t,"Link text (leave blank to keep selection)","text",""),r=this._makeField(t,"Title / tooltip","text",""),a=document.createElement("label");a.className="jotter-popup-label",a.textContent="Open in";let u=document.createElement("select");return u.className="jotter-popup-select",[["(same window)",""],["New tab (_blank)","_blank"],["Parent frame (_parent)","_parent"],["Top frame (_top)","_top"]].forEach(([p,c])=>{let l=document.createElement("option");l.value=c,l.textContent=p,u.appendChild(l)}),t.appendChild(a),t.appendChild(u),e?(i.value=e.getAttribute("href")||"",n.value=e.textContent||"",r.value=e.getAttribute("title")||"",u.value=e.getAttribute("target")||""):o&&(n.value=o),t.appendChild(this._makeSubmitBtn(e?"Update Link":"Insert Link",()=>{let p=i.value.trim();if(!p)return;let c=n.value.trim()||o||p,l=r.value.trim(),d=u.value;this._commitPopup(()=>{e?(e.href=p,d?e.target=d:e.removeAttribute("target"),l?e.title=l:e.removeAttribute("title"),e.textContent=c):document.execCommand("insertHTML",!1,this._linkHTML({href:p,text:c,title:l,target:d}))})})),t}_popupImage(){let t=document.createElement("div");t.className="jotter-popup-inner jotter-popup-form",t.appendChild(this._popupTitle("Insert Image"));let e=this._makeField(t,"Image URL","text","https://example.com/image.jpg"),o=this._makeField(t,"Alt text","text","Descriptive text"),i=this._makeField(t,"Width (e.g. 400px or 50%)","text","");return t.appendChild(this._makeSubmitBtn("Insert Image",()=>{let n=e.value.trim();if(!n)return;let r=this._imageHTML({src:n,alt:o.value.trim(),width:i.value.trim()});this._commitPopup(()=>document.execCommand("insertHTML",!1,r))})),t}_popupVideo(){let t=document.createElement("div");t.className="jotter-popup-inner jotter-popup-form",t.appendChild(this._popupTitle("Insert YouTube Video"));let e=this._makeField(t,"YouTube URL","text","https://www.youtube.com/watch?v=...");return t.appendChild(this._makeSubmitBtn("Embed Video",()=>{let o=this._ytId(e.value.trim());if(!o){e.classList.add("jotter-input--error");return}e.classList.remove("jotter-input--error"),this._commitPopup(()=>document.execCommand("insertHTML",!1,this._videoHTML(o)))})),t}_ytId(t){for(let e of[/[?&]v=([A-Za-z0-9_-]{11})/,/youtu\.be\/([A-Za-z0-9_-]{11})/,/embed\/([A-Za-z0-9_-]{11})/]){let o=t.match(e);if(o)return o[1]}return null}_popupEmbed(){let t=document.createElement("div");t.className="jotter-popup-inner jotter-popup-form",t.appendChild(this._popupTitle("Insert Embed"));let e=document.createElement("label");e.className="jotter-popup-label",e.textContent="Paste HTML / embed code";let o=document.createElement("textarea");return o.className="jotter-popup-textarea",o.placeholder='<iframe src="..." ...></iframe>',o.rows=4,t.appendChild(e),t.appendChild(o),t.appendChild(this._makeSubmitBtn("Insert",()=>{let i=o.value.trim();i&&this._commitPopup(()=>document.execCommand("insertHTML",!1,this._embedHTML(i)))})),t}_popupSymbol(){let t=document.createElement("div");return t.className="jotter-popup-inner",t.appendChild(this._popupTitle("Insert Symbol")),t.appendChild(this._charGrid(H)),t}_popupSpecialChar(){let t=document.createElement("div");return t.className="jotter-popup-inner",t.appendChild(this._popupTitle("Special Characters")),t.appendChild(this._charGrid(R)),t}_charGrid(t){let e=document.createElement("div");return e.className="jotter-char-grid",t.forEach(o=>{let i=document.createElement("button");i.type="button",i.className="jotter-char-btn",i.textContent=o,i.title=`U+${o.codePointAt(0).toString(16).toUpperCase().padStart(4,"0")}`,this._bindActivation(i,()=>{this._commitPopup(()=>document.execCommand("insertText",!1,o))}),e.appendChild(i)}),e}_popupLorem(){let t=document.createElement("div");return t.className="jotter-popup-inner",t.appendChild(this._popupTitle("Insert Lorem Ipsum")),F.forEach(e=>{let o=document.createElement("button");o.type="button",o.className="jotter-lorem-btn",o.textContent=e.label,this._bindActivation(o,()=>{this._commitPopup(()=>document.execCommand(e.isHTML?"insertHTML":"insertText",!1,e.text))}),t.appendChild(o)}),t}_popupTitle(t){let e=document.createElement("div");return e.className="jotter-popup-title",e.textContent=t,e}_makeField(t,e,o,i){let n=document.createElement("label");n.className="jotter-popup-label",n.textContent=e;let r=document.createElement("input");return r.type=o,r.className="jotter-popup-input",r.placeholder=i,t.appendChild(n),t.appendChild(r),r}_makeSubmitBtn(t,e){let o=document.createElement("button");return o.type="button",o.className="jotter-popup-submit",o.textContent=t,o.addEventListener("click",e),o}_esc(t){return String(t).replace(/"/g,"&quot;").replace(/</g,"&lt;").replace(/>/g,"&gt;")}_imageHTML({src:t,alt:e,width:o}){let i=o?`max-width:${o}`:"max-width:100%";return`<img src="${this._esc(t)}" alt="${this._esc(e||"")}" style="${this._esc(i)}">`}_linkHTML({href:t,text:e,title:o,target:i}){let n=`href="${this._esc(t)}"`;return i&&(n+=` target="${this._esc(i)}"`),o&&(n+=` title="${this._esc(o)}"`),`<a ${n}>${this._esc(e||t)}</a>`}_videoHTML(t){return/^[A-Za-z0-9_-]{11}$/.test(t)?`<div class="jotter-video-wrap"><iframe src="https://www.youtube.com/embed/${t}" frameborder="0" allowfullscreen loading="lazy" title="YouTube video"></iframe></div><p><br></p>`:null}_embedHTML(t){return t+"<p><br></p>"}_resolverFor(t){let e=A[t],o=e?this._options[e]:null;return typeof o=="function"?o:null}async _runResolver(t,e){let o=this._resolverContext(t);this.beginExternalUI();let i=null;try{i=await e(o)}catch{i=null}if(this._destroyed)return;let n=i==null||i===!1?null:this._resolvedHTML(t,i,o);this.endExternalUI(),n&&(this._applyEdit(()=>document.execCommand("insertHTML",!1,n)),this._updateToolbarState())}_resolverContext(t){switch(t){case"image":return{src:"",alt:"",width:"",selection:this._selectedText()};case"video":return{url:"",selection:this._selectedText()};case"embed":return{html:"",selection:this._selectedText()};case"link":return this._linkContext();default:return{selection:this._selectedText()}}}_linkContext(){let t=this._anchorInSelection();if(!t){let o=this._selectedText();return{href:"",text:o,title:"",target:"",selection:o,isEdit:!1}}let e=window.getSelection();if(e){let o=document.createRange();o.selectNode(t),e.removeAllRanges(),e.addRange(o)}return{href:t.getAttribute("href")||"",text:t.textContent||"",title:t.getAttribute("title")||"",target:t.getAttribute("target")||"",selection:t.textContent||"",isEdit:!0}}_resolvedHTML(t,e,o){switch(t){case"image":{let i=typeof e=="string"?{src:e}:e,n=String(i.src||i.url||"").trim();return n?this._imageHTML({...i,src:n}):null}case"link":{let i=typeof e=="string"?{href:e}:e,n=String(i.href||i.url||"").trim();if(!n)return null;let r=String(i.text!=null?i.text:o.text||"").trim();return this._linkHTML({...i,href:n,text:r})}case"video":{let i=typeof e=="string"?{url:e}:e,n=i.id?String(i.id).trim():this._ytId(String(i.url||"").trim());return n?this._videoHTML(n):null}case"embed":{let i=String(typeof e=="string"?e:e.html||"").trim();return i?this._embedHTML(i):null}default:return null}}_selectedText(){let t=window.getSelection();return!t||!t.rangeCount?"":this._editor.contains(t.getRangeAt(0).commonAncestorContainer)?t.toString():""}_anchorInSelection(){let t=window.getSelection();if(!t||!t.rangeCount)return null;let e=t.anchorNode;if(!e||!this._editor.contains(e))return null;for(;e&&e!==this._editor;){if(e.nodeName==="A")return e;e=e.parentNode}return null}_buildStatusBar(){let t=document.createElement("div");t.className="jotter-status",this._wordCountEl=document.createElement("span"),this._wordCountEl.className="jotter-status-words",this._charCountEl=document.createElement("span"),this._charCountEl.className="jotter-status-chars";let e=document.createElement("span");return e.className="jotter-status-mode",e.textContent="HTML",t.appendChild(this._wordCountEl),t.appendChild(this._charCountEl),t.appendChild(e),t}_bindEvents(){this._editor.addEventListener("input",()=>{this._editor.querySelectorAll(":scope > div").forEach(t=>{if(t.attributes.length>0)return;let e=document.createElement("p");e.innerHTML=t.innerHTML,t.replaceWith(e)}),Array.from(this._editor.childNodes).forEach(t=>{if(t.nodeType===Node.TEXT_NODE&&t.textContent.trim()!==""){let e=window.getSelection(),o=null;if(e&&e.rangeCount){let n=e.getRangeAt(0);n.startContainer===t&&(o=n.startOffset)}let i=document.createElement("p");if(t.replaceWith(i),i.appendChild(t),o!==null){let n=document.createRange();n.setStart(t,o),n.collapse(!0),e.removeAllRanges(),e.addRange(n)}}}),this._updateStatus(),this._emitChange()}),this._editor.addEventListener("keyup",()=>this._updateToolbarState()),this._editor.addEventListener("mouseup",()=>this._updateToolbarState()),this._editor.addEventListener("focusin",t=>{this._root.classList.add("jotter--focused"),!(this._externalDepth>0)&&(this._isInternalTarget(t.relatedTarget)||(this._emit("focus"),this._options.onFocus&&this._options.onFocus()))}),this._editor.addEventListener("focusout",t=>{this._externalDepth>0||this._isInternalTarget(t.relatedTarget)||setTimeout(()=>{this._destroyed||this._externalDepth>0||this._isInternalTarget(document.activeElement)||this._popupVisible()||(this._root.classList.remove("jotter--focused"),this._emit("blur"),this._options.onBlur&&this._options.onBlur())},0)}),this._editor.addEventListener("keydown",t=>{t.key==="Tab"&&(t.preventDefault(),document.execCommand("insertHTML",!1,"&nbsp;&nbsp;&nbsp;&nbsp;"))}),this._onDocMouseDown=t=>{this._popupVisible()&&!this._popup.contains(t.target)&&!this._toolbarEl.contains(t.target)&&this._hidePopup()},document.addEventListener("mousedown",this._onDocMouseDown),this._onDocKeyDown=t=>{t.key==="Escape"&&this._popupVisible()&&(this._restoreSavedBookmark(),this._hidePopup())},document.addEventListener("keydown",this._onDocKeyDown)}_isInternalTarget(t){return!!t&&(this._root.contains(t)||this._popup.contains(t))}_toggleSourceMode(){this._sourceMode=!this._sourceMode,this._sourceMode?(this._dropBookmarks(),this._source.value=this._prettyHTML(this._richHTML()),this._editor.style.display="none",this._source.style.display="block"):(this._editor.innerHTML=this._sanitize(this._source.value),this._source.style.display="none",this._editor.style.display="",this._updateStatus(),this._emitChange()),this._root.classList.toggle("jotter--source-mode",this._sourceMode);let t=this._toolbarEl.querySelector('[data-custom="toggleSource"]');t&&t.classList.toggle("jotter-btn--active",this._sourceMode)}_prettyHTML(t){let e=0,o=" ",i=new Set(["area","base","br","col","embed","hr","img","input","link","meta","param","source","track","wbr"]),n=new Set(["a","abbr","acronym","b","bdo","big","br","button","cite","code","dfn","em","i","img","input","kbd","label","map","object","output","q","samp","select","small","span","strong","sub","sup","textarea","time","tt","u","var"]);return t.replace(/>\s+</g,"><").replace(/(<[^>]+>)/g,`
1
+ var JotterJS=(()=>{var v=Object.defineProperty;var x=Object.getOwnPropertyDescriptor;var L=Object.getOwnPropertyNames;var T=Object.prototype.hasOwnProperty;var M=(h,e)=>{for(var t in e)v(h,t,{get:e[t],enumerable:!0})},w=(h,e,t,i)=>{if(e&&typeof e=="object"||typeof e=="function")for(let o of L(e))!T.call(h,o)&&o!==t&&v(h,o,{get:()=>e[o],enumerable:!(i=x(e,o))||i.enumerable});return h};var j=h=>w(v({},"__esModule",{value:!0}),h);var D={};M(D,{JotterJS:()=>m,default:()=>z});var f={source:{custom:"toggleSource",label:"Source",title:"Edit HTML Source"},sep:{type:"sep"},blockformat:{type:"blockformat"},fontfamily:{type:"fontfamily"},fontsize:{type:"fontsize"},theme:{type:"theme"},undo:{cmd:"undo",icon:"undo",title:"Undo (Ctrl+Z)"},redo:{cmd:"redo",icon:"redo",title:"Redo (Ctrl+Y)"},bold:{cmd:"bold",icon:"format_bold",title:"Bold (Ctrl+B)"},italic:{cmd:"italic",icon:"format_italic",title:"Italic (Ctrl+I)"},underline:{cmd:"underline",icon:"format_underlined",title:"Underline (Ctrl+U)"},strike:{cmd:"strikeThrough",icon:"strikethrough_s",title:"Strikethrough"},subscript:{cmd:"subscript",icon:"subscript",title:"Subscript"},superscript:{cmd:"superscript",icon:"superscript",title:"Superscript"},code:{custom:"code",icon:"code",title:"Inline Code"},copy:{cmd:"copy",icon:"content_copy",title:"Copy"},cut:{cmd:"cut",icon:"content_cut",title:"Cut"},paste:{cmd:"paste",icon:"content_paste",title:"Paste"},clearFormat:{cmd:"removeFormat",icon:"format_clear",title:"Clear Formatting"},alignLeft:{cmd:"justifyLeft",icon:"format_align_left",title:"Align Left"},alignCenter:{cmd:"justifyCenter",icon:"format_align_center",title:"Align Center"},alignRight:{cmd:"justifyRight",icon:"format_align_right",title:"Align Right"},bullets:{cmd:"insertUnorderedList",icon:"format_list_bulleted",title:"Bullet List"},numbered:{cmd:"insertOrderedList",icon:"format_list_numbered",title:"Numbered List"},link:{type:"popup",id:"link",icon:"insert_link",title:"Insert Link"},unlink:{cmd:"unlink",icon:"link_off",title:"Remove Link"},foreColor:{type:"color",cmd:"foreColor",icon:"format_color_text",title:"Text Color"},hiliteColor:{type:"color",cmd:"hiliteColor",icon:"format_color_fill",title:"Background Color"},image:{type:"popup",id:"image",icon:"image",title:"Insert Image"},video:{type:"popup",id:"video",icon:"smart_display",title:"Insert YouTube Video"},table:{type:"popup",id:"table",icon:"table_chart",title:"Insert Table"},embed:{type:"popup",id:"embed",icon:"html",title:"Insert Embed"},symbol:{type:"popup",id:"symbol",icon:"emoji_symbols",title:"Insert Symbol"},specialChar:{type:"popup",id:"specialchar",icon:"format_shapes",title:"Special Characters"},lorem:{type:"popup",id:"lorem",icon:"history_edu",title:"Insert Lorem Ipsum"}};Object.values(f).forEach(Object.freeze);Object.freeze(f);var n=f,_={minimal:[n.source,n.sep,n.bold,n.italic,n.underline,n.sep,n.link,n.unlink],writing:[n.source,n.sep,n.undo,n.redo,n.sep,n.blockformat,n.sep,n.bold,n.italic,n.underline,n.strike,n.sep,n.bullets,n.numbered,n.sep,n.link,n.unlink,n.sep,n.image],full:[n.source,n.sep,n.undo,n.redo,n.sep,n.copy,n.cut,n.paste,n.sep,n.clearFormat,n.sep,n.blockformat,n.fontfamily,n.fontsize,n.sep,n.bold,n.italic,n.underline,n.strike,n.subscript,n.superscript,n.code,n.sep,n.foreColor,n.hiliteColor,n.sep,n.alignLeft,n.alignCenter,n.alignRight,n.sep,n.bullets,n.numbered,n.sep,n.link,n.unlink,n.sep,n.image,n.video,n.table,n.embed,n.symbol,n.specialChar,n.lorem,n.sep,n.theme]};Object.values(_).forEach(Object.freeze);Object.freeze(_);var N=_.full,R={image:"onRequestImage",link:"onRequestLink",video:"onRequestVideo",embed:"onRequestEmbed"},k=[{label:"Paragraph",tag:"p"},{label:"Heading 1",tag:"h1"},{label:"Heading 2",tag:"h2"},{label:"Heading 3",tag:"h3"},{label:"Heading 4",tag:"h4"},{label:"Pre / Code",tag:"pre"},{label:"Blockquote",tag:"blockquote"}],A=["Arial","Arial Black","Comic Sans MS","Courier New","Georgia","Impact","Lucida Console","Palatino Linotype","Tahoma","Times New Roman","Trebuchet MS","Verdana"],I=[8,9,10,11,12,14,16,18,20,24,28,32,36,48,72],B=["\u2190","\u2192","\u2191","\u2193","\u2194","\u2195","\u21D0","\u21D2","\u21D1","\u21D3","\u21D4","\u2022","\xB7","\u25E6","\u25CB","\u25CF","\u25A1","\u25A0","\u25C6","\u25C7","\u25B2","\u25BC","\u2605","\u2606","\u2660","\u2663","\u2665","\u2666","\u2713","\u2717","\u2715","\u2718","\u2248","\u2260","\u2261","\u2264","\u2265","\xF7","\xD7","\xB1","\u221E","\u221A","\u2211","\u220F","\u222B","\u2202","\u2206","\u2207","\u03C0","\u03A9","\u03BC","\u03B1","\u03B2","\u03B3","\xA9","\xAE","\u2122","\xA7","\xB6","\u2020","\u2021","\xB0","\u2032","\u2033","\u2030","\u201C","\u201D","\u2018","\u2019","\xAB","\xBB","\u2039","\u203A","\u2014","\u2013","\u2026","\xBF","\xA1","\u20AC","\xA3","\xA5","\xA2","\u20B9","\u20BD","\u20BF"],H=["\xC0","\xC1","\xC2","\xC3","\xC4","\xC5","\xC6","\xC7","\xC8","\xC9","\xCA","\xCB","\xCC","\xCD","\xCE","\xCF","\xD0","\xD1","\xD2","\xD3","\xD4","\xD5","\xD6","\xD8","\xD9","\xDA","\xDB","\xDC","\xDD","\xDE","\xDF","\xE0","\xE1","\xE2","\xE3","\xE4","\xE5","\xE6","\xE7","\xE8","\xE9","\xEA","\xEB","\xEC","\xED","\xEE","\xEF","\xF0","\xF1","\xF2","\xF3","\xF4","\xF5","\xF6","\xF8","\xF9","\xFA","\xFB","\xFC","\xFD","\xFE","\xFF","\u0152","\u0153","\u0160","\u0161","\u0178","\u017D","\u017E"],E=[{id:"default",label:"Default"},{id:"warm",label:"Warm"},{id:"ink",label:"Ink / Navy"},{id:"forest",label:"Forest"}],F=[{label:"Short \u2014 1 sentence",text:"Lorem ipsum dolor sit amet, consectetur adipiscing elit."},{label:"Medium \u2014 1 paragraph",text:"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat."},{label:"Long \u2014 3 paragraphs",isHTML:!0,text:"<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris.</p><p>Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p><p>Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo.</p>"}],m=class{constructor(e,t={}){if(this._target=typeof e=="string"?document.querySelector(e):e,!this._target)throw new Error("[JotterJS] Target element not found.");this._options=Object.assign({placeholder:"Start typing\u2026",height:"320px",theme:"default",onChange:null,onFocus:null,onBlur:null,onRequestImage:null,onRequestLink:null,onRequestVideo:null,onRequestEmbed:null},t),this._listeners={},this._bookmarks=new Map,this._bmSeq=0,this._savedBookmark=null,this._externalBookmark=null,this._externalDepth=0,this._changeCount=0,this._destroyed=!1,this._lastForeColor="#e8e4d8",this._lastHiliteColor="#c8a96e",this._selectedMedia=null,this._resizeState=null,this._onResizeMove=this._onResizeMove.bind(this),this._onResizeEnd=this._onResizeEnd.bind(this),this._init()}_init(){let e=this._target.innerHTML||"";this._target.innerHTML="",this._target.classList.add("jotter-host"),this._root=document.createElement("div"),this._root.className="htmled",this._toolbar=this._buildToolbar(),this._editorWrap=document.createElement("div"),this._editorWrap.className="jotter-editor-wrap",this._editor=document.createElement("div"),this._editor.className="jotter-editor",this._editor.contentEditable="true",this._editor.setAttribute("data-placeholder",this._options.placeholder),this._editor.style.minHeight=this._options.height,this._editor.innerHTML=this._sanitize(e),this._editor.spellcheck=!0,document.execCommand("defaultParagraphSeparator",!1,"p");try{document.execCommand("enableObjectResizing",!1,!1)}catch{}try{document.execCommand("enableInlineTableEditing",!1,!1)}catch{}this._ensureMediaShields(),this._source=document.createElement("textarea"),this._source.className="jotter-source",this._source.setAttribute("aria-label","HTML source"),this._source.setAttribute("spellcheck","false"),this._source.style.minHeight=this._options.height,this._sourceMode=!1,this._statusBar=this._buildStatusBar(),this._mediaFrame=this._buildMediaFrame(),this._editorWrap.appendChild(this._editor),this._editorWrap.appendChild(this._source),this._editorWrap.appendChild(this._mediaFrame),this._root.appendChild(this._toolbar),this._root.appendChild(this._editorWrap),this._root.appendChild(this._statusBar),this._target.appendChild(this._root),this._popup=this._buildPopupContainer(),document.body.appendChild(this._popup),this._bindEvents(),this._updateToolbarState(),this._updateStatus(),this.setTheme(this._options.theme)}_buildToolbar(){let e=document.createElement("div");return e.className="jotter-toolbar",this._toolbarEl=e,(this._options.toolbar||N).forEach(t=>{let i=this._buildAction(t);i&&e.appendChild(i)}),e}_buildAction(e){if(typeof e.onClick=="function")return this._buildBtn(e);switch(e.type){case"sep":return this._makeSep();case"blockformat":return this._buildBlockFormatSelect();case"fontfamily":return this._buildFontFamilySelect();case"fontsize":return this._buildFontSizeSelect();case"color":return this._buildColorBtn(e);case"popup":return this._buildPopupBtn(e);case"theme":return this._buildThemeSelect();default:return this._buildBtn(e)}}_makeSep(){let e=document.createElement("span");return e.className="jotter-sep",e}_bindActivation(e,t){e.addEventListener("mousedown",i=>{i.preventDefault(),t(!1)}),e.addEventListener("keydown",i=>{i.key!=="Enter"&&i.key!==" "&&i.key!=="Spacebar"||i.repeat||(i.preventDefault(),t(!0))})}_returnFocus(e,t){t&&this._isInternalTarget(document.activeElement)&&e.focus()}_buildBtn(e){let t=document.createElement("button");if(t.type="button",t.className="jotter-btn",e.cmd&&(t.dataset.cmd=e.cmd),e.custom&&(t.dataset.custom=e.custom),t.title=e.title,t.setAttribute("aria-label",e.title),e.label)t.classList.add("jotter-btn--text"),t.appendChild(document.createTextNode(e.label));else{let i=document.createElement("span");i.className="material-icons",i.textContent=e.icon,t.appendChild(i)}return this._bindActivation(t,i=>{this._editor.focus(),this._applyEdit(()=>{if(e.onClick)e.onClick(this);else if(e.custom==="toggleSource")this._toggleSourceMode();else if(e.custom==="code")this._toggleInlineCode();else if(e.cmd==="copy")document.execCommand("copy");else if(e.cmd==="cut")document.execCommand("cut");else if(e.cmd==="paste")this._pasteFromClipboard();else if(e.prompt){let o=window.prompt(e.prompt);o&&document.execCommand(e.cmd,!1,o)}else document.execCommand(e.cmd,!1,null)}),this._updateToolbarState(),this._returnFocus(t,i)}),t}_bindSelectCaret(e){let t={viaKeyboard:!1};return e.addEventListener("mousedown",()=>{t.viaKeyboard=!1,this._saveBookmark()}),e.addEventListener("keydown",i=>{i.key==="Tab"||i.key==="Escape"||(t.viaKeyboard=!0,this._savedBookmark==null&&this._saveBookmark())}),t}_buildBlockFormatSelect(){let e=document.createElement("select");e.className="jotter-select",e.title="Block format",e.dataset.id="blockformat",k.forEach(({label:i,tag:o})=>{let s=document.createElement("option");s.value=o,s.textContent=i,e.appendChild(s)});let t=this._bindSelectCaret(e);return e.addEventListener("change",()=>{this._restoreSavedBookmark(),this._applyEdit(()=>document.execCommand("formatBlock",!1,e.value)),this._returnFocus(e,t.viaKeyboard)}),e}_buildFontFamilySelect(){let e=document.createElement("select");e.className="jotter-select jotter-select--font",e.title="Font family",e.dataset.id="fontfamily";let t=document.createElement("option");t.value="",t.textContent="Font",e.appendChild(t),A.forEach(o=>{let s=document.createElement("option");s.value=o,s.textContent=o,s.style.fontFamily=o,e.appendChild(s)});let i=this._bindSelectCaret(e);return e.addEventListener("change",()=>{e.value&&(this._restoreSavedBookmark(),this._applyEdit(()=>document.execCommand("fontName",!1,e.value)),this._returnFocus(e,i.viaKeyboard))}),e}_buildFontSizeSelect(){let e=document.createElement("select");e.className="jotter-select jotter-select--size",e.title="Font size",e.dataset.id="fontsize";let t=document.createElement("option");t.value="",t.textContent="Size",e.appendChild(t),I.forEach(o=>{let s=document.createElement("option");s.value=o,s.textContent=`${o}px`,e.appendChild(s)});let i=this._bindSelectCaret(e);return e.addEventListener("change",()=>{e.value&&(this._restoreSavedBookmark(),this._applyEdit(()=>this._applyFontSize(e.value)),this._returnFocus(e,i.viaKeyboard))}),e}_buildThemeSelect(){let e=document.createElement("select");return e.className="jotter-select jotter-select--theme",e.title="Editor theme",e.dataset.id="theme",E.forEach(({id:t,label:i})=>{let o=document.createElement("option");o.value=t,o.textContent=i,e.appendChild(o)}),e.value=this._options.theme,e.addEventListener("change",()=>this.setTheme(e.value)),this._themeSelect=e,e}_buildColorBtn(e){let t=document.createElement("span");t.className="jotter-color-wrap";let i=document.createElement("button");i.type="button",i.className="jotter-btn jotter-color-btn",i.dataset.cmd=e.cmd,i.title=e.title,i.setAttribute("aria-label",e.title);let o=document.createElement("span");o.className="material-icons",o.textContent=e.icon,i.appendChild(o);let s=document.createElement("span");s.className="jotter-color-swatch";let r=e.cmd==="foreColor"?this._lastForeColor:this._lastHiliteColor;s.style.background=r,i.appendChild(s);let a=document.createElement("input");a.type="color",a.className="jotter-color-input",a.value=r,a.tabIndex=-1;let u=!1;return a.addEventListener("change",()=>{let p=a.value;s.style.background=p,e.cmd==="foreColor"?this._lastForeColor=p:this._lastHiliteColor=p,this._restoreSavedBookmark(),this._applyEdit(()=>document.execCommand(e.cmd,!1,p)),this._returnFocus(i,u)}),this._bindActivation(i,p=>{u=p,this._saveBookmark(),a.click()}),t.appendChild(i),t.appendChild(a),t}_buildPopupBtn(e){let t=document.createElement("button");t.type="button",t.className="jotter-btn",t.title=e.title,t.setAttribute("aria-label",e.title);let i=document.createElement("span");return i.className="material-icons",i.textContent=e.icon,t.appendChild(i),this._bindActivation(t,o=>{let s=this._resolverFor(e.id);if(s){this._hidePopup(),this._runResolver(e.id,s);return}if(this._saveBookmark(),this._popupVisible()&&this._popup.dataset.popupId===e.id){this._hidePopup();return}this._showPopup(t,this._buildPopupContent(e.id),e.id),o&&this._focusPopup()}),t}_focusPopup(){let e=this._popup.querySelector('input, textarea, select, button, [tabindex]:not([tabindex="-1"])');e&&e.focus()}_buildPopupContainer(){let e=document.createElement("div");return e.className="jotter-popup",e.setAttribute("role","dialog"),e}_showPopup(e,t,i){this._popup.innerHTML="",this._popup.appendChild(t),this._popup.dataset.popupId=i,this._popup.classList.add("jotter-popup--visible");let o=e.getBoundingClientRect();this._popup.style.top=o.bottom+6+"px",this._popup.style.left=o.left+"px",this._popup.style.right="auto",requestAnimationFrame(()=>{let s=this._popup.getBoundingClientRect();s.right>window.innerWidth-8&&(this._popup.style.left=Math.max(8,o.left-(s.right-window.innerWidth+8))+"px")})}_popupVisible(){return this._popup.classList.contains("jotter-popup--visible")}_hidePopup(){this._popup.classList.remove("jotter-popup--visible"),this._popup.dataset.popupId="",this._releaseSavedBookmark()}_buildPopupContent(e){switch(e){case"link":return this._popupLink();case"table":return this._popupTable();case"image":return this._popupImage();case"video":return this._popupVideo();case"embed":return this._popupEmbed();case"symbol":return this._popupSymbol();case"specialchar":return this._popupSpecialChar();case"lorem":return this._popupLorem();default:{let t=document.createElement("div");return t.className="jotter-popup-inner",t.textContent="Unknown: "+e,t}}}_popupTable(){let e=document.createElement("div");e.className="jotter-popup-inner";let t=this._popupTitle("Insert Table");e.appendChild(t);let i=10,o=8,s=document.createElement("div");s.className="jotter-table-grid",s.style.gridTemplateColumns=`repeat(${i}, 1fr)`,s.setAttribute("role","grid"),s.setAttribute("aria-label","Table size");let r=document.createElement("div");r.className="jotter-popup-hint",r.textContent="Hover or arrow to select size";let a=[],u=(c,l)=>{r.textContent=`${c+1} \xD7 ${l+1} table`,a.forEach(d=>{d.classList.toggle("jotter-table-cell--active",+d.dataset.r<=c&&+d.dataset.c<=l)})};for(let c=0;c<o;c++)for(let l=0;l<i;l++){let d=document.createElement("span");d.className="jotter-table-cell",d.dataset.r=c,d.dataset.c=l,d.setAttribute("role","gridcell"),d.setAttribute("aria-label",`${c+1} by ${l+1} table`),d.tabIndex=c===0&&l===0?0:-1,d.addEventListener("mouseenter",()=>u(c,l)),d.addEventListener("focus",()=>u(c,l)),d.addEventListener("click",()=>this._insertTable(c+1,l+1)),a.push(d),s.appendChild(d)}let p={ArrowRight:[0,1],ArrowLeft:[0,-1],ArrowDown:[1,0],ArrowUp:[-1,0]};return s.addEventListener("keydown",c=>{let l=a.indexOf(document.activeElement)===-1?null:document.activeElement;if(!l)return;let d=+l.dataset.r,C=+l.dataset.c;if(c.key==="Enter"||c.key===" "||c.key==="Spacebar"){c.preventDefault(),this._insertTable(d+1,C+1);return}let b=p[c.key];if(!b)return;c.preventDefault();let S=Math.min(o-1,Math.max(0,d+b[0])),y=Math.min(i-1,Math.max(0,C+b[1])),g=a[S*i+y];g!==l&&(l.tabIndex=-1,g.tabIndex=0,g.focus())}),e.appendChild(s),e.appendChild(r),e}_commitPopup(e){this._restoreSavedBookmark(),this._hidePopup(),this._applyEdit(e)}_insertTable(e,t){let i="<table><tbody>";for(let o=0;o<e;o++){i+="<tr>";for(let s=0;s<t;s++)i+=o===0?"<th><br></th>":"<td><br></td>";i+="</tr>"}i+="</tbody></table><p><br></p>",this._commitPopup(()=>document.execCommand("insertHTML",!1,i))}_popupLink(){let e=document.createElement("div");e.className="jotter-popup-inner jotter-popup-form",e.appendChild(this._popupTitle("Insert Link"));let t=this._anchorInSelection(),i=this._selectedText(),o=this._makeField(e,"URL","url","https://"),s=this._makeField(e,"Link text (leave blank to keep selection)","text",""),r=this._makeField(e,"Title / tooltip","text",""),a=document.createElement("label");a.className="jotter-popup-label",a.textContent="Open in";let u=document.createElement("select");return u.className="jotter-popup-select",[["(same window)",""],["New tab (_blank)","_blank"],["Parent frame (_parent)","_parent"],["Top frame (_top)","_top"]].forEach(([p,c])=>{let l=document.createElement("option");l.value=c,l.textContent=p,u.appendChild(l)}),e.appendChild(a),e.appendChild(u),t?(o.value=t.getAttribute("href")||"",s.value=t.textContent||"",r.value=t.getAttribute("title")||"",u.value=t.getAttribute("target")||""):i&&(s.value=i),e.appendChild(this._makeSubmitBtn(t?"Update Link":"Insert Link",()=>{let p=o.value.trim();if(!p)return;let c=s.value.trim()||i||p,l=r.value.trim(),d=u.value;this._commitPopup(()=>{t?(t.href=p,d?t.target=d:t.removeAttribute("target"),l?t.title=l:t.removeAttribute("title"),t.textContent=c):document.execCommand("insertHTML",!1,this._linkHTML({href:p,text:c,title:l,target:d}))})})),e}_popupImage(){let e=document.createElement("div");e.className="jotter-popup-inner jotter-popup-form",e.appendChild(this._popupTitle("Insert Image"));let t=this._makeField(e,"Image URL","text","https://example.com/image.jpg"),i=this._makeField(e,"Alt text","text","Descriptive text"),o=this._makeField(e,"Width (e.g. 400px or 50%)","text","");return e.appendChild(this._makeSubmitBtn("Insert Image",()=>{let s=t.value.trim();if(!s)return;let r=this._imageHTML({src:s,alt:i.value.trim(),width:o.value.trim()});this._commitPopup(()=>document.execCommand("insertHTML",!1,r))})),e}_popupVideo(){let e=document.createElement("div");e.className="jotter-popup-inner jotter-popup-form",e.appendChild(this._popupTitle("Insert YouTube Video"));let t=this._makeField(e,"YouTube URL","text","https://www.youtube.com/watch?v=...");return e.appendChild(this._makeSubmitBtn("Embed Video",()=>{let i=this._ytId(t.value.trim());if(!i){t.classList.add("jotter-input--error");return}t.classList.remove("jotter-input--error"),this._commitPopup(()=>document.execCommand("insertHTML",!1,this._videoHTML(i)))})),e}_ytId(e){for(let t of[/[?&]v=([A-Za-z0-9_-]{11})/,/youtu\.be\/([A-Za-z0-9_-]{11})/,/embed\/([A-Za-z0-9_-]{11})/]){let i=e.match(t);if(i)return i[1]}return null}_popupEmbed(){let e=document.createElement("div");e.className="jotter-popup-inner jotter-popup-form",e.appendChild(this._popupTitle("Insert Embed"));let t=document.createElement("label");t.className="jotter-popup-label",t.textContent="Paste HTML / embed code";let i=document.createElement("textarea");return i.className="jotter-popup-textarea",i.placeholder='<iframe src="..." ...></iframe>',i.rows=4,e.appendChild(t),e.appendChild(i),e.appendChild(this._makeSubmitBtn("Insert",()=>{let o=i.value.trim();o&&this._commitPopup(()=>document.execCommand("insertHTML",!1,this._embedHTML(o)))})),e}_popupSymbol(){let e=document.createElement("div");return e.className="jotter-popup-inner",e.appendChild(this._popupTitle("Insert Symbol")),e.appendChild(this._charGrid(B)),e}_popupSpecialChar(){let e=document.createElement("div");return e.className="jotter-popup-inner",e.appendChild(this._popupTitle("Special Characters")),e.appendChild(this._charGrid(H)),e}_charGrid(e){let t=document.createElement("div");return t.className="jotter-char-grid",e.forEach(i=>{let o=document.createElement("button");o.type="button",o.className="jotter-char-btn",o.textContent=i,o.title=`U+${i.codePointAt(0).toString(16).toUpperCase().padStart(4,"0")}`,this._bindActivation(o,()=>{this._commitPopup(()=>document.execCommand("insertText",!1,i))}),t.appendChild(o)}),t}_popupLorem(){let e=document.createElement("div");return e.className="jotter-popup-inner",e.appendChild(this._popupTitle("Insert Lorem Ipsum")),F.forEach(t=>{let i=document.createElement("button");i.type="button",i.className="jotter-lorem-btn",i.textContent=t.label,this._bindActivation(i,()=>{this._commitPopup(()=>document.execCommand(t.isHTML?"insertHTML":"insertText",!1,t.text))}),e.appendChild(i)}),e}_popupTitle(e){let t=document.createElement("div");return t.className="jotter-popup-title",t.textContent=e,t}_makeField(e,t,i,o){let s=document.createElement("label");s.className="jotter-popup-label",s.textContent=t;let r=document.createElement("input");return r.type=i,r.className="jotter-popup-input",r.placeholder=o,e.appendChild(s),e.appendChild(r),r}_makeSubmitBtn(e,t){let i=document.createElement("button");return i.type="button",i.className="jotter-popup-submit",i.textContent=e,i.addEventListener("click",t),i}_esc(e){return String(e).replace(/"/g,"&quot;").replace(/</g,"&lt;").replace(/>/g,"&gt;")}_imageHTML({src:e,alt:t,width:i}){let o=i?`max-width:${i}`:"max-width:100%";return`<img src="${this._esc(e)}" alt="${this._esc(t||"")}" style="${this._esc(o)}">`}_linkHTML({href:e,text:t,title:i,target:o}){let s=`href="${this._esc(e)}"`;return o&&(s+=` target="${this._esc(o)}"`),i&&(s+=` title="${this._esc(i)}"`),`<a ${s}>${this._esc(t||e)}</a>`}_videoHTML(e){return/^[A-Za-z0-9_-]{11}$/.test(e)?`<div class="jotter-video-wrap"><iframe src="https://www.youtube.com/embed/${e}" frameborder="0" allowfullscreen loading="lazy" title="YouTube video"></iframe></div><p><br></p>`:null}_embedHTML(e){return`<div class="jotter-embed-wrap">${e}</div><p><br></p>`}_resolverFor(e){let t=R[e],i=t?this._options[t]:null;return typeof i=="function"?i:null}async _runResolver(e,t){let i=this._resolverContext(e);this.beginExternalUI();let o=null;try{o=await t(i)}catch{o=null}if(this._destroyed)return;let s=o==null||o===!1?null:this._resolvedHTML(e,o,i);this.endExternalUI(),s&&(this._applyEdit(()=>document.execCommand("insertHTML",!1,s)),this._updateToolbarState())}_resolverContext(e){switch(e){case"image":return{src:"",alt:"",width:"",selection:this._selectedText()};case"video":return{url:"",selection:this._selectedText()};case"embed":return{html:"",selection:this._selectedText()};case"link":return this._linkContext();default:return{selection:this._selectedText()}}}_linkContext(){let e=this._anchorInSelection();if(!e){let i=this._selectedText();return{href:"",text:i,title:"",target:"",selection:i,isEdit:!1}}let t=window.getSelection();if(t){let i=document.createRange();i.selectNode(e),t.removeAllRanges(),t.addRange(i)}return{href:e.getAttribute("href")||"",text:e.textContent||"",title:e.getAttribute("title")||"",target:e.getAttribute("target")||"",selection:e.textContent||"",isEdit:!0}}_resolvedHTML(e,t,i){switch(e){case"image":{let o=typeof t=="string"?{src:t}:t,s=String(o.src||o.url||"").trim();return s?this._imageHTML({...o,src:s}):null}case"link":{let o=typeof t=="string"?{href:t}:t,s=String(o.href||o.url||"").trim();if(!s)return null;let r=String(o.text!=null?o.text:i.text||"").trim();return this._linkHTML({...o,href:s,text:r})}case"video":{let o=typeof t=="string"?{url:t}:t,s=o.id?String(o.id).trim():this._ytId(String(o.url||"").trim());return s?this._videoHTML(s):null}case"embed":{let o=String(typeof t=="string"?t:t.html||"").trim();return o?this._embedHTML(o):null}default:return null}}_selectedText(){let e=window.getSelection();return!e||!e.rangeCount?"":this._editor.contains(e.getRangeAt(0).commonAncestorContainer)?e.toString():""}_anchorInSelection(){let e=window.getSelection();if(!e||!e.rangeCount)return null;let t=e.anchorNode;if(!t||!this._editor.contains(t))return null;for(;t&&t!==this._editor;){if(t.nodeName==="A")return t;t=t.parentNode}return null}_buildStatusBar(){let e=document.createElement("div");e.className="jotter-status",this._wordCountEl=document.createElement("span"),this._wordCountEl.className="jotter-status-words",this._charCountEl=document.createElement("span"),this._charCountEl.className="jotter-status-chars";let t=document.createElement("span");return t.className="jotter-status-mode",t.textContent="HTML",e.appendChild(this._wordCountEl),e.appendChild(this._charCountEl),e.appendChild(t),e}_buildMediaFrame(){let e=document.createElement("div");return e.className="jotter-media-frame",["nw","ne","sw","se","w","e"].forEach(t=>{let i=document.createElement("div");i.className="jotter-resize-handle jotter-resize-handle--"+t,i.dataset.handle=t,i.tabIndex=-1,e.appendChild(i)}),e.addEventListener("mousedown",t=>{let i=t.target.closest(".jotter-resize-handle");!i||!this._selectedMedia||(t.preventDefault(),this._beginResize(i.dataset.handle,t))}),e}_ensureMediaShields(){this._editor.querySelectorAll(".jotter-video-wrap, .jotter-embed-wrap").forEach(e=>{if(e.querySelector(":scope > .jotter-media-shield"))return;let t=document.createElement("div");t.className="jotter-media-shield",e.appendChild(t)})}_mediaElementFromTarget(e){if(!this._editor.contains(e))return null;let t=e.closest("img");if(t&&this._editor.contains(t))return t;let i=e.closest(".jotter-video-wrap, .jotter-embed-wrap");return i&&this._editor.contains(i)?i:null}_selectMedia(e){if(this._selectedMedia===e)return;this._deselectMedia(),this._selectedMedia=e,this._positionMediaFrame(),this._mediaFrame.classList.add("jotter-media-frame--visible"),this._editor.focus({preventScroll:!0});let t=document.createRange();t.setStartBefore(e),t.collapse(!0);let i=window.getSelection();i.removeAllRanges(),i.addRange(t),this._updateToolbarState()}_deselectMedia(){this._resizeState&&this._abortResize(),this._selectedMedia&&(this._selectedMedia=null,this._mediaFrame.classList.remove("jotter-media-frame--visible"))}_positionMediaFrame(){let e=this._selectedMedia;if(!e)return;let t=this._editorWrap.getBoundingClientRect(),i=e.getBoundingClientRect();this._mediaFrame.style.top=i.top-t.top+this._editorWrap.scrollTop+"px",this._mediaFrame.style.left=i.left-t.left+this._editorWrap.scrollLeft+"px",this._mediaFrame.style.width=i.width+"px",this._mediaFrame.style.height=i.height+"px"}_deleteSelectedMedia(){let e=this._selectedMedia;if(!e)return;this._deselectMedia();let t=document.createRange();t.selectNode(e);let i=window.getSelection();i.removeAllRanges(),i.addRange(t),this._applyEdit(()=>document.execCommand("delete",!1,null)),this._updateToolbarState()}_beginResize(e,t){let i=this._selectedMedia,o=i.getBoundingClientRect(),s=e.includes("w")?-1:1;this._resizeState={el:i,sign:s,startX:t.clientX,startWidth:o.width,startInlineWidth:i.style.width,before:this._richHTML()},document.addEventListener("mousemove",this._onResizeMove),document.addEventListener("mouseup",this._onResizeEnd,{once:!0})}_onResizeMove(e){let t=this._resizeState;if(!t)return;let i=(e.clientX-t.startX)*t.sign,o=40,s=Math.max(o,this._editor.clientWidth),r=Math.max(o,Math.min(s,Math.round(t.startWidth+i)));t.el.style.width=r+"px",t.el.style.removeProperty("max-width"),this._positionMediaFrame()}_onResizeEnd(){document.removeEventListener("mousemove",this._onResizeMove);let e=this._resizeState;this._resizeState=null,e&&(this._updateStatus(),this._richHTML()!==e.before&&this._emitChange())}_abortResize(){let e=this._resizeState;e&&(document.removeEventListener("mousemove",this._onResizeMove),document.removeEventListener("mouseup",this._onResizeEnd),e.el.style.width=e.startInlineWidth,this._resizeState=null,this._positionMediaFrame())}_bindEvents(){this._editor.addEventListener("input",()=>{this._editor.querySelectorAll(":scope > div").forEach(e=>{if(e.attributes.length>0)return;let t=document.createElement("p");t.innerHTML=e.innerHTML,e.replaceWith(t)}),Array.from(this._editor.childNodes).forEach(e=>{if(e.nodeType===Node.TEXT_NODE&&e.textContent.trim()!==""){let t=window.getSelection(),i=null;if(t&&t.rangeCount){let s=t.getRangeAt(0);s.startContainer===e&&(i=s.startOffset)}let o=document.createElement("p");if(e.replaceWith(o),o.appendChild(e),i!==null){let s=document.createRange();s.setStart(e,i),s.collapse(!0),t.removeAllRanges(),t.addRange(s)}}}),this._ensureMediaShields(),this._selectedMedia&&this._positionMediaFrame(),this._updateStatus(),this._emitChange()}),this._editor.addEventListener("keyup",()=>this._updateToolbarState()),this._editor.addEventListener("mouseup",()=>this._updateToolbarState()),this._editor.addEventListener("mousedown",e=>{let t=this._mediaElementFromTarget(e.target);t&&(e.preventDefault(),this._selectMedia(t))}),this._onWindowResize=()=>{this._selectedMedia&&this._positionMediaFrame()},window.addEventListener("resize",this._onWindowResize),this._editor.addEventListener("focusin",e=>{this._root.classList.add("jotter--focused"),!(this._externalDepth>0)&&(this._isInternalTarget(e.relatedTarget)||(this._emit("focus"),this._options.onFocus&&this._options.onFocus()))}),this._editor.addEventListener("focusout",e=>{this._deselectMedia(),!(this._externalDepth>0)&&(this._isInternalTarget(e.relatedTarget)||setTimeout(()=>{this._destroyed||this._externalDepth>0||this._isInternalTarget(document.activeElement)||this._popupVisible()||(this._root.classList.remove("jotter--focused"),this._emit("blur"),this._options.onBlur&&this._options.onBlur())},0))}),this._editor.addEventListener("keydown",e=>{if((e.key==="Backspace"||e.key==="Delete")&&this._selectedMedia){e.preventDefault(),this._deleteSelectedMedia();return}e.key==="Tab"&&(e.preventDefault(),document.execCommand("insertHTML",!1,"&nbsp;&nbsp;&nbsp;&nbsp;"))}),this._onDocMouseDown=e=>{this._popupVisible()&&!this._popup.contains(e.target)&&!this._toolbarEl.contains(e.target)&&this._hidePopup(),this._selectedMedia&&!this._mediaFrame.contains(e.target)&&e.target!==this._selectedMedia&&!this._selectedMedia.contains(e.target)&&this._deselectMedia()},document.addEventListener("mousedown",this._onDocMouseDown),this._onDocKeyDown=e=>{if(e.key==="Escape"){if(this._resizeState){this._abortResize();return}if(this._selectedMedia){this._deselectMedia();return}this._popupVisible()&&(this._restoreSavedBookmark(),this._hidePopup())}},document.addEventListener("keydown",this._onDocKeyDown)}_isInternalTarget(e){return!!e&&(this._root.contains(e)||this._popup.contains(e))}_toggleSourceMode(){this._deselectMedia(),this._sourceMode=!this._sourceMode,this._sourceMode?(this._dropBookmarks(),this._source.value=this._prettyHTML(this._richHTML()),this._editor.style.display="none",this._source.style.display="block"):(this._editor.innerHTML=this._sanitize(this._source.value),this._ensureMediaShields(),this._source.style.display="none",this._editor.style.display="",this._updateStatus(),this._emitChange()),this._root.classList.toggle("jotter--source-mode",this._sourceMode);let e=this._toolbarEl.querySelector('[data-custom="toggleSource"]');e&&e.classList.toggle("jotter-btn--active",this._sourceMode)}_prettyHTML(e){let t=0,i=" ",o=new Set(["area","base","br","col","embed","hr","img","input","link","meta","param","source","track","wbr"]),s=new Set(["a","abbr","acronym","b","bdo","big","br","button","cite","code","dfn","em","i","img","input","kbd","label","map","object","output","q","samp","select","small","span","strong","sub","sup","textarea","time","tt","u","var"]);return e.replace(/>\s+</g,"><").replace(/(<[^>]+>)/g,`
2
2
  $1
3
3
  `).split(`
4
- `).map(r=>r.trim()).filter(r=>r.length>0).map(r=>{let a=r.match(/^<\/(\w+)/),u=r.match(/^<(\w+)/),p=r.endsWith("/>"),c=u?u[1].toLowerCase():null,l=a?a[1].toLowerCase():null;l&&!n.has(l)&&(e=Math.max(0,e-1));let d=o.repeat(e)+r;return c&&!p&&!i.has(c)&&!l&&!n.has(c)&&e++,d}).join(`
5
- `)}_sanitize(t){let e=new DOMParser().parseFromString(t,"text/html");return e.querySelectorAll("script").forEach(o=>o.remove()),e.querySelectorAll("[data-jotter-bookmark]").forEach(o=>o.remove()),e.querySelectorAll("*").forEach(o=>{Array.from(o.attributes).forEach(i=>{(i.name.startsWith("on")||["href","src","action","formaction","data"].includes(i.name)&&/^\s*javascript:/i.test(i.value))&&o.removeAttribute(i.name)})}),e.body.innerHTML}_toggleInlineCode(){let t=window.getSelection();if(!t||t.rangeCount===0)return;let e=t.getRangeAt(0),o=e.commonAncestorContainer;o.nodeType===3&&(o=o.parentNode);let i=o.closest?o.closest("code"):null;if(i){let n=i.parentNode;for(;i.firstChild;)n.insertBefore(i.firstChild,i);n.removeChild(i)}else if(e.collapsed){let n=document.createElement("code");n.innerHTML="&#8203;",e.insertNode(n);let r=document.createRange();r.setStart(n,0),r.setEnd(n,n.childNodes.length),t.removeAllRanges(),t.addRange(r)}else{let n=document.createElement("code");try{e.surroundContents(n)}catch{let a=e.extractContents();n.appendChild(a),e.insertNode(n)}}}_applyFontSize(t){let e=window.getSelection();if(!e||e.rangeCount===0)return;let o=e.getRangeAt(0);if(o.collapsed)return;let i=document.createElement("span");i.style.fontSize=t+"px";try{o.surroundContents(i)}catch{let r=o.extractContents();i.appendChild(r),o.insertNode(i)}}async _pasteFromClipboard(){try{if(navigator.clipboard&&navigator.clipboard.readText){let t=await navigator.clipboard.readText();document.execCommand("insertText",!1,t)}else document.execCommand("paste")}catch{}}_updateToolbarState(){this._toolbarEl.querySelectorAll(".jotter-btn[data-cmd]").forEach(e=>{try{e.classList.toggle("jotter-btn--active",document.queryCommandState(e.dataset.cmd))}catch{}});let t=this._toolbarEl.querySelector('[data-id="blockformat"]');if(t){let e=document.queryCommandValue("formatBlock").toLowerCase().replace(/[<>]/g,""),o=v.find(i=>i.tag===e);o&&(t.value=o.tag)}}_updateStatus(){let t=this._editor.innerText||"",e=t.trim()===""?0:t.trim().split(/\s+/).length,o=t.replace(/\n/g,"").length;this._wordCountEl.textContent=`${e} word${e!==1?"s":""}`,this._charCountEl.textContent=`${o} char${o!==1?"s":""}`}_richHTML(){if(this._bookmarks.size===0)return this._editor.innerHTML;let t=this._editor.cloneNode(!0);return t.querySelectorAll("[data-jotter-bookmark]").forEach(e=>e.remove()),t.innerHTML}_makeMarker(t){let e=document.createElement("span");return e.className="jotter-bookmark",e.dataset.jotterBookmark=t,e}_takeRange(t){let e=t!=null?this._bookmarks.get(t):null;if(!e)return null;if(this._bookmarks.delete(t),e.atStart){let a=document.createRange();return a.setStart(this._editor,0),a.collapse(!0),a}let{start:o,end:i}=e,n=this._editor.contains(o)&&(!i||this._editor.contains(i)),r=null;return n&&(r=document.createRange(),r.setStartAfter(o),i?r.setEndBefore(i):r.collapse(!0)),o.parentNode&&o.remove(),i&&i.parentNode&&i.remove(),r}_saveBookmark(){this._releaseSavedBookmark(),this._savedBookmark=this.saveSelection()}_restoreSavedBookmark(){this.restoreSelection(this._savedBookmark),this._savedBookmark=null,this._editor.focus()}_releaseSavedBookmark(){this.releaseSelection(this._savedBookmark),this._savedBookmark=null}_dropBookmarks(){Array.from(this._bookmarks.keys()).forEach(t=>this.releaseSelection(t)),this._savedBookmark=null}_emit(t,e){(this._listeners[t]||[]).forEach(o=>o(e))}_emitChange(){let t=this.getHTML();this._changeCount++,this._emit("change",t),this._options.onChange&&this._options.onChange(t)}_applyEdit(t){let e=this._changeCount,o=this._richHTML();t(),this._updateStatus(),this._changeCount===e&&this._richHTML()!==o&&this._emitChange()}getHTML(){return this._sourceMode?this._source.value:this._richHTML()}getText(){return this._editor.innerText}isSourceMode(){return this._sourceMode}toggleSource(){return this._toggleSourceMode(),this}clear(){return this._dropBookmarks(),this._editor.innerHTML="",this._updateStatus(),this}focus(){return this._editor.focus(),this}insertHTML(t,e={}){return e.at!=null&&this.restoreSelection(e.at),this._editor.focus(),this._applyEdit(()=>document.execCommand("insertHTML",!1,this._sanitize(t))),this}insertText(t,e={}){return e.at!=null&&this.restoreSelection(e.at),this._editor.focus(),this._applyEdit(()=>document.execCommand("insertText",!1,t)),this}saveSelection(){let t=window.getSelection();if(!t||t.rangeCount===0)return null;let e=t.getRangeAt(0);if(!this._editor.contains(e.startContainer)||!this._editor.contains(e.endContainer))return null;let o="jbm"+ ++this._bmSeq;if(this._editor.childNodes.length===0)return this._bookmarks.set(o,{atStart:!0}),o;let i=this._makeMarker(o),n=e.collapsed?null:this._makeMarker(o);if(n){let u=e.cloneRange();u.collapse(!1),u.insertNode(n)}let r=e.cloneRange();r.collapse(!0),r.insertNode(i),this._bookmarks.set(o,{start:i,end:n});let a=document.createRange();return a.setStartAfter(i),n?a.setEndBefore(n):a.collapse(!0),t.removeAllRanges(),t.addRange(a),o}restoreSelection(t){let e=this._takeRange(t);if(!e)return this;this._sourceMode||this._editor.focus();let o=window.getSelection();return o.removeAllRanges(),o.addRange(e),this}releaseSelection(t){return this._takeRange(t),this}beginExternalUI(){return this._externalDepth===0&&(this._externalBookmark=this.saveSelection()),this._externalDepth++,this}endExternalUI(t={}){if(this._externalDepth===0)return this;if(this._externalDepth===1){let e=this._externalBookmark;this._externalBookmark=null,t.restore===!1?this.releaseSelection(e):this.restoreSelection(e)}return this._externalDepth--,this}setHTML(t){return this._dropBookmarks(),this._editor.innerHTML=this._sanitize(t),this._updateStatus(),this}setTheme(t){let o=E.find(i=>i.id===t)?t:"default";return this._editor.dataset.theme=o,this._options.theme=o,this._themeSelect&&(this._themeSelect.value=o),this}setEnabled(t){return this._editor.contentEditable=String(t),this._root.classList.toggle("jotter--disabled",!t),this}on(t,e){return this._listeners[t]||(this._listeners[t]=[]),this._listeners[t].push(e),this}off(t,e){return this._listeners[t]&&(this._listeners[t]=this._listeners[t].filter(o=>o!==e)),this}destroy(){let t=this.getHTML();return this._destroyed=!0,this._hidePopup(),this._dropBookmarks(),this._externalBookmark=null,this._externalDepth=0,document.removeEventListener("mousedown",this._onDocMouseDown),document.removeEventListener("keydown",this._onDocKeyDown),this._popup.parentNode&&this._popup.parentNode.removeChild(this._popup),this._target.classList.remove("jotter-host"),this._target.innerHTML=t,this._listeners={},t}};h.toolbar=_.full;h.actions=f;h.presets=_;var P=h;return j(q);})();
4
+ `).map(r=>r.trim()).filter(r=>r.length>0).map(r=>{let a=r.match(/^<\/(\w+)/),u=r.match(/^<(\w+)/),p=r.endsWith("/>"),c=u?u[1].toLowerCase():null,l=a?a[1].toLowerCase():null;l&&!s.has(l)&&(t=Math.max(0,t-1));let d=i.repeat(t)+r;return c&&!p&&!o.has(c)&&!l&&!s.has(c)&&t++,d}).join(`
5
+ `)}_sanitize(e){let t=new DOMParser().parseFromString(e,"text/html");return t.querySelectorAll("script").forEach(i=>i.remove()),t.querySelectorAll("[data-jotter-bookmark], .jotter-media-shield").forEach(i=>i.remove()),t.querySelectorAll("*").forEach(i=>{Array.from(i.attributes).forEach(o=>{(o.name.startsWith("on")||["href","src","action","formaction","data"].includes(o.name)&&/^\s*javascript:/i.test(o.value))&&i.removeAttribute(o.name)})}),t.body.innerHTML}_toggleInlineCode(){let e=window.getSelection();if(!e||e.rangeCount===0)return;let t=e.getRangeAt(0),i=t.commonAncestorContainer;i.nodeType===3&&(i=i.parentNode);let o=i.closest?i.closest("code"):null;if(o){let s=o.parentNode;for(;o.firstChild;)s.insertBefore(o.firstChild,o);s.removeChild(o)}else if(t.collapsed){let s=document.createElement("code");s.innerHTML="&#8203;",t.insertNode(s);let r=document.createRange();r.setStart(s,0),r.setEnd(s,s.childNodes.length),e.removeAllRanges(),e.addRange(r)}else{let s=document.createElement("code");try{t.surroundContents(s)}catch{let a=t.extractContents();s.appendChild(a),t.insertNode(s)}}}_applyFontSize(e){let t=window.getSelection();if(!t||t.rangeCount===0)return;let i=t.getRangeAt(0);if(i.collapsed)return;let o=document.createElement("span");o.style.fontSize=e+"px";try{i.surroundContents(o)}catch{let r=i.extractContents();o.appendChild(r),i.insertNode(o)}}async _pasteFromClipboard(){try{if(navigator.clipboard&&navigator.clipboard.readText){let e=await navigator.clipboard.readText();document.execCommand("insertText",!1,e)}else document.execCommand("paste")}catch{}}_updateToolbarState(){this._toolbarEl.querySelectorAll(".jotter-btn[data-cmd]").forEach(t=>{try{t.classList.toggle("jotter-btn--active",document.queryCommandState(t.dataset.cmd))}catch{}});let e=this._toolbarEl.querySelector('[data-id="blockformat"]');if(e){let t=document.queryCommandValue("formatBlock").toLowerCase().replace(/[<>]/g,""),i=k.find(o=>o.tag===t);i&&(e.value=i.tag)}}_updateStatus(){let e=this._editor.innerText||"",t=e.trim()===""?0:e.trim().split(/\s+/).length,i=e.replace(/\n/g,"").length;this._wordCountEl.textContent=`${t} word${t!==1?"s":""}`,this._charCountEl.textContent=`${i} char${i!==1?"s":""}`}_richHTML(){let e=this._editor.cloneNode(!0);return e.querySelectorAll("[data-jotter-bookmark], .jotter-media-shield").forEach(t=>t.remove()),e.innerHTML}_makeMarker(e){let t=document.createElement("span");return t.className="jotter-bookmark",t.dataset.jotterBookmark=e,t}_takeRange(e){let t=e!=null?this._bookmarks.get(e):null;if(!t)return null;if(this._bookmarks.delete(e),t.atStart){let a=document.createRange();return a.setStart(this._editor,0),a.collapse(!0),a}let{start:i,end:o}=t,s=this._editor.contains(i)&&(!o||this._editor.contains(o)),r=null;return s&&(r=document.createRange(),r.setStartAfter(i),o?r.setEndBefore(o):r.collapse(!0)),i.parentNode&&i.remove(),o&&o.parentNode&&o.remove(),r}_saveBookmark(){this._releaseSavedBookmark(),this._savedBookmark=this.saveSelection()}_restoreSavedBookmark(){this.restoreSelection(this._savedBookmark),this._savedBookmark=null,this._editor.focus()}_releaseSavedBookmark(){this.releaseSelection(this._savedBookmark),this._savedBookmark=null}_dropBookmarks(){Array.from(this._bookmarks.keys()).forEach(e=>this.releaseSelection(e)),this._savedBookmark=null}_emit(e,t){(this._listeners[e]||[]).forEach(i=>i(t))}_emitChange(){let e=this.getHTML();this._changeCount++,this._emit("change",e),this._options.onChange&&this._options.onChange(e)}_applyEdit(e){let t=this._changeCount,i=this._richHTML();e(),this._updateStatus(),this._changeCount===t&&this._richHTML()!==i&&this._emitChange()}getHTML(){return this._sourceMode?this._source.value:this._richHTML()}getText(){return this._editor.innerText}isSourceMode(){return this._sourceMode}toggleSource(){return this._toggleSourceMode(),this}clear(){return this._deselectMedia(),this._dropBookmarks(),this._editor.innerHTML="",this._updateStatus(),this}focus(){return this._editor.focus(),this}insertHTML(e,t={}){return t.at!=null&&this.restoreSelection(t.at),this._editor.focus(),this._applyEdit(()=>document.execCommand("insertHTML",!1,this._sanitize(e))),this}insertText(e,t={}){return t.at!=null&&this.restoreSelection(t.at),this._editor.focus(),this._applyEdit(()=>document.execCommand("insertText",!1,e)),this}saveSelection(){let e=window.getSelection();if(!e||e.rangeCount===0)return null;let t=e.getRangeAt(0);if(!this._editor.contains(t.startContainer)||!this._editor.contains(t.endContainer))return null;let i="jbm"+ ++this._bmSeq;if(this._editor.childNodes.length===0)return this._bookmarks.set(i,{atStart:!0}),i;let o=this._makeMarker(i),s=t.collapsed?null:this._makeMarker(i);if(s){let u=t.cloneRange();u.collapse(!1),u.insertNode(s)}let r=t.cloneRange();r.collapse(!0),r.insertNode(o),this._bookmarks.set(i,{start:o,end:s});let a=document.createRange();return a.setStartAfter(o),s?a.setEndBefore(s):a.collapse(!0),e.removeAllRanges(),e.addRange(a),i}restoreSelection(e){let t=this._takeRange(e);if(!t)return this;this._sourceMode||this._editor.focus();let i=window.getSelection();return i.removeAllRanges(),i.addRange(t),this}releaseSelection(e){return this._takeRange(e),this}beginExternalUI(){return this._externalDepth===0&&(this._externalBookmark=this.saveSelection()),this._externalDepth++,this}endExternalUI(e={}){if(this._externalDepth===0)return this;if(this._externalDepth===1){let t=this._externalBookmark;this._externalBookmark=null,e.restore===!1?this.releaseSelection(t):this.restoreSelection(t)}return this._externalDepth--,this}setHTML(e){return this._deselectMedia(),this._dropBookmarks(),this._editor.innerHTML=this._sanitize(e),this._ensureMediaShields(),this._updateStatus(),this}setTheme(e){let i=E.find(o=>o.id===e)?e:"default";return this._editor.dataset.theme=i,this._options.theme=i,this._themeSelect&&(this._themeSelect.value=i),this}setEnabled(e){return this._editor.contentEditable=String(e),this._root.classList.toggle("jotter--disabled",!e),this}on(e,t){return this._listeners[e]||(this._listeners[e]=[]),this._listeners[e].push(t),this}off(e,t){return this._listeners[e]&&(this._listeners[e]=this._listeners[e].filter(i=>i!==t)),this}destroy(){let e=this.getHTML();return this._destroyed=!0,this._deselectMedia(),this._hidePopup(),this._dropBookmarks(),this._externalBookmark=null,this._externalDepth=0,document.removeEventListener("mousedown",this._onDocMouseDown),document.removeEventListener("keydown",this._onDocKeyDown),window.removeEventListener("resize",this._onWindowResize),this._popup.parentNode&&this._popup.parentNode.removeChild(this._popup),this._target.classList.remove("jotter-host"),this._target.innerHTML=e,this._listeners={},e}};m.toolbar=_.full;m.actions=f;m.presets=_;var z=m;return j(D);})();
package/dist/jotter.js CHANGED
@@ -358,6 +358,10 @@ var JotterJS = class {
358
358
  this._destroyed = false;
359
359
  this._lastForeColor = "#e8e4d8";
360
360
  this._lastHiliteColor = "#c8a96e";
361
+ this._selectedMedia = null;
362
+ this._resizeState = null;
363
+ this._onResizeMove = this._onResizeMove.bind(this);
364
+ this._onResizeEnd = this._onResizeEnd.bind(this);
361
365
  this._init();
362
366
  }
363
367
  // ─── Init ─────────────────────────────────────────────────────────────────
@@ -381,6 +385,15 @@ var JotterJS = class {
381
385
  this._editor.innerHTML = this._sanitize(initialHTML);
382
386
  this._editor.spellcheck = true;
383
387
  document.execCommand("defaultParagraphSeparator", false, "p");
388
+ try {
389
+ document.execCommand("enableObjectResizing", false, false);
390
+ } catch (_) {
391
+ }
392
+ try {
393
+ document.execCommand("enableInlineTableEditing", false, false);
394
+ } catch (_) {
395
+ }
396
+ this._ensureMediaShields();
384
397
  this._source = document.createElement("textarea");
385
398
  this._source.className = "jotter-source";
386
399
  this._source.setAttribute("aria-label", "HTML source");
@@ -388,8 +401,10 @@ var JotterJS = class {
388
401
  this._source.style.minHeight = this._options.height;
389
402
  this._sourceMode = false;
390
403
  this._statusBar = this._buildStatusBar();
404
+ this._mediaFrame = this._buildMediaFrame();
391
405
  this._editorWrap.appendChild(this._editor);
392
406
  this._editorWrap.appendChild(this._source);
407
+ this._editorWrap.appendChild(this._mediaFrame);
393
408
  this._root.appendChild(this._toolbar);
394
409
  this._root.appendChild(this._editorWrap);
395
410
  this._root.appendChild(this._statusBar);
@@ -1138,9 +1153,14 @@ var JotterJS = class {
1138
1153
  return null;
1139
1154
  return `<div class="jotter-video-wrap"><iframe src="https://www.youtube.com/embed/${id}" frameborder="0" allowfullscreen loading="lazy" title="YouTube video"></iframe></div><p><br></p>`;
1140
1155
  }
1141
- /** Embeds are inserted verbatim — the host, not the end user, supplies them. */
1156
+ /**
1157
+ * The embed markup itself is inserted verbatim (the host, not the end user,
1158
+ * supplies it, so it is never sanitized) inside a .jotter-embed-wrap, added
1159
+ * purely so the block is selectable and can carry a click shield — same
1160
+ * treatment as the video wrap.
1161
+ */
1142
1162
  _embedHTML(html) {
1143
- return html + "<p><br></p>";
1163
+ return `<div class="jotter-embed-wrap">${html}</div><p><br></p>`;
1144
1164
  }
1145
1165
  // ─── Resolver hooks ───────────────────────────────────────────────────────
1146
1166
  // An onRequest* option replaces the built-in popup for that insertable. The
@@ -1282,6 +1302,183 @@ var JotterJS = class {
1282
1302
  bar.appendChild(modeEl);
1283
1303
  return bar;
1284
1304
  }
1305
+ // ─── Media selection ──────────────────────────────────────────────────────
1306
+ // Images, YouTube embeds and generic embeds are atomic blocks: clicking one
1307
+ // shows a floating frame (positioned over it, not part of the saved HTML)
1308
+ // with resize handles, and Backspace/Delete removes the whole element.
1309
+ //
1310
+ // The frame lives in _editorWrap, a sibling of _editor/_source, rather than
1311
+ // inside the editable content or on document.body like the popup — being a
1312
+ // normal descendant of the scrolling wrap means it scrolls with the content
1313
+ // for free, with no scroll listener needed.
1314
+ //
1315
+ // Video/embed content sits behind a permanent "shield" div so it can never
1316
+ // be interacted with while editing (no accidental playback, no swallowed
1317
+ // clicks) — every click on the block always just selects it. The shield is
1318
+ // injected live-DOM only and stripped out of getHTML()/_sanitize(), exactly
1319
+ // like the selection bookmarks above are, so published HTML keeps a normal,
1320
+ // interactive iframe.
1321
+ /** Builds the reusable floating selection frame with its 6 resize handles. */
1322
+ _buildMediaFrame() {
1323
+ const frame = document.createElement("div");
1324
+ frame.className = "jotter-media-frame";
1325
+ ["nw", "ne", "sw", "se", "w", "e"].forEach((pos) => {
1326
+ const h = document.createElement("div");
1327
+ h.className = "jotter-resize-handle jotter-resize-handle--" + pos;
1328
+ h.dataset.handle = pos;
1329
+ h.tabIndex = -1;
1330
+ frame.appendChild(h);
1331
+ });
1332
+ frame.addEventListener("mousedown", (e) => {
1333
+ const handle = e.target.closest(".jotter-resize-handle");
1334
+ if (!handle || !this._selectedMedia)
1335
+ return;
1336
+ e.preventDefault();
1337
+ this._beginResize(handle.dataset.handle, e);
1338
+ });
1339
+ return frame;
1340
+ }
1341
+ /** Adds a click shield to every video/embed block that doesn't already have one. */
1342
+ _ensureMediaShields() {
1343
+ this._editor.querySelectorAll(".jotter-video-wrap, .jotter-embed-wrap").forEach((wrap) => {
1344
+ if (wrap.querySelector(":scope > .jotter-media-shield"))
1345
+ return;
1346
+ const shield = document.createElement("div");
1347
+ shield.className = "jotter-media-shield";
1348
+ wrap.appendChild(shield);
1349
+ });
1350
+ }
1351
+ /** Nearest selectable media element (img / video-wrap / embed-wrap) under target, or null. */
1352
+ _mediaElementFromTarget(target) {
1353
+ if (!this._editor.contains(target))
1354
+ return null;
1355
+ const img = target.closest("img");
1356
+ if (img && this._editor.contains(img))
1357
+ return img;
1358
+ const wrap = target.closest(".jotter-video-wrap, .jotter-embed-wrap");
1359
+ if (wrap && this._editor.contains(wrap))
1360
+ return wrap;
1361
+ return null;
1362
+ }
1363
+ /** Selects a media element: shows the frame over it and parks a real caret before it. */
1364
+ _selectMedia(el) {
1365
+ if (this._selectedMedia === el)
1366
+ return;
1367
+ this._deselectMedia();
1368
+ this._selectedMedia = el;
1369
+ this._positionMediaFrame();
1370
+ this._mediaFrame.classList.add("jotter-media-frame--visible");
1371
+ this._editor.focus({ preventScroll: true });
1372
+ const range = document.createRange();
1373
+ range.setStartBefore(el);
1374
+ range.collapse(true);
1375
+ const sel = window.getSelection();
1376
+ sel.removeAllRanges();
1377
+ sel.addRange(range);
1378
+ this._updateToolbarState();
1379
+ }
1380
+ /** Clears the current media selection (and aborts any in-flight resize). */
1381
+ _deselectMedia() {
1382
+ if (this._resizeState)
1383
+ this._abortResize();
1384
+ if (!this._selectedMedia)
1385
+ return;
1386
+ this._selectedMedia = null;
1387
+ this._mediaFrame.classList.remove("jotter-media-frame--visible");
1388
+ }
1389
+ /** Repositions the floating frame to match the selected element's current box. */
1390
+ _positionMediaFrame() {
1391
+ const el = this._selectedMedia;
1392
+ if (!el)
1393
+ return;
1394
+ const wrapRect = this._editorWrap.getBoundingClientRect();
1395
+ const elRect = el.getBoundingClientRect();
1396
+ this._mediaFrame.style.top = elRect.top - wrapRect.top + this._editorWrap.scrollTop + "px";
1397
+ this._mediaFrame.style.left = elRect.left - wrapRect.left + this._editorWrap.scrollLeft + "px";
1398
+ this._mediaFrame.style.width = elRect.width + "px";
1399
+ this._mediaFrame.style.height = elRect.height + "px";
1400
+ }
1401
+ /**
1402
+ * Removes the selected element via execCommand('delete') rather than a plain
1403
+ * el.remove() — the browser's native undo stack (what Ctrl+Z / the Undo
1404
+ * button run via execCommand('undo')) only tracks edits made through
1405
+ * execCommand, so a raw DOM removal would be invisible to it. Selecting the
1406
+ * whole node first (rather than a collapsed caret before it) means 'delete'
1407
+ * removes exactly that node regardless of direction, and the browser
1408
+ * collapses the caret to where it used to be on its own.
1409
+ */
1410
+ _deleteSelectedMedia() {
1411
+ const el = this._selectedMedia;
1412
+ if (!el)
1413
+ return;
1414
+ this._deselectMedia();
1415
+ const range = document.createRange();
1416
+ range.selectNode(el);
1417
+ const sel = window.getSelection();
1418
+ sel.removeAllRanges();
1419
+ sel.addRange(range);
1420
+ this._applyEdit(() => document.execCommand("delete", false, null));
1421
+ this._updateToolbarState();
1422
+ }
1423
+ /**
1424
+ * Starts a width-only resize drag. Height is never set directly: an image's
1425
+ * natural aspect ratio, the video wrap's padding-bottom-percent-of-width box,
1426
+ * and an embed's normal reflow all keep it correct on their own once width
1427
+ * changes, so one code path covers all three media types.
1428
+ */
1429
+ _beginResize(handleType, e) {
1430
+ const el = this._selectedMedia;
1431
+ const rect = el.getBoundingClientRect();
1432
+ const sign = handleType.includes("w") ? -1 : 1;
1433
+ this._resizeState = {
1434
+ el,
1435
+ sign,
1436
+ startX: e.clientX,
1437
+ startWidth: rect.width,
1438
+ startInlineWidth: el.style.width,
1439
+ before: this._richHTML()
1440
+ };
1441
+ document.addEventListener("mousemove", this._onResizeMove);
1442
+ document.addEventListener("mouseup", this._onResizeEnd, { once: true });
1443
+ }
1444
+ _onResizeMove(e) {
1445
+ const s = this._resizeState;
1446
+ if (!s)
1447
+ return;
1448
+ const dx = (e.clientX - s.startX) * s.sign;
1449
+ const min = 40;
1450
+ const max = Math.max(min, this._editor.clientWidth);
1451
+ const width = Math.max(min, Math.min(max, Math.round(s.startWidth + dx)));
1452
+ s.el.style.width = width + "px";
1453
+ s.el.style.removeProperty("max-width");
1454
+ this._positionMediaFrame();
1455
+ }
1456
+ /**
1457
+ * A drag spans async mousemove/mouseup events, so it can't go through the
1458
+ * synchronous _applyEdit() helper — this manually replicates its contract
1459
+ * instead: emit 'change' exactly once, only if the width actually changed.
1460
+ */
1461
+ _onResizeEnd() {
1462
+ document.removeEventListener("mousemove", this._onResizeMove);
1463
+ const s = this._resizeState;
1464
+ this._resizeState = null;
1465
+ if (!s)
1466
+ return;
1467
+ this._updateStatus();
1468
+ if (this._richHTML() !== s.before)
1469
+ this._emitChange();
1470
+ }
1471
+ /** Escape mid-drag: revert to the pre-drag width and emit nothing. */
1472
+ _abortResize() {
1473
+ const s = this._resizeState;
1474
+ if (!s)
1475
+ return;
1476
+ document.removeEventListener("mousemove", this._onResizeMove);
1477
+ document.removeEventListener("mouseup", this._onResizeEnd);
1478
+ s.el.style.width = s.startInlineWidth;
1479
+ this._resizeState = null;
1480
+ this._positionMediaFrame();
1481
+ }
1285
1482
  // ─── Events ───────────────────────────────────────────────────────────────
1286
1483
  _bindEvents() {
1287
1484
  this._editor.addEventListener("input", () => {
@@ -1313,11 +1510,26 @@ var JotterJS = class {
1313
1510
  }
1314
1511
  }
1315
1512
  });
1513
+ this._ensureMediaShields();
1514
+ if (this._selectedMedia)
1515
+ this._positionMediaFrame();
1316
1516
  this._updateStatus();
1317
1517
  this._emitChange();
1318
1518
  });
1319
1519
  this._editor.addEventListener("keyup", () => this._updateToolbarState());
1320
1520
  this._editor.addEventListener("mouseup", () => this._updateToolbarState());
1521
+ this._editor.addEventListener("mousedown", (e) => {
1522
+ const media = this._mediaElementFromTarget(e.target);
1523
+ if (media) {
1524
+ e.preventDefault();
1525
+ this._selectMedia(media);
1526
+ }
1527
+ });
1528
+ this._onWindowResize = () => {
1529
+ if (this._selectedMedia)
1530
+ this._positionMediaFrame();
1531
+ };
1532
+ window.addEventListener("resize", this._onWindowResize);
1321
1533
  this._editor.addEventListener("focusin", (e) => {
1322
1534
  this._root.classList.add("jotter--focused");
1323
1535
  if (this._externalDepth > 0)
@@ -1329,6 +1541,7 @@ var JotterJS = class {
1329
1541
  this._options.onFocus();
1330
1542
  });
1331
1543
  this._editor.addEventListener("focusout", (e) => {
1544
+ this._deselectMedia();
1332
1545
  if (this._externalDepth > 0)
1333
1546
  return;
1334
1547
  if (this._isInternalTarget(e.relatedTarget))
@@ -1347,6 +1560,11 @@ var JotterJS = class {
1347
1560
  }, 0);
1348
1561
  });
1349
1562
  this._editor.addEventListener("keydown", (e) => {
1563
+ if ((e.key === "Backspace" || e.key === "Delete") && this._selectedMedia) {
1564
+ e.preventDefault();
1565
+ this._deleteSelectedMedia();
1566
+ return;
1567
+ }
1350
1568
  if (e.key === "Tab") {
1351
1569
  e.preventDefault();
1352
1570
  document.execCommand("insertHTML", false, "&nbsp;&nbsp;&nbsp;&nbsp;");
@@ -1356,10 +1574,23 @@ var JotterJS = class {
1356
1574
  if (this._popupVisible() && !this._popup.contains(e.target) && !this._toolbarEl.contains(e.target)) {
1357
1575
  this._hidePopup();
1358
1576
  }
1577
+ if (this._selectedMedia && !this._mediaFrame.contains(e.target) && e.target !== this._selectedMedia && !this._selectedMedia.contains(e.target)) {
1578
+ this._deselectMedia();
1579
+ }
1359
1580
  };
1360
1581
  document.addEventListener("mousedown", this._onDocMouseDown);
1361
1582
  this._onDocKeyDown = (e) => {
1362
- if (e.key === "Escape" && this._popupVisible()) {
1583
+ if (e.key !== "Escape")
1584
+ return;
1585
+ if (this._resizeState) {
1586
+ this._abortResize();
1587
+ return;
1588
+ }
1589
+ if (this._selectedMedia) {
1590
+ this._deselectMedia();
1591
+ return;
1592
+ }
1593
+ if (this._popupVisible()) {
1363
1594
  this._restoreSavedBookmark();
1364
1595
  this._hidePopup();
1365
1596
  }
@@ -1377,6 +1608,7 @@ var JotterJS = class {
1377
1608
  * Leaving source mode: sanitizes textarea value back into innerHTML.
1378
1609
  */
1379
1610
  _toggleSourceMode() {
1611
+ this._deselectMedia();
1380
1612
  this._sourceMode = !this._sourceMode;
1381
1613
  if (this._sourceMode) {
1382
1614
  this._dropBookmarks();
@@ -1385,6 +1617,7 @@ var JotterJS = class {
1385
1617
  this._source.style.display = "block";
1386
1618
  } else {
1387
1619
  this._editor.innerHTML = this._sanitize(this._source.value);
1620
+ this._ensureMediaShields();
1388
1621
  this._source.style.display = "none";
1389
1622
  this._editor.style.display = "";
1390
1623
  this._updateStatus();
@@ -1427,7 +1660,7 @@ var JotterJS = class {
1427
1660
  _sanitize(html) {
1428
1661
  const doc = new DOMParser().parseFromString(html, "text/html");
1429
1662
  doc.querySelectorAll("script").forEach((el) => el.remove());
1430
- doc.querySelectorAll("[data-jotter-bookmark]").forEach((el) => el.remove());
1663
+ doc.querySelectorAll("[data-jotter-bookmark], .jotter-media-shield").forEach((el) => el.remove());
1431
1664
  doc.querySelectorAll("*").forEach((el) => {
1432
1665
  Array.from(el.attributes).forEach((attr) => {
1433
1666
  if (attr.name.startsWith("on")) {
@@ -1551,12 +1784,14 @@ var JotterJS = class {
1551
1784
  // indicator or a host re-render. Empty marker <span>s move with the DOM
1552
1785
  // instead, so they still point at the right spot afterwards. They are stripped
1553
1786
  // from getHTML() and from _sanitize(), so hosts never see them.
1554
- /** Editable area's HTML, minus any live selection markers. */
1787
+ /**
1788
+ * Editable area's HTML, minus any live selection markers and media click-
1789
+ * shields. Always clones (no bookmark-free fast path): shields can be
1790
+ * present independently of bookmarks, so both must be stripped every time.
1791
+ */
1555
1792
  _richHTML() {
1556
- if (this._bookmarks.size === 0)
1557
- return this._editor.innerHTML;
1558
1793
  const clone = this._editor.cloneNode(true);
1559
- clone.querySelectorAll("[data-jotter-bookmark]").forEach((el) => el.remove());
1794
+ clone.querySelectorAll("[data-jotter-bookmark], .jotter-media-shield").forEach((el) => el.remove());
1560
1795
  return clone.innerHTML;
1561
1796
  }
1562
1797
  _makeMarker(id) {
@@ -1663,6 +1898,7 @@ var JotterJS = class {
1663
1898
  return this;
1664
1899
  }
1665
1900
  clear() {
1901
+ this._deselectMedia();
1666
1902
  this._dropBookmarks();
1667
1903
  this._editor.innerHTML = "";
1668
1904
  this._updateStatus();
@@ -1787,8 +2023,10 @@ var JotterJS = class {
1787
2023
  return this;
1788
2024
  }
1789
2025
  setHTML(html) {
2026
+ this._deselectMedia();
1790
2027
  this._dropBookmarks();
1791
2028
  this._editor.innerHTML = this._sanitize(html);
2029
+ this._ensureMediaShields();
1792
2030
  this._updateStatus();
1793
2031
  return this;
1794
2032
  }
@@ -1821,12 +2059,14 @@ var JotterJS = class {
1821
2059
  destroy() {
1822
2060
  const html = this.getHTML();
1823
2061
  this._destroyed = true;
2062
+ this._deselectMedia();
1824
2063
  this._hidePopup();
1825
2064
  this._dropBookmarks();
1826
2065
  this._externalBookmark = null;
1827
2066
  this._externalDepth = 0;
1828
2067
  document.removeEventListener("mousedown", this._onDocMouseDown);
1829
2068
  document.removeEventListener("keydown", this._onDocKeyDown);
2069
+ window.removeEventListener("resize", this._onWindowResize);
1830
2070
  if (this._popup.parentNode)
1831
2071
  this._popup.parentNode.removeChild(this._popup);
1832
2072
  this._target.classList.remove("jotter-host");
@@ -1 +1 @@
1
- @font-face{font-family:Material Icons;font-style:normal;font-weight:400;src:url("./fonts/material-symbols-rounded.woff2") format("woff2")}.material-icons{font-family:Material Icons;font-weight:400;font-style:normal;font-size:24px;line-height:1;letter-spacing:normal;text-transform:none;display:inline-block;white-space:nowrap;word-wrap:normal;direction:ltr;-webkit-font-feature-settings:"liga";font-feature-settings:"liga";-webkit-font-smoothing:antialiased}:root{--jotter-bg: #ffffff;--jotter-surface: #f4f3f0;--jotter-surface2: #eceae5;--jotter-border: #d8d4cc;--jotter-border-focus: #7a6a4a;--jotter-text: #1e1c18;--jotter-text-muted: #9a9488;--jotter-accent: #7a6a4a;--jotter-btn-hover: rgba(122, 106, 74, .07);--jotter-btn-active-bg: rgba(122, 106, 74, .14);--jotter-radius: 4px;--jotter-font-ui: "DM Mono", "Fira Mono", "Consolas", monospace;--jotter-font-editor: Georgia, "Times New Roman", serif;--jotter-status-h: 32px;--jotter-transition: .14s ease}.jotter-host{display:block}.htmled{display:flex;flex-direction:column;border:1px solid var(--jotter-border);border-radius:var(--jotter-radius);background:var(--jotter-bg);color:var(--jotter-text);font-family:var(--jotter-font-ui);overflow:hidden;transition:border-color var(--jotter-transition),box-shadow var(--jotter-transition)}.jotter--focused{border-color:var(--jotter-border-focus);box-shadow:0 0 0 3px #7a6a4a1a}.jotter--disabled{opacity:.55;pointer-events:none}.jotter-toolbar{display:flex;align-items:center;flex-wrap:wrap;gap:2px;padding:6px 8px;background:var(--jotter-surface);border-bottom:1px solid var(--jotter-border)}.jotter-select{appearance:none;-webkit-appearance:none;background:transparent;border:1px solid var(--jotter-border);border-radius:var(--jotter-radius);color:var(--jotter-text);font-family:var(--jotter-font-ui);font-size:11px;letter-spacing:.04em;padding:4px 8px;height:28px;cursor:pointer;flex-shrink:0;transition:border-color var(--jotter-transition),background var(--jotter-transition)}.jotter-select{min-width:108px;text-transform:uppercase}.jotter-select--font{min-width:130px;text-transform:none}.jotter-select--size{min-width:68px;text-transform:none}.jotter-select--theme{min-width:90px;text-transform:none}.jotter-select:hover{border-color:var(--jotter-accent);background:var(--jotter-btn-hover)}.jotter-select:focus{outline:none;border-color:var(--jotter-accent)}.jotter-select option{background:var(--jotter-surface2);color:var(--jotter-text)}.jotter-btn{display:flex;align-items:center;justify-content:center;flex-direction:column;width:32px;height:30px;padding:0;border:none;border-radius:var(--jotter-radius);background:transparent;color:var(--jotter-text-muted);cursor:pointer;flex-shrink:0;transition:color var(--jotter-transition),background var(--jotter-transition);position:relative}.jotter-btn .material-icons{pointer-events:none;font-size:18px;line-height:1;user-select:none}.jotter-btn:hover{color:var(--jotter-accent);background:var(--jotter-btn-hover)}.jotter-btn--active{color:var(--jotter-accent)!important;background:var(--jotter-btn-active-bg)!important}.jotter-btn--text{width:auto;padding:0 10px;font-family:var(--jotter-font-ui);font-size:11px;letter-spacing:.08em;text-transform:uppercase;border:1px solid var(--jotter-border)}.jotter-sep{width:1px;height:18px;background:var(--jotter-border);margin:0 4px;flex-shrink:0}.jotter-color-wrap{display:inline-flex;align-items:center;flex-shrink:0}.jotter-color-input{position:absolute;width:0;height:0;opacity:0;pointer-events:none}.jotter-color-btn{width:32px;height:34px;gap:0;padding-bottom:3px}.jotter-color-swatch{display:block;width:18px;height:3px;border-radius:1px;pointer-events:none;flex-shrink:0}.jotter-editor-wrap{flex:1;overflow-y:auto;background:var(--jotter-bg);scrollbar-width:thin;scrollbar-color:var(--jotter-border) transparent}.jotter-editor-wrap::-webkit-scrollbar{width:6px}.jotter-editor-wrap::-webkit-scrollbar-track{background:transparent}.jotter-editor-wrap::-webkit-scrollbar-thumb{background:var(--jotter-border);border-radius:3px}.jotter-editor{outline:none;padding:24px 28px;min-height:200px;font-family:var(--jotter-font-editor);font-size:16px;line-height:1.75;color:var(--jotter-text);caret-color:auto;word-break:break-word}.jotter-source{display:none;width:100%;min-height:200px;padding:24px 28px;background:var(--jotter-bg);color:#3a6030;font-family:var(--jotter-font-ui);font-size:13px;line-height:1.7;border:none;outline:none;resize:vertical;caret-color:var(--jotter-accent);tab-size:2;white-space:pre;overflow-wrap:normal;overflow-x:auto}.jotter--source-mode .jotter-btn:not([data-custom=toggleSource]),.jotter--source-mode .jotter-select,.jotter--source-mode .jotter-color-btn{opacity:.35;pointer-events:none}.jotter-editor:empty:before{content:attr(data-placeholder);color:var(--jotter-text-muted);pointer-events:none;font-style:italic}.jotter-editor .jotter-bookmark{display:none}.jotter-editor h1,.jotter-editor h2,.jotter-editor h3,.jotter-editor h4,.jotter-editor h5,.jotter-editor h6{text-transform:none;font-family:var(--ed-heading-font, inherit);letter-spacing:var(--ed-heading-tracking, normal)}.jotter-editor h1{font-size:2em;font-weight:700;margin:.6em 0 .3em;color:var(--ed-h1, inherit);border-bottom:var(--ed-h1-rule, none);padding-bottom:.25em}.jotter-editor h2{font-size:1.5em;font-weight:600;margin:.75em 0 .25em;color:var(--ed-h2, inherit)}.jotter-editor h3{font-size:1.2em;font-weight:600;margin:.75em 0 .25em;color:var(--ed-h3, inherit)}.jotter-editor h4{font-size:1em;font-weight:600;margin:.75em 0 .25em;color:var(--ed-h4, inherit)}.jotter-editor p{margin:0 0 .85em}.jotter-editor a{color:var(--ed-link, -webkit-link);text-decoration-color:var(--ed-link-deco, auto);text-underline-offset:3px}.jotter-editor a:hover{text-decoration-color:var(--ed-link, -webkit-link)}.jotter-editor strong,.jotter-editor b{color:var(--ed-strong, inherit);font-weight:700}.jotter-editor em,.jotter-editor i{color:var(--ed-em, inherit)}.jotter-editor blockquote{margin:1em 0;padding:8px 0 8px 20px;font-style:italic;border-left:3px solid var(--ed-quote-bar, #ccc);color:var(--ed-quote, inherit)}.jotter-editor pre{font-family:var(--ed-code-font, monospace);font-size:.875em;margin:.75em 0;padding:12px 16px;overflow-x:auto;white-space:pre-wrap;background:var(--ed-code-bg, transparent);color:var(--ed-code-text, inherit);border:1px solid var(--ed-code-border, transparent);border-radius:var(--jotter-radius)}.jotter-editor code{font-family:var(--ed-code-font, monospace);font-size:.875em;padding:1px 4px;background:var(--ed-code-bg, transparent);color:var(--ed-code-text, inherit);border:1px solid var(--ed-code-border, transparent);border-radius:2px}.jotter-editor ul,.jotter-editor ol{padding-left:24px;margin:.5em 0 .85em}.jotter-editor li{margin-bottom:.25em}.jotter-editor ul li::marker{color:var(--ed-marker, inherit)}.jotter-editor ol li::marker{color:var(--ed-marker, inherit)}.jotter-editor hr{border:none;border-top:1px solid var(--ed-hr, currentColor);opacity:.2;margin:1.5em 0}.jotter-editor sub,.jotter-editor sup{font-size:.75em}.jotter-editor ::selection{background:var(--ed-selection, highlight)}.jotter-editor table{border-collapse:collapse;width:100%;margin:.75em 0;font-size:.95em}.jotter-editor th,.jotter-editor td{border:1px solid var(--ed-table-border, #ccc);padding:7px 12px;text-align:left;vertical-align:top;min-width:40px}.jotter-editor th{background:var(--ed-th-bg, transparent);color:var(--ed-th-text, inherit);font-family:var(--ed-heading-font, inherit);font-size:.85em;font-weight:600;text-transform:none}.jotter-editor[data-theme=warm]{--ed-heading-font: "DM Mono", "Fira Mono", monospace;--ed-heading-tracking: -.01em;--ed-caret: #7a6a4a;--ed-selection: rgba(122, 106, 74, .18);--ed-h1: #7a6a4a;--ed-h2: #4a3e28;--ed-h3: #5a4e38;--ed-h4: #9a9488;--ed-h1-rule: 1px solid #d8d4cc;--ed-link: #7a6a4a;--ed-link-deco: rgba(122, 106, 74, .35);--ed-strong: #1a1612;--ed-em: #3a3028;--ed-quote: #7a7468;--ed-quote-bar: #7a6a4a;--ed-code-font: "DM Mono", "Fira Mono", monospace;--ed-code-bg: #eceae5;--ed-code-border: #d8d4cc;--ed-code-text: #3a6030;--ed-marker: #7a6a4a;--ed-hr: #d8d4cc;--ed-th-bg: #f4f3f0;--ed-th-text: #7a6a4a;--ed-table-border: #d8d4cc}.jotter-editor[data-theme=ink]{--ed-heading-font: "DM Mono", "Fira Mono", monospace;--ed-heading-tracking: -.01em;--ed-caret: #1a2a4a;--ed-selection: rgba(26, 42, 74, .14);--ed-h1: #0d1f3c;--ed-h2: #1a2a4a;--ed-h3: #243560;--ed-h4: #5a6888;--ed-h1-rule: 1px solid #b8c4d8;--ed-link: #1a4a8a;--ed-link-deco: rgba(26, 74, 138, .3);--ed-strong: #0a1428;--ed-em: #2a3a5a;--ed-quote: #4a5a78;--ed-quote-bar: #1a4a8a;--ed-code-font: "DM Mono", "Fira Mono", monospace;--ed-code-bg: #eef0f6;--ed-code-border: #c8cedd;--ed-code-text: #1a4a3a;--ed-marker: #1a4a8a;--ed-hr: #b8c4d8;--ed-th-bg: #eef0f6;--ed-th-text: #1a2a4a;--ed-table-border: #b8c4d8}.jotter-editor[data-theme=forest]{--ed-heading-font: "DM Mono", "Fira Mono", monospace;--ed-heading-tracking: -.01em;--ed-caret: #1a3a28;--ed-selection: rgba(26, 58, 40, .14);--ed-h1: #1a3a28;--ed-h2: #1e4430;--ed-h3: #2a5a40;--ed-h4: #5a7a68;--ed-h1-rule: 1px solid #b0ccc0;--ed-link: #1a6040;--ed-link-deco: rgba(26, 96, 64, .3);--ed-strong: #0e2018;--ed-em: #2a4038;--ed-quote: #3a5a48;--ed-quote-bar: #1a6040;--ed-code-font: "DM Mono", "Fira Mono", monospace;--ed-code-bg: #eef5f0;--ed-code-border: #c0d8c8;--ed-code-text: #1a5828;--ed-marker: #1a6040;--ed-hr: #b0ccc0;--ed-th-bg: #eef5f0;--ed-th-text: #1a3a28;--ed-table-border: #b0ccc0}.jotter-editor .jotter-video-wrap{position:relative;padding-bottom:56.25%;height:0;overflow:hidden;margin:.75em 0;border-radius:var(--jotter-radius);border:1px solid var(--jotter-border)}.jotter-editor .jotter-video-wrap iframe{position:absolute;top:0;left:0;width:100%;height:100%;border:none}.jotter-status{display:flex;align-items:center;gap:16px;padding:0 14px;height:var(--jotter-status-h);min-height:var(--jotter-status-h);background:var(--jotter-surface);border-top:1px solid var(--jotter-border);font-size:10.5px;letter-spacing:.06em;text-transform:uppercase;color:var(--jotter-text-muted)}.jotter-status-mode{margin-left:auto;color:var(--jotter-accent);font-weight:600}.jotter-popup{display:none;position:fixed;z-index:9999;background:#fff;border:1px solid #d8d4cc;border-radius:5px;box-shadow:0 8px 24px #0000001f,0 2px 6px #00000012;min-width:220px;max-width:360px}.jotter-popup--visible{display:block}.jotter-popup-inner{padding:14px}.jotter-popup-title{font-family:var(--jotter-font-ui);font-size:10px;text-transform:uppercase;letter-spacing:.12em;color:#9a9488;margin-bottom:10px;padding-bottom:8px;border-bottom:1px solid #d8d4cc}.jotter-popup-hint{font-size:11px;color:#9a9488;margin-top:8px;text-align:center;letter-spacing:.04em}.jotter-popup-form{display:flex;flex-direction:column;gap:6px;min-width:280px}.jotter-popup-label{font-size:10px;text-transform:uppercase;letter-spacing:.08em;color:#9a9488;margin-top:4px}.jotter-popup-input,.jotter-popup-select,.jotter-popup-textarea{width:100%;background:#f8f7f4;border:1px solid #d8d4cc;border-radius:3px;color:#1e1c18;font-family:DM Mono,Fira Mono,monospace;font-size:12px;padding:7px 9px;outline:none;transition:border-color .12s;resize:vertical}.jotter-popup-input:focus,.jotter-popup-select:focus,.jotter-popup-textarea:focus{border-color:#7a6a4a}.jotter-popup-select{appearance:auto;cursor:pointer;resize:none}.jotter-input--error{border-color:#b85050!important}.jotter-popup-submit{margin-top:6px;padding:7px 14px;background:#7a6a4a14;border:1px solid #7a6a4a;border-radius:3px;color:#7a6a4a;font-family:DM Mono,Fira Mono,monospace;font-size:11px;letter-spacing:.08em;text-transform:uppercase;cursor:pointer;transition:background .12s}.jotter-popup-submit:hover{background:#7a6a4a29}.jotter-table-grid{display:grid;gap:3px}.jotter-table-cell{width:18px;height:18px;border:1px solid #d8d4cc;border-radius:2px;cursor:pointer;transition:border-color 80ms,background 80ms}.jotter-table-cell--active{background:#7a6a4a24;border-color:#7a6a4a}.jotter-char-grid{display:flex;flex-wrap:wrap;gap:2px;max-width:300px;max-height:220px;overflow-y:auto;scrollbar-width:thin;scrollbar-color:#d8d4cc transparent}.jotter-char-btn{display:flex;align-items:center;justify-content:center;width:28px;height:28px;border:1px solid #d8d4cc;border-radius:3px;background:transparent;color:#1e1c18;font-size:14px;cursor:pointer;transition:background 80ms,border-color 80ms,color 80ms;flex-shrink:0}.jotter-char-btn:hover{background:#7a6a4a1a;border-color:#7a6a4a;color:#7a6a4a}.jotter-lorem-btn{display:block;width:100%;padding:9px 12px;background:transparent;border:1px solid #d8d4cc;border-radius:3px;color:#1e1c18;font-family:DM Mono,Fira Mono,monospace;font-size:11px;letter-spacing:.04em;text-align:left;cursor:pointer;margin-bottom:4px;transition:background .1s,border-color .1s,color .1s}.jotter-lorem-btn:hover{background:#7a6a4a12;border-color:#7a6a4a;color:#7a6a4a}.jotter-btn:focus-visible,.jotter-select:focus-visible,.jotter-char-btn:focus-visible,.jotter-lorem-btn:focus-visible,.jotter-popup-submit:focus-visible,.jotter-table-cell:focus-visible{outline:2px solid var(--jotter-accent);outline-offset:1px}
1
+ @font-face{font-family:Material Icons;font-style:normal;font-weight:400;src:url("./fonts/material-symbols-rounded.woff2") format("woff2")}.material-icons{font-family:Material Icons;font-weight:400;font-style:normal;font-size:24px;line-height:1;letter-spacing:normal;text-transform:none;display:inline-block;white-space:nowrap;word-wrap:normal;direction:ltr;-webkit-font-feature-settings:"liga";font-feature-settings:"liga";-webkit-font-smoothing:antialiased}:root{--jotter-bg: #ffffff;--jotter-surface: #f4f3f0;--jotter-surface2: #eceae5;--jotter-border: #d8d4cc;--jotter-border-focus: #7a6a4a;--jotter-text: #1e1c18;--jotter-text-muted: #9a9488;--jotter-accent: #7a6a4a;--jotter-btn-hover: rgba(122, 106, 74, .07);--jotter-btn-active-bg: rgba(122, 106, 74, .14);--jotter-radius: 4px;--jotter-font-ui: "DM Mono", "Fira Mono", "Consolas", monospace;--jotter-font-editor: Georgia, "Times New Roman", serif;--jotter-status-h: 32px;--jotter-transition: .14s ease}.jotter-host{display:block}.htmled{display:flex;flex-direction:column;border:1px solid var(--jotter-border);border-radius:var(--jotter-radius);background:var(--jotter-bg);color:var(--jotter-text);font-family:var(--jotter-font-ui);overflow:hidden;transition:border-color var(--jotter-transition),box-shadow var(--jotter-transition)}.jotter--focused{border-color:var(--jotter-border-focus);box-shadow:0 0 0 3px #7a6a4a1a}.jotter--disabled{opacity:.55;pointer-events:none}.jotter-toolbar{display:flex;align-items:center;flex-wrap:wrap;gap:2px;padding:6px 8px;background:var(--jotter-surface);border-bottom:1px solid var(--jotter-border)}.jotter-select{appearance:none;-webkit-appearance:none;background:transparent;border:1px solid var(--jotter-border);border-radius:var(--jotter-radius);color:var(--jotter-text);font-family:var(--jotter-font-ui);font-size:11px;letter-spacing:.04em;padding:4px 8px;height:28px;cursor:pointer;flex-shrink:0;transition:border-color var(--jotter-transition),background var(--jotter-transition)}.jotter-select{min-width:108px;text-transform:uppercase}.jotter-select--font{min-width:130px;text-transform:none}.jotter-select--size{min-width:68px;text-transform:none}.jotter-select--theme{min-width:90px;text-transform:none}.jotter-select:hover{border-color:var(--jotter-accent);background:var(--jotter-btn-hover)}.jotter-select:focus{outline:none;border-color:var(--jotter-accent)}.jotter-select option{background:var(--jotter-surface2);color:var(--jotter-text)}.jotter-btn{display:flex;align-items:center;justify-content:center;flex-direction:column;width:32px;height:30px;padding:0;border:none;border-radius:var(--jotter-radius);background:transparent;color:var(--jotter-text-muted);cursor:pointer;flex-shrink:0;transition:color var(--jotter-transition),background var(--jotter-transition);position:relative}.jotter-btn .material-icons{pointer-events:none;font-size:18px;line-height:1;user-select:none}.jotter-btn:hover{color:var(--jotter-accent);background:var(--jotter-btn-hover)}.jotter-btn--active{color:var(--jotter-accent)!important;background:var(--jotter-btn-active-bg)!important}.jotter-btn--text{width:auto;padding:0 10px;font-family:var(--jotter-font-ui);font-size:11px;letter-spacing:.08em;text-transform:uppercase;border:1px solid var(--jotter-border)}.jotter-sep{width:1px;height:18px;background:var(--jotter-border);margin:0 4px;flex-shrink:0}.jotter-color-wrap{display:inline-flex;align-items:center;flex-shrink:0}.jotter-color-input{position:absolute;width:0;height:0;opacity:0;pointer-events:none}.jotter-color-btn{width:32px;height:34px;gap:0;padding-bottom:3px}.jotter-color-swatch{display:block;width:18px;height:3px;border-radius:1px;pointer-events:none;flex-shrink:0}.jotter-editor-wrap{position:relative;flex:1;overflow-y:auto;background:var(--jotter-bg);scrollbar-width:thin;scrollbar-color:var(--jotter-border) transparent}.jotter-editor-wrap::-webkit-scrollbar{width:6px}.jotter-editor-wrap::-webkit-scrollbar-track{background:transparent}.jotter-editor-wrap::-webkit-scrollbar-thumb{background:var(--jotter-border);border-radius:3px}.jotter-editor{outline:none;padding:24px 28px;min-height:200px;font-family:var(--jotter-font-editor);font-size:16px;line-height:1.75;color:var(--jotter-text);caret-color:auto;word-break:break-word}.jotter-source{display:none;width:100%;min-height:200px;padding:24px 28px;background:var(--jotter-bg);color:#3a6030;font-family:var(--jotter-font-ui);font-size:13px;line-height:1.7;border:none;outline:none;resize:vertical;caret-color:var(--jotter-accent);tab-size:2;white-space:pre;overflow-wrap:normal;overflow-x:auto}.jotter--source-mode .jotter-btn:not([data-custom=toggleSource]),.jotter--source-mode .jotter-select,.jotter--source-mode .jotter-color-btn{opacity:.35;pointer-events:none}.jotter-editor:empty:before{content:attr(data-placeholder);color:var(--jotter-text-muted);pointer-events:none;font-style:italic}.jotter-editor .jotter-bookmark{display:none}.jotter-editor h1,.jotter-editor h2,.jotter-editor h3,.jotter-editor h4,.jotter-editor h5,.jotter-editor h6{text-transform:none;font-family:var(--ed-heading-font, inherit);letter-spacing:var(--ed-heading-tracking, normal)}.jotter-editor h1{font-size:2em;font-weight:700;margin:.6em 0 .3em;color:var(--ed-h1, inherit);border-bottom:var(--ed-h1-rule, none);padding-bottom:.25em}.jotter-editor h2{font-size:1.5em;font-weight:600;margin:.75em 0 .25em;color:var(--ed-h2, inherit)}.jotter-editor h3{font-size:1.2em;font-weight:600;margin:.75em 0 .25em;color:var(--ed-h3, inherit)}.jotter-editor h4{font-size:1em;font-weight:600;margin:.75em 0 .25em;color:var(--ed-h4, inherit)}.jotter-editor p{margin:0 0 .85em}.jotter-editor a{color:var(--ed-link, -webkit-link);text-decoration-color:var(--ed-link-deco, auto);text-underline-offset:3px}.jotter-editor a:hover{text-decoration-color:var(--ed-link, -webkit-link)}.jotter-editor strong,.jotter-editor b{color:var(--ed-strong, inherit);font-weight:700}.jotter-editor em,.jotter-editor i{color:var(--ed-em, inherit)}.jotter-editor blockquote{margin:1em 0;padding:8px 0 8px 20px;font-style:italic;border-left:3px solid var(--ed-quote-bar, #ccc);color:var(--ed-quote, inherit)}.jotter-editor pre{font-family:var(--ed-code-font, monospace);font-size:.875em;margin:.75em 0;padding:12px 16px;overflow-x:auto;white-space:pre-wrap;background:var(--ed-code-bg, transparent);color:var(--ed-code-text, inherit);border:1px solid var(--ed-code-border, transparent);border-radius:var(--jotter-radius)}.jotter-editor code{font-family:var(--ed-code-font, monospace);font-size:.875em;padding:1px 4px;background:var(--ed-code-bg, transparent);color:var(--ed-code-text, inherit);border:1px solid var(--ed-code-border, transparent);border-radius:2px}.jotter-editor ul,.jotter-editor ol{padding-left:24px;margin:.5em 0 .85em}.jotter-editor li{margin-bottom:.25em}.jotter-editor ul li::marker{color:var(--ed-marker, inherit)}.jotter-editor ol li::marker{color:var(--ed-marker, inherit)}.jotter-editor hr{border:none;border-top:1px solid var(--ed-hr, currentColor);opacity:.2;margin:1.5em 0}.jotter-editor sub,.jotter-editor sup{font-size:.75em}.jotter-editor ::selection{background:var(--ed-selection, highlight)}.jotter-editor table{border-collapse:collapse;width:100%;margin:.75em 0;font-size:.95em}.jotter-editor th,.jotter-editor td{border:1px solid var(--ed-table-border, #ccc);padding:7px 12px;text-align:left;vertical-align:top;min-width:40px}.jotter-editor th{background:var(--ed-th-bg, transparent);color:var(--ed-th-text, inherit);font-family:var(--ed-heading-font, inherit);font-size:.85em;font-weight:600;text-transform:none}.jotter-editor[data-theme=warm]{--ed-heading-font: "DM Mono", "Fira Mono", monospace;--ed-heading-tracking: -.01em;--ed-caret: #7a6a4a;--ed-selection: rgba(122, 106, 74, .18);--ed-h1: #7a6a4a;--ed-h2: #4a3e28;--ed-h3: #5a4e38;--ed-h4: #9a9488;--ed-h1-rule: 1px solid #d8d4cc;--ed-link: #7a6a4a;--ed-link-deco: rgba(122, 106, 74, .35);--ed-strong: #1a1612;--ed-em: #3a3028;--ed-quote: #7a7468;--ed-quote-bar: #7a6a4a;--ed-code-font: "DM Mono", "Fira Mono", monospace;--ed-code-bg: #eceae5;--ed-code-border: #d8d4cc;--ed-code-text: #3a6030;--ed-marker: #7a6a4a;--ed-hr: #d8d4cc;--ed-th-bg: #f4f3f0;--ed-th-text: #7a6a4a;--ed-table-border: #d8d4cc}.jotter-editor[data-theme=ink]{--ed-heading-font: "DM Mono", "Fira Mono", monospace;--ed-heading-tracking: -.01em;--ed-caret: #1a2a4a;--ed-selection: rgba(26, 42, 74, .14);--ed-h1: #0d1f3c;--ed-h2: #1a2a4a;--ed-h3: #243560;--ed-h4: #5a6888;--ed-h1-rule: 1px solid #b8c4d8;--ed-link: #1a4a8a;--ed-link-deco: rgba(26, 74, 138, .3);--ed-strong: #0a1428;--ed-em: #2a3a5a;--ed-quote: #4a5a78;--ed-quote-bar: #1a4a8a;--ed-code-font: "DM Mono", "Fira Mono", monospace;--ed-code-bg: #eef0f6;--ed-code-border: #c8cedd;--ed-code-text: #1a4a3a;--ed-marker: #1a4a8a;--ed-hr: #b8c4d8;--ed-th-bg: #eef0f6;--ed-th-text: #1a2a4a;--ed-table-border: #b8c4d8}.jotter-editor[data-theme=forest]{--ed-heading-font: "DM Mono", "Fira Mono", monospace;--ed-heading-tracking: -.01em;--ed-caret: #1a3a28;--ed-selection: rgba(26, 58, 40, .14);--ed-h1: #1a3a28;--ed-h2: #1e4430;--ed-h3: #2a5a40;--ed-h4: #5a7a68;--ed-h1-rule: 1px solid #b0ccc0;--ed-link: #1a6040;--ed-link-deco: rgba(26, 96, 64, .3);--ed-strong: #0e2018;--ed-em: #2a4038;--ed-quote: #3a5a48;--ed-quote-bar: #1a6040;--ed-code-font: "DM Mono", "Fira Mono", monospace;--ed-code-bg: #eef5f0;--ed-code-border: #c0d8c8;--ed-code-text: #1a5828;--ed-marker: #1a6040;--ed-hr: #b0ccc0;--ed-th-bg: #eef5f0;--ed-th-text: #1a3a28;--ed-table-border: #b0ccc0}.jotter-editor .jotter-video-wrap{position:relative;padding-bottom:56.25%;height:0;overflow:hidden;margin:.75em 0;border-radius:var(--jotter-radius);border:1px solid var(--jotter-border)}.jotter-editor .jotter-video-wrap iframe{position:absolute;top:0;left:0;width:100%;height:100%;border:none;z-index:1}.jotter-editor .jotter-embed-wrap{position:relative;display:block;width:100%;margin:.75em 0}.jotter-media-frame{position:absolute;display:none;box-sizing:border-box;border:2px solid var(--jotter-accent);border-radius:2px;pointer-events:none;z-index:5}.jotter-media-frame--visible{display:block}.jotter-resize-handle{position:absolute;width:10px;height:10px;background:var(--jotter-bg);border:2px solid var(--jotter-accent);border-radius:50%;pointer-events:auto;transform:translate(-50%,-50%)}.jotter-resize-handle--nw{top:0;left:0;cursor:nwse-resize}.jotter-resize-handle--ne{top:0;left:100%;cursor:nesw-resize}.jotter-resize-handle--sw{top:100%;left:0;cursor:nesw-resize}.jotter-resize-handle--se{top:100%;left:100%;cursor:nwse-resize}.jotter-resize-handle--w{top:50%;left:0;cursor:ew-resize}.jotter-resize-handle--e{top:50%;left:100%;cursor:ew-resize}.jotter--source-mode .jotter-media-frame{display:none!important}.jotter-media-shield{position:absolute;inset:0;z-index:2;background:transparent;cursor:pointer}.jotter-status{display:flex;align-items:center;gap:16px;padding:0 14px;height:var(--jotter-status-h);min-height:var(--jotter-status-h);background:var(--jotter-surface);border-top:1px solid var(--jotter-border);font-size:10.5px;letter-spacing:.06em;text-transform:uppercase;color:var(--jotter-text-muted)}.jotter-status-mode{margin-left:auto;color:var(--jotter-accent);font-weight:600}.jotter-popup{display:none;position:fixed;z-index:9999;background:#fff;border:1px solid #d8d4cc;border-radius:5px;box-shadow:0 8px 24px #0000001f,0 2px 6px #00000012;min-width:220px;max-width:360px}.jotter-popup--visible{display:block}.jotter-popup-inner{padding:14px}.jotter-popup-title{font-family:var(--jotter-font-ui);font-size:10px;text-transform:uppercase;letter-spacing:.12em;color:#9a9488;margin-bottom:10px;padding-bottom:8px;border-bottom:1px solid #d8d4cc}.jotter-popup-hint{font-size:11px;color:#9a9488;margin-top:8px;text-align:center;letter-spacing:.04em}.jotter-popup-form{display:flex;flex-direction:column;gap:6px;min-width:280px}.jotter-popup-label{font-size:10px;text-transform:uppercase;letter-spacing:.08em;color:#9a9488;margin-top:4px}.jotter-popup-input,.jotter-popup-select,.jotter-popup-textarea{width:100%;background:#f8f7f4;border:1px solid #d8d4cc;border-radius:3px;color:#1e1c18;font-family:DM Mono,Fira Mono,monospace;font-size:12px;padding:7px 9px;outline:none;transition:border-color .12s;resize:vertical}.jotter-popup-input:focus,.jotter-popup-select:focus,.jotter-popup-textarea:focus{border-color:#7a6a4a}.jotter-popup-select{appearance:auto;cursor:pointer;resize:none}.jotter-input--error{border-color:#b85050!important}.jotter-popup-submit{margin-top:6px;padding:7px 14px;background:#7a6a4a14;border:1px solid #7a6a4a;border-radius:3px;color:#7a6a4a;font-family:DM Mono,Fira Mono,monospace;font-size:11px;letter-spacing:.08em;text-transform:uppercase;cursor:pointer;transition:background .12s}.jotter-popup-submit:hover{background:#7a6a4a29}.jotter-table-grid{display:grid;gap:3px}.jotter-table-cell{width:18px;height:18px;border:1px solid #d8d4cc;border-radius:2px;cursor:pointer;transition:border-color 80ms,background 80ms}.jotter-table-cell--active{background:#7a6a4a24;border-color:#7a6a4a}.jotter-char-grid{display:flex;flex-wrap:wrap;gap:2px;max-width:300px;max-height:220px;overflow-y:auto;scrollbar-width:thin;scrollbar-color:#d8d4cc transparent}.jotter-char-btn{display:flex;align-items:center;justify-content:center;width:28px;height:28px;border:1px solid #d8d4cc;border-radius:3px;background:transparent;color:#1e1c18;font-size:14px;cursor:pointer;transition:background 80ms,border-color 80ms,color 80ms;flex-shrink:0}.jotter-char-btn:hover{background:#7a6a4a1a;border-color:#7a6a4a;color:#7a6a4a}.jotter-lorem-btn{display:block;width:100%;padding:9px 12px;background:transparent;border:1px solid #d8d4cc;border-radius:3px;color:#1e1c18;font-family:DM Mono,Fira Mono,monospace;font-size:11px;letter-spacing:.04em;text-align:left;cursor:pointer;margin-bottom:4px;transition:background .1s,border-color .1s,color .1s}.jotter-lorem-btn:hover{background:#7a6a4a12;border-color:#7a6a4a;color:#7a6a4a}.jotter-btn:focus-visible,.jotter-select:focus-visible,.jotter-char-btn:focus-visible,.jotter-lorem-btn:focus-visible,.jotter-popup-submit:focus-visible,.jotter-table-cell:focus-visible{outline:2px solid var(--jotter-accent);outline-offset:1px}
@@ -1,5 +1,5 @@
1
- var _={source:{custom:"toggleSource",label:"Source",title:"Edit HTML Source"},sep:{type:"sep"},blockformat:{type:"blockformat"},fontfamily:{type:"fontfamily"},fontsize:{type:"fontsize"},theme:{type:"theme"},undo:{cmd:"undo",icon:"undo",title:"Undo (Ctrl+Z)"},redo:{cmd:"redo",icon:"redo",title:"Redo (Ctrl+Y)"},bold:{cmd:"bold",icon:"format_bold",title:"Bold (Ctrl+B)"},italic:{cmd:"italic",icon:"format_italic",title:"Italic (Ctrl+I)"},underline:{cmd:"underline",icon:"format_underlined",title:"Underline (Ctrl+U)"},strike:{cmd:"strikeThrough",icon:"strikethrough_s",title:"Strikethrough"},subscript:{cmd:"subscript",icon:"subscript",title:"Subscript"},superscript:{cmd:"superscript",icon:"superscript",title:"Superscript"},code:{custom:"code",icon:"code",title:"Inline Code"},copy:{cmd:"copy",icon:"content_copy",title:"Copy"},cut:{cmd:"cut",icon:"content_cut",title:"Cut"},paste:{cmd:"paste",icon:"content_paste",title:"Paste"},clearFormat:{cmd:"removeFormat",icon:"format_clear",title:"Clear Formatting"},alignLeft:{cmd:"justifyLeft",icon:"format_align_left",title:"Align Left"},alignCenter:{cmd:"justifyCenter",icon:"format_align_center",title:"Align Center"},alignRight:{cmd:"justifyRight",icon:"format_align_right",title:"Align Right"},bullets:{cmd:"insertUnorderedList",icon:"format_list_bulleted",title:"Bullet List"},numbered:{cmd:"insertOrderedList",icon:"format_list_numbered",title:"Numbered List"},link:{type:"popup",id:"link",icon:"insert_link",title:"Insert Link"},unlink:{cmd:"unlink",icon:"link_off",title:"Remove Link"},foreColor:{type:"color",cmd:"foreColor",icon:"format_color_text",title:"Text Color"},hiliteColor:{type:"color",cmd:"hiliteColor",icon:"format_color_fill",title:"Background Color"},image:{type:"popup",id:"image",icon:"image",title:"Insert Image"},video:{type:"popup",id:"video",icon:"smart_display",title:"Insert YouTube Video"},table:{type:"popup",id:"table",icon:"table_chart",title:"Insert Table"},embed:{type:"popup",id:"embed",icon:"html",title:"Insert Embed"},symbol:{type:"popup",id:"symbol",icon:"emoji_symbols",title:"Insert Symbol"},specialChar:{type:"popup",id:"specialchar",icon:"format_shapes",title:"Special Characters"},lorem:{type:"popup",id:"lorem",icon:"history_edu",title:"Insert Lorem Ipsum"}};Object.values(_).forEach(Object.freeze);Object.freeze(_);var s=_,h={minimal:[s.source,s.sep,s.bold,s.italic,s.underline,s.sep,s.link,s.unlink],writing:[s.source,s.sep,s.undo,s.redo,s.sep,s.blockformat,s.sep,s.bold,s.italic,s.underline,s.strike,s.sep,s.bullets,s.numbered,s.sep,s.link,s.unlink,s.sep,s.image],full:[s.source,s.sep,s.undo,s.redo,s.sep,s.copy,s.cut,s.paste,s.sep,s.clearFormat,s.sep,s.blockformat,s.fontfamily,s.fontsize,s.sep,s.bold,s.italic,s.underline,s.strike,s.subscript,s.superscript,s.code,s.sep,s.foreColor,s.hiliteColor,s.sep,s.alignLeft,s.alignCenter,s.alignRight,s.sep,s.bullets,s.numbered,s.sep,s.link,s.unlink,s.sep,s.image,s.video,s.table,s.embed,s.symbol,s.specialChar,s.lorem,s.sep,s.theme]};Object.values(h).forEach(Object.freeze);Object.freeze(h);var y=h.full,S={image:"onRequestImage",link:"onRequestLink",video:"onRequestVideo",embed:"onRequestEmbed"},C=[{label:"Paragraph",tag:"p"},{label:"Heading 1",tag:"h1"},{label:"Heading 2",tag:"h2"},{label:"Heading 3",tag:"h3"},{label:"Heading 4",tag:"h4"},{label:"Pre / Code",tag:"pre"},{label:"Blockquote",tag:"blockquote"}],x=["Arial","Arial Black","Comic Sans MS","Courier New","Georgia","Impact","Lucida Console","Palatino Linotype","Tahoma","Times New Roman","Trebuchet MS","Verdana"],T=[8,9,10,11,12,14,16,18,20,24,28,32,36,48,72],L=["\u2190","\u2192","\u2191","\u2193","\u2194","\u2195","\u21D0","\u21D2","\u21D1","\u21D3","\u21D4","\u2022","\xB7","\u25E6","\u25CB","\u25CF","\u25A1","\u25A0","\u25C6","\u25C7","\u25B2","\u25BC","\u2605","\u2606","\u2660","\u2663","\u2665","\u2666","\u2713","\u2717","\u2715","\u2718","\u2248","\u2260","\u2261","\u2264","\u2265","\xF7","\xD7","\xB1","\u221E","\u221A","\u2211","\u220F","\u222B","\u2202","\u2206","\u2207","\u03C0","\u03A9","\u03BC","\u03B1","\u03B2","\u03B3","\xA9","\xAE","\u2122","\xA7","\xB6","\u2020","\u2021","\xB0","\u2032","\u2033","\u2030","\u201C","\u201D","\u2018","\u2019","\xAB","\xBB","\u2039","\u203A","\u2014","\u2013","\u2026","\xBF","\xA1","\u20AC","\xA3","\xA5","\xA2","\u20B9","\u20BD","\u20BF"],w=["\xC0","\xC1","\xC2","\xC3","\xC4","\xC5","\xC6","\xC7","\xC8","\xC9","\xCA","\xCB","\xCC","\xCD","\xCE","\xCF","\xD0","\xD1","\xD2","\xD3","\xD4","\xD5","\xD6","\xD8","\xD9","\xDA","\xDB","\xDC","\xDD","\xDE","\xDF","\xE0","\xE1","\xE2","\xE3","\xE4","\xE5","\xE6","\xE7","\xE8","\xE9","\xEA","\xEB","\xEC","\xED","\xEE","\xEF","\xF0","\xF1","\xF2","\xF3","\xF4","\xF5","\xF6","\xF8","\xF9","\xFA","\xFB","\xFC","\xFD","\xFE","\xFF","\u0152","\u0153","\u0160","\u0161","\u0178","\u017D","\u017E"],k=[{id:"default",label:"Default"},{id:"warm",label:"Warm"},{id:"ink",label:"Ink / Navy"},{id:"forest",label:"Forest"}],M=[{label:"Short \u2014 1 sentence",text:"Lorem ipsum dolor sit amet, consectetur adipiscing elit."},{label:"Medium \u2014 1 paragraph",text:"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat."},{label:"Long \u2014 3 paragraphs",isHTML:!0,text:"<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris.</p><p>Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p><p>Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo.</p>"}],m=class{constructor(t,e={}){if(this._target=typeof t=="string"?document.querySelector(t):t,!this._target)throw new Error("[JotterJS] Target element not found.");this._options=Object.assign({placeholder:"Start typing\u2026",height:"320px",theme:"default",onChange:null,onFocus:null,onBlur:null,onRequestImage:null,onRequestLink:null,onRequestVideo:null,onRequestEmbed:null},e),this._listeners={},this._bookmarks=new Map,this._bmSeq=0,this._savedBookmark=null,this._externalBookmark=null,this._externalDepth=0,this._changeCount=0,this._destroyed=!1,this._lastForeColor="#e8e4d8",this._lastHiliteColor="#c8a96e",this._init()}_init(){let t=this._target.innerHTML||"";this._target.innerHTML="",this._target.classList.add("jotter-host"),this._root=document.createElement("div"),this._root.className="htmled",this._toolbar=this._buildToolbar(),this._editorWrap=document.createElement("div"),this._editorWrap.className="jotter-editor-wrap",this._editor=document.createElement("div"),this._editor.className="jotter-editor",this._editor.contentEditable="true",this._editor.setAttribute("data-placeholder",this._options.placeholder),this._editor.style.minHeight=this._options.height,this._editor.innerHTML=this._sanitize(t),this._editor.spellcheck=!0,document.execCommand("defaultParagraphSeparator",!1,"p"),this._source=document.createElement("textarea"),this._source.className="jotter-source",this._source.setAttribute("aria-label","HTML source"),this._source.setAttribute("spellcheck","false"),this._source.style.minHeight=this._options.height,this._sourceMode=!1,this._statusBar=this._buildStatusBar(),this._editorWrap.appendChild(this._editor),this._editorWrap.appendChild(this._source),this._root.appendChild(this._toolbar),this._root.appendChild(this._editorWrap),this._root.appendChild(this._statusBar),this._target.appendChild(this._root),this._popup=this._buildPopupContainer(),document.body.appendChild(this._popup),this._bindEvents(),this._updateToolbarState(),this._updateStatus(),this.setTheme(this._options.theme)}_buildToolbar(){let t=document.createElement("div");return t.className="jotter-toolbar",this._toolbarEl=t,(this._options.toolbar||y).forEach(e=>{let o=this._buildAction(e);o&&t.appendChild(o)}),t}_buildAction(t){if(typeof t.onClick=="function")return this._buildBtn(t);switch(t.type){case"sep":return this._makeSep();case"blockformat":return this._buildBlockFormatSelect();case"fontfamily":return this._buildFontFamilySelect();case"fontsize":return this._buildFontSizeSelect();case"color":return this._buildColorBtn(t);case"popup":return this._buildPopupBtn(t);case"theme":return this._buildThemeSelect();default:return this._buildBtn(t)}}_makeSep(){let t=document.createElement("span");return t.className="jotter-sep",t}_bindActivation(t,e){t.addEventListener("mousedown",o=>{o.preventDefault(),e(!1)}),t.addEventListener("keydown",o=>{o.key!=="Enter"&&o.key!==" "&&o.key!=="Spacebar"||o.repeat||(o.preventDefault(),e(!0))})}_returnFocus(t,e){e&&this._isInternalTarget(document.activeElement)&&t.focus()}_buildBtn(t){let e=document.createElement("button");if(e.type="button",e.className="jotter-btn",t.cmd&&(e.dataset.cmd=t.cmd),t.custom&&(e.dataset.custom=t.custom),e.title=t.title,e.setAttribute("aria-label",t.title),t.label)e.classList.add("jotter-btn--text"),e.appendChild(document.createTextNode(t.label));else{let o=document.createElement("span");o.className="material-icons",o.textContent=t.icon,e.appendChild(o)}return this._bindActivation(e,o=>{this._editor.focus(),this._applyEdit(()=>{if(t.onClick)t.onClick(this);else if(t.custom==="toggleSource")this._toggleSourceMode();else if(t.custom==="code")this._toggleInlineCode();else if(t.cmd==="copy")document.execCommand("copy");else if(t.cmd==="cut")document.execCommand("cut");else if(t.cmd==="paste")this._pasteFromClipboard();else if(t.prompt){let i=window.prompt(t.prompt);i&&document.execCommand(t.cmd,!1,i)}else document.execCommand(t.cmd,!1,null)}),this._updateToolbarState(),this._returnFocus(e,o)}),e}_bindSelectCaret(t){let e={viaKeyboard:!1};return t.addEventListener("mousedown",()=>{e.viaKeyboard=!1,this._saveBookmark()}),t.addEventListener("keydown",o=>{o.key==="Tab"||o.key==="Escape"||(e.viaKeyboard=!0,this._savedBookmark==null&&this._saveBookmark())}),e}_buildBlockFormatSelect(){let t=document.createElement("select");t.className="jotter-select",t.title="Block format",t.dataset.id="blockformat",C.forEach(({label:o,tag:i})=>{let n=document.createElement("option");n.value=i,n.textContent=o,t.appendChild(n)});let e=this._bindSelectCaret(t);return t.addEventListener("change",()=>{this._restoreSavedBookmark(),this._applyEdit(()=>document.execCommand("formatBlock",!1,t.value)),this._returnFocus(t,e.viaKeyboard)}),t}_buildFontFamilySelect(){let t=document.createElement("select");t.className="jotter-select jotter-select--font",t.title="Font family",t.dataset.id="fontfamily";let e=document.createElement("option");e.value="",e.textContent="Font",t.appendChild(e),x.forEach(i=>{let n=document.createElement("option");n.value=i,n.textContent=i,n.style.fontFamily=i,t.appendChild(n)});let o=this._bindSelectCaret(t);return t.addEventListener("change",()=>{t.value&&(this._restoreSavedBookmark(),this._applyEdit(()=>document.execCommand("fontName",!1,t.value)),this._returnFocus(t,o.viaKeyboard))}),t}_buildFontSizeSelect(){let t=document.createElement("select");t.className="jotter-select jotter-select--size",t.title="Font size",t.dataset.id="fontsize";let e=document.createElement("option");e.value="",e.textContent="Size",t.appendChild(e),T.forEach(i=>{let n=document.createElement("option");n.value=i,n.textContent=`${i}px`,t.appendChild(n)});let o=this._bindSelectCaret(t);return t.addEventListener("change",()=>{t.value&&(this._restoreSavedBookmark(),this._applyEdit(()=>this._applyFontSize(t.value)),this._returnFocus(t,o.viaKeyboard))}),t}_buildThemeSelect(){let t=document.createElement("select");return t.className="jotter-select jotter-select--theme",t.title="Editor theme",t.dataset.id="theme",k.forEach(({id:e,label:o})=>{let i=document.createElement("option");i.value=e,i.textContent=o,t.appendChild(i)}),t.value=this._options.theme,t.addEventListener("change",()=>this.setTheme(t.value)),this._themeSelect=t,t}_buildColorBtn(t){let e=document.createElement("span");e.className="jotter-color-wrap";let o=document.createElement("button");o.type="button",o.className="jotter-btn jotter-color-btn",o.dataset.cmd=t.cmd,o.title=t.title,o.setAttribute("aria-label",t.title);let i=document.createElement("span");i.className="material-icons",i.textContent=t.icon,o.appendChild(i);let n=document.createElement("span");n.className="jotter-color-swatch";let r=t.cmd==="foreColor"?this._lastForeColor:this._lastHiliteColor;n.style.background=r,o.appendChild(n);let a=document.createElement("input");a.type="color",a.className="jotter-color-input",a.value=r,a.tabIndex=-1;let u=!1;return a.addEventListener("change",()=>{let p=a.value;n.style.background=p,t.cmd==="foreColor"?this._lastForeColor=p:this._lastHiliteColor=p,this._restoreSavedBookmark(),this._applyEdit(()=>document.execCommand(t.cmd,!1,p)),this._returnFocus(o,u)}),this._bindActivation(o,p=>{u=p,this._saveBookmark(),a.click()}),e.appendChild(o),e.appendChild(a),e}_buildPopupBtn(t){let e=document.createElement("button");e.type="button",e.className="jotter-btn",e.title=t.title,e.setAttribute("aria-label",t.title);let o=document.createElement("span");return o.className="material-icons",o.textContent=t.icon,e.appendChild(o),this._bindActivation(e,i=>{let n=this._resolverFor(t.id);if(n){this._hidePopup(),this._runResolver(t.id,n);return}if(this._saveBookmark(),this._popupVisible()&&this._popup.dataset.popupId===t.id){this._hidePopup();return}this._showPopup(e,this._buildPopupContent(t.id),t.id),i&&this._focusPopup()}),e}_focusPopup(){let t=this._popup.querySelector('input, textarea, select, button, [tabindex]:not([tabindex="-1"])');t&&t.focus()}_buildPopupContainer(){let t=document.createElement("div");return t.className="jotter-popup",t.setAttribute("role","dialog"),t}_showPopup(t,e,o){this._popup.innerHTML="",this._popup.appendChild(e),this._popup.dataset.popupId=o,this._popup.classList.add("jotter-popup--visible");let i=t.getBoundingClientRect();this._popup.style.top=i.bottom+6+"px",this._popup.style.left=i.left+"px",this._popup.style.right="auto",requestAnimationFrame(()=>{let n=this._popup.getBoundingClientRect();n.right>window.innerWidth-8&&(this._popup.style.left=Math.max(8,i.left-(n.right-window.innerWidth+8))+"px")})}_popupVisible(){return this._popup.classList.contains("jotter-popup--visible")}_hidePopup(){this._popup.classList.remove("jotter-popup--visible"),this._popup.dataset.popupId="",this._releaseSavedBookmark()}_buildPopupContent(t){switch(t){case"link":return this._popupLink();case"table":return this._popupTable();case"image":return this._popupImage();case"video":return this._popupVideo();case"embed":return this._popupEmbed();case"symbol":return this._popupSymbol();case"specialchar":return this._popupSpecialChar();case"lorem":return this._popupLorem();default:{let e=document.createElement("div");return e.className="jotter-popup-inner",e.textContent="Unknown: "+t,e}}}_popupTable(){let t=document.createElement("div");t.className="jotter-popup-inner";let e=this._popupTitle("Insert Table");t.appendChild(e);let o=10,i=8,n=document.createElement("div");n.className="jotter-table-grid",n.style.gridTemplateColumns=`repeat(${o}, 1fr)`,n.setAttribute("role","grid"),n.setAttribute("aria-label","Table size");let r=document.createElement("div");r.className="jotter-popup-hint",r.textContent="Hover or arrow to select size";let a=[],u=(c,l)=>{r.textContent=`${c+1} \xD7 ${l+1} table`,a.forEach(d=>{d.classList.toggle("jotter-table-cell--active",+d.dataset.r<=c&&+d.dataset.c<=l)})};for(let c=0;c<i;c++)for(let l=0;l<o;l++){let d=document.createElement("span");d.className="jotter-table-cell",d.dataset.r=c,d.dataset.c=l,d.setAttribute("role","gridcell"),d.setAttribute("aria-label",`${c+1} by ${l+1} table`),d.tabIndex=c===0&&l===0?0:-1,d.addEventListener("mouseenter",()=>u(c,l)),d.addEventListener("focus",()=>u(c,l)),d.addEventListener("click",()=>this._insertTable(c+1,l+1)),a.push(d),n.appendChild(d)}let p={ArrowRight:[0,1],ArrowLeft:[0,-1],ArrowDown:[1,0],ArrowUp:[-1,0]};return n.addEventListener("keydown",c=>{let l=a.indexOf(document.activeElement)===-1?null:document.activeElement;if(!l)return;let d=+l.dataset.r,g=+l.dataset.c;if(c.key==="Enter"||c.key===" "||c.key==="Spacebar"){c.preventDefault(),this._insertTable(d+1,g+1);return}let f=p[c.key];if(!f)return;c.preventDefault();let v=Math.min(i-1,Math.max(0,d+f[0])),E=Math.min(o-1,Math.max(0,g+f[1])),b=a[v*o+E];b!==l&&(l.tabIndex=-1,b.tabIndex=0,b.focus())}),t.appendChild(n),t.appendChild(r),t}_commitPopup(t){this._restoreSavedBookmark(),this._hidePopup(),this._applyEdit(t)}_insertTable(t,e){let o="<table><tbody>";for(let i=0;i<t;i++){o+="<tr>";for(let n=0;n<e;n++)o+=i===0?"<th><br></th>":"<td><br></td>";o+="</tr>"}o+="</tbody></table><p><br></p>",this._commitPopup(()=>document.execCommand("insertHTML",!1,o))}_popupLink(){let t=document.createElement("div");t.className="jotter-popup-inner jotter-popup-form",t.appendChild(this._popupTitle("Insert Link"));let e=this._anchorInSelection(),o=this._selectedText(),i=this._makeField(t,"URL","url","https://"),n=this._makeField(t,"Link text (leave blank to keep selection)","text",""),r=this._makeField(t,"Title / tooltip","text",""),a=document.createElement("label");a.className="jotter-popup-label",a.textContent="Open in";let u=document.createElement("select");return u.className="jotter-popup-select",[["(same window)",""],["New tab (_blank)","_blank"],["Parent frame (_parent)","_parent"],["Top frame (_top)","_top"]].forEach(([p,c])=>{let l=document.createElement("option");l.value=c,l.textContent=p,u.appendChild(l)}),t.appendChild(a),t.appendChild(u),e?(i.value=e.getAttribute("href")||"",n.value=e.textContent||"",r.value=e.getAttribute("title")||"",u.value=e.getAttribute("target")||""):o&&(n.value=o),t.appendChild(this._makeSubmitBtn(e?"Update Link":"Insert Link",()=>{let p=i.value.trim();if(!p)return;let c=n.value.trim()||o||p,l=r.value.trim(),d=u.value;this._commitPopup(()=>{e?(e.href=p,d?e.target=d:e.removeAttribute("target"),l?e.title=l:e.removeAttribute("title"),e.textContent=c):document.execCommand("insertHTML",!1,this._linkHTML({href:p,text:c,title:l,target:d}))})})),t}_popupImage(){let t=document.createElement("div");t.className="jotter-popup-inner jotter-popup-form",t.appendChild(this._popupTitle("Insert Image"));let e=this._makeField(t,"Image URL","text","https://example.com/image.jpg"),o=this._makeField(t,"Alt text","text","Descriptive text"),i=this._makeField(t,"Width (e.g. 400px or 50%)","text","");return t.appendChild(this._makeSubmitBtn("Insert Image",()=>{let n=e.value.trim();if(!n)return;let r=this._imageHTML({src:n,alt:o.value.trim(),width:i.value.trim()});this._commitPopup(()=>document.execCommand("insertHTML",!1,r))})),t}_popupVideo(){let t=document.createElement("div");t.className="jotter-popup-inner jotter-popup-form",t.appendChild(this._popupTitle("Insert YouTube Video"));let e=this._makeField(t,"YouTube URL","text","https://www.youtube.com/watch?v=...");return t.appendChild(this._makeSubmitBtn("Embed Video",()=>{let o=this._ytId(e.value.trim());if(!o){e.classList.add("jotter-input--error");return}e.classList.remove("jotter-input--error"),this._commitPopup(()=>document.execCommand("insertHTML",!1,this._videoHTML(o)))})),t}_ytId(t){for(let e of[/[?&]v=([A-Za-z0-9_-]{11})/,/youtu\.be\/([A-Za-z0-9_-]{11})/,/embed\/([A-Za-z0-9_-]{11})/]){let o=t.match(e);if(o)return o[1]}return null}_popupEmbed(){let t=document.createElement("div");t.className="jotter-popup-inner jotter-popup-form",t.appendChild(this._popupTitle("Insert Embed"));let e=document.createElement("label");e.className="jotter-popup-label",e.textContent="Paste HTML / embed code";let o=document.createElement("textarea");return o.className="jotter-popup-textarea",o.placeholder='<iframe src="..." ...></iframe>',o.rows=4,t.appendChild(e),t.appendChild(o),t.appendChild(this._makeSubmitBtn("Insert",()=>{let i=o.value.trim();i&&this._commitPopup(()=>document.execCommand("insertHTML",!1,this._embedHTML(i)))})),t}_popupSymbol(){let t=document.createElement("div");return t.className="jotter-popup-inner",t.appendChild(this._popupTitle("Insert Symbol")),t.appendChild(this._charGrid(L)),t}_popupSpecialChar(){let t=document.createElement("div");return t.className="jotter-popup-inner",t.appendChild(this._popupTitle("Special Characters")),t.appendChild(this._charGrid(w)),t}_charGrid(t){let e=document.createElement("div");return e.className="jotter-char-grid",t.forEach(o=>{let i=document.createElement("button");i.type="button",i.className="jotter-char-btn",i.textContent=o,i.title=`U+${o.codePointAt(0).toString(16).toUpperCase().padStart(4,"0")}`,this._bindActivation(i,()=>{this._commitPopup(()=>document.execCommand("insertText",!1,o))}),e.appendChild(i)}),e}_popupLorem(){let t=document.createElement("div");return t.className="jotter-popup-inner",t.appendChild(this._popupTitle("Insert Lorem Ipsum")),M.forEach(e=>{let o=document.createElement("button");o.type="button",o.className="jotter-lorem-btn",o.textContent=e.label,this._bindActivation(o,()=>{this._commitPopup(()=>document.execCommand(e.isHTML?"insertHTML":"insertText",!1,e.text))}),t.appendChild(o)}),t}_popupTitle(t){let e=document.createElement("div");return e.className="jotter-popup-title",e.textContent=t,e}_makeField(t,e,o,i){let n=document.createElement("label");n.className="jotter-popup-label",n.textContent=e;let r=document.createElement("input");return r.type=o,r.className="jotter-popup-input",r.placeholder=i,t.appendChild(n),t.appendChild(r),r}_makeSubmitBtn(t,e){let o=document.createElement("button");return o.type="button",o.className="jotter-popup-submit",o.textContent=t,o.addEventListener("click",e),o}_esc(t){return String(t).replace(/"/g,"&quot;").replace(/</g,"&lt;").replace(/>/g,"&gt;")}_imageHTML({src:t,alt:e,width:o}){let i=o?`max-width:${o}`:"max-width:100%";return`<img src="${this._esc(t)}" alt="${this._esc(e||"")}" style="${this._esc(i)}">`}_linkHTML({href:t,text:e,title:o,target:i}){let n=`href="${this._esc(t)}"`;return i&&(n+=` target="${this._esc(i)}"`),o&&(n+=` title="${this._esc(o)}"`),`<a ${n}>${this._esc(e||t)}</a>`}_videoHTML(t){return/^[A-Za-z0-9_-]{11}$/.test(t)?`<div class="jotter-video-wrap"><iframe src="https://www.youtube.com/embed/${t}" frameborder="0" allowfullscreen loading="lazy" title="YouTube video"></iframe></div><p><br></p>`:null}_embedHTML(t){return t+"<p><br></p>"}_resolverFor(t){let e=S[t],o=e?this._options[e]:null;return typeof o=="function"?o:null}async _runResolver(t,e){let o=this._resolverContext(t);this.beginExternalUI();let i=null;try{i=await e(o)}catch{i=null}if(this._destroyed)return;let n=i==null||i===!1?null:this._resolvedHTML(t,i,o);this.endExternalUI(),n&&(this._applyEdit(()=>document.execCommand("insertHTML",!1,n)),this._updateToolbarState())}_resolverContext(t){switch(t){case"image":return{src:"",alt:"",width:"",selection:this._selectedText()};case"video":return{url:"",selection:this._selectedText()};case"embed":return{html:"",selection:this._selectedText()};case"link":return this._linkContext();default:return{selection:this._selectedText()}}}_linkContext(){let t=this._anchorInSelection();if(!t){let o=this._selectedText();return{href:"",text:o,title:"",target:"",selection:o,isEdit:!1}}let e=window.getSelection();if(e){let o=document.createRange();o.selectNode(t),e.removeAllRanges(),e.addRange(o)}return{href:t.getAttribute("href")||"",text:t.textContent||"",title:t.getAttribute("title")||"",target:t.getAttribute("target")||"",selection:t.textContent||"",isEdit:!0}}_resolvedHTML(t,e,o){switch(t){case"image":{let i=typeof e=="string"?{src:e}:e,n=String(i.src||i.url||"").trim();return n?this._imageHTML({...i,src:n}):null}case"link":{let i=typeof e=="string"?{href:e}:e,n=String(i.href||i.url||"").trim();if(!n)return null;let r=String(i.text!=null?i.text:o.text||"").trim();return this._linkHTML({...i,href:n,text:r})}case"video":{let i=typeof e=="string"?{url:e}:e,n=i.id?String(i.id).trim():this._ytId(String(i.url||"").trim());return n?this._videoHTML(n):null}case"embed":{let i=String(typeof e=="string"?e:e.html||"").trim();return i?this._embedHTML(i):null}default:return null}}_selectedText(){let t=window.getSelection();return!t||!t.rangeCount?"":this._editor.contains(t.getRangeAt(0).commonAncestorContainer)?t.toString():""}_anchorInSelection(){let t=window.getSelection();if(!t||!t.rangeCount)return null;let e=t.anchorNode;if(!e||!this._editor.contains(e))return null;for(;e&&e!==this._editor;){if(e.nodeName==="A")return e;e=e.parentNode}return null}_buildStatusBar(){let t=document.createElement("div");t.className="jotter-status",this._wordCountEl=document.createElement("span"),this._wordCountEl.className="jotter-status-words",this._charCountEl=document.createElement("span"),this._charCountEl.className="jotter-status-chars";let e=document.createElement("span");return e.className="jotter-status-mode",e.textContent="HTML",t.appendChild(this._wordCountEl),t.appendChild(this._charCountEl),t.appendChild(e),t}_bindEvents(){this._editor.addEventListener("input",()=>{this._editor.querySelectorAll(":scope > div").forEach(t=>{if(t.attributes.length>0)return;let e=document.createElement("p");e.innerHTML=t.innerHTML,t.replaceWith(e)}),Array.from(this._editor.childNodes).forEach(t=>{if(t.nodeType===Node.TEXT_NODE&&t.textContent.trim()!==""){let e=window.getSelection(),o=null;if(e&&e.rangeCount){let n=e.getRangeAt(0);n.startContainer===t&&(o=n.startOffset)}let i=document.createElement("p");if(t.replaceWith(i),i.appendChild(t),o!==null){let n=document.createRange();n.setStart(t,o),n.collapse(!0),e.removeAllRanges(),e.addRange(n)}}}),this._updateStatus(),this._emitChange()}),this._editor.addEventListener("keyup",()=>this._updateToolbarState()),this._editor.addEventListener("mouseup",()=>this._updateToolbarState()),this._editor.addEventListener("focusin",t=>{this._root.classList.add("jotter--focused"),!(this._externalDepth>0)&&(this._isInternalTarget(t.relatedTarget)||(this._emit("focus"),this._options.onFocus&&this._options.onFocus()))}),this._editor.addEventListener("focusout",t=>{this._externalDepth>0||this._isInternalTarget(t.relatedTarget)||setTimeout(()=>{this._destroyed||this._externalDepth>0||this._isInternalTarget(document.activeElement)||this._popupVisible()||(this._root.classList.remove("jotter--focused"),this._emit("blur"),this._options.onBlur&&this._options.onBlur())},0)}),this._editor.addEventListener("keydown",t=>{t.key==="Tab"&&(t.preventDefault(),document.execCommand("insertHTML",!1,"&nbsp;&nbsp;&nbsp;&nbsp;"))}),this._onDocMouseDown=t=>{this._popupVisible()&&!this._popup.contains(t.target)&&!this._toolbarEl.contains(t.target)&&this._hidePopup()},document.addEventListener("mousedown",this._onDocMouseDown),this._onDocKeyDown=t=>{t.key==="Escape"&&this._popupVisible()&&(this._restoreSavedBookmark(),this._hidePopup())},document.addEventListener("keydown",this._onDocKeyDown)}_isInternalTarget(t){return!!t&&(this._root.contains(t)||this._popup.contains(t))}_toggleSourceMode(){this._sourceMode=!this._sourceMode,this._sourceMode?(this._dropBookmarks(),this._source.value=this._prettyHTML(this._richHTML()),this._editor.style.display="none",this._source.style.display="block"):(this._editor.innerHTML=this._sanitize(this._source.value),this._source.style.display="none",this._editor.style.display="",this._updateStatus(),this._emitChange()),this._root.classList.toggle("jotter--source-mode",this._sourceMode);let t=this._toolbarEl.querySelector('[data-custom="toggleSource"]');t&&t.classList.toggle("jotter-btn--active",this._sourceMode)}_prettyHTML(t){let e=0,o=" ",i=new Set(["area","base","br","col","embed","hr","img","input","link","meta","param","source","track","wbr"]),n=new Set(["a","abbr","acronym","b","bdo","big","br","button","cite","code","dfn","em","i","img","input","kbd","label","map","object","output","q","samp","select","small","span","strong","sub","sup","textarea","time","tt","u","var"]);return t.replace(/>\s+</g,"><").replace(/(<[^>]+>)/g,`
1
+ var _={source:{custom:"toggleSource",label:"Source",title:"Edit HTML Source"},sep:{type:"sep"},blockformat:{type:"blockformat"},fontfamily:{type:"fontfamily"},fontsize:{type:"fontsize"},theme:{type:"theme"},undo:{cmd:"undo",icon:"undo",title:"Undo (Ctrl+Z)"},redo:{cmd:"redo",icon:"redo",title:"Redo (Ctrl+Y)"},bold:{cmd:"bold",icon:"format_bold",title:"Bold (Ctrl+B)"},italic:{cmd:"italic",icon:"format_italic",title:"Italic (Ctrl+I)"},underline:{cmd:"underline",icon:"format_underlined",title:"Underline (Ctrl+U)"},strike:{cmd:"strikeThrough",icon:"strikethrough_s",title:"Strikethrough"},subscript:{cmd:"subscript",icon:"subscript",title:"Subscript"},superscript:{cmd:"superscript",icon:"superscript",title:"Superscript"},code:{custom:"code",icon:"code",title:"Inline Code"},copy:{cmd:"copy",icon:"content_copy",title:"Copy"},cut:{cmd:"cut",icon:"content_cut",title:"Cut"},paste:{cmd:"paste",icon:"content_paste",title:"Paste"},clearFormat:{cmd:"removeFormat",icon:"format_clear",title:"Clear Formatting"},alignLeft:{cmd:"justifyLeft",icon:"format_align_left",title:"Align Left"},alignCenter:{cmd:"justifyCenter",icon:"format_align_center",title:"Align Center"},alignRight:{cmd:"justifyRight",icon:"format_align_right",title:"Align Right"},bullets:{cmd:"insertUnorderedList",icon:"format_list_bulleted",title:"Bullet List"},numbered:{cmd:"insertOrderedList",icon:"format_list_numbered",title:"Numbered List"},link:{type:"popup",id:"link",icon:"insert_link",title:"Insert Link"},unlink:{cmd:"unlink",icon:"link_off",title:"Remove Link"},foreColor:{type:"color",cmd:"foreColor",icon:"format_color_text",title:"Text Color"},hiliteColor:{type:"color",cmd:"hiliteColor",icon:"format_color_fill",title:"Background Color"},image:{type:"popup",id:"image",icon:"image",title:"Insert Image"},video:{type:"popup",id:"video",icon:"smart_display",title:"Insert YouTube Video"},table:{type:"popup",id:"table",icon:"table_chart",title:"Insert Table"},embed:{type:"popup",id:"embed",icon:"html",title:"Insert Embed"},symbol:{type:"popup",id:"symbol",icon:"emoji_symbols",title:"Insert Symbol"},specialChar:{type:"popup",id:"specialchar",icon:"format_shapes",title:"Special Characters"},lorem:{type:"popup",id:"lorem",icon:"history_edu",title:"Insert Lorem Ipsum"}};Object.values(_).forEach(Object.freeze);Object.freeze(_);var n=_,m={minimal:[n.source,n.sep,n.bold,n.italic,n.underline,n.sep,n.link,n.unlink],writing:[n.source,n.sep,n.undo,n.redo,n.sep,n.blockformat,n.sep,n.bold,n.italic,n.underline,n.strike,n.sep,n.bullets,n.numbered,n.sep,n.link,n.unlink,n.sep,n.image],full:[n.source,n.sep,n.undo,n.redo,n.sep,n.copy,n.cut,n.paste,n.sep,n.clearFormat,n.sep,n.blockformat,n.fontfamily,n.fontsize,n.sep,n.bold,n.italic,n.underline,n.strike,n.subscript,n.superscript,n.code,n.sep,n.foreColor,n.hiliteColor,n.sep,n.alignLeft,n.alignCenter,n.alignRight,n.sep,n.bullets,n.numbered,n.sep,n.link,n.unlink,n.sep,n.image,n.video,n.table,n.embed,n.symbol,n.specialChar,n.lorem,n.sep,n.theme]};Object.values(m).forEach(Object.freeze);Object.freeze(m);var S=m.full,y={image:"onRequestImage",link:"onRequestLink",video:"onRequestVideo",embed:"onRequestEmbed"},v=[{label:"Paragraph",tag:"p"},{label:"Heading 1",tag:"h1"},{label:"Heading 2",tag:"h2"},{label:"Heading 3",tag:"h3"},{label:"Heading 4",tag:"h4"},{label:"Pre / Code",tag:"pre"},{label:"Blockquote",tag:"blockquote"}],x=["Arial","Arial Black","Comic Sans MS","Courier New","Georgia","Impact","Lucida Console","Palatino Linotype","Tahoma","Times New Roman","Trebuchet MS","Verdana"],L=[8,9,10,11,12,14,16,18,20,24,28,32,36,48,72],T=["\u2190","\u2192","\u2191","\u2193","\u2194","\u2195","\u21D0","\u21D2","\u21D1","\u21D3","\u21D4","\u2022","\xB7","\u25E6","\u25CB","\u25CF","\u25A1","\u25A0","\u25C6","\u25C7","\u25B2","\u25BC","\u2605","\u2606","\u2660","\u2663","\u2665","\u2666","\u2713","\u2717","\u2715","\u2718","\u2248","\u2260","\u2261","\u2264","\u2265","\xF7","\xD7","\xB1","\u221E","\u221A","\u2211","\u220F","\u222B","\u2202","\u2206","\u2207","\u03C0","\u03A9","\u03BC","\u03B1","\u03B2","\u03B3","\xA9","\xAE","\u2122","\xA7","\xB6","\u2020","\u2021","\xB0","\u2032","\u2033","\u2030","\u201C","\u201D","\u2018","\u2019","\xAB","\xBB","\u2039","\u203A","\u2014","\u2013","\u2026","\xBF","\xA1","\u20AC","\xA3","\xA5","\xA2","\u20B9","\u20BD","\u20BF"],M=["\xC0","\xC1","\xC2","\xC3","\xC4","\xC5","\xC6","\xC7","\xC8","\xC9","\xCA","\xCB","\xCC","\xCD","\xCE","\xCF","\xD0","\xD1","\xD2","\xD3","\xD4","\xD5","\xD6","\xD8","\xD9","\xDA","\xDB","\xDC","\xDD","\xDE","\xDF","\xE0","\xE1","\xE2","\xE3","\xE4","\xE5","\xE6","\xE7","\xE8","\xE9","\xEA","\xEB","\xEC","\xED","\xEE","\xEF","\xF0","\xF1","\xF2","\xF3","\xF4","\xF5","\xF6","\xF8","\xF9","\xFA","\xFB","\xFC","\xFD","\xFE","\xFF","\u0152","\u0153","\u0160","\u0161","\u0178","\u017D","\u017E"],C=[{id:"default",label:"Default"},{id:"warm",label:"Warm"},{id:"ink",label:"Ink / Navy"},{id:"forest",label:"Forest"}],w=[{label:"Short \u2014 1 sentence",text:"Lorem ipsum dolor sit amet, consectetur adipiscing elit."},{label:"Medium \u2014 1 paragraph",text:"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat."},{label:"Long \u2014 3 paragraphs",isHTML:!0,text:"<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris.</p><p>Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p><p>Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo.</p>"}],h=class{constructor(e,t={}){if(this._target=typeof e=="string"?document.querySelector(e):e,!this._target)throw new Error("[JotterJS] Target element not found.");this._options=Object.assign({placeholder:"Start typing\u2026",height:"320px",theme:"default",onChange:null,onFocus:null,onBlur:null,onRequestImage:null,onRequestLink:null,onRequestVideo:null,onRequestEmbed:null},t),this._listeners={},this._bookmarks=new Map,this._bmSeq=0,this._savedBookmark=null,this._externalBookmark=null,this._externalDepth=0,this._changeCount=0,this._destroyed=!1,this._lastForeColor="#e8e4d8",this._lastHiliteColor="#c8a96e",this._selectedMedia=null,this._resizeState=null,this._onResizeMove=this._onResizeMove.bind(this),this._onResizeEnd=this._onResizeEnd.bind(this),this._init()}_init(){let e=this._target.innerHTML||"";this._target.innerHTML="",this._target.classList.add("jotter-host"),this._root=document.createElement("div"),this._root.className="htmled",this._toolbar=this._buildToolbar(),this._editorWrap=document.createElement("div"),this._editorWrap.className="jotter-editor-wrap",this._editor=document.createElement("div"),this._editor.className="jotter-editor",this._editor.contentEditable="true",this._editor.setAttribute("data-placeholder",this._options.placeholder),this._editor.style.minHeight=this._options.height,this._editor.innerHTML=this._sanitize(e),this._editor.spellcheck=!0,document.execCommand("defaultParagraphSeparator",!1,"p");try{document.execCommand("enableObjectResizing",!1,!1)}catch{}try{document.execCommand("enableInlineTableEditing",!1,!1)}catch{}this._ensureMediaShields(),this._source=document.createElement("textarea"),this._source.className="jotter-source",this._source.setAttribute("aria-label","HTML source"),this._source.setAttribute("spellcheck","false"),this._source.style.minHeight=this._options.height,this._sourceMode=!1,this._statusBar=this._buildStatusBar(),this._mediaFrame=this._buildMediaFrame(),this._editorWrap.appendChild(this._editor),this._editorWrap.appendChild(this._source),this._editorWrap.appendChild(this._mediaFrame),this._root.appendChild(this._toolbar),this._root.appendChild(this._editorWrap),this._root.appendChild(this._statusBar),this._target.appendChild(this._root),this._popup=this._buildPopupContainer(),document.body.appendChild(this._popup),this._bindEvents(),this._updateToolbarState(),this._updateStatus(),this.setTheme(this._options.theme)}_buildToolbar(){let e=document.createElement("div");return e.className="jotter-toolbar",this._toolbarEl=e,(this._options.toolbar||S).forEach(t=>{let i=this._buildAction(t);i&&e.appendChild(i)}),e}_buildAction(e){if(typeof e.onClick=="function")return this._buildBtn(e);switch(e.type){case"sep":return this._makeSep();case"blockformat":return this._buildBlockFormatSelect();case"fontfamily":return this._buildFontFamilySelect();case"fontsize":return this._buildFontSizeSelect();case"color":return this._buildColorBtn(e);case"popup":return this._buildPopupBtn(e);case"theme":return this._buildThemeSelect();default:return this._buildBtn(e)}}_makeSep(){let e=document.createElement("span");return e.className="jotter-sep",e}_bindActivation(e,t){e.addEventListener("mousedown",i=>{i.preventDefault(),t(!1)}),e.addEventListener("keydown",i=>{i.key!=="Enter"&&i.key!==" "&&i.key!=="Spacebar"||i.repeat||(i.preventDefault(),t(!0))})}_returnFocus(e,t){t&&this._isInternalTarget(document.activeElement)&&e.focus()}_buildBtn(e){let t=document.createElement("button");if(t.type="button",t.className="jotter-btn",e.cmd&&(t.dataset.cmd=e.cmd),e.custom&&(t.dataset.custom=e.custom),t.title=e.title,t.setAttribute("aria-label",e.title),e.label)t.classList.add("jotter-btn--text"),t.appendChild(document.createTextNode(e.label));else{let i=document.createElement("span");i.className="material-icons",i.textContent=e.icon,t.appendChild(i)}return this._bindActivation(t,i=>{this._editor.focus(),this._applyEdit(()=>{if(e.onClick)e.onClick(this);else if(e.custom==="toggleSource")this._toggleSourceMode();else if(e.custom==="code")this._toggleInlineCode();else if(e.cmd==="copy")document.execCommand("copy");else if(e.cmd==="cut")document.execCommand("cut");else if(e.cmd==="paste")this._pasteFromClipboard();else if(e.prompt){let o=window.prompt(e.prompt);o&&document.execCommand(e.cmd,!1,o)}else document.execCommand(e.cmd,!1,null)}),this._updateToolbarState(),this._returnFocus(t,i)}),t}_bindSelectCaret(e){let t={viaKeyboard:!1};return e.addEventListener("mousedown",()=>{t.viaKeyboard=!1,this._saveBookmark()}),e.addEventListener("keydown",i=>{i.key==="Tab"||i.key==="Escape"||(t.viaKeyboard=!0,this._savedBookmark==null&&this._saveBookmark())}),t}_buildBlockFormatSelect(){let e=document.createElement("select");e.className="jotter-select",e.title="Block format",e.dataset.id="blockformat",v.forEach(({label:i,tag:o})=>{let s=document.createElement("option");s.value=o,s.textContent=i,e.appendChild(s)});let t=this._bindSelectCaret(e);return e.addEventListener("change",()=>{this._restoreSavedBookmark(),this._applyEdit(()=>document.execCommand("formatBlock",!1,e.value)),this._returnFocus(e,t.viaKeyboard)}),e}_buildFontFamilySelect(){let e=document.createElement("select");e.className="jotter-select jotter-select--font",e.title="Font family",e.dataset.id="fontfamily";let t=document.createElement("option");t.value="",t.textContent="Font",e.appendChild(t),x.forEach(o=>{let s=document.createElement("option");s.value=o,s.textContent=o,s.style.fontFamily=o,e.appendChild(s)});let i=this._bindSelectCaret(e);return e.addEventListener("change",()=>{e.value&&(this._restoreSavedBookmark(),this._applyEdit(()=>document.execCommand("fontName",!1,e.value)),this._returnFocus(e,i.viaKeyboard))}),e}_buildFontSizeSelect(){let e=document.createElement("select");e.className="jotter-select jotter-select--size",e.title="Font size",e.dataset.id="fontsize";let t=document.createElement("option");t.value="",t.textContent="Size",e.appendChild(t),L.forEach(o=>{let s=document.createElement("option");s.value=o,s.textContent=`${o}px`,e.appendChild(s)});let i=this._bindSelectCaret(e);return e.addEventListener("change",()=>{e.value&&(this._restoreSavedBookmark(),this._applyEdit(()=>this._applyFontSize(e.value)),this._returnFocus(e,i.viaKeyboard))}),e}_buildThemeSelect(){let e=document.createElement("select");return e.className="jotter-select jotter-select--theme",e.title="Editor theme",e.dataset.id="theme",C.forEach(({id:t,label:i})=>{let o=document.createElement("option");o.value=t,o.textContent=i,e.appendChild(o)}),e.value=this._options.theme,e.addEventListener("change",()=>this.setTheme(e.value)),this._themeSelect=e,e}_buildColorBtn(e){let t=document.createElement("span");t.className="jotter-color-wrap";let i=document.createElement("button");i.type="button",i.className="jotter-btn jotter-color-btn",i.dataset.cmd=e.cmd,i.title=e.title,i.setAttribute("aria-label",e.title);let o=document.createElement("span");o.className="material-icons",o.textContent=e.icon,i.appendChild(o);let s=document.createElement("span");s.className="jotter-color-swatch";let r=e.cmd==="foreColor"?this._lastForeColor:this._lastHiliteColor;s.style.background=r,i.appendChild(s);let a=document.createElement("input");a.type="color",a.className="jotter-color-input",a.value=r,a.tabIndex=-1;let u=!1;return a.addEventListener("change",()=>{let p=a.value;s.style.background=p,e.cmd==="foreColor"?this._lastForeColor=p:this._lastHiliteColor=p,this._restoreSavedBookmark(),this._applyEdit(()=>document.execCommand(e.cmd,!1,p)),this._returnFocus(i,u)}),this._bindActivation(i,p=>{u=p,this._saveBookmark(),a.click()}),t.appendChild(i),t.appendChild(a),t}_buildPopupBtn(e){let t=document.createElement("button");t.type="button",t.className="jotter-btn",t.title=e.title,t.setAttribute("aria-label",e.title);let i=document.createElement("span");return i.className="material-icons",i.textContent=e.icon,t.appendChild(i),this._bindActivation(t,o=>{let s=this._resolverFor(e.id);if(s){this._hidePopup(),this._runResolver(e.id,s);return}if(this._saveBookmark(),this._popupVisible()&&this._popup.dataset.popupId===e.id){this._hidePopup();return}this._showPopup(t,this._buildPopupContent(e.id),e.id),o&&this._focusPopup()}),t}_focusPopup(){let e=this._popup.querySelector('input, textarea, select, button, [tabindex]:not([tabindex="-1"])');e&&e.focus()}_buildPopupContainer(){let e=document.createElement("div");return e.className="jotter-popup",e.setAttribute("role","dialog"),e}_showPopup(e,t,i){this._popup.innerHTML="",this._popup.appendChild(t),this._popup.dataset.popupId=i,this._popup.classList.add("jotter-popup--visible");let o=e.getBoundingClientRect();this._popup.style.top=o.bottom+6+"px",this._popup.style.left=o.left+"px",this._popup.style.right="auto",requestAnimationFrame(()=>{let s=this._popup.getBoundingClientRect();s.right>window.innerWidth-8&&(this._popup.style.left=Math.max(8,o.left-(s.right-window.innerWidth+8))+"px")})}_popupVisible(){return this._popup.classList.contains("jotter-popup--visible")}_hidePopup(){this._popup.classList.remove("jotter-popup--visible"),this._popup.dataset.popupId="",this._releaseSavedBookmark()}_buildPopupContent(e){switch(e){case"link":return this._popupLink();case"table":return this._popupTable();case"image":return this._popupImage();case"video":return this._popupVideo();case"embed":return this._popupEmbed();case"symbol":return this._popupSymbol();case"specialchar":return this._popupSpecialChar();case"lorem":return this._popupLorem();default:{let t=document.createElement("div");return t.className="jotter-popup-inner",t.textContent="Unknown: "+e,t}}}_popupTable(){let e=document.createElement("div");e.className="jotter-popup-inner";let t=this._popupTitle("Insert Table");e.appendChild(t);let i=10,o=8,s=document.createElement("div");s.className="jotter-table-grid",s.style.gridTemplateColumns=`repeat(${i}, 1fr)`,s.setAttribute("role","grid"),s.setAttribute("aria-label","Table size");let r=document.createElement("div");r.className="jotter-popup-hint",r.textContent="Hover or arrow to select size";let a=[],u=(c,l)=>{r.textContent=`${c+1} \xD7 ${l+1} table`,a.forEach(d=>{d.classList.toggle("jotter-table-cell--active",+d.dataset.r<=c&&+d.dataset.c<=l)})};for(let c=0;c<o;c++)for(let l=0;l<i;l++){let d=document.createElement("span");d.className="jotter-table-cell",d.dataset.r=c,d.dataset.c=l,d.setAttribute("role","gridcell"),d.setAttribute("aria-label",`${c+1} by ${l+1} table`),d.tabIndex=c===0&&l===0?0:-1,d.addEventListener("mouseenter",()=>u(c,l)),d.addEventListener("focus",()=>u(c,l)),d.addEventListener("click",()=>this._insertTable(c+1,l+1)),a.push(d),s.appendChild(d)}let p={ArrowRight:[0,1],ArrowLeft:[0,-1],ArrowDown:[1,0],ArrowUp:[-1,0]};return s.addEventListener("keydown",c=>{let l=a.indexOf(document.activeElement)===-1?null:document.activeElement;if(!l)return;let d=+l.dataset.r,g=+l.dataset.c;if(c.key==="Enter"||c.key===" "||c.key==="Spacebar"){c.preventDefault(),this._insertTable(d+1,g+1);return}let f=p[c.key];if(!f)return;c.preventDefault();let k=Math.min(o-1,Math.max(0,d+f[0])),E=Math.min(i-1,Math.max(0,g+f[1])),b=a[k*i+E];b!==l&&(l.tabIndex=-1,b.tabIndex=0,b.focus())}),e.appendChild(s),e.appendChild(r),e}_commitPopup(e){this._restoreSavedBookmark(),this._hidePopup(),this._applyEdit(e)}_insertTable(e,t){let i="<table><tbody>";for(let o=0;o<e;o++){i+="<tr>";for(let s=0;s<t;s++)i+=o===0?"<th><br></th>":"<td><br></td>";i+="</tr>"}i+="</tbody></table><p><br></p>",this._commitPopup(()=>document.execCommand("insertHTML",!1,i))}_popupLink(){let e=document.createElement("div");e.className="jotter-popup-inner jotter-popup-form",e.appendChild(this._popupTitle("Insert Link"));let t=this._anchorInSelection(),i=this._selectedText(),o=this._makeField(e,"URL","url","https://"),s=this._makeField(e,"Link text (leave blank to keep selection)","text",""),r=this._makeField(e,"Title / tooltip","text",""),a=document.createElement("label");a.className="jotter-popup-label",a.textContent="Open in";let u=document.createElement("select");return u.className="jotter-popup-select",[["(same window)",""],["New tab (_blank)","_blank"],["Parent frame (_parent)","_parent"],["Top frame (_top)","_top"]].forEach(([p,c])=>{let l=document.createElement("option");l.value=c,l.textContent=p,u.appendChild(l)}),e.appendChild(a),e.appendChild(u),t?(o.value=t.getAttribute("href")||"",s.value=t.textContent||"",r.value=t.getAttribute("title")||"",u.value=t.getAttribute("target")||""):i&&(s.value=i),e.appendChild(this._makeSubmitBtn(t?"Update Link":"Insert Link",()=>{let p=o.value.trim();if(!p)return;let c=s.value.trim()||i||p,l=r.value.trim(),d=u.value;this._commitPopup(()=>{t?(t.href=p,d?t.target=d:t.removeAttribute("target"),l?t.title=l:t.removeAttribute("title"),t.textContent=c):document.execCommand("insertHTML",!1,this._linkHTML({href:p,text:c,title:l,target:d}))})})),e}_popupImage(){let e=document.createElement("div");e.className="jotter-popup-inner jotter-popup-form",e.appendChild(this._popupTitle("Insert Image"));let t=this._makeField(e,"Image URL","text","https://example.com/image.jpg"),i=this._makeField(e,"Alt text","text","Descriptive text"),o=this._makeField(e,"Width (e.g. 400px or 50%)","text","");return e.appendChild(this._makeSubmitBtn("Insert Image",()=>{let s=t.value.trim();if(!s)return;let r=this._imageHTML({src:s,alt:i.value.trim(),width:o.value.trim()});this._commitPopup(()=>document.execCommand("insertHTML",!1,r))})),e}_popupVideo(){let e=document.createElement("div");e.className="jotter-popup-inner jotter-popup-form",e.appendChild(this._popupTitle("Insert YouTube Video"));let t=this._makeField(e,"YouTube URL","text","https://www.youtube.com/watch?v=...");return e.appendChild(this._makeSubmitBtn("Embed Video",()=>{let i=this._ytId(t.value.trim());if(!i){t.classList.add("jotter-input--error");return}t.classList.remove("jotter-input--error"),this._commitPopup(()=>document.execCommand("insertHTML",!1,this._videoHTML(i)))})),e}_ytId(e){for(let t of[/[?&]v=([A-Za-z0-9_-]{11})/,/youtu\.be\/([A-Za-z0-9_-]{11})/,/embed\/([A-Za-z0-9_-]{11})/]){let i=e.match(t);if(i)return i[1]}return null}_popupEmbed(){let e=document.createElement("div");e.className="jotter-popup-inner jotter-popup-form",e.appendChild(this._popupTitle("Insert Embed"));let t=document.createElement("label");t.className="jotter-popup-label",t.textContent="Paste HTML / embed code";let i=document.createElement("textarea");return i.className="jotter-popup-textarea",i.placeholder='<iframe src="..." ...></iframe>',i.rows=4,e.appendChild(t),e.appendChild(i),e.appendChild(this._makeSubmitBtn("Insert",()=>{let o=i.value.trim();o&&this._commitPopup(()=>document.execCommand("insertHTML",!1,this._embedHTML(o)))})),e}_popupSymbol(){let e=document.createElement("div");return e.className="jotter-popup-inner",e.appendChild(this._popupTitle("Insert Symbol")),e.appendChild(this._charGrid(T)),e}_popupSpecialChar(){let e=document.createElement("div");return e.className="jotter-popup-inner",e.appendChild(this._popupTitle("Special Characters")),e.appendChild(this._charGrid(M)),e}_charGrid(e){let t=document.createElement("div");return t.className="jotter-char-grid",e.forEach(i=>{let o=document.createElement("button");o.type="button",o.className="jotter-char-btn",o.textContent=i,o.title=`U+${i.codePointAt(0).toString(16).toUpperCase().padStart(4,"0")}`,this._bindActivation(o,()=>{this._commitPopup(()=>document.execCommand("insertText",!1,i))}),t.appendChild(o)}),t}_popupLorem(){let e=document.createElement("div");return e.className="jotter-popup-inner",e.appendChild(this._popupTitle("Insert Lorem Ipsum")),w.forEach(t=>{let i=document.createElement("button");i.type="button",i.className="jotter-lorem-btn",i.textContent=t.label,this._bindActivation(i,()=>{this._commitPopup(()=>document.execCommand(t.isHTML?"insertHTML":"insertText",!1,t.text))}),e.appendChild(i)}),e}_popupTitle(e){let t=document.createElement("div");return t.className="jotter-popup-title",t.textContent=e,t}_makeField(e,t,i,o){let s=document.createElement("label");s.className="jotter-popup-label",s.textContent=t;let r=document.createElement("input");return r.type=i,r.className="jotter-popup-input",r.placeholder=o,e.appendChild(s),e.appendChild(r),r}_makeSubmitBtn(e,t){let i=document.createElement("button");return i.type="button",i.className="jotter-popup-submit",i.textContent=e,i.addEventListener("click",t),i}_esc(e){return String(e).replace(/"/g,"&quot;").replace(/</g,"&lt;").replace(/>/g,"&gt;")}_imageHTML({src:e,alt:t,width:i}){let o=i?`max-width:${i}`:"max-width:100%";return`<img src="${this._esc(e)}" alt="${this._esc(t||"")}" style="${this._esc(o)}">`}_linkHTML({href:e,text:t,title:i,target:o}){let s=`href="${this._esc(e)}"`;return o&&(s+=` target="${this._esc(o)}"`),i&&(s+=` title="${this._esc(i)}"`),`<a ${s}>${this._esc(t||e)}</a>`}_videoHTML(e){return/^[A-Za-z0-9_-]{11}$/.test(e)?`<div class="jotter-video-wrap"><iframe src="https://www.youtube.com/embed/${e}" frameborder="0" allowfullscreen loading="lazy" title="YouTube video"></iframe></div><p><br></p>`:null}_embedHTML(e){return`<div class="jotter-embed-wrap">${e}</div><p><br></p>`}_resolverFor(e){let t=y[e],i=t?this._options[t]:null;return typeof i=="function"?i:null}async _runResolver(e,t){let i=this._resolverContext(e);this.beginExternalUI();let o=null;try{o=await t(i)}catch{o=null}if(this._destroyed)return;let s=o==null||o===!1?null:this._resolvedHTML(e,o,i);this.endExternalUI(),s&&(this._applyEdit(()=>document.execCommand("insertHTML",!1,s)),this._updateToolbarState())}_resolverContext(e){switch(e){case"image":return{src:"",alt:"",width:"",selection:this._selectedText()};case"video":return{url:"",selection:this._selectedText()};case"embed":return{html:"",selection:this._selectedText()};case"link":return this._linkContext();default:return{selection:this._selectedText()}}}_linkContext(){let e=this._anchorInSelection();if(!e){let i=this._selectedText();return{href:"",text:i,title:"",target:"",selection:i,isEdit:!1}}let t=window.getSelection();if(t){let i=document.createRange();i.selectNode(e),t.removeAllRanges(),t.addRange(i)}return{href:e.getAttribute("href")||"",text:e.textContent||"",title:e.getAttribute("title")||"",target:e.getAttribute("target")||"",selection:e.textContent||"",isEdit:!0}}_resolvedHTML(e,t,i){switch(e){case"image":{let o=typeof t=="string"?{src:t}:t,s=String(o.src||o.url||"").trim();return s?this._imageHTML({...o,src:s}):null}case"link":{let o=typeof t=="string"?{href:t}:t,s=String(o.href||o.url||"").trim();if(!s)return null;let r=String(o.text!=null?o.text:i.text||"").trim();return this._linkHTML({...o,href:s,text:r})}case"video":{let o=typeof t=="string"?{url:t}:t,s=o.id?String(o.id).trim():this._ytId(String(o.url||"").trim());return s?this._videoHTML(s):null}case"embed":{let o=String(typeof t=="string"?t:t.html||"").trim();return o?this._embedHTML(o):null}default:return null}}_selectedText(){let e=window.getSelection();return!e||!e.rangeCount?"":this._editor.contains(e.getRangeAt(0).commonAncestorContainer)?e.toString():""}_anchorInSelection(){let e=window.getSelection();if(!e||!e.rangeCount)return null;let t=e.anchorNode;if(!t||!this._editor.contains(t))return null;for(;t&&t!==this._editor;){if(t.nodeName==="A")return t;t=t.parentNode}return null}_buildStatusBar(){let e=document.createElement("div");e.className="jotter-status",this._wordCountEl=document.createElement("span"),this._wordCountEl.className="jotter-status-words",this._charCountEl=document.createElement("span"),this._charCountEl.className="jotter-status-chars";let t=document.createElement("span");return t.className="jotter-status-mode",t.textContent="HTML",e.appendChild(this._wordCountEl),e.appendChild(this._charCountEl),e.appendChild(t),e}_buildMediaFrame(){let e=document.createElement("div");return e.className="jotter-media-frame",["nw","ne","sw","se","w","e"].forEach(t=>{let i=document.createElement("div");i.className="jotter-resize-handle jotter-resize-handle--"+t,i.dataset.handle=t,i.tabIndex=-1,e.appendChild(i)}),e.addEventListener("mousedown",t=>{let i=t.target.closest(".jotter-resize-handle");!i||!this._selectedMedia||(t.preventDefault(),this._beginResize(i.dataset.handle,t))}),e}_ensureMediaShields(){this._editor.querySelectorAll(".jotter-video-wrap, .jotter-embed-wrap").forEach(e=>{if(e.querySelector(":scope > .jotter-media-shield"))return;let t=document.createElement("div");t.className="jotter-media-shield",e.appendChild(t)})}_mediaElementFromTarget(e){if(!this._editor.contains(e))return null;let t=e.closest("img");if(t&&this._editor.contains(t))return t;let i=e.closest(".jotter-video-wrap, .jotter-embed-wrap");return i&&this._editor.contains(i)?i:null}_selectMedia(e){if(this._selectedMedia===e)return;this._deselectMedia(),this._selectedMedia=e,this._positionMediaFrame(),this._mediaFrame.classList.add("jotter-media-frame--visible"),this._editor.focus({preventScroll:!0});let t=document.createRange();t.setStartBefore(e),t.collapse(!0);let i=window.getSelection();i.removeAllRanges(),i.addRange(t),this._updateToolbarState()}_deselectMedia(){this._resizeState&&this._abortResize(),this._selectedMedia&&(this._selectedMedia=null,this._mediaFrame.classList.remove("jotter-media-frame--visible"))}_positionMediaFrame(){let e=this._selectedMedia;if(!e)return;let t=this._editorWrap.getBoundingClientRect(),i=e.getBoundingClientRect();this._mediaFrame.style.top=i.top-t.top+this._editorWrap.scrollTop+"px",this._mediaFrame.style.left=i.left-t.left+this._editorWrap.scrollLeft+"px",this._mediaFrame.style.width=i.width+"px",this._mediaFrame.style.height=i.height+"px"}_deleteSelectedMedia(){let e=this._selectedMedia;if(!e)return;this._deselectMedia();let t=document.createRange();t.selectNode(e);let i=window.getSelection();i.removeAllRanges(),i.addRange(t),this._applyEdit(()=>document.execCommand("delete",!1,null)),this._updateToolbarState()}_beginResize(e,t){let i=this._selectedMedia,o=i.getBoundingClientRect(),s=e.includes("w")?-1:1;this._resizeState={el:i,sign:s,startX:t.clientX,startWidth:o.width,startInlineWidth:i.style.width,before:this._richHTML()},document.addEventListener("mousemove",this._onResizeMove),document.addEventListener("mouseup",this._onResizeEnd,{once:!0})}_onResizeMove(e){let t=this._resizeState;if(!t)return;let i=(e.clientX-t.startX)*t.sign,o=40,s=Math.max(o,this._editor.clientWidth),r=Math.max(o,Math.min(s,Math.round(t.startWidth+i)));t.el.style.width=r+"px",t.el.style.removeProperty("max-width"),this._positionMediaFrame()}_onResizeEnd(){document.removeEventListener("mousemove",this._onResizeMove);let e=this._resizeState;this._resizeState=null,e&&(this._updateStatus(),this._richHTML()!==e.before&&this._emitChange())}_abortResize(){let e=this._resizeState;e&&(document.removeEventListener("mousemove",this._onResizeMove),document.removeEventListener("mouseup",this._onResizeEnd),e.el.style.width=e.startInlineWidth,this._resizeState=null,this._positionMediaFrame())}_bindEvents(){this._editor.addEventListener("input",()=>{this._editor.querySelectorAll(":scope > div").forEach(e=>{if(e.attributes.length>0)return;let t=document.createElement("p");t.innerHTML=e.innerHTML,e.replaceWith(t)}),Array.from(this._editor.childNodes).forEach(e=>{if(e.nodeType===Node.TEXT_NODE&&e.textContent.trim()!==""){let t=window.getSelection(),i=null;if(t&&t.rangeCount){let s=t.getRangeAt(0);s.startContainer===e&&(i=s.startOffset)}let o=document.createElement("p");if(e.replaceWith(o),o.appendChild(e),i!==null){let s=document.createRange();s.setStart(e,i),s.collapse(!0),t.removeAllRanges(),t.addRange(s)}}}),this._ensureMediaShields(),this._selectedMedia&&this._positionMediaFrame(),this._updateStatus(),this._emitChange()}),this._editor.addEventListener("keyup",()=>this._updateToolbarState()),this._editor.addEventListener("mouseup",()=>this._updateToolbarState()),this._editor.addEventListener("mousedown",e=>{let t=this._mediaElementFromTarget(e.target);t&&(e.preventDefault(),this._selectMedia(t))}),this._onWindowResize=()=>{this._selectedMedia&&this._positionMediaFrame()},window.addEventListener("resize",this._onWindowResize),this._editor.addEventListener("focusin",e=>{this._root.classList.add("jotter--focused"),!(this._externalDepth>0)&&(this._isInternalTarget(e.relatedTarget)||(this._emit("focus"),this._options.onFocus&&this._options.onFocus()))}),this._editor.addEventListener("focusout",e=>{this._deselectMedia(),!(this._externalDepth>0)&&(this._isInternalTarget(e.relatedTarget)||setTimeout(()=>{this._destroyed||this._externalDepth>0||this._isInternalTarget(document.activeElement)||this._popupVisible()||(this._root.classList.remove("jotter--focused"),this._emit("blur"),this._options.onBlur&&this._options.onBlur())},0))}),this._editor.addEventListener("keydown",e=>{if((e.key==="Backspace"||e.key==="Delete")&&this._selectedMedia){e.preventDefault(),this._deleteSelectedMedia();return}e.key==="Tab"&&(e.preventDefault(),document.execCommand("insertHTML",!1,"&nbsp;&nbsp;&nbsp;&nbsp;"))}),this._onDocMouseDown=e=>{this._popupVisible()&&!this._popup.contains(e.target)&&!this._toolbarEl.contains(e.target)&&this._hidePopup(),this._selectedMedia&&!this._mediaFrame.contains(e.target)&&e.target!==this._selectedMedia&&!this._selectedMedia.contains(e.target)&&this._deselectMedia()},document.addEventListener("mousedown",this._onDocMouseDown),this._onDocKeyDown=e=>{if(e.key==="Escape"){if(this._resizeState){this._abortResize();return}if(this._selectedMedia){this._deselectMedia();return}this._popupVisible()&&(this._restoreSavedBookmark(),this._hidePopup())}},document.addEventListener("keydown",this._onDocKeyDown)}_isInternalTarget(e){return!!e&&(this._root.contains(e)||this._popup.contains(e))}_toggleSourceMode(){this._deselectMedia(),this._sourceMode=!this._sourceMode,this._sourceMode?(this._dropBookmarks(),this._source.value=this._prettyHTML(this._richHTML()),this._editor.style.display="none",this._source.style.display="block"):(this._editor.innerHTML=this._sanitize(this._source.value),this._ensureMediaShields(),this._source.style.display="none",this._editor.style.display="",this._updateStatus(),this._emitChange()),this._root.classList.toggle("jotter--source-mode",this._sourceMode);let e=this._toolbarEl.querySelector('[data-custom="toggleSource"]');e&&e.classList.toggle("jotter-btn--active",this._sourceMode)}_prettyHTML(e){let t=0,i=" ",o=new Set(["area","base","br","col","embed","hr","img","input","link","meta","param","source","track","wbr"]),s=new Set(["a","abbr","acronym","b","bdo","big","br","button","cite","code","dfn","em","i","img","input","kbd","label","map","object","output","q","samp","select","small","span","strong","sub","sup","textarea","time","tt","u","var"]);return e.replace(/>\s+</g,"><").replace(/(<[^>]+>)/g,`
2
2
  $1
3
3
  `).split(`
4
- `).map(r=>r.trim()).filter(r=>r.length>0).map(r=>{let a=r.match(/^<\/(\w+)/),u=r.match(/^<(\w+)/),p=r.endsWith("/>"),c=u?u[1].toLowerCase():null,l=a?a[1].toLowerCase():null;l&&!n.has(l)&&(e=Math.max(0,e-1));let d=o.repeat(e)+r;return c&&!p&&!i.has(c)&&!l&&!n.has(c)&&e++,d}).join(`
5
- `)}_sanitize(t){let e=new DOMParser().parseFromString(t,"text/html");return e.querySelectorAll("script").forEach(o=>o.remove()),e.querySelectorAll("[data-jotter-bookmark]").forEach(o=>o.remove()),e.querySelectorAll("*").forEach(o=>{Array.from(o.attributes).forEach(i=>{(i.name.startsWith("on")||["href","src","action","formaction","data"].includes(i.name)&&/^\s*javascript:/i.test(i.value))&&o.removeAttribute(i.name)})}),e.body.innerHTML}_toggleInlineCode(){let t=window.getSelection();if(!t||t.rangeCount===0)return;let e=t.getRangeAt(0),o=e.commonAncestorContainer;o.nodeType===3&&(o=o.parentNode);let i=o.closest?o.closest("code"):null;if(i){let n=i.parentNode;for(;i.firstChild;)n.insertBefore(i.firstChild,i);n.removeChild(i)}else if(e.collapsed){let n=document.createElement("code");n.innerHTML="&#8203;",e.insertNode(n);let r=document.createRange();r.setStart(n,0),r.setEnd(n,n.childNodes.length),t.removeAllRanges(),t.addRange(r)}else{let n=document.createElement("code");try{e.surroundContents(n)}catch{let a=e.extractContents();n.appendChild(a),e.insertNode(n)}}}_applyFontSize(t){let e=window.getSelection();if(!e||e.rangeCount===0)return;let o=e.getRangeAt(0);if(o.collapsed)return;let i=document.createElement("span");i.style.fontSize=t+"px";try{o.surroundContents(i)}catch{let r=o.extractContents();i.appendChild(r),o.insertNode(i)}}async _pasteFromClipboard(){try{if(navigator.clipboard&&navigator.clipboard.readText){let t=await navigator.clipboard.readText();document.execCommand("insertText",!1,t)}else document.execCommand("paste")}catch{}}_updateToolbarState(){this._toolbarEl.querySelectorAll(".jotter-btn[data-cmd]").forEach(e=>{try{e.classList.toggle("jotter-btn--active",document.queryCommandState(e.dataset.cmd))}catch{}});let t=this._toolbarEl.querySelector('[data-id="blockformat"]');if(t){let e=document.queryCommandValue("formatBlock").toLowerCase().replace(/[<>]/g,""),o=C.find(i=>i.tag===e);o&&(t.value=o.tag)}}_updateStatus(){let t=this._editor.innerText||"",e=t.trim()===""?0:t.trim().split(/\s+/).length,o=t.replace(/\n/g,"").length;this._wordCountEl.textContent=`${e} word${e!==1?"s":""}`,this._charCountEl.textContent=`${o} char${o!==1?"s":""}`}_richHTML(){if(this._bookmarks.size===0)return this._editor.innerHTML;let t=this._editor.cloneNode(!0);return t.querySelectorAll("[data-jotter-bookmark]").forEach(e=>e.remove()),t.innerHTML}_makeMarker(t){let e=document.createElement("span");return e.className="jotter-bookmark",e.dataset.jotterBookmark=t,e}_takeRange(t){let e=t!=null?this._bookmarks.get(t):null;if(!e)return null;if(this._bookmarks.delete(t),e.atStart){let a=document.createRange();return a.setStart(this._editor,0),a.collapse(!0),a}let{start:o,end:i}=e,n=this._editor.contains(o)&&(!i||this._editor.contains(i)),r=null;return n&&(r=document.createRange(),r.setStartAfter(o),i?r.setEndBefore(i):r.collapse(!0)),o.parentNode&&o.remove(),i&&i.parentNode&&i.remove(),r}_saveBookmark(){this._releaseSavedBookmark(),this._savedBookmark=this.saveSelection()}_restoreSavedBookmark(){this.restoreSelection(this._savedBookmark),this._savedBookmark=null,this._editor.focus()}_releaseSavedBookmark(){this.releaseSelection(this._savedBookmark),this._savedBookmark=null}_dropBookmarks(){Array.from(this._bookmarks.keys()).forEach(t=>this.releaseSelection(t)),this._savedBookmark=null}_emit(t,e){(this._listeners[t]||[]).forEach(o=>o(e))}_emitChange(){let t=this.getHTML();this._changeCount++,this._emit("change",t),this._options.onChange&&this._options.onChange(t)}_applyEdit(t){let e=this._changeCount,o=this._richHTML();t(),this._updateStatus(),this._changeCount===e&&this._richHTML()!==o&&this._emitChange()}getHTML(){return this._sourceMode?this._source.value:this._richHTML()}getText(){return this._editor.innerText}isSourceMode(){return this._sourceMode}toggleSource(){return this._toggleSourceMode(),this}clear(){return this._dropBookmarks(),this._editor.innerHTML="",this._updateStatus(),this}focus(){return this._editor.focus(),this}insertHTML(t,e={}){return e.at!=null&&this.restoreSelection(e.at),this._editor.focus(),this._applyEdit(()=>document.execCommand("insertHTML",!1,this._sanitize(t))),this}insertText(t,e={}){return e.at!=null&&this.restoreSelection(e.at),this._editor.focus(),this._applyEdit(()=>document.execCommand("insertText",!1,t)),this}saveSelection(){let t=window.getSelection();if(!t||t.rangeCount===0)return null;let e=t.getRangeAt(0);if(!this._editor.contains(e.startContainer)||!this._editor.contains(e.endContainer))return null;let o="jbm"+ ++this._bmSeq;if(this._editor.childNodes.length===0)return this._bookmarks.set(o,{atStart:!0}),o;let i=this._makeMarker(o),n=e.collapsed?null:this._makeMarker(o);if(n){let u=e.cloneRange();u.collapse(!1),u.insertNode(n)}let r=e.cloneRange();r.collapse(!0),r.insertNode(i),this._bookmarks.set(o,{start:i,end:n});let a=document.createRange();return a.setStartAfter(i),n?a.setEndBefore(n):a.collapse(!0),t.removeAllRanges(),t.addRange(a),o}restoreSelection(t){let e=this._takeRange(t);if(!e)return this;this._sourceMode||this._editor.focus();let o=window.getSelection();return o.removeAllRanges(),o.addRange(e),this}releaseSelection(t){return this._takeRange(t),this}beginExternalUI(){return this._externalDepth===0&&(this._externalBookmark=this.saveSelection()),this._externalDepth++,this}endExternalUI(t={}){if(this._externalDepth===0)return this;if(this._externalDepth===1){let e=this._externalBookmark;this._externalBookmark=null,t.restore===!1?this.releaseSelection(e):this.restoreSelection(e)}return this._externalDepth--,this}setHTML(t){return this._dropBookmarks(),this._editor.innerHTML=this._sanitize(t),this._updateStatus(),this}setTheme(t){let o=k.find(i=>i.id===t)?t:"default";return this._editor.dataset.theme=o,this._options.theme=o,this._themeSelect&&(this._themeSelect.value=o),this}setEnabled(t){return this._editor.contentEditable=String(t),this._root.classList.toggle("jotter--disabled",!t),this}on(t,e){return this._listeners[t]||(this._listeners[t]=[]),this._listeners[t].push(e),this}off(t,e){return this._listeners[t]&&(this._listeners[t]=this._listeners[t].filter(o=>o!==e)),this}destroy(){let t=this.getHTML();return this._destroyed=!0,this._hidePopup(),this._dropBookmarks(),this._externalBookmark=null,this._externalDepth=0,document.removeEventListener("mousedown",this._onDocMouseDown),document.removeEventListener("keydown",this._onDocKeyDown),this._popup.parentNode&&this._popup.parentNode.removeChild(this._popup),this._target.classList.remove("jotter-host"),this._target.innerHTML=t,this._listeners={},t}};m.toolbar=h.full;m.actions=_;m.presets=h;var N=m;export{m as JotterJS,N as default};
4
+ `).map(r=>r.trim()).filter(r=>r.length>0).map(r=>{let a=r.match(/^<\/(\w+)/),u=r.match(/^<(\w+)/),p=r.endsWith("/>"),c=u?u[1].toLowerCase():null,l=a?a[1].toLowerCase():null;l&&!s.has(l)&&(t=Math.max(0,t-1));let d=i.repeat(t)+r;return c&&!p&&!o.has(c)&&!l&&!s.has(c)&&t++,d}).join(`
5
+ `)}_sanitize(e){let t=new DOMParser().parseFromString(e,"text/html");return t.querySelectorAll("script").forEach(i=>i.remove()),t.querySelectorAll("[data-jotter-bookmark], .jotter-media-shield").forEach(i=>i.remove()),t.querySelectorAll("*").forEach(i=>{Array.from(i.attributes).forEach(o=>{(o.name.startsWith("on")||["href","src","action","formaction","data"].includes(o.name)&&/^\s*javascript:/i.test(o.value))&&i.removeAttribute(o.name)})}),t.body.innerHTML}_toggleInlineCode(){let e=window.getSelection();if(!e||e.rangeCount===0)return;let t=e.getRangeAt(0),i=t.commonAncestorContainer;i.nodeType===3&&(i=i.parentNode);let o=i.closest?i.closest("code"):null;if(o){let s=o.parentNode;for(;o.firstChild;)s.insertBefore(o.firstChild,o);s.removeChild(o)}else if(t.collapsed){let s=document.createElement("code");s.innerHTML="&#8203;",t.insertNode(s);let r=document.createRange();r.setStart(s,0),r.setEnd(s,s.childNodes.length),e.removeAllRanges(),e.addRange(r)}else{let s=document.createElement("code");try{t.surroundContents(s)}catch{let a=t.extractContents();s.appendChild(a),t.insertNode(s)}}}_applyFontSize(e){let t=window.getSelection();if(!t||t.rangeCount===0)return;let i=t.getRangeAt(0);if(i.collapsed)return;let o=document.createElement("span");o.style.fontSize=e+"px";try{i.surroundContents(o)}catch{let r=i.extractContents();o.appendChild(r),i.insertNode(o)}}async _pasteFromClipboard(){try{if(navigator.clipboard&&navigator.clipboard.readText){let e=await navigator.clipboard.readText();document.execCommand("insertText",!1,e)}else document.execCommand("paste")}catch{}}_updateToolbarState(){this._toolbarEl.querySelectorAll(".jotter-btn[data-cmd]").forEach(t=>{try{t.classList.toggle("jotter-btn--active",document.queryCommandState(t.dataset.cmd))}catch{}});let e=this._toolbarEl.querySelector('[data-id="blockformat"]');if(e){let t=document.queryCommandValue("formatBlock").toLowerCase().replace(/[<>]/g,""),i=v.find(o=>o.tag===t);i&&(e.value=i.tag)}}_updateStatus(){let e=this._editor.innerText||"",t=e.trim()===""?0:e.trim().split(/\s+/).length,i=e.replace(/\n/g,"").length;this._wordCountEl.textContent=`${t} word${t!==1?"s":""}`,this._charCountEl.textContent=`${i} char${i!==1?"s":""}`}_richHTML(){let e=this._editor.cloneNode(!0);return e.querySelectorAll("[data-jotter-bookmark], .jotter-media-shield").forEach(t=>t.remove()),e.innerHTML}_makeMarker(e){let t=document.createElement("span");return t.className="jotter-bookmark",t.dataset.jotterBookmark=e,t}_takeRange(e){let t=e!=null?this._bookmarks.get(e):null;if(!t)return null;if(this._bookmarks.delete(e),t.atStart){let a=document.createRange();return a.setStart(this._editor,0),a.collapse(!0),a}let{start:i,end:o}=t,s=this._editor.contains(i)&&(!o||this._editor.contains(o)),r=null;return s&&(r=document.createRange(),r.setStartAfter(i),o?r.setEndBefore(o):r.collapse(!0)),i.parentNode&&i.remove(),o&&o.parentNode&&o.remove(),r}_saveBookmark(){this._releaseSavedBookmark(),this._savedBookmark=this.saveSelection()}_restoreSavedBookmark(){this.restoreSelection(this._savedBookmark),this._savedBookmark=null,this._editor.focus()}_releaseSavedBookmark(){this.releaseSelection(this._savedBookmark),this._savedBookmark=null}_dropBookmarks(){Array.from(this._bookmarks.keys()).forEach(e=>this.releaseSelection(e)),this._savedBookmark=null}_emit(e,t){(this._listeners[e]||[]).forEach(i=>i(t))}_emitChange(){let e=this.getHTML();this._changeCount++,this._emit("change",e),this._options.onChange&&this._options.onChange(e)}_applyEdit(e){let t=this._changeCount,i=this._richHTML();e(),this._updateStatus(),this._changeCount===t&&this._richHTML()!==i&&this._emitChange()}getHTML(){return this._sourceMode?this._source.value:this._richHTML()}getText(){return this._editor.innerText}isSourceMode(){return this._sourceMode}toggleSource(){return this._toggleSourceMode(),this}clear(){return this._deselectMedia(),this._dropBookmarks(),this._editor.innerHTML="",this._updateStatus(),this}focus(){return this._editor.focus(),this}insertHTML(e,t={}){return t.at!=null&&this.restoreSelection(t.at),this._editor.focus(),this._applyEdit(()=>document.execCommand("insertHTML",!1,this._sanitize(e))),this}insertText(e,t={}){return t.at!=null&&this.restoreSelection(t.at),this._editor.focus(),this._applyEdit(()=>document.execCommand("insertText",!1,e)),this}saveSelection(){let e=window.getSelection();if(!e||e.rangeCount===0)return null;let t=e.getRangeAt(0);if(!this._editor.contains(t.startContainer)||!this._editor.contains(t.endContainer))return null;let i="jbm"+ ++this._bmSeq;if(this._editor.childNodes.length===0)return this._bookmarks.set(i,{atStart:!0}),i;let o=this._makeMarker(i),s=t.collapsed?null:this._makeMarker(i);if(s){let u=t.cloneRange();u.collapse(!1),u.insertNode(s)}let r=t.cloneRange();r.collapse(!0),r.insertNode(o),this._bookmarks.set(i,{start:o,end:s});let a=document.createRange();return a.setStartAfter(o),s?a.setEndBefore(s):a.collapse(!0),e.removeAllRanges(),e.addRange(a),i}restoreSelection(e){let t=this._takeRange(e);if(!t)return this;this._sourceMode||this._editor.focus();let i=window.getSelection();return i.removeAllRanges(),i.addRange(t),this}releaseSelection(e){return this._takeRange(e),this}beginExternalUI(){return this._externalDepth===0&&(this._externalBookmark=this.saveSelection()),this._externalDepth++,this}endExternalUI(e={}){if(this._externalDepth===0)return this;if(this._externalDepth===1){let t=this._externalBookmark;this._externalBookmark=null,e.restore===!1?this.releaseSelection(t):this.restoreSelection(t)}return this._externalDepth--,this}setHTML(e){return this._deselectMedia(),this._dropBookmarks(),this._editor.innerHTML=this._sanitize(e),this._ensureMediaShields(),this._updateStatus(),this}setTheme(e){let i=C.find(o=>o.id===e)?e:"default";return this._editor.dataset.theme=i,this._options.theme=i,this._themeSelect&&(this._themeSelect.value=i),this}setEnabled(e){return this._editor.contentEditable=String(e),this._root.classList.toggle("jotter--disabled",!e),this}on(e,t){return this._listeners[e]||(this._listeners[e]=[]),this._listeners[e].push(t),this}off(e,t){return this._listeners[e]&&(this._listeners[e]=this._listeners[e].filter(i=>i!==t)),this}destroy(){let e=this.getHTML();return this._destroyed=!0,this._deselectMedia(),this._hidePopup(),this._dropBookmarks(),this._externalBookmark=null,this._externalDepth=0,document.removeEventListener("mousedown",this._onDocMouseDown),document.removeEventListener("keydown",this._onDocKeyDown),window.removeEventListener("resize",this._onWindowResize),this._popup.parentNode&&this._popup.parentNode.removeChild(this._popup),this._target.classList.remove("jotter-host"),this._target.innerHTML=e,this._listeners={},e}};h.toolbar=m.full;h.actions=_;h.presets=m;var N=h;export{h as JotterJS,N as default};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "jotterjs",
3
- "version": "0.5.0",
3
+ "version": "0.6.0",
4
4
  "description": "A lightweight, vanilla JS rich-text editor component. No dependencies.",
5
5
  "main": "dist/jotter.min.js",
6
6
  "module": "dist/jotter.js",