diff --git a/app/javascript/controllers/local_save_controller.js b/app/javascript/controllers/local_save_controller.js
index aaea8fa87..5d9b89a72 100644
--- a/app/javascript/controllers/local_save_controller.js
+++ b/app/javascript/controllers/local_save_controller.js
@@ -1,5 +1,5 @@
import { Controller } from "@hotwired/stimulus"
-import { debounce } from "helpers/timing_helpers"
+import { debounce, nextFrame } from "helpers/timing_helpers"
export default class extends Controller {
static targets = ["input"]
@@ -10,7 +10,7 @@ export default class extends Controller {
}
connect() {
- this.#restoreContent()
+ this.restoreContent()
}
submit({ detail: { success } }) {
@@ -28,20 +28,22 @@ export default class extends Controller {
}
}
- // Private
-
- #clear() {
- localStorage.removeItem(this.keyValue)
- }
-
- #restoreContent() {
+ async restoreContent() {
+ await nextFrame()
const savedContent = localStorage.getItem(this.keyValue)
+
if (savedContent) {
this.inputTarget.value = savedContent
this.#triggerChangeEvent(savedContent)
}
}
+ // Private
+
+ #clear() {
+ localStorage.removeItem(this.keyValue)
+ }
+
#triggerChangeEvent(newValue) {
if (this.inputTarget.tagName === "HOUSE-MD") {
this.inputTarget.dispatchEvent(new CustomEvent('house-md:change', {
diff --git a/app/views/bubbles/index.html.erb b/app/views/bubbles/index.html.erb
index f8dfd9dea..0e52a9a59 100644
--- a/app/views/bubbles/index.html.erb
+++ b/app/views/bubbles/index.html.erb
@@ -1,6 +1,5 @@
<% @page_title = @filter.summary %>
-<% turbo_refreshes_with method: :morph, scroll: :preserve %>
<%= render "filters/broadcasts", filter: @filter %>
<% content_for :header do %>
diff --git a/app/views/comments/_new.html.erb b/app/views/comments/_new.html.erb
index 6c0d9d54a..c0c2def66 100644
--- a/app/views/comments/_new.html.erb
+++ b/app/views/comments/_new.html.erb
@@ -10,7 +10,7 @@
local_save_key_value: "comment-#{bubble.id}",
action: "turbo:submit-end->local-save#submit keydown.ctrl+enter->form#submit:prevent keydown.meta+enter->form#submit:prevent keydown.esc->form#cancel:stop paste->paste#pasteFiles" } do |form| %>
<%= form.markdown_area :body, class: "input comment__input", required: true, placeholder: new_comment_placeholder(bubble),
- data: { local_save_target: "input", action: "house-md:change->local-save#save" } %>
+ data: { local_save_target: "input", action: "house-md:change->local-save#save turbo:morph-element->local-save#restoreContent" } %>
<%= form.button class: "comment__submit btn btn--reversed flex-item-justify-start" do %>
Post this comment
<% end %>
diff --git a/app/views/layouts/application.html.erb b/app/views/layouts/application.html.erb
index 6ed45d42a..606f72330 100644
--- a/app/views/layouts/application.html.erb
+++ b/app/views/layouts/application.html.erb
@@ -12,6 +12,8 @@
<%= csp_meta_tag %>
<%= tag.meta name: "current-user-id", content: Current.user.id if Current.user %>
+ <% turbo_refreshes_with method: :morph, scroll: :preserve %>
+
<%= stylesheet_link_tag :app, "data-turbo-track": "reload" %>
<%= javascript_importmap_tags %>
diff --git a/vendor/javascript/house.min.js b/vendor/javascript/house.min.js
index 6d717f5ee..d1241d73c 100644
--- a/vendor/javascript/house.min.js
+++ b/vendor/javascript/house.min.js
@@ -1 +1,43 @@
-function t(t){return"string"==typeof t}function e(t,e,n=null,s=!1){return t.dispatchEvent(new CustomEvent(e,{bubbles:!0,detail:n,cancelable:s}))}class n extends HTMLElement{constructor(){super()}connectedCallback(){this.#t(),this.addEventListener("click",this.#e),this.#n?.addEventListener("change",this.#s)}disconnectedCallback(){this.#n?.removeEventListener("change",this.#s),this.removeEventListener("click",this.#e)}get#n(){return this.querySelector("[data-house-md-toolbar-file-picker]")}#t(){this.#r()&&(this.innerHTML=this.#i())}#e=t=>{const n=t.target.closest("[data-house-md-action]")?.dataset?.houseMdAction;n&&(t.preventDefault(),e(this,"house-md:toolbar-action",{houseMdAction:n}))};#s=t=>{for(const n of t.target.files)e(this,"house-md:toolbar-action",{houseMdAction:"uploadFile",file:n})};#r(){return 0===this.children.length}#i(){return'\n \n \n \n \n \n \n \n '}}customElements.define("house-md-toolbar",n);class s{start=0;end=0;static fromDOMRange(t,e){const{startOffset:n,startContainer:i,endOffset:o,endContainer:l}=t,a=r(e,i,n);if(t.collapsed)return new s(e,a,a);const c=r(e,l,o);return new s(e,a,c)}constructor(t,e,n){this.container=t,this.start=e,this.end=n}toDOMRange(){const t=document.createRange();t.setStart(this.container,1),t.setEnd(this.container,this.container.childNodes.length);const e=document.createTreeWalker(this.container,NodeFilter.SHOW_TEXT);let n=0,s=!1,r=!1;for(;e.nextNode()&&(!s||!r);){const i=e.currentNode.textContent.length;n+i>=this.start&&!s&&(s=!0,t.setStart(e.currentNode,this.start-n)),n+i>=this.end&&!r&&(r=!0,t.setEnd(e.currentNode,this.end-n)),n+=i}return t}isEqual(t){return this.container===t.container&&this.start===t.start&&this.end===t.end}}function r(t,e,n){return e.nodeType===Node.ELEMENT_NODE?function(t,e,n){const s=e.childNodes[n];let r=0;const i=document.createTreeWalker(t);for(;i.nextNode();){if(i.currentNode===s)return r;i.currentNode.nodeType===Node.TEXT_NODE&&(r+=i.currentNode.textContent.length)}return r}(t,e,n):function(t,e,n){const s=document.createTreeWalker(t,NodeFilter.SHOW_TEXT);for(;s.nextNode();){if(s.currentNode===e)return n;n+=s.currentNode.textContent.length}return n}(t,e,n)}class i{#o;#l;#a;constructor(t){this.#o=t,this.#l=new s(this.contentElement,0,0),this.#a=""}current(){return{start:this.start,end:this.end,selection:this.#a}}currentLine(){return this.lineAt(this.end)}previousLine(){const{content:t}=this.#o,e=Math.max(t.lastIndexOf("\n",this.start-1),0);return this.lineAt(e)}lineAt(t){const{content:e}=this.#o,n=Math.max(e.lastIndexOf("\n",t-1)+1,0),s=e.indexOf("\n",t),r=-1===s?e.length:s+1;return{start:n,end:r,content:e.slice(n,r)}}select({start:t,end:e}){this.documentRange=new s(this.contentElement,t,e);const n=this.documentRange.toDOMRange();if(n){const t=window.getSelection();t.removeAllRanges(),t.addRange(n),this.update()}else console.error("Failed to create range",{start:t,end:e})}update=()=>{const t=document.getSelection()?.getRangeAt(0),n=this.#l;t.intersectsNode(this.contentElement)&&(this.#l=s.fromDOMRange(t,this.contentElement),this.#a=this.#o.content.slice(this.start,this.end)),this.#l.isEqual(n)||e(this.element,"house-md:selectionchange",{start:this.start,end:this.end})};get start(){return this.#l.start}get end(){return this.#l.end}get element(){return this.#o.element}get contentElement(){return this.#o.contentElement}get isEmpty(){return this.start===this.end}get isMultiline(){return this.current().selection.includes("\n")}get isBold(){return this.#c("strong")}get isItalic(){return this.#c("em")}get isStrikethrough(){return this.#c("s")}get isLink(){return this.#c(".link")}get isCode(){return this.#c(".code")}get isQuote(){return this.#c(".quote")}get isBulletList(){return this.#c(".ul-li")}get isNumberList(){return this.#c(".ol-li")}#c(t){let e=window.getSelection().getRangeAt(0).endContainer;if(e.nodeType===Node.TEXT_NODE&&(e=e.parentElement),this.contentElement.contains(e))return!!e.closest(t)}}class o{static saveInterval=1e3;constructor(t=500){this.maxSize=t,this.undoStack=[],this.redoStack=[]}undo(t){const e=this.undoStack.pop();return e?(this.redoStack.push(t),e):{}}redo(t){const e=this.redoStack.pop();return e?(this.undoStack.push(t),e):{}}add=function(t){let e;return(...n)=>{e||(t(...n),e=setTimeout((()=>{e=null}),o.saveInterval))}}((t=>{this.undoStack.push(t),this.redoStack=[],this.undoStack.length>this.maxSize&&this.undoStack.shift()}))}function l(t){let e=t;return e=function(t){return t=t.replaceAll(/&/g,"&"),t=t.replaceAll(//g,">"),t=t.replaceAll(/"/g,"""),t=t.replaceAll(/'/g,"'"),t}(e),e=function(t){return t=function(t){return t=t.replaceAll(/(?***$1***"),t=t.replaceAll(/(?___$1___"),t}(t),t=function(t){return t=t.replaceAll(/(?**$1**"),t=t.replaceAll(/(?__$1__"),t}(t),t=function(t){return t=t.replaceAll(/(?*$1*"),t=t.replaceAll(/(?_$1_"),t}(t),t=function(t){return t.replaceAll(/~~(.*)?~~/gm,"~~$1~~")}(t),t=function(t){return t.replaceAll(/==(.*?)==/gm,"==$1==")}(t),t}(e),e=function(t){return t=function(t){return t=t.replaceAll(/^# (.*)$/gm,'# $1'),t=t.replaceAll(/^## (.*)$/gm,'## $1'),t=t.replaceAll(/^### (.*)$/gm,'### $1'),t=t.replaceAll(/^#### (.*)$/gm,'#### $1'),t=t.replaceAll(/^##### (.*)$/gm,'##### $1'),t=t.replaceAll(/^###### (.*)$/gm,'###### $1'),t}(t),t=function(t){return t.replaceAll(/^(\d+\.\s.*)$/gm,'$1')}(t),t=function(t){return t.replaceAll(/^(-\s.*)$/gm,'$1')}(t),t=function(t){return t.replaceAll(/^>(.*)$/gm,'>$1')}(t),t}(e),e=function(t){return function(t){return t.replaceAll(/\n---\n/gm,'\n---\n')}(t)}(e),e=function(t){return t.replaceAll(/(?[$1]($2)')}(e),e=function(t){return t.replaceAll(/!\[(.*?)\]\((.*?)\)/gm,'$&')}(e),e=function(t){return t=t.replaceAll(/^```(.*?)```$/gms,'```$1```'),t=t.replaceAll(/([^`])`([^`]+)`([^`])/gm,'$1`$2`$3'),t}(e),e=function(t){return t.replaceAll(/<!--(.*?)-->/gm,'')}(e),e}class a{constructor(t,e){this.content=t,this.element=e,this.selection=new i(this),this.history=new o}select(t,e){this.selection.select({start:t,end:e})}insertText(t){this.replaceText(t,this.currentSelection.start,this.currentSelection.end)}replaceText(t,e,n){const s=this.content.slice(0,e),r=`${s}${t}${this.content.slice(n)}`,i={start:s.length+t.length,end:s.length+t.length};this.#h(),this.#d(r,i)}insertParagraph(t,e){this.select(t,e),this.selection.isBulletList?this.#u():this.selection.isNumberList?this.#m():this.replaceText("\n",t,e)}insertLink(t,e,n=""){const{start:s,end:r}=this.currentSelection,i=` ${n}[${t}](${e}) `;this.replaceText(i,s,r),this.selection.select({start:s+i.length,end:s+i.length})}insertFile(t,e,n){n.startsWith("image/")?this.insertImage(t,e):this.insertLink(t,e)}insertImage(t,e){this.insertLink(t,e,"!")}deleteText(t,e){this.replaceText("",Math.max(t,0),e)}deleteCurrentLine(){const{start:t,end:e}=this.currentLine;this.deleteText(t,e)}toggleBold(){this.#p(this.selection.isBold,"**")}toggleItalic(){this.#p(this.selection.isItalic,"_")}toggleStrikethrough(){this.#p(this.selection.isStrikethrough,"~~")}toggleCode(){const[t,e]=this.selection.isMultiline?["```\n","\n```"]:["`","`"];this.#p(this.selection.isCode,t,e)}toggleLink(){this.selection.isLink?this.#g():this.#v()}toggleQuote(){this.selection.isQuote?this.#f("> "):this.#L("> ")}toggleBulletList(){this.selection.isBulletList?this.#f("- "):this.#L("- ")}toggleNumberList(){this.selection.isNumberList?this.#f(/\d+\. /):this.#L(`${this.#b+1}. `)}undo(){const{content:e,start:n,end:s}=this.history.undo(this.#x);t(e)&&this.#d(e,{start:n,end:s})}redo(){const{content:e,start:n,end:s}=this.history.redo(this.#x);t(e)&&this.#d(e,{start:n,end:s})}render(){this.contentElement.innerHTML=l(this.content)+""}get isEmpty(){return!this.content.trim()}get contentElement(){return this.element.contentWrapper}get currentSelection(){return this.selection.current()}get currentLine(){return this.selection.currentLine()}#p(t,e,n=e){t?this.#E(e,n):this.#w(e,n)}#w(t,e=t){const{start:n,end:s,selection:r}=this.currentSelection,i=`${t}${r}${e}`;this.replaceText(i,n,s),this.selection.select({start:n,end:n+r.length+t.length+e.length})}#E(t,e=t){const{start:n,end:s,selection:r}=this.currentSelection;r.startsWith(t)&&r.endsWith(e)&&(this.replaceText("",s-e.length,s),this.replaceText("",n,n+t.length),this.selection.select({start:n,end:s-t.length-e.length}))}#v(){const{start:t,end:e,selection:n}=this.currentSelection,s=this.selection.isEmpty,r=s?"title":n;this.replaceText(`[${r}](url)`,t,e),s?this.selection.select({start:t+1,end:t+r.length+1}):this.selection.select({start:t+n.length+3,end:t+n.length+6})}#g(){const{start:t,end:e,selection:n}=this.currentSelection,s=n.replace(/\[(.*)\]\(.*\)/,"$1");this.replaceText(s,t,e)}#u(){this.#T.match(/^-\s+$/)?this.deleteCurrentLine():(this.replaceText("\n",this.currentSelection.end,this.currentSelection.end),this.replaceText("- ",this.currentSelection.end+1,this.currentSelection.end+1))}#m(){this.#T.match(/^\d+\.\s+$/)?this.deleteCurrentLine():(this.replaceText("\n",this.currentSelection.end,this.currentSelection.end),this.replaceText(`${this.#b+1}. `,this.currentSelection.end+1,this.currentSelection.end+1))}#L(t){const{start:e,end:n}=this.currentSelection,s=this.currentLine;this.replaceText(t,s.start,s.start),this.selection.select({start:e+t.length,end:n+t.length})}#f(t){const{start:e,end:n}=this.currentSelection,s=this.currentLine;if(t instanceof RegExp){const e=s.content.match(t);if(!e)return;t=e[0]}s.content.startsWith(t)&&(this.deleteText(s.start,s.start+t.length),this.selection.select({start:e-t.length,end:n-t.length}))}#h(){this.history.add(this.#x)}#d(t,n){const s=this.content;this.content=t,this.element.value=t,this.selection.select(n),e(this.element,"house-md:change",{previousContent:s,newContent:t})}get#x(){const{start:t,end:e}=this.currentSelection;return{content:this.content,start:t,end:e}}get#T(){return this.currentLine.content}get#b(){const t=this.selection.previousLine().content.match(/^(\d+). /);return t?parseInt(t[1]):0}}class c{#S;constructor(t){this.#S=t}asPlainText(){const t=(new window.DOMParser).parseFromString(this.#S,"text/html");return this.#A(t.body).trim()}#A(t){return t.nodeType===Node.TEXT_NODE?t.nodeValue:Array.from(t.childNodes).map(((e,n)=>{const s=this.#k(e),r=n>0&&this.#k(t.childNodes[n-1]);return(s&&r?"\n\n":"")+this.#A(e)})).join("")}#k(t){return["BR","DIV","H1","H2","H3","H4","H5","H6","LI","P","TR"].includes(t.tagName)}}class h{constructor(t){this.document=t}handleInput(t,e){t.preventDefault();const n=this[`${t.inputType}Handler`];if(n){const r=t.getTargetRanges()[0],{start:i,end:o}=s.fromDOMRange(r,e);n.call(this,t,i,o)}else console.error("Not handling:",t.inputType)}insertTextHandler(t,e,n){this.#C(t,e,n)}insertCompositionTextHandler(t,e,n){this.#C(t,e,n)}insertParagraphHandler(t,e,n){this.document.insertParagraph(e,n)}insertLinkHandler(t,e,n){this.#C(t,e,n)}insertFromYankHandler(t,e,n){this.#C(t,e,n)}insertFromDropHandler(t,e,n){this.#C(t,e,n)}insertFromPasteAsQuotationHandler(t,e,n){const s=t.dataTransfer.getData("text/plain");this.document.replaceText(`> ${s}`,e,n)}insertTransposeHandler(t,e,n){this.#C(t,e,n)}insertReplacementTextHandler(t,e,n){this.#C(t,e,n)}insertFromPasteHandler(t,e,n){this.#C(t,e,n)}deleteContentBackwardHandler(t,e,n){this.document.deleteText(e,n)}deleteByCutHandler(t,e,n){this.document.deleteText(e,n)}deleteWordBackwardHandler(t,e,n){this.document.deleteText(e,n)}deleteWordForwardHandler(t,e,n){this.document.deleteText(e,n)}deleteSoftLineBackwardHandler(t,e,n){this.document.deleteText(e,n)}deleteSoftLineForwardHandler(t,e,n){this.document.deleteText(e,n)}deleteEntireSoftLineHandler(t,e,n){this.document.deleteText(e,n)}deleteHardLineBackwardHandler(t,e,n){this.document.deleteText(e,n)}deleteHardLineForwardHandler(t,e,n){this.document.deleteText(e,n)}deleteByDragHandler(t,e,n){this.document.deleteText(e,n)}deleteContentHandler(t,e,n){this.document.deleteText(e,n)}deleteContentForwardHandler(t,e,n){this.document.deleteText(e,n)}#C(t,e,n){let s;if(t.data)s=t.data;else{const e=t.dataTransfer.getData("text/html");s=e?new c(e).asPlainText():t.dataTransfer.getData("text/plain")}this.document.replaceText(s,e,n)}}class d{constructor(t,e){this.element=t.closest("house-md"),this.file=e}upload(){if(e(this.element,"house-md:before-upload",{file:this.file})){const t=document.createElement("house-md-upload");t.file=this.file,t.uploadsURL=this.#$,this.element.appendChild(t)}}get#$(){return this.element.dataset.uploadsUrl||document.head.querySelector("meta[name=house-uploads-url]")?.content||"/uploads"}}class u{constructor(t){this.document=t}handleAction(t,e){const n=this[t];n?n.call(this,e):console.error("Not handling:",t)}bold(){this.document.toggleBold()}italic(){this.document.toggleItalic()}strikethrough(){this.document.toggleStrikethrough()}quote(){this.document.toggleQuote()}code(){this.document.toggleCode()}link(){this.document.toggleLink()}bulletList(){this.document.toggleBulletList()}numberList(){this.document.toggleNumberList()}undo(){this.document.undo()}redo(){this.document.redo()}uploadFile({file:t}){new d(this.document.element,t).upload()}}class m{constructor(t){this.element=t.closest("house-md")}handleDragOver(t){t.preventDefault()}async handleDrop(t){t.preventDefault();for(const e of t.dataTransfer.items)"file"===e.kind&&new d(this.element,e.getAsFile()).upload()}}const p={"Ctrl+B":"bold","Ctrl+I":"italic","Ctrl+S":"strikethrough","Ctrl+Z":"undo","Ctrl+Shift+Z":"redo"};class g extends HTMLElement{static formAssociated=!0;constructor(){super(),this.internals=this.attachInternals(),this.internals.ariaRole="textbox"}connectedCallback(){const t=this.querySelector(".house-md-content")?.textContent||this.textContent;this.document=new a(t,this),this.#y(),this.#H(),this.inputHandler=new h(this.document),this.actionHandler=new u(this.document),this.dropAndDropHandler=new m(this),this.autofocus&&this.focus(),this.setAttribute("initialized",""),this.value=t}disconnectedCallback(){this.#N()}validate=t=>{this.required&&this.document.isEmpty?(t.preventDefault(),this.internals.setValidity({valueMissing:!0},"This field is required.",this.element),this.focus()):this.internals.setValidity({})};render(){this.document.render()}focus(){this.contentWrapper.focus()}get required(){return this.hasAttribute("required")}set required(t){t?this.setAttribute("required",""):this.removeAttribute("required")}get autofocus(){return this.hasAttribute("autofocus")}set autofocus(t){t?this.setAttribute("autofocus",""):this.removeAttribute("autofocus")}get value(){return this.document.content}set value(t){this.document.content=t,this.internals.setFormValue(t),this.internals.setValidity({}),this.render()}get form(){return this.internals.form}#y(){this.textContent="",this.toolbar=this.#_(),this.contentWrapper=document.createElement("div"),this.contentWrapper.classList.add("house-md-content"),this.contentWrapper.setAttribute("contenteditable",!0),this.contentWrapper.setAttribute("placeholder",this.getAttribute("placeholder")),this.append(this.contentWrapper),this.#D(),this.getAttribute("tabindex")||this.contentWrapper.setAttribute("tabindex",0)}#D(){this.contentWrapper.classList.toggle("house-md-content-empty",this.document.isEmpty)}#_(){if(this.getAttribute("toolbar"))return document.getElementById(this.getAttribute("toolbar"));{const t=document.createElement("house-md-toolbar");return this.prepend(t),t}}#H(){this.addEventListener("beforeinput",this.#I),this.addEventListener("keydown",this.#B),this.addEventListener("dragover",this.#F),this.addEventListener("drop",this.#R),this.addEventListener("house-md:change",this.#M),this.toolbar.addEventListener("house-md:toolbar-action",this.#z),document.addEventListener("selectionchange",this.#O),this.internals.form.addEventListener("submit",this.validate)}#N(){this.removeEventListener("beforeinput",this.#I),this.removeEventListener("keydown",this.#B),this.removeEventListener("dragover",this.#F),this.removeEventListener("drop",this.#R),this.removeEventListener("house-md:change",this.#M),this.toolbar.removeEventListener("house-md:toolbar-action",this.#z),document.removeEventListener("selectionchange",this.#O),this.internals.form.removeEventListener("submit",this.validate)}#I=t=>{this.inputHandler.handleInput(t,this.contentWrapper)};#B(t){const e=function(t){return p[function(t){const e=[];return(t.metaKey||t.ctrlKey)&&e.push("Ctrl"),t.altKey&&e.push("Alt"),t.shiftKey&&e.push("Shift"),e.push(t.key.toUpperCase()),e.join("+")}(t)]}(t);e&&(t.preventDefault(),this.actionHandler.handleAction(e))}#F=t=>{this.dropAndDropHandler.handleDragOver(t)};#R=t=>{this.dropAndDropHandler.handleDrop(t)};#M=()=>{this.#D()};#z=({detail:t})=>{this.actionHandler.handleAction(t.houseMdAction,t)};#O=()=>{this.document.selection.update()}}customElements.define("house-md",g);class v extends HTMLElement{#W;#$;#q;constructor(){super(),this.percentComplete=0,this.status="pending"}connectedCallback(){this.#t(),this.#P(),this.addEventListener("click",this.#e)}disconnectedCallback(){this.removeEventListener("click",this.#e)}async#P(){const t=new FormData;t.append("file",this.file),this.csrfParamName&&t.append(this.csrfParamName,this.csrfToken),this.xhr=new XMLHttpRequest,this.xhr.open("POST",this.uploadsURL,!0),this.xhr.upload.onprogress=this.#U,this.xhr.onload=this.#K,this.xhr.onerror=this.#Q,this.xhr.onabort=this.#V,this.xhr.send(t),this.status="uploading",this.#t()}#t(){this.setAttribute("status",this.status),this.innerHTML=`\n ${this.#X()}\n ${this.#j()}\n ${this.#Z()}\n ${this.#J()}\n `}#X(){return"failed"===this.status?"":""}#j(){return`
${this.file.name}
`}#Z(){return``}#J(){return this.#q?`${this.#q}
`:""}#U=t=>{t.lengthComputable&&(this.percentComplete=t.loaded/t.total*100),this.#t()};#K=async()=>{if(this.xhr.status>=400)this.status="failed",this.#q=this.xhr.responseText||"Upload failed";else{const t=JSON.parse(this.xhr.responseText);await this.document.insertFile(t.fileName,t.fileUrl,t.mimetype),this.status="complete",this.#Y()}this.#t()};#Q=()=>{this.status="failed",this.#t()};#V=()=>{this.status="aborted",this.#t()};#e=t=>{t.target.matches("[data-md-action=close]")&&this.remove()};async#Y(t=500){await function(t){return new Promise((e=>setTimeout(e,t)))}(t),this.remove()}get document(){return this.closest("house-md").document}get file(){return this.#W}set file(t){this.#W=t}get uploadsURL(){return this.#$}set uploadsURL(t){this.#$=t}get csrfParamName(){return document.head.querySelector("meta[name=csrf-param]")?.content}get csrfToken(){return document.head.querySelector("meta[name=csrf-token]")?.content}}customElements.define("house-md-upload",v);export{a as Document,g as Editor,o as History,i as Selection,n as Toolbar,v as Upload};
+function w(s){return typeof s=="string"}function T(s){return s instanceof RegExp}function l(s,t,e=null,n=!1){return s.dispatchEvent(new CustomEvent(t,{bubbles:!0,detail:e,cancelable:n}))}function k(s){return new Promise(t=>setTimeout(t,s))}var p=class extends HTMLElement{constructor(){super()}connectedCallback(){this.#e(),this.addEventListener("click",this.#s),this.#t?.addEventListener("change",this.#n)}disconnectedCallback(){this.#t?.removeEventListener("change",this.#n),this.removeEventListener("click",this.#s)}get#t(){return this.querySelector("[data-house-md-toolbar-file-picker]")}#e(){this.#i()&&(this.innerHTML=this.#c())}#s=t=>{let e=t.target.closest("[data-house-md-action]")?.dataset?.houseMdAction;e&&(t.preventDefault(),l(this,"house-md:toolbar-action",{houseMdAction:e}))};#n=t=>{for(let e of t.target.files)l(this,"house-md:toolbar-action",{houseMdAction:"uploadFile",file:e})};#i(){return this.children.length===0}#c(){return`
+
+
+
+
+
+
+
+ `}};customElements.define("house-md-toolbar",p);var a=class s{start=0;end=0;static fromDOMRange(t,e){let{startOffset:n,startContainer:i,endOffset:r,endContainer:o}=t,m=E(e,i,n);if(t.collapsed)return new s(e,m,m);let C=E(e,o,r);return new s(e,m,C)}constructor(t,e,n){this.container=t,this.start=e,this.end=n}toDOMRange(){let t=document.createRange();t.setStart(this.container,1),t.setEnd(this.container,this.container.childNodes.length);let e=document.createTreeWalker(this.container,NodeFilter.SHOW_TEXT),n=0,i=!1,r=!1;for(;e.nextNode()&&!(i&&r);){let o=e.currentNode.textContent.length;n+o>=this.start&&!i&&(i=!0,t.setStart(e.currentNode,this.start-n)),n+o>=this.end&&!r&&(r=!0,t.setEnd(e.currentNode,this.end-n)),n+=o}return t}isEqual(t){return this.container===t.container&&this.start===t.start&&this.end===t.end}};function E(s,t,e){return t.nodeType===Node.ELEMENT_NODE?$(s,t,e):y(s,t,e)}function $(s,t,e){let n=t.childNodes[e],i=0,r=document.createTreeWalker(s);for(;r.nextNode();){if(r.currentNode===n)return i;r.currentNode.nodeType===Node.TEXT_NODE&&(i+=r.currentNode.textContent.length)}return i}function y(s,t,e){let n=document.createTreeWalker(s,NodeFilter.SHOW_TEXT);for(;n.nextNode();){if(n.currentNode===t)return e;e+=n.currentNode.textContent.length}return e}var d=class{#t;#e;#s;constructor(t){this.#t=t,this.#e=new a(this.contentElement,0,0),this.#s=""}current(){return{start:this.start,end:this.end,selection:this.#s}}currentLine(){return this.lineAt(this.end)}previousLine(){let{content:t}=this.#t,e=Math.max(t.lastIndexOf(`
+`,this.start-1),0);return this.lineAt(e)}lineAt(t){let{content:e}=this.#t,n=Math.max(e.lastIndexOf(`
+`,t-1)+1,0),i=e.indexOf(`
+`,t),r=i===-1?e.length:i+1,o=e.slice(n,r);return{start:n,end:r,content:o}}select({start:t,end:e}){this.documentRange=new a(this.contentElement,t,e);let n=this.documentRange.toDOMRange();if(n){let i=window.getSelection();i.removeAllRanges(),i.addRange(n),this.update()}else console.error("Failed to create range",{start:t,end:e})}update=()=>{let t=document.getSelection()?.getRangeAt(0),e=this.#e;t.intersectsNode(this.contentElement)&&(this.#e=a.fromDOMRange(t,this.contentElement),this.#s=this.#t.content.slice(this.start,this.end)),this.#e.isEqual(e)||l(this.element,"house-md:selectionchange",{start:this.start,end:this.end})};get start(){return this.#e.start}get end(){return this.#e.end}get element(){return this.#t.element}get contentElement(){return this.#t.contentElement}get isEmpty(){return this.start===this.end}get isMultiline(){return this.current().selection.includes(`
+`)}get isBold(){return this.#n("strong")}get isItalic(){return this.#n("em")}get isStrikethrough(){return this.#n("s")}get isLink(){return this.#n(".link")}get isCode(){return this.#n(".code")}get isQuote(){return this.#n(".quote")}get isBulletList(){return this.#n(".ul-li")}get isNumberList(){return this.#n(".ol-li")}#n(t){let i=window.getSelection().getRangeAt(0).endContainer;if(i.nodeType===Node.TEXT_NODE&&(i=i.parentElement),this.contentElement.contains(i))return!!i.closest(t)}};var c=class{static saveInterval=1e3;constructor(t=500){this.maxSize=t,this.undoStack=[],this.redoStack=[]}undo(t){let e=this.undoStack.pop();return e?(this.redoStack.push(t),e):{}}redo(t){let e=this.redoStack.pop();return e?(this.undoStack.push(t),e):{}}add=H(t=>{this.undoStack.push(t),this.redoStack=[],this.undoStack.length>this.maxSize&&this.undoStack.shift()})};function H(s){let t;return(...e)=>{t||(s(...e),t=setTimeout(()=>{t=null},c.saveInterval))}}function A(s){let t=s;return t=_(t),t=N(t),t=B(t),t=D(t),t=R(t),t=F(t),t=z(t),t=I(t),t}function _(s){return s=s.replaceAll(/&/g,"&"),s=s.replaceAll(//g,">"),s=s.replaceAll(/"/g,"""),s=s.replaceAll(/'/g,"'"),s}function N(s){return s=M(s),s=O(s),s=W(s),s=q(s),s=P(s),s}function B(s){return s=U(s),s=K(s),s=Q(s),s=X(s),s}function D(s){return V(s)}function R(s){return s.replaceAll(/(?[$1]($2)')}function F(s){return s.replaceAll(/!\[(.*?)\]\((.*?)\)/gm,'$&')}function z(s){return s=s.replaceAll(/^```(.*?)```$/gms,'```$1```'),s=s.replaceAll(/([^`])`([^`]+)`([^`])/gm,'$1`$2`$3'),s}function I(s){return s.replaceAll(/<!--(.*?)-->/gm,'')}function M(s){return s=s.replaceAll(/(?***$1***"),s=s.replaceAll(/(?___$1___"),s}function O(s){return s=s.replaceAll(/(?**$1**"),s=s.replaceAll(/(?__$1__"),s}function W(s){return s=s.replaceAll(/(?*$1*"),s=s.replaceAll(/(?_$1_"),s}function q(s){return s.replaceAll(/~~(.*)?~~/gm,"~~$1~~")}function P(s){return s.replaceAll(/==(.*?)==/gm,"==$1==")}function U(s){return s=s.replaceAll(/^# (.*)$/gm,'# $1'),s=s.replaceAll(/^## (.*)$/gm,'## $1'),s=s.replaceAll(/^### (.*)$/gm,'### $1'),s=s.replaceAll(/^#### (.*)$/gm,'#### $1'),s=s.replaceAll(/^##### (.*)$/gm,'##### $1'),s=s.replaceAll(/^###### (.*)$/gm,'###### $1'),s}function K(s){return s.replaceAll(/^(\d+\.\s.*)$/gm,'$1')}function Q(s){return s.replaceAll(/^(-\s.*)$/gm,'$1')}function X(s){return s.replaceAll(/^>(.*)$/gm,'>$1')}function V(s){return s.replaceAll(/\n---\n/gm,`
+---
+`)}var j="",u=class{constructor(t,e){this.content=t,this.element=e,this.selection=new d(this),this.history=new c}select(t,e){this.selection.select({start:t,end:e})}insertText(t){this.replaceText(t,this.currentSelection.start,this.currentSelection.end)}replaceText(t,e,n){let i=this.content.slice(0,e),r=this.content.slice(n),o=`${i}${t}${r}`,m={start:i.length+t.length,end:i.length+t.length};this.#d(),this.#l(o,m)}insertParagraph(t,e){this.select(t,e),this.selection.isBulletList?this.#c():this.selection.isNumberList?this.#h():this.replaceText(`
+`,t,e)}insertLink(t,e,n=""){let{start:i,end:r}=this.currentSelection,o=` ${n}[${t}](${e}) `;this.replaceText(o,i,r),this.selection.select({start:i+o.length,end:i+o.length})}insertFile(t,e,n){n.startsWith("image/")?this.insertImage(t,e):this.insertLink(t,e)}insertImage(t,e){this.insertLink(t,e,"!")}deleteText(t,e){this.replaceText("",Math.max(t,0),e)}deleteCurrentLine(){let{start:t,end:e}=this.currentLine;this.deleteText(t,e)}toggleBold(){this.#t(this.selection.isBold,"**")}toggleItalic(){this.#t(this.selection.isItalic,"_")}toggleStrikethrough(){this.#t(this.selection.isStrikethrough,"~~")}toggleCode(){let[t,e]=this.selection.isMultiline?["```\n","\n```"]:["`","`"];this.#t(this.selection.isCode,t,e)}toggleLink(){this.selection.isLink?this.#i():this.#n()}toggleQuote(){this.selection.isQuote?this.#o("> "):this.#r("> ")}toggleBulletList(){this.selection.isBulletList?this.#o("- "):this.#r("- ")}toggleNumberList(){this.selection.isNumberList?this.#o(/\d+\. /):this.#r(`${this.#u+1}. `)}undo(){let{content:t,start:e,end:n}=this.history.undo(this.#a);w(t)&&this.#l(t,{start:e,end:n})}redo(){let{content:t,start:e,end:n}=this.history.redo(this.#a);w(t)&&this.#l(t,{start:e,end:n})}render(){this.contentElement.innerHTML=A(this.content)+j}get isEmpty(){return!this.content.trim()}get contentElement(){return this.element.contentWrapper}get currentSelection(){return this.selection.current()}get currentLine(){return this.selection.currentLine()}#t(t,e,n=e){t?this.#s(e,n):this.#e(e,n)}#e(t,e=t){let{start:n,end:i,selection:r}=this.currentSelection,o=`${t}${r}${e}`;this.replaceText(o,n,i),this.selection.select({start:n,end:n+r.length+t.length+e.length})}#s(t,e=t){let{start:n,end:i,selection:r}=this.currentSelection;r.startsWith(t)&&r.endsWith(e)&&(this.replaceText("",i-e.length,i),this.replaceText("",n,n+t.length),this.selection.select({start:n,end:i-t.length-e.length}))}#n(){let{start:t,end:e,selection:n}=this.currentSelection,i=this.selection.isEmpty,r=i?"title":n;this.replaceText(`[${r}](url)`,t,e),i?this.selection.select({start:t+1,end:t+r.length+1}):this.selection.select({start:t+n.length+3,end:t+n.length+6})}#i(){let{start:t,end:e,selection:n}=this.currentSelection,i=n.replace(/\[(.*)\]\(.*\)/,"$1");this.replaceText(i,t,e)}#c(){this.#m.match(/^-\s+$/)?this.deleteCurrentLine():(this.replaceText(`
+`,this.currentSelection.end,this.currentSelection.end),this.replaceText("- ",this.currentSelection.end+1,this.currentSelection.end+1))}#h(){this.#m.match(/^\d+\.\s+$/)?this.deleteCurrentLine():(this.replaceText(`
+`,this.currentSelection.end,this.currentSelection.end),this.replaceText(`${this.#u+1}. `,this.currentSelection.end+1,this.currentSelection.end+1))}#r(t){let{start:e,end:n}=this.currentSelection,i=this.currentLine;this.replaceText(t,i.start,i.start),this.selection.select({start:e+t.length,end:n+t.length})}#o(t){let{start:e,end:n}=this.currentSelection,i=this.currentLine;if(T(t)){let r=i.content.match(t);if(r)t=r[0];else return}i.content.startsWith(t)&&(this.deleteText(i.start,i.start+t.length),this.selection.select({start:e-t.length,end:n-t.length}))}#d(){this.history.add(this.#a)}#l(t,e){let n=this.content;this.content=t,this.element.value=t,this.selection.select(e),l(this.element,"house-md:change",{previousContent:n,newContent:t})}get#a(){let{start:t,end:e}=this.currentSelection;return{content:this.content,start:t,end:e}}get#m(){return this.currentLine.content}get#u(){let e=this.selection.previousLine().content.match(/^(\d+). /);return e?parseInt(e[1]):0}};var g=class{#t;constructor(t){this.#t=t}asPlainText(){let e=new window.DOMParser().parseFromString(this.#t,"text/html");return this.#e(e.body).trim()}#e(t){return t.nodeType===Node.TEXT_NODE?t.nodeValue:Array.from(t.childNodes).map((e,n)=>{let i=this.#s(e),r=n>0&&this.#s(t.childNodes[n-1]);return(i&&r?`
+
+`:"")+this.#e(e)}).join("")}#s(t){return["BR","DIV","H1","H2","H3","H4","H5","H6","LI","P","TR"].includes(t.tagName)}};var f=class{constructor(t){this.document=t}handleInput(t,e){t.preventDefault();let n=this[`${t.inputType}Handler`];if(n){let i=t.getTargetRanges()[0],{start:r,end:o}=a.fromDOMRange(i,e);n.call(this,t,r,o)}else console.error("Not handling:",t.inputType)}insertTextHandler(t,e,n){this.#t(t,e,n)}insertCompositionTextHandler(t,e,n){this.#t(t,e,n)}insertParagraphHandler(t,e,n){this.document.insertParagraph(e,n)}insertLineBreakHandler(t,e,n){this.document.insertParagraph(e,n)}insertLinkHandler(t,e,n){this.#t(t,e,n)}insertFromYankHandler(t,e,n){this.#t(t,e,n)}insertFromDropHandler(t,e,n){this.#t(t,e,n)}insertFromPasteAsQuotationHandler(t,e,n){let i=t.dataTransfer.getData("text/plain");this.document.replaceText(`> ${i}`,e,n)}insertTransposeHandler(t,e,n){this.#t(t,e,n)}insertReplacementTextHandler(t,e,n){this.#t(t,e,n)}insertFromPasteHandler(t,e,n){this.#t(t,e,n)}deleteContentBackwardHandler(t,e,n){this.document.deleteText(e,n)}deleteByCutHandler(t,e,n){this.document.deleteText(e,n)}deleteWordBackwardHandler(t,e,n){this.document.deleteText(e,n)}deleteWordForwardHandler(t,e,n){this.document.deleteText(e,n)}deleteSoftLineBackwardHandler(t,e,n){this.document.deleteText(e,n)}deleteSoftLineForwardHandler(t,e,n){this.document.deleteText(e,n)}deleteEntireSoftLineHandler(t,e,n){this.document.deleteText(e,n)}deleteHardLineBackwardHandler(t,e,n){this.document.deleteText(e,n)}deleteHardLineForwardHandler(t,e,n){this.document.deleteText(e,n)}deleteByDragHandler(t,e,n){this.document.deleteText(e,n)}deleteContentHandler(t,e,n){this.document.deleteText(e,n)}deleteContentForwardHandler(t,e,n){this.document.deleteText(e,n)}#t(t,e,n){let i;if(t.data)i=t.data;else{let r=t.dataTransfer.getData("text/html");r?i=new g(r).asPlainText():i=t.dataTransfer.getData("text/plain")}this.document.replaceText(i,e,n)}};var h=class{constructor(t,e){this.element=t.closest("house-md"),this.file=e}upload(){if(l(this.element,"house-md:before-upload",{file:this.file})){let t=document.createElement("house-md-upload");t.file=this.file,t.uploadsURL=this.#t,this.element.appendChild(t)}}get#t(){return this.element.dataset.uploadsUrl||document.head.querySelector("meta[name=house-uploads-url]")?.content||"/uploads"}};var v=class{constructor(t){this.document=t}handleAction(t,e){let n=this[t];n?n.call(this,e):console.error("Not handling:",t)}bold(){this.document.toggleBold()}italic(){this.document.toggleItalic()}strikethrough(){this.document.toggleStrikethrough()}quote(){this.document.toggleQuote()}code(){this.document.toggleCode()}link(){this.document.toggleLink()}bulletList(){this.document.toggleBulletList()}numberList(){this.document.toggleNumberList()}undo(){this.document.undo()}redo(){this.document.redo()}uploadFile({file:t}){new h(this.document.element,t).upload()}};var b=class{constructor(t){this.element=t.closest("house-md")}handleDragOver(t){t.preventDefault()}async handleDrop(t){t.preventDefault();for(let e of t.dataTransfer.items)e.kind==="file"&&new h(this.element,e.getAsFile()).upload()}};var Y={"Ctrl+B":"bold","Ctrl+I":"italic","Ctrl+S":"strikethrough","Ctrl+Z":"undo","Ctrl+Shift+Z":"redo"};function S(s){return Y[Z(s)]}function Z(s){let t=[];return(s.metaKey||s.ctrlKey)&&t.push("Ctrl"),s.altKey&&t.push("Alt"),s.shiftKey&&t.push("Shift"),t.push(s.key.toUpperCase()),t.join("+")}var L=class extends HTMLElement{static formAssociated=!0;static observedAttributes=["initialized"];#t;constructor(){super(),this.internals=this.attachInternals(),this.internals.ariaRole="textbox"}attributeChangedCallback(t,e,n){t==="initialized"&&this.isConnected&&e!=null&&e!==n&&requestAnimationFrame(()=>this.#n())}connectedCallback(){let t=this.querySelector(".house-md-content")?.textContent||this.textContent;this.document=new u(t,this),this.#e(),this.#i(),this.inputHandler=new f(this.document),this.actionHandler=new v(this.document),this.dropAndDropHandler=new b(this),this.autofocus&&this.focus(),this.setAttribute("initialized",""),this.value=t}disconnectedCallback(){this.#c()}validate=t=>{this.required&&this.document.isEmpty?(t.preventDefault(),this.internals.setValidity({valueMissing:!0},"This field is required.",this.element),this.focus()):this.internals.setValidity({})};render(){this.document.render()}focus(){this.contentWrapper.focus()}get required(){return this.hasAttribute("required")}set required(t){t?this.setAttribute("required",""):this.removeAttribute("required")}get autofocus(){return this.hasAttribute("autofocus")}set autofocus(t){t?this.setAttribute("autofocus",""):this.removeAttribute("autofocus")}get value(){return this.document.content}set value(t){this.document.content=t,this.internals.setFormValue(t),this.internals.setValidity({}),this.render()}get form(){return this.internals.form}#e(){this.textContent="",this.toolbar=this.#s(),this.contentWrapper=document.createElement("div"),this.contentWrapper.classList.add("house-md-content"),this.contentWrapper.setAttribute("contenteditable",!0),this.contentWrapper.setAttribute("role","textbox"),this.contentWrapper.setAttribute("aria-multiline",!0),this.append(this.contentWrapper),this.getAttribute("tabindex")?(this.contentWrapper.setAttribute("tabindex",this.getAttribute("tabindex")),this.removeAttribute("tabindex")):this.contentWrapper.setAttribute("tabindex",0)}#s(){if(this.getAttribute("toolbar"))return document.getElementById(this.getAttribute("toolbar"));{let t=document.createElement("house-md-toolbar");return this.prepend(t),t}}#n(){this.disconnectedCallback(),this.getAttribute("toolbar")||this.toolbar.remove(),this.contentWrapper.remove(),this.connectedCallback()}#i(){this.addEventListener("beforeinput",this.#h),this.addEventListener("keydown",this.#r),this.addEventListener("dragover",this.#o),this.addEventListener("drop",this.#d),this.toolbar.addEventListener("house-md:toolbar-action",this.#l),document.addEventListener("selectionchange",this.#a),this.internals.form.addEventListener("submit",this.validate)}#c(){this.removeEventListener("beforeinput",this.#h),this.removeEventListener("keydown",this.#r),this.removeEventListener("dragover",this.#o),this.removeEventListener("drop",this.#d),this.toolbar.removeEventListener("house-md:toolbar-action",this.#l),document.removeEventListener("selectionchange",this.#a),this.internals.form.removeEventListener("submit",this.validate)}#h=t=>{this.inputHandler.handleInput(t,this.contentWrapper)};#r(t){let e=S(t);e&&(t.preventDefault(),this.actionHandler.handleAction(e))}#o=t=>{this.dropAndDropHandler.handleDragOver(t)};#d=t=>{this.dropAndDropHandler.handleDrop(t)};#l=({detail:t})=>{this.actionHandler.handleAction(t.houseMdAction,t)};#a=()=>{this.document.selection.update()}};customElements.define("house-md",L);var x=class extends HTMLElement{#t;#e;#s;constructor(){super(),this.percentComplete=0,this.status="pending"}connectedCallback(){this.#i(),this.#n(),this.addEventListener("click",this.#u)}disconnectedCallback(){this.removeEventListener("click",this.#u)}async#n(){let t=new FormData;t.append("file",this.file),this.csrfParamName&&t.append(this.csrfParamName,this.csrfToken),this.xhr=new XMLHttpRequest,this.xhr.open("POST",this.uploadsURL,!0),this.xhr.upload.onprogress=this.#d,this.xhr.onload=this.#l,this.xhr.onerror=this.#a,this.xhr.onabort=this.#m,this.xhr.send(t),this.status="uploading",this.#i()}#i(){this.setAttribute("status",this.status),this.innerHTML=`
+ ${this.#c()}
+ ${this.#h()}
+ ${this.#r()}
+ ${this.#o()}
+ `}#c(){return this.status==="failed"?"":""}#h(){return`${this.file.name}
`}#r(){return``}#o(){return this.#s?`${this.#s}
`:""}#d=t=>{t.lengthComputable&&(this.percentComplete=t.loaded/t.total*100),this.#i()};#l=async()=>{if(this.xhr.status>=400)this.status="failed",this.#s=this.xhr.responseText||"Upload failed";else{let t=JSON.parse(this.xhr.responseText);await this.document.insertFile(t.fileName,t.fileUrl,t.mimetype),this.status="complete",this.#p()}this.#i()};#a=()=>{this.status="failed",this.#i()};#m=()=>{this.status="aborted",this.#i()};#u=t=>{t.target.matches("[data-md-action=close]")&&this.remove()};async#p(t=500){await k(t),this.remove()}get document(){return this.closest("house-md").document}get file(){return this.#t}set file(t){this.#t=t}get uploadsURL(){return this.#e}set uploadsURL(t){this.#e=t}get csrfParamName(){return document.head.querySelector("meta[name=csrf-param]")?.content}get csrfToken(){return document.head.querySelector("meta[name=csrf-token]")?.content}};customElements.define("house-md-upload",x);export{u as Document,L as Editor,c as History,d as Selection,p as Toolbar,x as Upload};
+//# sourceMappingURL=house.min.js.map