katalyst-content 2.3.0 → 2.3.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 86aa5ff124fb4175818c4e2fdbe017cdaecc50df97dc63ae069c33ada1bb1bc8
4
- data.tar.gz: 7eb9de0943680c5aef75425a17677966d18ecea6eab5d7238c0e50d0b627d24d
3
+ metadata.gz: 6514b8584c595435b0faafa8c2deb0a8c55f68b50c2ae1cfa1711a2ea04c9e19
4
+ data.tar.gz: a18b11993855fc869c8e066738d04676c351cddb8d3cf1b783ce7a5a902d3d78
5
5
  SHA512:
6
- metadata.gz: 918d42e7e35390b201c1ec38ae7831b9a2f7c92aeaddc5978c63475e1c02e4e056baf977e6de662d002336dcfefc71589567fd8daf2a411fad9b51a4494ba856
7
- data.tar.gz: 94e6e0c3ce6556775bc6295c1e8ac81b37189d6ff2d81222a12eb5e15cc4f025674b49bf48b3b8482d94728d38ff4df1dad4c1d8dc5835f964183687a49f8d9a
6
+ metadata.gz: 527092db7219dc854ee1ae0fbdfeff26ac30408b435db466be8af2f605b076fadcebea8cc1612c5366af859dedc1c53edb5bd9ddb3ff67afb4620a27ca62e235
7
+ data.tar.gz: 0a144f07560924951e4e3ff453fe74583a3a6b610d98440f716286ac7a894617c523ef6be0b0d4eaeb45f70d2875f3c132137c88340feb1b196204b8ad394117
@@ -968,8 +968,16 @@ class StatusBarController extends Controller {
968
968
  }
969
969
  }
970
970
 
971
+ const EDITOR = `
972
+ <div class="content--editor--table-editor"
973
+ contenteditable="true"
974
+ data-content--editor--table-target="content"
975
+ data-action="paste->content--editor--table#paste"
976
+ id="item-content-field">
977
+ </div>`;
978
+
971
979
  class TableController extends Controller {
972
- static targets = ["content", "input", "update"];
980
+ static targets = ["input", "update"];
973
981
 
974
982
  constructor(config) {
975
983
  super(config);
@@ -978,7 +986,15 @@ class TableController extends Controller {
978
986
  }
979
987
 
980
988
  connect() {
981
- this.observer.observe(this.contentTarget, {
989
+ const template = document.createElement("TEMPLATE");
990
+ template.innerHTML = EDITOR;
991
+ this.content = template.content.firstElementChild;
992
+ this.content.innerHTML = this.inputTarget.value;
993
+ this.content.className += ` ${this.inputTarget.className}`;
994
+ this.inputTarget.insertAdjacentElement("beforebegin", this.content);
995
+ this.inputTarget.hidden = true;
996
+
997
+ this.observer.observe(this.content, {
982
998
  attributes: true,
983
999
  childList: true,
984
1000
  characterData: true,
@@ -988,10 +1004,12 @@ class TableController extends Controller {
988
1004
 
989
1005
  disconnect() {
990
1006
  this.observer.disconnect();
1007
+ this.content.remove();
1008
+ delete this.content;
991
1009
  }
992
1010
 
993
1011
  change = (mutations) => {
994
- this.inputTarget.value = this.table.outerHTML;
1012
+ this.inputTarget.value = this.table?.outerHTML;
995
1013
  };
996
1014
 
997
1015
  update = () => {
@@ -999,6 +1017,8 @@ class TableController extends Controller {
999
1017
  };
1000
1018
 
1001
1019
  paste = (e) => {
1020
+ if (e.clipboardData.getData("text/html").indexOf("<table") === -1) return;
1021
+
1002
1022
  e.preventDefault();
1003
1023
 
1004
1024
  this.inputTarget.value = e.clipboardData.getData("text/html");
@@ -1010,7 +1030,7 @@ class TableController extends Controller {
1010
1030
  * @returns {HTMLTableElement} The table element from the content target
1011
1031
  */
1012
1032
  get table() {
1013
- return this.contentTarget.querySelector("table");
1033
+ return this.content.querySelector("table");
1014
1034
  }
1015
1035
  }
1016
1036
 
@@ -968,8 +968,16 @@ class StatusBarController extends Controller {
968
968
  }
969
969
  }
970
970
 
971
+ const EDITOR = `
972
+ <div class="content--editor--table-editor"
973
+ contenteditable="true"
974
+ data-content--editor--table-target="content"
975
+ data-action="paste->content--editor--table#paste"
976
+ id="item-content-field">
977
+ </div>`;
978
+
971
979
  class TableController extends Controller {
972
- static targets = ["content", "input", "update"];
980
+ static targets = ["input", "update"];
973
981
 
974
982
  constructor(config) {
975
983
  super(config);
@@ -978,7 +986,15 @@ class TableController extends Controller {
978
986
  }
979
987
 
980
988
  connect() {
981
- this.observer.observe(this.contentTarget, {
989
+ const template = document.createElement("TEMPLATE");
990
+ template.innerHTML = EDITOR;
991
+ this.content = template.content.firstElementChild;
992
+ this.content.innerHTML = this.inputTarget.value;
993
+ this.content.className += ` ${this.inputTarget.className}`;
994
+ this.inputTarget.insertAdjacentElement("beforebegin", this.content);
995
+ this.inputTarget.hidden = true;
996
+
997
+ this.observer.observe(this.content, {
982
998
  attributes: true,
983
999
  childList: true,
984
1000
  characterData: true,
@@ -988,10 +1004,12 @@ class TableController extends Controller {
988
1004
 
989
1005
  disconnect() {
990
1006
  this.observer.disconnect();
1007
+ this.content.remove();
1008
+ delete this.content;
991
1009
  }
992
1010
 
993
1011
  change = (mutations) => {
994
- this.inputTarget.value = this.table.outerHTML;
1012
+ this.inputTarget.value = this.table?.outerHTML;
995
1013
  };
996
1014
 
997
1015
  update = () => {
@@ -999,6 +1017,8 @@ class TableController extends Controller {
999
1017
  };
1000
1018
 
1001
1019
  paste = (e) => {
1020
+ if (e.clipboardData.getData("text/html").indexOf("<table") === -1) return;
1021
+
1002
1022
  e.preventDefault();
1003
1023
 
1004
1024
  this.inputTarget.value = e.clipboardData.getData("text/html");
@@ -1010,7 +1030,7 @@ class TableController extends Controller {
1010
1030
  * @returns {HTMLTableElement} The table element from the content target
1011
1031
  */
1012
1032
  get table() {
1013
- return this.contentTarget.querySelector("table");
1033
+ return this.content.querySelector("table");
1014
1034
  }
1015
1035
  }
1016
1036
 
@@ -1,2 +1,2 @@
1
- import{Controller as t}from"@hotwired/stimulus";import"trix";class e{static comparator(t,e){return t.index-e.index}constructor(t){this.node=t}get itemId(){return this.node.dataset.contentItemId}get#t(){return this.node.querySelector('input[name$="[id]"]')}set itemId(t){this.itemId!==t&&(this.node.dataset.contentItemId=`${t}`,this.#t.value=`${t}`)}get depth(){return parseInt(this.node.dataset.contentDepth)||0}get#e(){return this.node.querySelector('input[name$="[depth]"]')}set depth(t){this.depth!==t&&(this.node.dataset.contentDepth=`${t}`,this.#e.value=`${t}`)}get index(){return parseInt(this.node.dataset.contentIndex)}get#n(){return this.node.querySelector('input[name$="[index]"]')}set index(t){this.index!==t&&(this.node.dataset.contentIndex=`${t}`,this.#n.value=`${t}`)}get isLayout(){return this.node.hasAttribute("data-content-layout")}get previousItem(){let t=this.node.previousElementSibling;if(t)return new e(t)}get nextItem(){let t=this.node.nextElementSibling;if(t)return new e(t)}hasCollapsedDescendants(){let t=this.#i;return!!t&&t.children.length>0}hasExpandedDescendants(){let t=this.nextItem;return!!t&&t.depth>this.depth}traverse(t){const e=this.#a;t(this),this.#s(t),e.forEach((e=>e.#s(t)))}#s(t){this.hasCollapsedDescendants()&&this.#r.forEach((e=>{t(e),e.#s(t)}))}collapseChild(t){this.#i.appendChild(t.node)}collapse(){let t=this.#i;t||(t=function(t){const e=document.createElement("ol");return e.setAttribute("class","hidden"),e.dataset.contentChildren="",t.appendChild(e),e}(this.node)),this.#a.forEach((e=>t.appendChild(e.node)))}expand(){this.hasCollapsedDescendants()&&Array.from(this.#i.children).reverse().forEach((t=>{this.node.insertAdjacentElement("afterend",t)}))}toggleRule(t,e=!1){this.node.dataset.hasOwnProperty(t)&&!e&&delete this.node.dataset[t],!this.node.dataset.hasOwnProperty(t)&&e&&(this.node.dataset[t]=""),"denyDrag"===t&&(this.node.hasAttribute("draggable")||e||this.node.setAttribute("draggable","true"),this.node.hasAttribute("draggable")&&e&&this.node.removeAttribute("draggable"))}hasItemIdChanged(){return!(this.#t.value===this.itemId)}updateAfterChange(){this.itemId=this.#t.value,this.#n.value=this.index,this.#e.value=this.depth}get#i(){return this.node.querySelector(":scope > [data-content-children]")}get#a(){const t=[];let e=this.nextItem;for(;e&&e.depth>this.depth;)t.push(e),e=e.nextItem;return t}get#r(){return this.hasCollapsedDescendants()?Array.from(this.#i.children).map((t=>new e(t))):[]}}class n{constructor(t){this.node=t}get items(){return t=this.node.querySelectorAll("[data-content-index]"),Array.from(t).map((t=>new e(t)));var t}get state(){const t=this.node.querySelectorAll("li input[type=hidden]");return Array.from(t).map((t=>t.value)).join("/")}reindex(){this.items.map(((t,e)=>t.index=e))}reset(){this.items.sort(e.comparator).forEach((t=>{this.node.appendChild(t.node)}))}}class i{static rules=["denyDeNest","denyNest","denyCollapse","denyExpand","denyRemove","denyDrag","denyEdit"];constructor(t=!1){this.debug=t?(...t)=>console.log(...t):()=>{}}normalize(t){this.firstItemDepthZero(t),this.depthMustBeSet(t),this.itemCannotHaveInvalidDepth(t),this.parentMustBeLayout(t),this.parentCannotHaveExpandedAndCollapsedChildren(t)}update(t){this.rules={},this.parentsCannotDeNest(t),this.rootsCannotDeNest(t),this.onlyLastItemCanDeNest(t),this.nestingNeedsParent(t),this.leavesCannotCollapse(t),this.needHiddenItemsToExpand(t),this.parentsCannotBeDeleted(t),this.parentsCannotBeDragged(t),i.rules.forEach((e=>{t.toggleRule(e,!!this.rules[e])}))}firstItemDepthZero(t){0===t.index&&0!==t.depth&&(this.debug(`enforce depth on item ${t.index}: ${t.depth} => 0`),t.depth=0)}depthMustBeSet(t){(isNaN(t.depth)||t.depth<0)&&(this.debug(`unset depth on item ${t.index}: => 0`),t.depth=0)}itemCannotHaveInvalidDepth(t){const e=t.previousItem;e&&e.depth<t.depth-1&&(this.debug(`invalid depth on item ${t.index}: ${t.depth} => ${e.depth+1}`),t.depth=e.depth+1)}parentMustBeLayout(t){const e=t.previousItem;e&&e.depth<t.depth&&!e.isLayout&&(this.debug(`invalid parent for item ${t.index}: ${t.depth} => ${e.depth}`),t.depth=e.depth)}parentCannotHaveExpandedAndCollapsedChildren(t){t.hasCollapsedDescendants()&&t.hasExpandedDescendants()&&(this.debug(`expanding collapsed children of item ${t.index}`),t.expand())}parentsCannotDeNest(t){t.hasExpandedDescendants()&&this.#o("denyDeNest")}rootsCannotDeNest(t){0===t.depth&&this.#o("denyDeNest")}onlyLastItemCanDeNest(t){const e=t.nextItem;e&&e.depth===t.depth&&!t.isLayout&&this.#o("denyDeNest")}leavesCannotCollapse(t){t.hasExpandedDescendants()||this.#o("denyCollapse")}needHiddenItemsToExpand(t){t.hasCollapsedDescendants()||this.#o("denyExpand")}nestingNeedsParent(t){const e=t.previousItem;e?e.depth<t.depth?this.#o("denyNest"):e.depth!==t.depth||e.isLayout||this.#o("denyNest"):this.#o("denyNest")}parentsCannotBeDeleted(t){t.itemId&&!t.hasExpandedDescendants()||this.#o("denyRemove")}parentsCannotBeDragged(t){t.hasExpandedDescendants()&&this.#o("denyDrag")}#o(t){this.rules[t]=!0}}function a(t){return new e(t.target.closest("[data-content-item]"))}function s(t,e){if(t&&t!==e){if("LI"===t.nodeName){const n=t.compareDocumentPosition(e);n&Node.DOCUMENT_POSITION_FOLLOWING?t.insertAdjacentElement("beforebegin",e):n&Node.DOCUMENT_POSITION_PRECEDING&&t.insertAdjacentElement("afterend",e)}"OL"===t.nodeName&&t.appendChild(e)}}function r(t){return t&&(t.closest("[data-controller='content--editor--list'] > *")||t.closest("[data-controller='content--editor--list']"))}const o=window.Trix;o.config.blockAttributes.heading4={tagName:"h4",terminal:!0,breakOnReturn:!0,group:!1},delete o.config.blockAttributes.heading1;o.config.toolbar.getDefaultHTML=()=>{const{lang:t}=o.config;return`\n<div class="trix-button-row">\n <span class="trix-button-group trix-button-group--text-tools" data-trix-button-group="text-tools">\n <button type="button" class="trix-button trix-button--icon trix-button--icon-bold" data-trix-attribute="bold" data-trix-key="b" title="${t.bold}" tabindex="-1">${t.bold}</button>\n <button type="button" class="trix-button trix-button--icon trix-button--icon-italic" data-trix-attribute="italic" data-trix-key="i" title="${t.italic}" tabindex="-1">${t.italic}</button>\n <button type="button" class="trix-button trix-button--icon trix-button--icon-strike" data-trix-attribute="strike" title="${t.strike}" tabindex="-1">${t.strike}</button>\n <button type="button" class="trix-button trix-button--icon trix-button--icon-link" data-trix-attribute="href" data-trix-action="link" data-trix-key="k" title="${t.link}" tabindex="-1">${t.link}</button>\n </span>\n <span class="trix-button-group trix-button-group--block-tools" data-trix-button-group="block-tools">\n <button type="button" class="trix-button trix-button--icon trix-button--icon-heading-1" data-trix-attribute="heading4" title="${t.heading1}" tabindex="-1">${t.heading1}</button>\n <button type="button" class="trix-button trix-button--icon trix-button--icon-quote" data-trix-attribute="quote" title="${t.quote}" tabindex="-1">${t.quote}</button>\n <button type="button" class="trix-button trix-button--icon trix-button--icon-code" data-trix-attribute="code" title="${t.code}" tabindex="-1">${t.code}</button>\n <button type="button" class="trix-button trix-button--icon trix-button--icon-bullet-list" data-trix-attribute="bullet" title="${t.bullets}" tabindex="-1">${t.bullets}</button>\n <button type="button" class="trix-button trix-button--icon trix-button--icon-number-list" data-trix-attribute="number" title="${t.numbers}" tabindex="-1">${t.numbers}</button>\n <button type="button" class="trix-button trix-button--icon trix-button--icon-decrease-nesting-level" data-trix-action="decreaseNestingLevel" title="${t.outdent}" tabindex="-1">${t.outdent}</button>\n <button type="button" class="trix-button trix-button--icon trix-button--icon-increase-nesting-level" data-trix-action="increaseNestingLevel" title="${t.indent}" tabindex="-1">${t.indent}</button>\n </span>\n <span class="trix-button-group trix-button-group--file-tools" data-trix-button-group="file-tools">\n <button type="button" class="trix-button trix-button--icon trix-button--icon-attach" data-trix-action="attachFiles" title="${t.attachFiles}" tabindex="-1">${t.attachFiles}</button>\n </span>\n <span class="trix-button-group-spacer"></span>\n <span class="trix-button-group trix-button-group--history-tools" data-trix-button-group="history-tools">\n <button type="button" class="trix-button trix-button--icon trix-button--icon-undo" data-trix-action="undo" data-trix-key="z" title="${t.undo}" tabindex="-1">${t.undo}</button>\n <button type="button" class="trix-button trix-button--icon trix-button--icon-redo" data-trix-action="redo" data-trix-key="shift+z" title="${t.redo}" tabindex="-1">${t.redo}</button>\n </span>\n</div>\n<div class="trix-dialogs" data-trix-dialogs>\n <div class="trix-dialog trix-dialog--link" data-trix-dialog="href" data-trix-dialog-attribute="href">\n <div class="trix-dialog__link-fields">\n <input type="text" name="href" pattern="(https?|mailto:|tel:|/|#).*?" class="trix-input trix-input--dialog" placeholder="${t.urlPlaceholder}" aria-label="${t.url}" required data-trix-input>\n <div class="trix-button-group">\n <input type="button" class="trix-button trix-button--dialog" value="${t.link}" data-trix-method="setAttribute">\n <input type="button" class="trix-button trix-button--dialog" value="${t.unlink}" data-trix-method="removeAttribute">\n </div>\n </div>\n </div>\n</div>\n`},document.querySelectorAll("trix-toolbar").forEach((t=>{t.innerHTML=o.config.toolbar.getDefaultHTML()}));const d=[{identifier:"content--editor--container",controllerConstructor:class extends t{static targets=["container"];connect(){this.state=this.container.state,this.reindex()}get container(){return new n(this.containerTarget)}reindex(){this.container.reindex(),this.#d()}reset(){this.container.reset()}drop(t){this.container.reindex();const e=a(t),n=e.previousItem;let i=0;i=void 0===n?-e.depth:n.isLayout&&e.nextItem&&e.nextItem.depth>n.depth?n.depth-e.depth+1:n.depth-e.depth,e.traverse((t=>{t.depth+=i})),this.#d(),t.preventDefault()}remove(t){a(t).node.remove(),this.#d(),t.preventDefault()}nest(t){a(t).traverse((t=>{t.depth+=1})),this.#d(),t.preventDefault()}deNest(t){a(t).traverse((t=>{t.depth-=1})),this.#d(),t.preventDefault()}collapse(t){a(t).collapse(),this.#d(),t.preventDefault()}expand(t){a(t).expand(),this.#d(),t.preventDefault()}#d(){this.updateRequested=!0,setTimeout((()=>{if(!this.updateRequested)return;this.updateRequested=!1;const t=new i;this.container.items.forEach((e=>t.normalize(e))),this.container.items.forEach((e=>t.update(e))),this.#l()}),0)}#l(){this.dispatch("change",{bubbles:!0,prefix:"content",detail:{dirty:this.#u()}})}#u(){return this.container.state!==this.state}}},{identifier:"content--editor--item",controllerConstructor:class extends t{get item(){return new e(this.li)}get ol(){return this.element.closest("ol")}get li(){return this.element.closest("li")}connect(){this.element.dataset.hasOwnProperty("delete")?this.remove():this.item.index>=0?this.item.hasItemIdChanged()&&(this.item.updateAfterChange(),this.reindex()):this.reindex()}remove(){this.ol,this.li.remove(),this.reindex()}reindex(){this.dispatch("reindex",{bubbles:!0,prefix:"content"})}}},{identifier:"content--editor--list",controllerConstructor:class extends t{connect(){this.enterCount=0}dragstart(t){if(this.element!==t.target.parentElement)return;const e=t.target;t.dataTransfer.effectAllowed="move",requestAnimationFrame((()=>e.dataset.dragging=""))}dragover(t){const e=this.dragItem;if(e)return s(r(t.target),e),t.preventDefault(),!0}dragenter(t){if(t.preventDefault(),this.enterCount++,function(t){return"copy"===t.dataTransfer.effectAllowed||"copyMove"===t.dataTransfer.effectAllowed}(t)&&!this.dragItem){const t=document.createElement("li");t.dataset.dragging="",t.dataset.newItem="",this.element.appendChild(t)}}dragleave(t){this.enterCount--,this.enterCount<=0&&this.dragItem.dataset.hasOwnProperty("newItem")&&(this.dragItem.remove(),this.reset())}drop(t){let e=this.dragItem;if(e){if(t.preventDefault(),delete e.dataset.dragging,s(r(t.target),e),e.dataset.hasOwnProperty("newItem")){const n=e,i=document.createElement("template");i.innerHTML=t.dataTransfer.getData("text/html"),e=i.content.querySelector("li"),this.element.replaceChild(e,n),requestAnimationFrame((()=>e.querySelector("[role='button'][value='edit']").click()))}this.dispatch("drop",{target:e,bubbles:!0,prefix:"content"})}}dragend(){const t=this.dragItem;t&&(t.dataset.hasOwnProperty("newItem")?t.remove():(delete t.dataset.dragging,this.reset()))}get isDragging(){return!!this.dragItem}get dragItem(){return this.element.querySelector("[data-dragging]")}reindex(){this.dispatch("reindex",{bubbles:!0,prefix:"content"})}reset(){this.dispatch("reset",{bubbles:!0,prefix:"content"})}}},{identifier:"content--editor--new-item",controllerConstructor:class extends t{static targets=["template"];dragstart(t){this.element===t.target&&(t.dataTransfer.setData("text/html",this.templateTarget.innerHTML),t.dataTransfer.effectAllowed="copy")}}},{identifier:"content--editor--status-bar",controllerConstructor:class extends t{connect(){this.versionState=this.element.dataset.state}change(t){t.detail&&t.detail.hasOwnProperty("dirty")&&this.update(t.detail)}update({dirty:t}){this.element.dataset.state=t?"dirty":this.versionState}}},{identifier:"content--editor--table",controllerConstructor:class extends t{static targets=["content","input","update"];constructor(t){super(t),this.observer=new MutationObserver(this.change)}connect(){this.observer.observe(this.contentTarget,{attributes:!0,childList:!0,characterData:!0,subtree:!0})}disconnect(){this.observer.disconnect()}change=t=>{this.inputTarget.value=this.table.outerHTML};update=()=>{this.updateTarget.click()};paste=t=>{t.preventDefault(),this.inputTarget.value=t.clipboardData.getData("text/html"),this.update()};get table(){return this.contentTarget.querySelector("table")}}},{identifier:"content--editor--trix",controllerConstructor:class extends t{trixInitialize(t){}}}];export{d as default};
1
+ import{Controller as t}from"@hotwired/stimulus";import"trix";class e{static comparator(t,e){return t.index-e.index}constructor(t){this.node=t}get itemId(){return this.node.dataset.contentItemId}get#t(){return this.node.querySelector('input[name$="[id]"]')}set itemId(t){this.itemId!==t&&(this.node.dataset.contentItemId=`${t}`,this.#t.value=`${t}`)}get depth(){return parseInt(this.node.dataset.contentDepth)||0}get#e(){return this.node.querySelector('input[name$="[depth]"]')}set depth(t){this.depth!==t&&(this.node.dataset.contentDepth=`${t}`,this.#e.value=`${t}`)}get index(){return parseInt(this.node.dataset.contentIndex)}get#n(){return this.node.querySelector('input[name$="[index]"]')}set index(t){this.index!==t&&(this.node.dataset.contentIndex=`${t}`,this.#n.value=`${t}`)}get isLayout(){return this.node.hasAttribute("data-content-layout")}get previousItem(){let t=this.node.previousElementSibling;if(t)return new e(t)}get nextItem(){let t=this.node.nextElementSibling;if(t)return new e(t)}hasCollapsedDescendants(){let t=this.#i;return!!t&&t.children.length>0}hasExpandedDescendants(){let t=this.nextItem;return!!t&&t.depth>this.depth}traverse(t){const e=this.#a;t(this),this.#s(t),e.forEach((e=>e.#s(t)))}#s(t){this.hasCollapsedDescendants()&&this.#r.forEach((e=>{t(e),e.#s(t)}))}collapseChild(t){this.#i.appendChild(t.node)}collapse(){let t=this.#i;t||(t=function(t){const e=document.createElement("ol");return e.setAttribute("class","hidden"),e.dataset.contentChildren="",t.appendChild(e),e}(this.node)),this.#a.forEach((e=>t.appendChild(e.node)))}expand(){this.hasCollapsedDescendants()&&Array.from(this.#i.children).reverse().forEach((t=>{this.node.insertAdjacentElement("afterend",t)}))}toggleRule(t,e=!1){this.node.dataset.hasOwnProperty(t)&&!e&&delete this.node.dataset[t],!this.node.dataset.hasOwnProperty(t)&&e&&(this.node.dataset[t]=""),"denyDrag"===t&&(this.node.hasAttribute("draggable")||e||this.node.setAttribute("draggable","true"),this.node.hasAttribute("draggable")&&e&&this.node.removeAttribute("draggable"))}hasItemIdChanged(){return!(this.#t.value===this.itemId)}updateAfterChange(){this.itemId=this.#t.value,this.#n.value=this.index,this.#e.value=this.depth}get#i(){return this.node.querySelector(":scope > [data-content-children]")}get#a(){const t=[];let e=this.nextItem;for(;e&&e.depth>this.depth;)t.push(e),e=e.nextItem;return t}get#r(){return this.hasCollapsedDescendants()?Array.from(this.#i.children).map((t=>new e(t))):[]}}class n{constructor(t){this.node=t}get items(){return t=this.node.querySelectorAll("[data-content-index]"),Array.from(t).map((t=>new e(t)));var t}get state(){const t=this.node.querySelectorAll("li input[type=hidden]");return Array.from(t).map((t=>t.value)).join("/")}reindex(){this.items.map(((t,e)=>t.index=e))}reset(){this.items.sort(e.comparator).forEach((t=>{this.node.appendChild(t.node)}))}}class i{static rules=["denyDeNest","denyNest","denyCollapse","denyExpand","denyRemove","denyDrag","denyEdit"];constructor(t=!1){this.debug=t?(...t)=>console.log(...t):()=>{}}normalize(t){this.firstItemDepthZero(t),this.depthMustBeSet(t),this.itemCannotHaveInvalidDepth(t),this.parentMustBeLayout(t),this.parentCannotHaveExpandedAndCollapsedChildren(t)}update(t){this.rules={},this.parentsCannotDeNest(t),this.rootsCannotDeNest(t),this.onlyLastItemCanDeNest(t),this.nestingNeedsParent(t),this.leavesCannotCollapse(t),this.needHiddenItemsToExpand(t),this.parentsCannotBeDeleted(t),this.parentsCannotBeDragged(t),i.rules.forEach((e=>{t.toggleRule(e,!!this.rules[e])}))}firstItemDepthZero(t){0===t.index&&0!==t.depth&&(this.debug(`enforce depth on item ${t.index}: ${t.depth} => 0`),t.depth=0)}depthMustBeSet(t){(isNaN(t.depth)||t.depth<0)&&(this.debug(`unset depth on item ${t.index}: => 0`),t.depth=0)}itemCannotHaveInvalidDepth(t){const e=t.previousItem;e&&e.depth<t.depth-1&&(this.debug(`invalid depth on item ${t.index}: ${t.depth} => ${e.depth+1}`),t.depth=e.depth+1)}parentMustBeLayout(t){const e=t.previousItem;e&&e.depth<t.depth&&!e.isLayout&&(this.debug(`invalid parent for item ${t.index}: ${t.depth} => ${e.depth}`),t.depth=e.depth)}parentCannotHaveExpandedAndCollapsedChildren(t){t.hasCollapsedDescendants()&&t.hasExpandedDescendants()&&(this.debug(`expanding collapsed children of item ${t.index}`),t.expand())}parentsCannotDeNest(t){t.hasExpandedDescendants()&&this.#o("denyDeNest")}rootsCannotDeNest(t){0===t.depth&&this.#o("denyDeNest")}onlyLastItemCanDeNest(t){const e=t.nextItem;e&&e.depth===t.depth&&!t.isLayout&&this.#o("denyDeNest")}leavesCannotCollapse(t){t.hasExpandedDescendants()||this.#o("denyCollapse")}needHiddenItemsToExpand(t){t.hasCollapsedDescendants()||this.#o("denyExpand")}nestingNeedsParent(t){const e=t.previousItem;e?e.depth<t.depth?this.#o("denyNest"):e.depth!==t.depth||e.isLayout||this.#o("denyNest"):this.#o("denyNest")}parentsCannotBeDeleted(t){t.itemId&&!t.hasExpandedDescendants()||this.#o("denyRemove")}parentsCannotBeDragged(t){t.hasExpandedDescendants()&&this.#o("denyDrag")}#o(t){this.rules[t]=!0}}function a(t){return new e(t.target.closest("[data-content-item]"))}function s(t,e){if(t&&t!==e){if("LI"===t.nodeName){const n=t.compareDocumentPosition(e);n&Node.DOCUMENT_POSITION_FOLLOWING?t.insertAdjacentElement("beforebegin",e):n&Node.DOCUMENT_POSITION_PRECEDING&&t.insertAdjacentElement("afterend",e)}"OL"===t.nodeName&&t.appendChild(e)}}function r(t){return t&&(t.closest("[data-controller='content--editor--list'] > *")||t.closest("[data-controller='content--editor--list']"))}const o=window.Trix;o.config.blockAttributes.heading4={tagName:"h4",terminal:!0,breakOnReturn:!0,group:!1},delete o.config.blockAttributes.heading1;o.config.toolbar.getDefaultHTML=()=>{const{lang:t}=o.config;return`\n<div class="trix-button-row">\n <span class="trix-button-group trix-button-group--text-tools" data-trix-button-group="text-tools">\n <button type="button" class="trix-button trix-button--icon trix-button--icon-bold" data-trix-attribute="bold" data-trix-key="b" title="${t.bold}" tabindex="-1">${t.bold}</button>\n <button type="button" class="trix-button trix-button--icon trix-button--icon-italic" data-trix-attribute="italic" data-trix-key="i" title="${t.italic}" tabindex="-1">${t.italic}</button>\n <button type="button" class="trix-button trix-button--icon trix-button--icon-strike" data-trix-attribute="strike" title="${t.strike}" tabindex="-1">${t.strike}</button>\n <button type="button" class="trix-button trix-button--icon trix-button--icon-link" data-trix-attribute="href" data-trix-action="link" data-trix-key="k" title="${t.link}" tabindex="-1">${t.link}</button>\n </span>\n <span class="trix-button-group trix-button-group--block-tools" data-trix-button-group="block-tools">\n <button type="button" class="trix-button trix-button--icon trix-button--icon-heading-1" data-trix-attribute="heading4" title="${t.heading1}" tabindex="-1">${t.heading1}</button>\n <button type="button" class="trix-button trix-button--icon trix-button--icon-quote" data-trix-attribute="quote" title="${t.quote}" tabindex="-1">${t.quote}</button>\n <button type="button" class="trix-button trix-button--icon trix-button--icon-code" data-trix-attribute="code" title="${t.code}" tabindex="-1">${t.code}</button>\n <button type="button" class="trix-button trix-button--icon trix-button--icon-bullet-list" data-trix-attribute="bullet" title="${t.bullets}" tabindex="-1">${t.bullets}</button>\n <button type="button" class="trix-button trix-button--icon trix-button--icon-number-list" data-trix-attribute="number" title="${t.numbers}" tabindex="-1">${t.numbers}</button>\n <button type="button" class="trix-button trix-button--icon trix-button--icon-decrease-nesting-level" data-trix-action="decreaseNestingLevel" title="${t.outdent}" tabindex="-1">${t.outdent}</button>\n <button type="button" class="trix-button trix-button--icon trix-button--icon-increase-nesting-level" data-trix-action="increaseNestingLevel" title="${t.indent}" tabindex="-1">${t.indent}</button>\n </span>\n <span class="trix-button-group trix-button-group--file-tools" data-trix-button-group="file-tools">\n <button type="button" class="trix-button trix-button--icon trix-button--icon-attach" data-trix-action="attachFiles" title="${t.attachFiles}" tabindex="-1">${t.attachFiles}</button>\n </span>\n <span class="trix-button-group-spacer"></span>\n <span class="trix-button-group trix-button-group--history-tools" data-trix-button-group="history-tools">\n <button type="button" class="trix-button trix-button--icon trix-button--icon-undo" data-trix-action="undo" data-trix-key="z" title="${t.undo}" tabindex="-1">${t.undo}</button>\n <button type="button" class="trix-button trix-button--icon trix-button--icon-redo" data-trix-action="redo" data-trix-key="shift+z" title="${t.redo}" tabindex="-1">${t.redo}</button>\n </span>\n</div>\n<div class="trix-dialogs" data-trix-dialogs>\n <div class="trix-dialog trix-dialog--link" data-trix-dialog="href" data-trix-dialog-attribute="href">\n <div class="trix-dialog__link-fields">\n <input type="text" name="href" pattern="(https?|mailto:|tel:|/|#).*?" class="trix-input trix-input--dialog" placeholder="${t.urlPlaceholder}" aria-label="${t.url}" required data-trix-input>\n <div class="trix-button-group">\n <input type="button" class="trix-button trix-button--dialog" value="${t.link}" data-trix-method="setAttribute">\n <input type="button" class="trix-button trix-button--dialog" value="${t.unlink}" data-trix-method="removeAttribute">\n </div>\n </div>\n </div>\n</div>\n`},document.querySelectorAll("trix-toolbar").forEach((t=>{t.innerHTML=o.config.toolbar.getDefaultHTML()}));const d=[{identifier:"content--editor--container",controllerConstructor:class extends t{static targets=["container"];connect(){this.state=this.container.state,this.reindex()}get container(){return new n(this.containerTarget)}reindex(){this.container.reindex(),this.#d()}reset(){this.container.reset()}drop(t){this.container.reindex();const e=a(t),n=e.previousItem;let i=0;i=void 0===n?-e.depth:n.isLayout&&e.nextItem&&e.nextItem.depth>n.depth?n.depth-e.depth+1:n.depth-e.depth,e.traverse((t=>{t.depth+=i})),this.#d(),t.preventDefault()}remove(t){a(t).node.remove(),this.#d(),t.preventDefault()}nest(t){a(t).traverse((t=>{t.depth+=1})),this.#d(),t.preventDefault()}deNest(t){a(t).traverse((t=>{t.depth-=1})),this.#d(),t.preventDefault()}collapse(t){a(t).collapse(),this.#d(),t.preventDefault()}expand(t){a(t).expand(),this.#d(),t.preventDefault()}#d(){this.updateRequested=!0,setTimeout((()=>{if(!this.updateRequested)return;this.updateRequested=!1;const t=new i;this.container.items.forEach((e=>t.normalize(e))),this.container.items.forEach((e=>t.update(e))),this.#l()}),0)}#l(){this.dispatch("change",{bubbles:!0,prefix:"content",detail:{dirty:this.#u()}})}#u(){return this.container.state!==this.state}}},{identifier:"content--editor--item",controllerConstructor:class extends t{get item(){return new e(this.li)}get ol(){return this.element.closest("ol")}get li(){return this.element.closest("li")}connect(){this.element.dataset.hasOwnProperty("delete")?this.remove():this.item.index>=0?this.item.hasItemIdChanged()&&(this.item.updateAfterChange(),this.reindex()):this.reindex()}remove(){this.ol,this.li.remove(),this.reindex()}reindex(){this.dispatch("reindex",{bubbles:!0,prefix:"content"})}}},{identifier:"content--editor--list",controllerConstructor:class extends t{connect(){this.enterCount=0}dragstart(t){if(this.element!==t.target.parentElement)return;const e=t.target;t.dataTransfer.effectAllowed="move",requestAnimationFrame((()=>e.dataset.dragging=""))}dragover(t){const e=this.dragItem;if(e)return s(r(t.target),e),t.preventDefault(),!0}dragenter(t){if(t.preventDefault(),this.enterCount++,function(t){return"copy"===t.dataTransfer.effectAllowed||"copyMove"===t.dataTransfer.effectAllowed}(t)&&!this.dragItem){const t=document.createElement("li");t.dataset.dragging="",t.dataset.newItem="",this.element.appendChild(t)}}dragleave(t){this.enterCount--,this.enterCount<=0&&this.dragItem.dataset.hasOwnProperty("newItem")&&(this.dragItem.remove(),this.reset())}drop(t){let e=this.dragItem;if(e){if(t.preventDefault(),delete e.dataset.dragging,s(r(t.target),e),e.dataset.hasOwnProperty("newItem")){const n=e,i=document.createElement("template");i.innerHTML=t.dataTransfer.getData("text/html"),e=i.content.querySelector("li"),this.element.replaceChild(e,n),requestAnimationFrame((()=>e.querySelector("[role='button'][value='edit']").click()))}this.dispatch("drop",{target:e,bubbles:!0,prefix:"content"})}}dragend(){const t=this.dragItem;t&&(t.dataset.hasOwnProperty("newItem")?t.remove():(delete t.dataset.dragging,this.reset()))}get isDragging(){return!!this.dragItem}get dragItem(){return this.element.querySelector("[data-dragging]")}reindex(){this.dispatch("reindex",{bubbles:!0,prefix:"content"})}reset(){this.dispatch("reset",{bubbles:!0,prefix:"content"})}}},{identifier:"content--editor--new-item",controllerConstructor:class extends t{static targets=["template"];dragstart(t){this.element===t.target&&(t.dataTransfer.setData("text/html",this.templateTarget.innerHTML),t.dataTransfer.effectAllowed="copy")}}},{identifier:"content--editor--status-bar",controllerConstructor:class extends t{connect(){this.versionState=this.element.dataset.state}change(t){t.detail&&t.detail.hasOwnProperty("dirty")&&this.update(t.detail)}update({dirty:t}){this.element.dataset.state=t?"dirty":this.versionState}}},{identifier:"content--editor--table",controllerConstructor:class extends t{static targets=["input","update"];constructor(t){super(t),this.observer=new MutationObserver(this.change)}connect(){const t=document.createElement("TEMPLATE");t.innerHTML='\n<div class="content--editor--table-editor"\n contenteditable="true"\n data-content--editor--table-target="content"\n data-action="paste->content--editor--table#paste"\n id="item-content-field">\n</div>',this.content=t.content.firstElementChild,this.content.innerHTML=this.inputTarget.value,this.content.className+=` ${this.inputTarget.className}`,this.inputTarget.insertAdjacentElement("beforebegin",this.content),this.inputTarget.hidden=!0,this.observer.observe(this.content,{attributes:!0,childList:!0,characterData:!0,subtree:!0})}disconnect(){this.observer.disconnect(),this.content.remove(),delete this.content}change=t=>{this.inputTarget.value=this.table?.outerHTML};update=()=>{this.updateTarget.click()};paste=t=>{-1!==t.clipboardData.getData("text/html").indexOf("<table")&&(t.preventDefault(),this.inputTarget.value=t.clipboardData.getData("text/html"),this.update())};get table(){return this.content.querySelector("table")}}},{identifier:"content--editor--trix",controllerConstructor:class extends t{trixInitialize(t){}}}];export{d as default};
2
2
  //# sourceMappingURL=content.min.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"content.min.js","sources":["../../../javascript/content/editor/item.js","../../../javascript/content/editor/container.js","../../../javascript/content/editor/rules_engine.js","../../../javascript/content/editor/container_controller.js","../../../javascript/content/editor/list_controller.js","../../../javascript/content/editor/trix_controller.js","../../../javascript/content/application.js","../../../javascript/content/editor/item_controller.js","../../../javascript/content/editor/new_item_controller.js","../../../javascript/content/editor/status_bar_controller.js","../../../javascript/content/editor/table_controller.js"],"sourcesContent":["export default class Item {\n /**\n * Sort items by their index.\n *\n * @param a {Item}\n * @param b {Item}\n * @returns {number}\n */\n static comparator(a, b) {\n return a.index - b.index;\n }\n\n /**\n * @param node {Element} li[data-content-index]\n */\n constructor(node) {\n this.node = node;\n }\n\n /**\n * @returns {String} id of the node's item (from data attributes)\n */\n get itemId() {\n return this.node.dataset[`contentItemId`];\n }\n\n get #itemIdInput() {\n return this.node.querySelector(`input[name$=\"[id]\"]`);\n }\n\n /**\n * @param itemId {String} id\n */\n set itemId(id) {\n if (this.itemId === id) return;\n\n this.node.dataset[`contentItemId`] = `${id}`;\n this.#itemIdInput.value = `${id}`;\n }\n\n /**\n * @returns {number} logical nesting depth of node in container\n */\n get depth() {\n return parseInt(this.node.dataset[`contentDepth`]) || 0;\n }\n\n get #depthInput() {\n return this.node.querySelector(`input[name$=\"[depth]\"]`);\n }\n\n /**\n * @param depth {number} depth >= 0\n */\n set depth(depth) {\n if (this.depth === depth) return;\n\n this.node.dataset[`contentDepth`] = `${depth}`;\n this.#depthInput.value = `${depth}`;\n }\n\n /**\n * @returns {number} logical index of node in container (pre-order traversal)\n */\n get index() {\n return parseInt(this.node.dataset[`contentIndex`]);\n }\n\n get #indexInput() {\n return this.node.querySelector(`input[name$=\"[index]\"]`);\n }\n\n /**\n * @param index {number} index >= 0\n */\n set index(index) {\n if (this.index === index) return;\n\n this.node.dataset[`contentIndex`] = `${index}`;\n this.#indexInput.value = `${index}`;\n }\n\n /**\n * @returns {boolean} true if this item can have children\n */\n get isLayout() {\n return this.node.hasAttribute(\"data-content-layout\");\n }\n\n /**\n * @returns {Item} nearest neighbour (index - 1)\n */\n get previousItem() {\n let sibling = this.node.previousElementSibling;\n if (sibling) return new Item(sibling);\n }\n\n /**\n * @returns {Item} nearest neighbour (index + 1)\n */\n get nextItem() {\n let sibling = this.node.nextElementSibling;\n if (sibling) return new Item(sibling);\n }\n\n /**\n * @returns {boolean} true if this item has any collapsed children\n */\n hasCollapsedDescendants() {\n let childrenList = this.#childrenListElement;\n return !!childrenList && childrenList.children.length > 0;\n }\n\n /**\n * @returns {boolean} true if this item has any expanded children\n */\n hasExpandedDescendants() {\n let sibling = this.nextItem;\n return !!sibling && sibling.depth > this.depth;\n }\n\n /**\n * Recursively traverse the node and its descendants.\n *\n * @callback {Item}\n */\n traverse(callback) {\n // capture descendants before traversal in case of side-effects\n // specifically, setting depth affects calculation\n const expanded = this.#expandedDescendants;\n\n callback(this);\n this.#traverseCollapsed(callback);\n expanded.forEach((item) => item.#traverseCollapsed(callback));\n }\n\n /**\n * Recursively traverse the node's collapsed descendants, if any.\n *\n * @callback {Item}\n */\n #traverseCollapsed(callback) {\n if (!this.hasCollapsedDescendants()) return;\n\n this.#collapsedDescendants.forEach((item) => {\n callback(item);\n item.#traverseCollapsed(callback);\n });\n }\n\n /**\n * Move the given item into this element's hidden children list.\n * Assumes the list already exists.\n *\n * @param item {Item}\n */\n collapseChild(item) {\n this.#childrenListElement.appendChild(item.node);\n }\n\n /**\n * Collapses visible (logical) children into this element's hidden children\n * list, creating it if it doesn't already exist.\n */\n collapse() {\n let listElement = this.#childrenListElement;\n\n if (!listElement) listElement = createChildrenList(this.node);\n\n this.#expandedDescendants.forEach((child) =>\n listElement.appendChild(child.node),\n );\n }\n\n /**\n * Moves any collapsed children back into the parent container.\n */\n expand() {\n if (!this.hasCollapsedDescendants()) return;\n\n Array.from(this.#childrenListElement.children)\n .reverse()\n .forEach((node) => {\n this.node.insertAdjacentElement(\"afterend\", node);\n });\n }\n\n /**\n * Sets the state of a given rule on the target node.\n *\n * @param rule {String}\n * @param deny {boolean}\n */\n toggleRule(rule, deny = false) {\n if (this.node.dataset.hasOwnProperty(rule) && !deny) {\n delete this.node.dataset[rule];\n }\n if (!this.node.dataset.hasOwnProperty(rule) && deny) {\n this.node.dataset[rule] = \"\";\n }\n\n if (rule === \"denyDrag\") {\n if (!this.node.hasAttribute(\"draggable\") && !deny) {\n this.node.setAttribute(\"draggable\", \"true\");\n }\n if (this.node.hasAttribute(\"draggable\") && deny) {\n this.node.removeAttribute(\"draggable\");\n }\n }\n }\n\n /**\n * Detects turbo item changes by comparing the dataset id with the input\n */\n hasItemIdChanged() {\n return !(this.#itemIdInput.value === this.itemId);\n }\n\n /**\n * Updates inputs, in case they don't match the data values, e.g., when the\n * nested inputs have been hot-swapped by turbo with data from the server.\n *\n * Updates itemId from input as that is the canonical source.\n */\n updateAfterChange() {\n this.itemId = this.#itemIdInput.value;\n this.#indexInput.value = this.index;\n this.#depthInput.value = this.depth;\n }\n\n /**\n * Finds the dom container for storing collapsed (hidden) children, if present.\n *\n * @returns {Element} ol[data-content-children]\n */\n get #childrenListElement() {\n return this.node.querySelector(`:scope > [data-content-children]`);\n }\n\n /**\n * @returns {Item[]} all items that follow this element that have a greater depth.\n */\n get #expandedDescendants() {\n const descendants = [];\n\n let sibling = this.nextItem;\n while (sibling && sibling.depth > this.depth) {\n descendants.push(sibling);\n sibling = sibling.nextItem;\n }\n\n return descendants;\n }\n\n /**\n * @returns {Item[]} all items directly contained inside this element's hidden children element.\n */\n get #collapsedDescendants() {\n if (!this.hasCollapsedDescendants()) return [];\n\n return Array.from(this.#childrenListElement.children).map(\n (node) => new Item(node),\n );\n }\n}\n\n/**\n * Finds or creates a dom container for storing collapsed (hidden) children.\n *\n * @param node {Element} li[data-content-index]\n * @returns {Element} ol[data-content-children]\n */\nfunction createChildrenList(node) {\n const childrenList = document.createElement(\"ol\");\n childrenList.setAttribute(\"class\", \"hidden\");\n\n // if objectType is \"rich-content\" set richContentChildren as a data attribute\n childrenList.dataset[`contentChildren`] = \"\";\n\n node.appendChild(childrenList);\n\n return childrenList;\n}\n","import Item from \"./item\";\n\n/**\n * @param nodes {NodeList}\n * @returns {Item[]}\n */\nfunction createItemList(nodes) {\n return Array.from(nodes).map((node) => new Item(node));\n}\n\nexport default class Container {\n /**\n * @param node {Element} content editor list\n */\n constructor(node) {\n this.node = node;\n }\n\n /**\n * @return {Item[]} an ordered list of all items in the container\n */\n get items() {\n return createItemList(this.node.querySelectorAll(\"[data-content-index]\"));\n }\n\n /**\n * @return {String} a serialized description of the structure of the container\n */\n get state() {\n const inputs = this.node.querySelectorAll(\"li input[type=hidden]\");\n return Array.from(inputs)\n .map((e) => e.value)\n .join(\"/\");\n }\n\n /**\n * Set the index of items based on their current position.\n */\n reindex() {\n this.items.map((item, index) => (item.index = index));\n }\n\n /**\n * Resets the order of items to their defined index.\n * Useful after an aborted drag.\n */\n reset() {\n this.items.sort(Item.comparator).forEach((item) => {\n this.node.appendChild(item.node);\n });\n }\n}\n","export default class RulesEngine {\n static rules = [\n \"denyDeNest\",\n \"denyNest\",\n \"denyCollapse\",\n \"denyExpand\",\n \"denyRemove\",\n \"denyDrag\",\n \"denyEdit\",\n ];\n\n constructor(debug = false) {\n if (debug) {\n this.debug = (...args) => console.log(...args);\n } else {\n this.debug = () => {};\n }\n }\n\n /**\n * Enforce structural rules to ensure that the given item is currently in a\n * valid state.\n *\n * @param {Item} item\n */\n normalize(item) {\n // structural rules enforce a valid tree structure\n this.firstItemDepthZero(item);\n this.depthMustBeSet(item);\n this.itemCannotHaveInvalidDepth(item);\n this.parentMustBeLayout(item);\n this.parentCannotHaveExpandedAndCollapsedChildren(item);\n }\n\n /**\n * Apply rules to the given item to determine what operations are permitted.\n *\n * @param {Item} item\n */\n update(item) {\n this.rules = {};\n\n // behavioural rules define what the user is allowed to do\n this.parentsCannotDeNest(item);\n this.rootsCannotDeNest(item);\n this.onlyLastItemCanDeNest(item);\n this.nestingNeedsParent(item);\n this.leavesCannotCollapse(item);\n this.needHiddenItemsToExpand(item);\n this.parentsCannotBeDeleted(item);\n this.parentsCannotBeDragged(item);\n\n RulesEngine.rules.forEach((rule) => {\n item.toggleRule(rule, !!this.rules[rule]);\n });\n }\n\n /**\n * First item can't have a parent, so its depth should always be 0\n */\n firstItemDepthZero(item) {\n if (item.index === 0 && item.depth !== 0) {\n this.debug(`enforce depth on item ${item.index}: ${item.depth} => 0`);\n\n item.depth = 0;\n }\n }\n\n /**\n * Every item should have a non-negative depth set.\n *\n * @param {Item} item\n */\n depthMustBeSet(item) {\n if (isNaN(item.depth) || item.depth < 0) {\n this.debug(`unset depth on item ${item.index}: => 0`);\n\n item.depth = 0;\n }\n }\n\n /**\n * Depth must increase stepwise.\n *\n * @param {Item} item\n */\n itemCannotHaveInvalidDepth(item) {\n const previous = item.previousItem;\n if (previous && previous.depth < item.depth - 1) {\n this.debug(\n `invalid depth on item ${item.index}: ${item.depth} => ${\n previous.depth + 1\n }`,\n );\n\n item.depth = previous.depth + 1;\n }\n }\n\n /**\n * Parent item, if any, must be a layout.\n *\n * @param {Item} item\n */\n parentMustBeLayout(item) {\n // if we're the first child, make sure our parent is a layout\n // if we're a sibling, we know the previous item is valid so we must be too\n const previous = item.previousItem;\n if (previous && previous.depth < item.depth && !previous.isLayout) {\n this.debug(\n `invalid parent for item ${item.index}: ${item.depth} => ${previous.depth}`,\n );\n\n item.depth = previous.depth;\n }\n }\n\n /**\n * If a parent has expanded and collapsed children, expand.\n *\n * @param {Item} item\n */\n parentCannotHaveExpandedAndCollapsedChildren(item) {\n if (item.hasCollapsedDescendants() && item.hasExpandedDescendants()) {\n this.debug(`expanding collapsed children of item ${item.index}`);\n\n item.expand();\n }\n }\n\n /**\n * De-nesting an item would create a gap of 2 between itself and its children\n *\n * @param {Item} item\n */\n parentsCannotDeNest(item) {\n if (item.hasExpandedDescendants()) this.#deny(\"denyDeNest\");\n }\n\n /**\n * Item depth can't go below 0.\n *\n * @param {Item} item\n */\n rootsCannotDeNest(item) {\n if (item.depth === 0) this.#deny(\"denyDeNest\");\n }\n\n /**\n * De-nesting an item that has siblings would make it a container.\n *\n * @param {Item} item\n */\n onlyLastItemCanDeNest(item) {\n const next = item.nextItem;\n if (next && next.depth === item.depth && !item.isLayout)\n this.#deny(\"denyDeNest\");\n }\n\n /**\n * If an item doesn't have children it can't be collapsed.\n *\n * @param {Item} item\n */\n leavesCannotCollapse(item) {\n if (!item.hasExpandedDescendants()) this.#deny(\"denyCollapse\");\n }\n\n /**\n * If an item doesn't have any hidden descendants then it can't be expanded.\n *\n * @param {Item} item\n */\n needHiddenItemsToExpand(item) {\n if (!item.hasCollapsedDescendants()) this.#deny(\"denyExpand\");\n }\n\n /**\n * An item can't be nested (indented) if it doesn't have a valid parent.\n *\n * @param {Item} item\n */\n nestingNeedsParent(item) {\n const previous = item.previousItem;\n // no previous, so cannot nest\n if (!previous) this.#deny(\"denyNest\");\n // previous is too shallow, nesting would increase depth too much\n else if (previous.depth < item.depth) this.#deny(\"denyNest\");\n // new parent is not a layout\n else if (previous.depth === item.depth && !previous.isLayout)\n this.#deny(\"denyNest\");\n }\n\n /**\n * An item can't be deleted if it has visible children.\n *\n * @param {Item} item\n */\n parentsCannotBeDeleted(item) {\n if (!item.itemId || item.hasExpandedDescendants()) this.#deny(\"denyRemove\");\n }\n\n /**\n * Items cannot be dragged if they have visible children.\n *\n * @param {Item} item\n */\n parentsCannotBeDragged(item) {\n if (item.hasExpandedDescendants()) this.#deny(\"denyDrag\");\n }\n\n /**\n * Record a deny.\n *\n * @param rule {String}\n */\n #deny(rule) {\n this.rules[rule] = true;\n }\n}\n","import { Controller } from \"@hotwired/stimulus\";\n\nimport Item from \"./item\";\nimport Container from \"./container\";\nimport RulesEngine from \"./rules_engine\";\n\nexport default class ContainerController extends Controller {\n static targets = [\"container\"];\n\n connect() {\n this.state = this.container.state;\n\n this.reindex();\n }\n\n get container() {\n return new Container(this.containerTarget);\n }\n\n reindex() {\n this.container.reindex();\n this.#update();\n }\n\n reset() {\n this.container.reset();\n }\n\n drop(event) {\n this.container.reindex(); // set indexes before calculating previous\n\n const item = getEventItem(event);\n const previous = item.previousItem;\n\n let delta = 0;\n if (previous === undefined) {\n // if previous does not exist, set depth to 0\n delta = -item.depth;\n } else if (\n previous.isLayout &&\n item.nextItem &&\n item.nextItem.depth > previous.depth\n ) {\n // if previous is a layout and next is a child of previous, make item a child of previous\n delta = previous.depth - item.depth + 1;\n } else {\n // otherwise, make item a sibling of previous\n delta = previous.depth - item.depth;\n }\n\n item.traverse((child) => {\n child.depth += delta;\n });\n\n this.#update();\n event.preventDefault();\n }\n\n remove(event) {\n const item = getEventItem(event);\n\n item.node.remove();\n\n this.#update();\n event.preventDefault();\n }\n\n nest(event) {\n const item = getEventItem(event);\n\n item.traverse((child) => {\n child.depth += 1;\n });\n\n this.#update();\n event.preventDefault();\n }\n\n deNest(event) {\n const item = getEventItem(event);\n\n item.traverse((child) => {\n child.depth -= 1;\n });\n\n this.#update();\n event.preventDefault();\n }\n\n collapse(event) {\n const item = getEventItem(event);\n\n item.collapse();\n\n this.#update();\n event.preventDefault();\n }\n\n expand(event) {\n const item = getEventItem(event);\n\n item.expand();\n\n this.#update();\n event.preventDefault();\n }\n\n /**\n * Re-apply rules to items to enable/disable appropriate actions.\n */\n #update() {\n // debounce requests to ensure that we only update once per tick\n this.updateRequested = true;\n setTimeout(() => {\n if (!this.updateRequested) return;\n\n this.updateRequested = false;\n const engine = new RulesEngine();\n this.container.items.forEach((item) => engine.normalize(item));\n this.container.items.forEach((item) => engine.update(item));\n\n this.#notifyChange();\n }, 0);\n }\n\n #notifyChange() {\n this.dispatch(\"change\", {\n bubbles: true,\n prefix: \"content\",\n detail: { dirty: this.#isDirty() },\n });\n }\n\n #isDirty() {\n return this.container.state !== this.state;\n }\n}\n\nfunction getEventItem(event) {\n return new Item(event.target.closest(\"[data-content-item]\"));\n}\n","import { Controller } from \"@hotwired/stimulus\";\n\nexport default class ListController extends Controller {\n connect() {\n this.enterCount = 0;\n }\n\n /**\n * When the user starts a drag within the list, set the item's dataTransfer\n * properties to indicate that it's being dragged and update its style.\n *\n * We delay setting the dataset property until the next animation frame\n * so that the style updates can be computed before the drag begins.\n *\n * @param event {DragEvent}\n */\n dragstart(event) {\n if (this.element !== event.target.parentElement) return;\n\n const target = event.target;\n event.dataTransfer.effectAllowed = \"move\";\n\n // update element style after drag has begun\n requestAnimationFrame(() => (target.dataset.dragging = \"\"));\n }\n\n /**\n * When the user drags an item over another item in the last, swap the\n * dragging item with the item under the cursor.\n *\n * As a special case, if the item is dragged over placeholder space at the end\n * of the list, move the item to the bottom of the list instead. This allows\n * users to hit the list element more easily when adding new items to an empty\n * list.\n *\n * @param event {DragEvent}\n */\n dragover(event) {\n const item = this.dragItem;\n if (!item) return;\n\n swap(dropTarget(event.target), item);\n\n event.preventDefault();\n return true;\n }\n\n /**\n * When the user drags an item into the list, create a placeholder item to\n * represent the new item. Note that we can't access the drag data\n * until drop, so we assume that this is our template item for now.\n *\n * Users can cancel the drag by dragging the item out of the list or by\n * pressing escape. Both are handled by `cancelDrag`.\n *\n * @param event {DragEvent}\n */\n dragenter(event) {\n event.preventDefault();\n\n // Safari doesn't support relatedTarget, so we count enter/leave pairs\n this.enterCount++;\n\n if (copyAllowed(event) && !this.dragItem) {\n const item = document.createElement(\"li\");\n item.dataset.dragging = \"\";\n item.dataset.newItem = \"\";\n this.element.appendChild(item);\n }\n }\n\n /**\n * When the user drags the item out of the list, remove the placeholder.\n * This allows users to cancel the drag by dragging the item out of the list.\n *\n * @param event {DragEvent}\n */\n dragleave(event) {\n // Safari doesn't support relatedTarget, so we count enter/leave pairs\n // https://bugs.webkit.org/show_bug.cgi?id=66547\n this.enterCount--;\n\n if (\n this.enterCount <= 0 &&\n this.dragItem.dataset.hasOwnProperty(\"newItem\")\n ) {\n this.dragItem.remove();\n this.reset();\n }\n }\n\n /**\n * When the user drops an item into the list, end the drag and reindex the list.\n *\n * If the item is a new item, we replace the placeholder with the template\n * item data from the dataTransfer API.\n *\n * @param event {DragEvent}\n */\n drop(event) {\n let item = this.dragItem;\n\n if (!item) return;\n\n event.preventDefault();\n delete item.dataset.dragging;\n swap(dropTarget(event.target), item);\n\n if (item.dataset.hasOwnProperty(\"newItem\")) {\n const placeholder = item;\n const template = document.createElement(\"template\");\n template.innerHTML = event.dataTransfer.getData(\"text/html\");\n item = template.content.querySelector(\"li\");\n\n this.element.replaceChild(item, placeholder);\n requestAnimationFrame(() =>\n item.querySelector(\"[role='button'][value='edit']\").click(),\n );\n }\n\n this.dispatch(\"drop\", { target: item, bubbles: true, prefix: \"content\" });\n }\n\n /**\n * End an in-progress drag. If the item is a new item, remove it, otherwise\n * reset the item's style and restore its original position in the list.\n */\n dragend() {\n const item = this.dragItem;\n\n if (!item) {\n } else if (item.dataset.hasOwnProperty(\"newItem\")) {\n item.remove();\n } else {\n delete item.dataset.dragging;\n this.reset();\n }\n }\n\n get isDragging() {\n return !!this.dragItem;\n }\n\n get dragItem() {\n return this.element.querySelector(\"[data-dragging]\");\n }\n\n reindex() {\n this.dispatch(\"reindex\", { bubbles: true, prefix: \"content\" });\n }\n\n reset() {\n this.dispatch(\"reset\", { bubbles: true, prefix: \"content\" });\n }\n}\n\n/**\n * Swaps two list items. If target is a list, the item is appended.\n *\n * @param target the target element to swap with\n * @param item the item the user is dragging\n */\nfunction swap(target, item) {\n if (!target) return;\n if (target === item) return;\n\n if (target.nodeName === \"LI\") {\n const positionComparison = target.compareDocumentPosition(item);\n if (positionComparison & Node.DOCUMENT_POSITION_FOLLOWING) {\n target.insertAdjacentElement(\"beforebegin\", item);\n } else if (positionComparison & Node.DOCUMENT_POSITION_PRECEDING) {\n target.insertAdjacentElement(\"afterend\", item);\n }\n }\n\n if (target.nodeName === \"OL\") {\n target.appendChild(item);\n }\n}\n\n/**\n * Returns true if the event supports copy or copy move.\n *\n * Chrome and Firefox use copy, but Safari only supports copyMove.\n */\nfunction copyAllowed(event) {\n return (\n event.dataTransfer.effectAllowed === \"copy\" ||\n event.dataTransfer.effectAllowed === \"copyMove\"\n );\n}\n\n/**\n * Given an event target, return the closest drop target, if any.\n */\nfunction dropTarget(e) {\n return (\n e &&\n (e.closest(\"[data-controller='content--editor--list'] > *\") ||\n e.closest(\"[data-controller='content--editor--list']\"))\n );\n}\n","import { Controller } from \"@hotwired/stimulus\";\nimport \"trix\";\n\n// Note, action_text 7.1.2 changes how Trix is bundled and loaded. This\n// seems to have broken the default export from trix. This is a workaround\n// that relies on the backwards compatibility of the old export to window.Trix.\nconst Trix = window.Trix;\n\n// Stimulus controller doesn't do anything, but having one ensures that trix\n// will be lazy loaded when a trix-editor is added to the dom.\nexport default class TrixController extends Controller {\n trixInitialize(e) {\n // noop, useful as an extension point for registering behaviour on load\n }\n}\n\n// Add H4 as an acceptable tag\nTrix.config.blockAttributes[\"heading4\"] = {\n tagName: \"h4\",\n terminal: true,\n breakOnReturn: true,\n group: false,\n};\n\n// Remove H1 from trix list of acceptable tags\ndelete Trix.config.blockAttributes.heading1;\n\n/**\n * Allow users to enter path and fragment URIs which the input[type=url] browser\n * input does not permit. Uses a permissive regex pattern which is not suitable\n * for untrusted use cases.\n */\nconst LINK_PATTERN = \"(https?|mailto:|tel:|/|#).*?\";\n\n/**\n * Customize default toolbar:\n *\n * * headings: h4 instead of h1\n * * links: use type=text instead of type=url\n *\n * @returns {String} toolbar html fragment\n */\nTrix.config.toolbar.getDefaultHTML = () => {\n const { lang } = Trix.config;\n return `\n<div class=\"trix-button-row\">\n <span class=\"trix-button-group trix-button-group--text-tools\" data-trix-button-group=\"text-tools\">\n <button type=\"button\" class=\"trix-button trix-button--icon trix-button--icon-bold\" data-trix-attribute=\"bold\" data-trix-key=\"b\" title=\"${lang.bold}\" tabindex=\"-1\">${lang.bold}</button>\n <button type=\"button\" class=\"trix-button trix-button--icon trix-button--icon-italic\" data-trix-attribute=\"italic\" data-trix-key=\"i\" title=\"${lang.italic}\" tabindex=\"-1\">${lang.italic}</button>\n <button type=\"button\" class=\"trix-button trix-button--icon trix-button--icon-strike\" data-trix-attribute=\"strike\" title=\"${lang.strike}\" tabindex=\"-1\">${lang.strike}</button>\n <button type=\"button\" class=\"trix-button trix-button--icon trix-button--icon-link\" data-trix-attribute=\"href\" data-trix-action=\"link\" data-trix-key=\"k\" title=\"${lang.link}\" tabindex=\"-1\">${lang.link}</button>\n </span>\n <span class=\"trix-button-group trix-button-group--block-tools\" data-trix-button-group=\"block-tools\">\n <button type=\"button\" class=\"trix-button trix-button--icon trix-button--icon-heading-1\" data-trix-attribute=\"heading4\" title=\"${lang.heading1}\" tabindex=\"-1\">${lang.heading1}</button>\n <button type=\"button\" class=\"trix-button trix-button--icon trix-button--icon-quote\" data-trix-attribute=\"quote\" title=\"${lang.quote}\" tabindex=\"-1\">${lang.quote}</button>\n <button type=\"button\" class=\"trix-button trix-button--icon trix-button--icon-code\" data-trix-attribute=\"code\" title=\"${lang.code}\" tabindex=\"-1\">${lang.code}</button>\n <button type=\"button\" class=\"trix-button trix-button--icon trix-button--icon-bullet-list\" data-trix-attribute=\"bullet\" title=\"${lang.bullets}\" tabindex=\"-1\">${lang.bullets}</button>\n <button type=\"button\" class=\"trix-button trix-button--icon trix-button--icon-number-list\" data-trix-attribute=\"number\" title=\"${lang.numbers}\" tabindex=\"-1\">${lang.numbers}</button>\n <button type=\"button\" class=\"trix-button trix-button--icon trix-button--icon-decrease-nesting-level\" data-trix-action=\"decreaseNestingLevel\" title=\"${lang.outdent}\" tabindex=\"-1\">${lang.outdent}</button>\n <button type=\"button\" class=\"trix-button trix-button--icon trix-button--icon-increase-nesting-level\" data-trix-action=\"increaseNestingLevel\" title=\"${lang.indent}\" tabindex=\"-1\">${lang.indent}</button>\n </span>\n <span class=\"trix-button-group trix-button-group--file-tools\" data-trix-button-group=\"file-tools\">\n <button type=\"button\" class=\"trix-button trix-button--icon trix-button--icon-attach\" data-trix-action=\"attachFiles\" title=\"${lang.attachFiles}\" tabindex=\"-1\">${lang.attachFiles}</button>\n </span>\n <span class=\"trix-button-group-spacer\"></span>\n <span class=\"trix-button-group trix-button-group--history-tools\" data-trix-button-group=\"history-tools\">\n <button type=\"button\" class=\"trix-button trix-button--icon trix-button--icon-undo\" data-trix-action=\"undo\" data-trix-key=\"z\" title=\"${lang.undo}\" tabindex=\"-1\">${lang.undo}</button>\n <button type=\"button\" class=\"trix-button trix-button--icon trix-button--icon-redo\" data-trix-action=\"redo\" data-trix-key=\"shift+z\" title=\"${lang.redo}\" tabindex=\"-1\">${lang.redo}</button>\n </span>\n</div>\n<div class=\"trix-dialogs\" data-trix-dialogs>\n <div class=\"trix-dialog trix-dialog--link\" data-trix-dialog=\"href\" data-trix-dialog-attribute=\"href\">\n <div class=\"trix-dialog__link-fields\">\n <input type=\"text\" name=\"href\" pattern=\"${LINK_PATTERN}\" class=\"trix-input trix-input--dialog\" placeholder=\"${lang.urlPlaceholder}\" aria-label=\"${lang.url}\" required data-trix-input>\n <div class=\"trix-button-group\">\n <input type=\"button\" class=\"trix-button trix-button--dialog\" value=\"${lang.link}\" data-trix-method=\"setAttribute\">\n <input type=\"button\" class=\"trix-button trix-button--dialog\" value=\"${lang.unlink}\" data-trix-method=\"removeAttribute\">\n </div>\n </div>\n </div>\n</div>\n`;\n};\n\n/**\n * If the <trix-editor> element is in the HTML when Trix loads, then Trix will have already injected the toolbar content\n * before our code gets a chance to run. Fix that now.\n *\n * Note: in Trix 2 this is likely to no longer be necessary.\n */\ndocument.querySelectorAll(\"trix-toolbar\").forEach((e) => {\n e.innerHTML = Trix.config.toolbar.getDefaultHTML();\n});\n","import ContainerController from \"./editor/container_controller\";\nimport ItemController from \"./editor/item_controller\";\nimport ListController from \"./editor/list_controller\";\nimport NewItemController from \"./editor/new_item_controller\";\nimport StatusBarController from \"./editor/status_bar_controller\";\nimport TableController from \"./editor/table_controller\";\nimport TrixController from \"./editor/trix_controller\";\n\nconst Definitions = [\n {\n identifier: \"content--editor--container\",\n controllerConstructor: ContainerController,\n },\n {\n identifier: \"content--editor--item\",\n controllerConstructor: ItemController,\n },\n {\n identifier: \"content--editor--list\",\n controllerConstructor: ListController,\n },\n {\n identifier: \"content--editor--new-item\",\n controllerConstructor: NewItemController,\n },\n {\n identifier: \"content--editor--status-bar\",\n controllerConstructor: StatusBarController,\n },\n {\n identifier: \"content--editor--table\",\n controllerConstructor: TableController,\n },\n {\n identifier: \"content--editor--trix\",\n controllerConstructor: TrixController,\n },\n];\n\nexport { Definitions as default };\n","import { Controller } from \"@hotwired/stimulus\";\nimport Item from \"./item\";\n\nexport default class ItemController extends Controller {\n get item() {\n return new Item(this.li);\n }\n\n get ol() {\n return this.element.closest(\"ol\");\n }\n\n get li() {\n return this.element.closest(\"li\");\n }\n\n connect() {\n if (this.element.dataset.hasOwnProperty(\"delete\")) {\n this.remove();\n }\n // if index is not already set, re-index will set it\n else if (!(this.item.index >= 0)) {\n this.reindex();\n }\n // if item has been replaced via turbo, re-index will run the rules engine\n // update our depth and index with values from the li's data attributes\n else if (this.item.hasItemIdChanged()) {\n this.item.updateAfterChange();\n this.reindex();\n }\n }\n\n remove() {\n // capture ol\n const ol = this.ol;\n // remove self from dom\n this.li.remove();\n // reindex ol\n this.reindex();\n }\n\n reindex() {\n this.dispatch(\"reindex\", { bubbles: true, prefix: \"content\" });\n }\n}\n","import { Controller } from \"@hotwired/stimulus\";\n\nexport default class NewItemController extends Controller {\n static targets = [\"template\"];\n\n dragstart(event) {\n if (this.element !== event.target) return;\n\n event.dataTransfer.setData(\"text/html\", this.templateTarget.innerHTML);\n event.dataTransfer.effectAllowed = \"copy\";\n }\n}\n","import { Controller } from \"@hotwired/stimulus\";\n\nexport default class StatusBarController extends Controller {\n connect() {\n // cache the version's state in the controller on connect\n this.versionState = this.element.dataset.state;\n }\n\n change(e) {\n if (e.detail && e.detail.hasOwnProperty(\"dirty\")) {\n this.update(e.detail);\n }\n }\n\n update({ dirty }) {\n if (dirty) {\n this.element.dataset.state = \"dirty\";\n } else {\n this.element.dataset.state = this.versionState;\n }\n }\n}\n","import { Controller } from \"@hotwired/stimulus\";\n\nexport default class TableController extends Controller {\n static targets = [\"content\", \"input\", \"update\"];\n\n constructor(config) {\n super(config);\n\n this.observer = new MutationObserver(this.change);\n }\n\n connect() {\n this.observer.observe(this.contentTarget, {\n attributes: true,\n childList: true,\n characterData: true,\n subtree: true,\n });\n }\n\n disconnect() {\n this.observer.disconnect();\n }\n\n change = (mutations) => {\n this.inputTarget.value = this.table.outerHTML;\n };\n\n update = () => {\n this.updateTarget.click();\n };\n\n paste = (e) => {\n e.preventDefault();\n\n this.inputTarget.value = e.clipboardData.getData(\"text/html\");\n\n this.update();\n };\n\n /**\n * @returns {HTMLTableElement} The table element from the content target\n */\n get table() {\n return this.contentTarget.querySelector(\"table\");\n }\n}\n"],"names":["Item","comparator","a","b","index","constructor","node","this","itemId","dataset","itemIdInput","querySelector","id","value","depth","parseInt","depthInput","indexInput","isLayout","hasAttribute","previousItem","sibling","previousElementSibling","nextItem","nextElementSibling","hasCollapsedDescendants","childrenList","childrenListElement","children","length","hasExpandedDescendants","traverse","callback","expanded","expandedDescendants","traverseCollapsed","forEach","item","collapsedDescendants","collapseChild","appendChild","collapse","listElement","document","createElement","setAttribute","createChildrenList","child","expand","Array","from","reverse","insertAdjacentElement","toggleRule","rule","deny","hasOwnProperty","removeAttribute","hasItemIdChanged","updateAfterChange","descendants","push","map","Container","items","nodes","querySelectorAll","state","inputs","e","join","reindex","reset","sort","RulesEngine","static","debug","args","console","log","normalize","firstItemDepthZero","depthMustBeSet","itemCannotHaveInvalidDepth","parentMustBeLayout","parentCannotHaveExpandedAndCollapsedChildren","update","rules","parentsCannotDeNest","rootsCannotDeNest","onlyLastItemCanDeNest","nestingNeedsParent","leavesCannotCollapse","needHiddenItemsToExpand","parentsCannotBeDeleted","parentsCannotBeDragged","isNaN","previous","next","getEventItem","event","target","closest","swap","nodeName","positionComparison","compareDocumentPosition","Node","DOCUMENT_POSITION_FOLLOWING","DOCUMENT_POSITION_PRECEDING","dropTarget","Trix","window","config","blockAttributes","tagName","terminal","breakOnReturn","group","heading1","toolbar","getDefaultHTML","lang","bold","italic","strike","link","quote","code","bullets","numbers","outdent","indent","attachFiles","undo","redo","urlPlaceholder","url","unlink","innerHTML","Definitions","identifier","controllerConstructor","Controller","connect","container","containerTarget","drop","delta","undefined","preventDefault","remove","nest","deNest","updateRequested","setTimeout","engine","notifyChange","dispatch","bubbles","prefix","detail","dirty","isDirty","li","ol","element","enterCount","dragstart","parentElement","dataTransfer","effectAllowed","requestAnimationFrame","dragging","dragover","dragItem","dragenter","copyAllowed","newItem","dragleave","placeholder","template","getData","content","replaceChild","click","dragend","isDragging","setData","templateTarget","versionState","change","super","observer","MutationObserver","observe","contentTarget","attributes","childList","characterData","subtree","disconnect","mutations","inputTarget","table","outerHTML","updateTarget","paste","clipboardData","trixInitialize"],"mappings":"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"}
1
+ {"version":3,"file":"content.min.js","sources":["../../../javascript/content/editor/item.js","../../../javascript/content/editor/container.js","../../../javascript/content/editor/rules_engine.js","../../../javascript/content/editor/container_controller.js","../../../javascript/content/editor/list_controller.js","../../../javascript/content/editor/trix_controller.js","../../../javascript/content/application.js","../../../javascript/content/editor/item_controller.js","../../../javascript/content/editor/new_item_controller.js","../../../javascript/content/editor/status_bar_controller.js","../../../javascript/content/editor/table_controller.js"],"sourcesContent":["export default class Item {\n /**\n * Sort items by their index.\n *\n * @param a {Item}\n * @param b {Item}\n * @returns {number}\n */\n static comparator(a, b) {\n return a.index - b.index;\n }\n\n /**\n * @param node {Element} li[data-content-index]\n */\n constructor(node) {\n this.node = node;\n }\n\n /**\n * @returns {String} id of the node's item (from data attributes)\n */\n get itemId() {\n return this.node.dataset[`contentItemId`];\n }\n\n get #itemIdInput() {\n return this.node.querySelector(`input[name$=\"[id]\"]`);\n }\n\n /**\n * @param itemId {String} id\n */\n set itemId(id) {\n if (this.itemId === id) return;\n\n this.node.dataset[`contentItemId`] = `${id}`;\n this.#itemIdInput.value = `${id}`;\n }\n\n /**\n * @returns {number} logical nesting depth of node in container\n */\n get depth() {\n return parseInt(this.node.dataset[`contentDepth`]) || 0;\n }\n\n get #depthInput() {\n return this.node.querySelector(`input[name$=\"[depth]\"]`);\n }\n\n /**\n * @param depth {number} depth >= 0\n */\n set depth(depth) {\n if (this.depth === depth) return;\n\n this.node.dataset[`contentDepth`] = `${depth}`;\n this.#depthInput.value = `${depth}`;\n }\n\n /**\n * @returns {number} logical index of node in container (pre-order traversal)\n */\n get index() {\n return parseInt(this.node.dataset[`contentIndex`]);\n }\n\n get #indexInput() {\n return this.node.querySelector(`input[name$=\"[index]\"]`);\n }\n\n /**\n * @param index {number} index >= 0\n */\n set index(index) {\n if (this.index === index) return;\n\n this.node.dataset[`contentIndex`] = `${index}`;\n this.#indexInput.value = `${index}`;\n }\n\n /**\n * @returns {boolean} true if this item can have children\n */\n get isLayout() {\n return this.node.hasAttribute(\"data-content-layout\");\n }\n\n /**\n * @returns {Item} nearest neighbour (index - 1)\n */\n get previousItem() {\n let sibling = this.node.previousElementSibling;\n if (sibling) return new Item(sibling);\n }\n\n /**\n * @returns {Item} nearest neighbour (index + 1)\n */\n get nextItem() {\n let sibling = this.node.nextElementSibling;\n if (sibling) return new Item(sibling);\n }\n\n /**\n * @returns {boolean} true if this item has any collapsed children\n */\n hasCollapsedDescendants() {\n let childrenList = this.#childrenListElement;\n return !!childrenList && childrenList.children.length > 0;\n }\n\n /**\n * @returns {boolean} true if this item has any expanded children\n */\n hasExpandedDescendants() {\n let sibling = this.nextItem;\n return !!sibling && sibling.depth > this.depth;\n }\n\n /**\n * Recursively traverse the node and its descendants.\n *\n * @callback {Item}\n */\n traverse(callback) {\n // capture descendants before traversal in case of side-effects\n // specifically, setting depth affects calculation\n const expanded = this.#expandedDescendants;\n\n callback(this);\n this.#traverseCollapsed(callback);\n expanded.forEach((item) => item.#traverseCollapsed(callback));\n }\n\n /**\n * Recursively traverse the node's collapsed descendants, if any.\n *\n * @callback {Item}\n */\n #traverseCollapsed(callback) {\n if (!this.hasCollapsedDescendants()) return;\n\n this.#collapsedDescendants.forEach((item) => {\n callback(item);\n item.#traverseCollapsed(callback);\n });\n }\n\n /**\n * Move the given item into this element's hidden children list.\n * Assumes the list already exists.\n *\n * @param item {Item}\n */\n collapseChild(item) {\n this.#childrenListElement.appendChild(item.node);\n }\n\n /**\n * Collapses visible (logical) children into this element's hidden children\n * list, creating it if it doesn't already exist.\n */\n collapse() {\n let listElement = this.#childrenListElement;\n\n if (!listElement) listElement = createChildrenList(this.node);\n\n this.#expandedDescendants.forEach((child) =>\n listElement.appendChild(child.node),\n );\n }\n\n /**\n * Moves any collapsed children back into the parent container.\n */\n expand() {\n if (!this.hasCollapsedDescendants()) return;\n\n Array.from(this.#childrenListElement.children)\n .reverse()\n .forEach((node) => {\n this.node.insertAdjacentElement(\"afterend\", node);\n });\n }\n\n /**\n * Sets the state of a given rule on the target node.\n *\n * @param rule {String}\n * @param deny {boolean}\n */\n toggleRule(rule, deny = false) {\n if (this.node.dataset.hasOwnProperty(rule) && !deny) {\n delete this.node.dataset[rule];\n }\n if (!this.node.dataset.hasOwnProperty(rule) && deny) {\n this.node.dataset[rule] = \"\";\n }\n\n if (rule === \"denyDrag\") {\n if (!this.node.hasAttribute(\"draggable\") && !deny) {\n this.node.setAttribute(\"draggable\", \"true\");\n }\n if (this.node.hasAttribute(\"draggable\") && deny) {\n this.node.removeAttribute(\"draggable\");\n }\n }\n }\n\n /**\n * Detects turbo item changes by comparing the dataset id with the input\n */\n hasItemIdChanged() {\n return !(this.#itemIdInput.value === this.itemId);\n }\n\n /**\n * Updates inputs, in case they don't match the data values, e.g., when the\n * nested inputs have been hot-swapped by turbo with data from the server.\n *\n * Updates itemId from input as that is the canonical source.\n */\n updateAfterChange() {\n this.itemId = this.#itemIdInput.value;\n this.#indexInput.value = this.index;\n this.#depthInput.value = this.depth;\n }\n\n /**\n * Finds the dom container for storing collapsed (hidden) children, if present.\n *\n * @returns {Element} ol[data-content-children]\n */\n get #childrenListElement() {\n return this.node.querySelector(`:scope > [data-content-children]`);\n }\n\n /**\n * @returns {Item[]} all items that follow this element that have a greater depth.\n */\n get #expandedDescendants() {\n const descendants = [];\n\n let sibling = this.nextItem;\n while (sibling && sibling.depth > this.depth) {\n descendants.push(sibling);\n sibling = sibling.nextItem;\n }\n\n return descendants;\n }\n\n /**\n * @returns {Item[]} all items directly contained inside this element's hidden children element.\n */\n get #collapsedDescendants() {\n if (!this.hasCollapsedDescendants()) return [];\n\n return Array.from(this.#childrenListElement.children).map(\n (node) => new Item(node),\n );\n }\n}\n\n/**\n * Finds or creates a dom container for storing collapsed (hidden) children.\n *\n * @param node {Element} li[data-content-index]\n * @returns {Element} ol[data-content-children]\n */\nfunction createChildrenList(node) {\n const childrenList = document.createElement(\"ol\");\n childrenList.setAttribute(\"class\", \"hidden\");\n\n // if objectType is \"rich-content\" set richContentChildren as a data attribute\n childrenList.dataset[`contentChildren`] = \"\";\n\n node.appendChild(childrenList);\n\n return childrenList;\n}\n","import Item from \"./item\";\n\n/**\n * @param nodes {NodeList}\n * @returns {Item[]}\n */\nfunction createItemList(nodes) {\n return Array.from(nodes).map((node) => new Item(node));\n}\n\nexport default class Container {\n /**\n * @param node {Element} content editor list\n */\n constructor(node) {\n this.node = node;\n }\n\n /**\n * @return {Item[]} an ordered list of all items in the container\n */\n get items() {\n return createItemList(this.node.querySelectorAll(\"[data-content-index]\"));\n }\n\n /**\n * @return {String} a serialized description of the structure of the container\n */\n get state() {\n const inputs = this.node.querySelectorAll(\"li input[type=hidden]\");\n return Array.from(inputs)\n .map((e) => e.value)\n .join(\"/\");\n }\n\n /**\n * Set the index of items based on their current position.\n */\n reindex() {\n this.items.map((item, index) => (item.index = index));\n }\n\n /**\n * Resets the order of items to their defined index.\n * Useful after an aborted drag.\n */\n reset() {\n this.items.sort(Item.comparator).forEach((item) => {\n this.node.appendChild(item.node);\n });\n }\n}\n","export default class RulesEngine {\n static rules = [\n \"denyDeNest\",\n \"denyNest\",\n \"denyCollapse\",\n \"denyExpand\",\n \"denyRemove\",\n \"denyDrag\",\n \"denyEdit\",\n ];\n\n constructor(debug = false) {\n if (debug) {\n this.debug = (...args) => console.log(...args);\n } else {\n this.debug = () => {};\n }\n }\n\n /**\n * Enforce structural rules to ensure that the given item is currently in a\n * valid state.\n *\n * @param {Item} item\n */\n normalize(item) {\n // structural rules enforce a valid tree structure\n this.firstItemDepthZero(item);\n this.depthMustBeSet(item);\n this.itemCannotHaveInvalidDepth(item);\n this.parentMustBeLayout(item);\n this.parentCannotHaveExpandedAndCollapsedChildren(item);\n }\n\n /**\n * Apply rules to the given item to determine what operations are permitted.\n *\n * @param {Item} item\n */\n update(item) {\n this.rules = {};\n\n // behavioural rules define what the user is allowed to do\n this.parentsCannotDeNest(item);\n this.rootsCannotDeNest(item);\n this.onlyLastItemCanDeNest(item);\n this.nestingNeedsParent(item);\n this.leavesCannotCollapse(item);\n this.needHiddenItemsToExpand(item);\n this.parentsCannotBeDeleted(item);\n this.parentsCannotBeDragged(item);\n\n RulesEngine.rules.forEach((rule) => {\n item.toggleRule(rule, !!this.rules[rule]);\n });\n }\n\n /**\n * First item can't have a parent, so its depth should always be 0\n */\n firstItemDepthZero(item) {\n if (item.index === 0 && item.depth !== 0) {\n this.debug(`enforce depth on item ${item.index}: ${item.depth} => 0`);\n\n item.depth = 0;\n }\n }\n\n /**\n * Every item should have a non-negative depth set.\n *\n * @param {Item} item\n */\n depthMustBeSet(item) {\n if (isNaN(item.depth) || item.depth < 0) {\n this.debug(`unset depth on item ${item.index}: => 0`);\n\n item.depth = 0;\n }\n }\n\n /**\n * Depth must increase stepwise.\n *\n * @param {Item} item\n */\n itemCannotHaveInvalidDepth(item) {\n const previous = item.previousItem;\n if (previous && previous.depth < item.depth - 1) {\n this.debug(\n `invalid depth on item ${item.index}: ${item.depth} => ${\n previous.depth + 1\n }`,\n );\n\n item.depth = previous.depth + 1;\n }\n }\n\n /**\n * Parent item, if any, must be a layout.\n *\n * @param {Item} item\n */\n parentMustBeLayout(item) {\n // if we're the first child, make sure our parent is a layout\n // if we're a sibling, we know the previous item is valid so we must be too\n const previous = item.previousItem;\n if (previous && previous.depth < item.depth && !previous.isLayout) {\n this.debug(\n `invalid parent for item ${item.index}: ${item.depth} => ${previous.depth}`,\n );\n\n item.depth = previous.depth;\n }\n }\n\n /**\n * If a parent has expanded and collapsed children, expand.\n *\n * @param {Item} item\n */\n parentCannotHaveExpandedAndCollapsedChildren(item) {\n if (item.hasCollapsedDescendants() && item.hasExpandedDescendants()) {\n this.debug(`expanding collapsed children of item ${item.index}`);\n\n item.expand();\n }\n }\n\n /**\n * De-nesting an item would create a gap of 2 between itself and its children\n *\n * @param {Item} item\n */\n parentsCannotDeNest(item) {\n if (item.hasExpandedDescendants()) this.#deny(\"denyDeNest\");\n }\n\n /**\n * Item depth can't go below 0.\n *\n * @param {Item} item\n */\n rootsCannotDeNest(item) {\n if (item.depth === 0) this.#deny(\"denyDeNest\");\n }\n\n /**\n * De-nesting an item that has siblings would make it a container.\n *\n * @param {Item} item\n */\n onlyLastItemCanDeNest(item) {\n const next = item.nextItem;\n if (next && next.depth === item.depth && !item.isLayout)\n this.#deny(\"denyDeNest\");\n }\n\n /**\n * If an item doesn't have children it can't be collapsed.\n *\n * @param {Item} item\n */\n leavesCannotCollapse(item) {\n if (!item.hasExpandedDescendants()) this.#deny(\"denyCollapse\");\n }\n\n /**\n * If an item doesn't have any hidden descendants then it can't be expanded.\n *\n * @param {Item} item\n */\n needHiddenItemsToExpand(item) {\n if (!item.hasCollapsedDescendants()) this.#deny(\"denyExpand\");\n }\n\n /**\n * An item can't be nested (indented) if it doesn't have a valid parent.\n *\n * @param {Item} item\n */\n nestingNeedsParent(item) {\n const previous = item.previousItem;\n // no previous, so cannot nest\n if (!previous) this.#deny(\"denyNest\");\n // previous is too shallow, nesting would increase depth too much\n else if (previous.depth < item.depth) this.#deny(\"denyNest\");\n // new parent is not a layout\n else if (previous.depth === item.depth && !previous.isLayout)\n this.#deny(\"denyNest\");\n }\n\n /**\n * An item can't be deleted if it has visible children.\n *\n * @param {Item} item\n */\n parentsCannotBeDeleted(item) {\n if (!item.itemId || item.hasExpandedDescendants()) this.#deny(\"denyRemove\");\n }\n\n /**\n * Items cannot be dragged if they have visible children.\n *\n * @param {Item} item\n */\n parentsCannotBeDragged(item) {\n if (item.hasExpandedDescendants()) this.#deny(\"denyDrag\");\n }\n\n /**\n * Record a deny.\n *\n * @param rule {String}\n */\n #deny(rule) {\n this.rules[rule] = true;\n }\n}\n","import { Controller } from \"@hotwired/stimulus\";\n\nimport Item from \"./item\";\nimport Container from \"./container\";\nimport RulesEngine from \"./rules_engine\";\n\nexport default class ContainerController extends Controller {\n static targets = [\"container\"];\n\n connect() {\n this.state = this.container.state;\n\n this.reindex();\n }\n\n get container() {\n return new Container(this.containerTarget);\n }\n\n reindex() {\n this.container.reindex();\n this.#update();\n }\n\n reset() {\n this.container.reset();\n }\n\n drop(event) {\n this.container.reindex(); // set indexes before calculating previous\n\n const item = getEventItem(event);\n const previous = item.previousItem;\n\n let delta = 0;\n if (previous === undefined) {\n // if previous does not exist, set depth to 0\n delta = -item.depth;\n } else if (\n previous.isLayout &&\n item.nextItem &&\n item.nextItem.depth > previous.depth\n ) {\n // if previous is a layout and next is a child of previous, make item a child of previous\n delta = previous.depth - item.depth + 1;\n } else {\n // otherwise, make item a sibling of previous\n delta = previous.depth - item.depth;\n }\n\n item.traverse((child) => {\n child.depth += delta;\n });\n\n this.#update();\n event.preventDefault();\n }\n\n remove(event) {\n const item = getEventItem(event);\n\n item.node.remove();\n\n this.#update();\n event.preventDefault();\n }\n\n nest(event) {\n const item = getEventItem(event);\n\n item.traverse((child) => {\n child.depth += 1;\n });\n\n this.#update();\n event.preventDefault();\n }\n\n deNest(event) {\n const item = getEventItem(event);\n\n item.traverse((child) => {\n child.depth -= 1;\n });\n\n this.#update();\n event.preventDefault();\n }\n\n collapse(event) {\n const item = getEventItem(event);\n\n item.collapse();\n\n this.#update();\n event.preventDefault();\n }\n\n expand(event) {\n const item = getEventItem(event);\n\n item.expand();\n\n this.#update();\n event.preventDefault();\n }\n\n /**\n * Re-apply rules to items to enable/disable appropriate actions.\n */\n #update() {\n // debounce requests to ensure that we only update once per tick\n this.updateRequested = true;\n setTimeout(() => {\n if (!this.updateRequested) return;\n\n this.updateRequested = false;\n const engine = new RulesEngine();\n this.container.items.forEach((item) => engine.normalize(item));\n this.container.items.forEach((item) => engine.update(item));\n\n this.#notifyChange();\n }, 0);\n }\n\n #notifyChange() {\n this.dispatch(\"change\", {\n bubbles: true,\n prefix: \"content\",\n detail: { dirty: this.#isDirty() },\n });\n }\n\n #isDirty() {\n return this.container.state !== this.state;\n }\n}\n\nfunction getEventItem(event) {\n return new Item(event.target.closest(\"[data-content-item]\"));\n}\n","import { Controller } from \"@hotwired/stimulus\";\n\nexport default class ListController extends Controller {\n connect() {\n this.enterCount = 0;\n }\n\n /**\n * When the user starts a drag within the list, set the item's dataTransfer\n * properties to indicate that it's being dragged and update its style.\n *\n * We delay setting the dataset property until the next animation frame\n * so that the style updates can be computed before the drag begins.\n *\n * @param event {DragEvent}\n */\n dragstart(event) {\n if (this.element !== event.target.parentElement) return;\n\n const target = event.target;\n event.dataTransfer.effectAllowed = \"move\";\n\n // update element style after drag has begun\n requestAnimationFrame(() => (target.dataset.dragging = \"\"));\n }\n\n /**\n * When the user drags an item over another item in the last, swap the\n * dragging item with the item under the cursor.\n *\n * As a special case, if the item is dragged over placeholder space at the end\n * of the list, move the item to the bottom of the list instead. This allows\n * users to hit the list element more easily when adding new items to an empty\n * list.\n *\n * @param event {DragEvent}\n */\n dragover(event) {\n const item = this.dragItem;\n if (!item) return;\n\n swap(dropTarget(event.target), item);\n\n event.preventDefault();\n return true;\n }\n\n /**\n * When the user drags an item into the list, create a placeholder item to\n * represent the new item. Note that we can't access the drag data\n * until drop, so we assume that this is our template item for now.\n *\n * Users can cancel the drag by dragging the item out of the list or by\n * pressing escape. Both are handled by `cancelDrag`.\n *\n * @param event {DragEvent}\n */\n dragenter(event) {\n event.preventDefault();\n\n // Safari doesn't support relatedTarget, so we count enter/leave pairs\n this.enterCount++;\n\n if (copyAllowed(event) && !this.dragItem) {\n const item = document.createElement(\"li\");\n item.dataset.dragging = \"\";\n item.dataset.newItem = \"\";\n this.element.appendChild(item);\n }\n }\n\n /**\n * When the user drags the item out of the list, remove the placeholder.\n * This allows users to cancel the drag by dragging the item out of the list.\n *\n * @param event {DragEvent}\n */\n dragleave(event) {\n // Safari doesn't support relatedTarget, so we count enter/leave pairs\n // https://bugs.webkit.org/show_bug.cgi?id=66547\n this.enterCount--;\n\n if (\n this.enterCount <= 0 &&\n this.dragItem.dataset.hasOwnProperty(\"newItem\")\n ) {\n this.dragItem.remove();\n this.reset();\n }\n }\n\n /**\n * When the user drops an item into the list, end the drag and reindex the list.\n *\n * If the item is a new item, we replace the placeholder with the template\n * item data from the dataTransfer API.\n *\n * @param event {DragEvent}\n */\n drop(event) {\n let item = this.dragItem;\n\n if (!item) return;\n\n event.preventDefault();\n delete item.dataset.dragging;\n swap(dropTarget(event.target), item);\n\n if (item.dataset.hasOwnProperty(\"newItem\")) {\n const placeholder = item;\n const template = document.createElement(\"template\");\n template.innerHTML = event.dataTransfer.getData(\"text/html\");\n item = template.content.querySelector(\"li\");\n\n this.element.replaceChild(item, placeholder);\n requestAnimationFrame(() =>\n item.querySelector(\"[role='button'][value='edit']\").click(),\n );\n }\n\n this.dispatch(\"drop\", { target: item, bubbles: true, prefix: \"content\" });\n }\n\n /**\n * End an in-progress drag. If the item is a new item, remove it, otherwise\n * reset the item's style and restore its original position in the list.\n */\n dragend() {\n const item = this.dragItem;\n\n if (!item) {\n } else if (item.dataset.hasOwnProperty(\"newItem\")) {\n item.remove();\n } else {\n delete item.dataset.dragging;\n this.reset();\n }\n }\n\n get isDragging() {\n return !!this.dragItem;\n }\n\n get dragItem() {\n return this.element.querySelector(\"[data-dragging]\");\n }\n\n reindex() {\n this.dispatch(\"reindex\", { bubbles: true, prefix: \"content\" });\n }\n\n reset() {\n this.dispatch(\"reset\", { bubbles: true, prefix: \"content\" });\n }\n}\n\n/**\n * Swaps two list items. If target is a list, the item is appended.\n *\n * @param target the target element to swap with\n * @param item the item the user is dragging\n */\nfunction swap(target, item) {\n if (!target) return;\n if (target === item) return;\n\n if (target.nodeName === \"LI\") {\n const positionComparison = target.compareDocumentPosition(item);\n if (positionComparison & Node.DOCUMENT_POSITION_FOLLOWING) {\n target.insertAdjacentElement(\"beforebegin\", item);\n } else if (positionComparison & Node.DOCUMENT_POSITION_PRECEDING) {\n target.insertAdjacentElement(\"afterend\", item);\n }\n }\n\n if (target.nodeName === \"OL\") {\n target.appendChild(item);\n }\n}\n\n/**\n * Returns true if the event supports copy or copy move.\n *\n * Chrome and Firefox use copy, but Safari only supports copyMove.\n */\nfunction copyAllowed(event) {\n return (\n event.dataTransfer.effectAllowed === \"copy\" ||\n event.dataTransfer.effectAllowed === \"copyMove\"\n );\n}\n\n/**\n * Given an event target, return the closest drop target, if any.\n */\nfunction dropTarget(e) {\n return (\n e &&\n (e.closest(\"[data-controller='content--editor--list'] > *\") ||\n e.closest(\"[data-controller='content--editor--list']\"))\n );\n}\n","import { Controller } from \"@hotwired/stimulus\";\nimport \"trix\";\n\n// Note, action_text 7.1.2 changes how Trix is bundled and loaded. This\n// seems to have broken the default export from trix. This is a workaround\n// that relies on the backwards compatibility of the old export to window.Trix.\nconst Trix = window.Trix;\n\n// Stimulus controller doesn't do anything, but having one ensures that trix\n// will be lazy loaded when a trix-editor is added to the dom.\nexport default class TrixController extends Controller {\n trixInitialize(e) {\n // noop, useful as an extension point for registering behaviour on load\n }\n}\n\n// Add H4 as an acceptable tag\nTrix.config.blockAttributes[\"heading4\"] = {\n tagName: \"h4\",\n terminal: true,\n breakOnReturn: true,\n group: false,\n};\n\n// Remove H1 from trix list of acceptable tags\ndelete Trix.config.blockAttributes.heading1;\n\n/**\n * Allow users to enter path and fragment URIs which the input[type=url] browser\n * input does not permit. Uses a permissive regex pattern which is not suitable\n * for untrusted use cases.\n */\nconst LINK_PATTERN = \"(https?|mailto:|tel:|/|#).*?\";\n\n/**\n * Customize default toolbar:\n *\n * * headings: h4 instead of h1\n * * links: use type=text instead of type=url\n *\n * @returns {String} toolbar html fragment\n */\nTrix.config.toolbar.getDefaultHTML = () => {\n const { lang } = Trix.config;\n return `\n<div class=\"trix-button-row\">\n <span class=\"trix-button-group trix-button-group--text-tools\" data-trix-button-group=\"text-tools\">\n <button type=\"button\" class=\"trix-button trix-button--icon trix-button--icon-bold\" data-trix-attribute=\"bold\" data-trix-key=\"b\" title=\"${lang.bold}\" tabindex=\"-1\">${lang.bold}</button>\n <button type=\"button\" class=\"trix-button trix-button--icon trix-button--icon-italic\" data-trix-attribute=\"italic\" data-trix-key=\"i\" title=\"${lang.italic}\" tabindex=\"-1\">${lang.italic}</button>\n <button type=\"button\" class=\"trix-button trix-button--icon trix-button--icon-strike\" data-trix-attribute=\"strike\" title=\"${lang.strike}\" tabindex=\"-1\">${lang.strike}</button>\n <button type=\"button\" class=\"trix-button trix-button--icon trix-button--icon-link\" data-trix-attribute=\"href\" data-trix-action=\"link\" data-trix-key=\"k\" title=\"${lang.link}\" tabindex=\"-1\">${lang.link}</button>\n </span>\n <span class=\"trix-button-group trix-button-group--block-tools\" data-trix-button-group=\"block-tools\">\n <button type=\"button\" class=\"trix-button trix-button--icon trix-button--icon-heading-1\" data-trix-attribute=\"heading4\" title=\"${lang.heading1}\" tabindex=\"-1\">${lang.heading1}</button>\n <button type=\"button\" class=\"trix-button trix-button--icon trix-button--icon-quote\" data-trix-attribute=\"quote\" title=\"${lang.quote}\" tabindex=\"-1\">${lang.quote}</button>\n <button type=\"button\" class=\"trix-button trix-button--icon trix-button--icon-code\" data-trix-attribute=\"code\" title=\"${lang.code}\" tabindex=\"-1\">${lang.code}</button>\n <button type=\"button\" class=\"trix-button trix-button--icon trix-button--icon-bullet-list\" data-trix-attribute=\"bullet\" title=\"${lang.bullets}\" tabindex=\"-1\">${lang.bullets}</button>\n <button type=\"button\" class=\"trix-button trix-button--icon trix-button--icon-number-list\" data-trix-attribute=\"number\" title=\"${lang.numbers}\" tabindex=\"-1\">${lang.numbers}</button>\n <button type=\"button\" class=\"trix-button trix-button--icon trix-button--icon-decrease-nesting-level\" data-trix-action=\"decreaseNestingLevel\" title=\"${lang.outdent}\" tabindex=\"-1\">${lang.outdent}</button>\n <button type=\"button\" class=\"trix-button trix-button--icon trix-button--icon-increase-nesting-level\" data-trix-action=\"increaseNestingLevel\" title=\"${lang.indent}\" tabindex=\"-1\">${lang.indent}</button>\n </span>\n <span class=\"trix-button-group trix-button-group--file-tools\" data-trix-button-group=\"file-tools\">\n <button type=\"button\" class=\"trix-button trix-button--icon trix-button--icon-attach\" data-trix-action=\"attachFiles\" title=\"${lang.attachFiles}\" tabindex=\"-1\">${lang.attachFiles}</button>\n </span>\n <span class=\"trix-button-group-spacer\"></span>\n <span class=\"trix-button-group trix-button-group--history-tools\" data-trix-button-group=\"history-tools\">\n <button type=\"button\" class=\"trix-button trix-button--icon trix-button--icon-undo\" data-trix-action=\"undo\" data-trix-key=\"z\" title=\"${lang.undo}\" tabindex=\"-1\">${lang.undo}</button>\n <button type=\"button\" class=\"trix-button trix-button--icon trix-button--icon-redo\" data-trix-action=\"redo\" data-trix-key=\"shift+z\" title=\"${lang.redo}\" tabindex=\"-1\">${lang.redo}</button>\n </span>\n</div>\n<div class=\"trix-dialogs\" data-trix-dialogs>\n <div class=\"trix-dialog trix-dialog--link\" data-trix-dialog=\"href\" data-trix-dialog-attribute=\"href\">\n <div class=\"trix-dialog__link-fields\">\n <input type=\"text\" name=\"href\" pattern=\"${LINK_PATTERN}\" class=\"trix-input trix-input--dialog\" placeholder=\"${lang.urlPlaceholder}\" aria-label=\"${lang.url}\" required data-trix-input>\n <div class=\"trix-button-group\">\n <input type=\"button\" class=\"trix-button trix-button--dialog\" value=\"${lang.link}\" data-trix-method=\"setAttribute\">\n <input type=\"button\" class=\"trix-button trix-button--dialog\" value=\"${lang.unlink}\" data-trix-method=\"removeAttribute\">\n </div>\n </div>\n </div>\n</div>\n`;\n};\n\n/**\n * If the <trix-editor> element is in the HTML when Trix loads, then Trix will have already injected the toolbar content\n * before our code gets a chance to run. Fix that now.\n *\n * Note: in Trix 2 this is likely to no longer be necessary.\n */\ndocument.querySelectorAll(\"trix-toolbar\").forEach((e) => {\n e.innerHTML = Trix.config.toolbar.getDefaultHTML();\n});\n","import ContainerController from \"./editor/container_controller\";\nimport ItemController from \"./editor/item_controller\";\nimport ListController from \"./editor/list_controller\";\nimport NewItemController from \"./editor/new_item_controller\";\nimport StatusBarController from \"./editor/status_bar_controller\";\nimport TableController from \"./editor/table_controller\";\nimport TrixController from \"./editor/trix_controller\";\n\nconst Definitions = [\n {\n identifier: \"content--editor--container\",\n controllerConstructor: ContainerController,\n },\n {\n identifier: \"content--editor--item\",\n controllerConstructor: ItemController,\n },\n {\n identifier: \"content--editor--list\",\n controllerConstructor: ListController,\n },\n {\n identifier: \"content--editor--new-item\",\n controllerConstructor: NewItemController,\n },\n {\n identifier: \"content--editor--status-bar\",\n controllerConstructor: StatusBarController,\n },\n {\n identifier: \"content--editor--table\",\n controllerConstructor: TableController,\n },\n {\n identifier: \"content--editor--trix\",\n controllerConstructor: TrixController,\n },\n];\n\nexport { Definitions as default };\n","import { Controller } from \"@hotwired/stimulus\";\nimport Item from \"./item\";\n\nexport default class ItemController extends Controller {\n get item() {\n return new Item(this.li);\n }\n\n get ol() {\n return this.element.closest(\"ol\");\n }\n\n get li() {\n return this.element.closest(\"li\");\n }\n\n connect() {\n if (this.element.dataset.hasOwnProperty(\"delete\")) {\n this.remove();\n }\n // if index is not already set, re-index will set it\n else if (!(this.item.index >= 0)) {\n this.reindex();\n }\n // if item has been replaced via turbo, re-index will run the rules engine\n // update our depth and index with values from the li's data attributes\n else if (this.item.hasItemIdChanged()) {\n this.item.updateAfterChange();\n this.reindex();\n }\n }\n\n remove() {\n // capture ol\n const ol = this.ol;\n // remove self from dom\n this.li.remove();\n // reindex ol\n this.reindex();\n }\n\n reindex() {\n this.dispatch(\"reindex\", { bubbles: true, prefix: \"content\" });\n }\n}\n","import { Controller } from \"@hotwired/stimulus\";\n\nexport default class NewItemController extends Controller {\n static targets = [\"template\"];\n\n dragstart(event) {\n if (this.element !== event.target) return;\n\n event.dataTransfer.setData(\"text/html\", this.templateTarget.innerHTML);\n event.dataTransfer.effectAllowed = \"copy\";\n }\n}\n","import { Controller } from \"@hotwired/stimulus\";\n\nexport default class StatusBarController extends Controller {\n connect() {\n // cache the version's state in the controller on connect\n this.versionState = this.element.dataset.state;\n }\n\n change(e) {\n if (e.detail && e.detail.hasOwnProperty(\"dirty\")) {\n this.update(e.detail);\n }\n }\n\n update({ dirty }) {\n if (dirty) {\n this.element.dataset.state = \"dirty\";\n } else {\n this.element.dataset.state = this.versionState;\n }\n }\n}\n","import { Controller } from \"@hotwired/stimulus\";\n\nconst EDITOR = `\n<div class=\"content--editor--table-editor\"\n contenteditable=\"true\"\n data-content--editor--table-target=\"content\"\n data-action=\"paste->content--editor--table#paste\"\n id=\"item-content-field\">\n</div>`;\n\nexport default class TableController extends Controller {\n static targets = [\"input\", \"update\"];\n\n constructor(config) {\n super(config);\n\n this.observer = new MutationObserver(this.change);\n }\n\n connect() {\n const template = document.createElement(\"TEMPLATE\");\n template.innerHTML = EDITOR;\n this.content = template.content.firstElementChild;\n this.content.innerHTML = this.inputTarget.value;\n this.content.className += ` ${this.inputTarget.className}`;\n this.inputTarget.insertAdjacentElement(\"beforebegin\", this.content);\n this.inputTarget.hidden = true;\n\n this.observer.observe(this.content, {\n attributes: true,\n childList: true,\n characterData: true,\n subtree: true,\n });\n }\n\n disconnect() {\n this.observer.disconnect();\n this.content.remove();\n delete this.content;\n }\n\n change = (mutations) => {\n this.inputTarget.value = this.table?.outerHTML;\n };\n\n update = () => {\n this.updateTarget.click();\n };\n\n paste = (e) => {\n if (e.clipboardData.getData(\"text/html\").indexOf(\"<table\") === -1) return;\n\n e.preventDefault();\n\n this.inputTarget.value = e.clipboardData.getData(\"text/html\");\n\n this.update();\n };\n\n /**\n * @returns {HTMLTableElement} The table element from the content target\n */\n get table() {\n return this.content.querySelector(\"table\");\n }\n}\n"],"names":["Item","comparator","a","b","index","constructor","node","this","itemId","dataset","itemIdInput","querySelector","id","value","depth","parseInt","depthInput","indexInput","isLayout","hasAttribute","previousItem","sibling","previousElementSibling","nextItem","nextElementSibling","hasCollapsedDescendants","childrenList","childrenListElement","children","length","hasExpandedDescendants","traverse","callback","expanded","expandedDescendants","traverseCollapsed","forEach","item","collapsedDescendants","collapseChild","appendChild","collapse","listElement","document","createElement","setAttribute","createChildrenList","child","expand","Array","from","reverse","insertAdjacentElement","toggleRule","rule","deny","hasOwnProperty","removeAttribute","hasItemIdChanged","updateAfterChange","descendants","push","map","Container","items","nodes","querySelectorAll","state","inputs","e","join","reindex","reset","sort","RulesEngine","static","debug","args","console","log","normalize","firstItemDepthZero","depthMustBeSet","itemCannotHaveInvalidDepth","parentMustBeLayout","parentCannotHaveExpandedAndCollapsedChildren","update","rules","parentsCannotDeNest","rootsCannotDeNest","onlyLastItemCanDeNest","nestingNeedsParent","leavesCannotCollapse","needHiddenItemsToExpand","parentsCannotBeDeleted","parentsCannotBeDragged","isNaN","previous","next","getEventItem","event","target","closest","swap","nodeName","positionComparison","compareDocumentPosition","Node","DOCUMENT_POSITION_FOLLOWING","DOCUMENT_POSITION_PRECEDING","dropTarget","Trix","window","config","blockAttributes","tagName","terminal","breakOnReturn","group","heading1","toolbar","getDefaultHTML","lang","bold","italic","strike","link","quote","code","bullets","numbers","outdent","indent","attachFiles","undo","redo","urlPlaceholder","url","unlink","innerHTML","Definitions","identifier","controllerConstructor","Controller","connect","container","containerTarget","drop","delta","undefined","preventDefault","remove","nest","deNest","updateRequested","setTimeout","engine","notifyChange","dispatch","bubbles","prefix","detail","dirty","isDirty","li","ol","element","enterCount","dragstart","parentElement","dataTransfer","effectAllowed","requestAnimationFrame","dragging","dragover","dragItem","dragenter","copyAllowed","newItem","dragleave","placeholder","template","getData","content","replaceChild","click","dragend","isDragging","setData","templateTarget","versionState","change","super","observer","MutationObserver","firstElementChild","inputTarget","className","hidden","observe","attributes","childList","characterData","subtree","disconnect","mutations","table","outerHTML","updateTarget","paste","clipboardData","indexOf","trixInitialize"],"mappings":"6DAAe,MAAMA,EAQnB,iBAAOC,CAAWC,EAAGC,GACnB,OAAOD,EAAEE,MAAQD,EAAEC,KACpB,CAKD,WAAAC,CAAYC,GACVC,KAAKD,KAAOA,CACb,CAKD,UAAIE,GACF,OAAOD,KAAKD,KAAKG,QAAuB,aACzC,CAED,KAAIC,GACF,OAAOH,KAAKD,KAAKK,cAAc,sBAChC,CAKD,UAAIH,CAAOI,GACLL,KAAKC,SAAWI,IAEpBL,KAAKD,KAAKG,QAAuB,cAAI,GAAGG,IACxCL,MAAKG,EAAaG,MAAQ,GAAGD,IAC9B,CAKD,SAAIE,GACF,OAAOC,SAASR,KAAKD,KAAKG,QAAsB,eAAM,CACvD,CAED,KAAIO,GACF,OAAOT,KAAKD,KAAKK,cAAc,yBAChC,CAKD,SAAIG,CAAMA,GACJP,KAAKO,QAAUA,IAEnBP,KAAKD,KAAKG,QAAsB,aAAI,GAAGK,IACvCP,MAAKS,EAAYH,MAAQ,GAAGC,IAC7B,CAKD,SAAIV,GACF,OAAOW,SAASR,KAAKD,KAAKG,QAAsB,aACjD,CAED,KAAIQ,GACF,OAAOV,KAAKD,KAAKK,cAAc,yBAChC,CAKD,SAAIP,CAAMA,GACJG,KAAKH,QAAUA,IAEnBG,KAAKD,KAAKG,QAAsB,aAAI,GAAGL,IACvCG,MAAKU,EAAYJ,MAAQ,GAAGT,IAC7B,CAKD,YAAIc,GACF,OAAOX,KAAKD,KAAKa,aAAa,sBAC/B,CAKD,gBAAIC,GACF,IAAIC,EAAUd,KAAKD,KAAKgB,uBACxB,GAAID,EAAS,OAAO,IAAIrB,EAAKqB,EAC9B,CAKD,YAAIE,GACF,IAAIF,EAAUd,KAAKD,KAAKkB,mBACxB,GAAIH,EAAS,OAAO,IAAIrB,EAAKqB,EAC9B,CAKD,uBAAAI,GACE,IAAIC,EAAenB,MAAKoB,EACxB,QAASD,GAAgBA,EAAaE,SAASC,OAAS,CACzD,CAKD,sBAAAC,GACE,IAAIT,EAAUd,KAAKgB,SACnB,QAASF,GAAWA,EAAQP,MAAQP,KAAKO,KAC1C,CAOD,QAAAiB,CAASC,GAGP,MAAMC,EAAW1B,MAAK2B,EAEtBF,EAASzB,MACTA,MAAK4B,EAAmBH,GACxBC,EAASG,SAASC,GAASA,GAAKF,EAAmBH,IACpD,CAOD,EAAAG,CAAmBH,GACZzB,KAAKkB,2BAEVlB,MAAK+B,EAAsBF,SAASC,IAClCL,EAASK,GACTA,GAAKF,EAAmBH,EAAS,GAEpC,CAQD,aAAAO,CAAcF,GACZ9B,MAAKoB,EAAqBa,YAAYH,EAAK/B,KAC5C,CAMD,QAAAmC,GACE,IAAIC,EAAcnC,MAAKoB,EAElBe,IAAaA,EAyGtB,SAA4BpC,GAC1B,MAAMoB,EAAeiB,SAASC,cAAc,MAQ5C,OAPAlB,EAAamB,aAAa,QAAS,UAGnCnB,EAAajB,QAAyB,gBAAI,GAE1CH,EAAKkC,YAAYd,GAEVA,CACT,CAnHoCoB,CAAmBvC,KAAKD,OAExDC,MAAK2B,EAAqBE,SAASW,GACjCL,EAAYF,YAAYO,EAAMzC,OAEjC,CAKD,MAAA0C,GACOzC,KAAKkB,2BAEVwB,MAAMC,KAAK3C,MAAKoB,EAAqBC,UAClCuB,UACAf,SAAS9B,IACRC,KAAKD,KAAK8C,sBAAsB,WAAY9C,EAAK,GAEtD,CAQD,UAAA+C,CAAWC,EAAMC,GAAO,GAClBhD,KAAKD,KAAKG,QAAQ+C,eAAeF,KAAUC,UACtChD,KAAKD,KAAKG,QAAQ6C,IAEtB/C,KAAKD,KAAKG,QAAQ+C,eAAeF,IAASC,IAC7ChD,KAAKD,KAAKG,QAAQ6C,GAAQ,IAGf,aAATA,IACG/C,KAAKD,KAAKa,aAAa,cAAiBoC,GAC3ChD,KAAKD,KAAKuC,aAAa,YAAa,QAElCtC,KAAKD,KAAKa,aAAa,cAAgBoC,GACzChD,KAAKD,KAAKmD,gBAAgB,aAG/B,CAKD,gBAAAC,GACE,QAASnD,MAAKG,EAAaG,QAAUN,KAAKC,OAC3C,CAQD,iBAAAmD,GACEpD,KAAKC,OAASD,MAAKG,EAAaG,MAChCN,MAAKU,EAAYJ,MAAQN,KAAKH,MAC9BG,MAAKS,EAAYH,MAAQN,KAAKO,KAC/B,CAOD,KAAIa,GACF,OAAOpB,KAAKD,KAAKK,cAAc,mCAChC,CAKD,KAAIuB,GACF,MAAM0B,EAAc,GAEpB,IAAIvC,EAAUd,KAAKgB,SACnB,KAAOF,GAAWA,EAAQP,MAAQP,KAAKO,OACrC8C,EAAYC,KAAKxC,GACjBA,EAAUA,EAAQE,SAGpB,OAAOqC,CACR,CAKD,KAAItB,GACF,OAAK/B,KAAKkB,0BAEHwB,MAAMC,KAAK3C,MAAKoB,EAAqBC,UAAUkC,KACnDxD,GAAS,IAAIN,EAAKM,KAHuB,EAK7C,EC7PY,MAAMyD,EAInB,WAAA1D,CAAYC,GACVC,KAAKD,KAAOA,CACb,CAKD,SAAI0D,GACF,OAhBoBC,EAgBE1D,KAAKD,KAAK4D,iBAAiB,wBAf5CjB,MAAMC,KAAKe,GAAOH,KAAKxD,GAAS,IAAIN,EAAKM,KADlD,IAAwB2D,CAiBrB,CAKD,SAAIE,GACF,MAAMC,EAAS7D,KAAKD,KAAK4D,iBAAiB,yBAC1C,OAAOjB,MAAMC,KAAKkB,GACfN,KAAKO,GAAMA,EAAExD,QACbyD,KAAK,IACT,CAKD,OAAAC,GACEhE,KAAKyD,MAAMF,KAAI,CAACzB,EAAMjC,IAAWiC,EAAKjC,MAAQA,GAC/C,CAMD,KAAAoE,GACEjE,KAAKyD,MAAMS,KAAKzE,EAAKC,YAAYmC,SAASC,IACxC9B,KAAKD,KAAKkC,YAAYH,EAAK/B,KAAK,GAEnC,EClDY,MAAMoE,EACnBC,aAAe,CACb,aACA,WACA,eACA,aACA,aACA,WACA,YAGF,WAAAtE,CAAYuE,GAAQ,GAEhBrE,KAAKqE,MADHA,EACW,IAAIC,IAASC,QAAQC,OAAOF,GAE5B,MAEhB,CAQD,SAAAG,CAAU3C,GAER9B,KAAK0E,mBAAmB5C,GACxB9B,KAAK2E,eAAe7C,GACpB9B,KAAK4E,2BAA2B9C,GAChC9B,KAAK6E,mBAAmB/C,GACxB9B,KAAK8E,6CAA6ChD,EACnD,CAOD,MAAAiD,CAAOjD,GACL9B,KAAKgF,MAAQ,GAGbhF,KAAKiF,oBAAoBnD,GACzB9B,KAAKkF,kBAAkBpD,GACvB9B,KAAKmF,sBAAsBrD,GAC3B9B,KAAKoF,mBAAmBtD,GACxB9B,KAAKqF,qBAAqBvD,GAC1B9B,KAAKsF,wBAAwBxD,GAC7B9B,KAAKuF,uBAAuBzD,GAC5B9B,KAAKwF,uBAAuB1D,GAE5BqC,EAAYa,MAAMnD,SAASkB,IACzBjB,EAAKgB,WAAWC,IAAQ/C,KAAKgF,MAAMjC,GAAM,GAE5C,CAKD,kBAAA2B,CAAmB5C,GACE,IAAfA,EAAKjC,OAA8B,IAAfiC,EAAKvB,QAC3BP,KAAKqE,MAAM,yBAAyBvC,EAAKjC,UAAUiC,EAAKvB,cAExDuB,EAAKvB,MAAQ,EAEhB,CAOD,cAAAoE,CAAe7C,IACT2D,MAAM3D,EAAKvB,QAAUuB,EAAKvB,MAAQ,KACpCP,KAAKqE,MAAM,uBAAuBvC,EAAKjC,eAEvCiC,EAAKvB,MAAQ,EAEhB,CAOD,0BAAAqE,CAA2B9C,GACzB,MAAM4D,EAAW5D,EAAKjB,aAClB6E,GAAYA,EAASnF,MAAQuB,EAAKvB,MAAQ,IAC5CP,KAAKqE,MACH,yBAAyBvC,EAAKjC,UAAUiC,EAAKvB,YAC3CmF,EAASnF,MAAQ,KAIrBuB,EAAKvB,MAAQmF,EAASnF,MAAQ,EAEjC,CAOD,kBAAAsE,CAAmB/C,GAGjB,MAAM4D,EAAW5D,EAAKjB,aAClB6E,GAAYA,EAASnF,MAAQuB,EAAKvB,QAAUmF,EAAS/E,WACvDX,KAAKqE,MACH,2BAA2BvC,EAAKjC,UAAUiC,EAAKvB,YAAYmF,EAASnF,SAGtEuB,EAAKvB,MAAQmF,EAASnF,MAEzB,CAOD,4CAAAuE,CAA6ChD,GACvCA,EAAKZ,2BAA6BY,EAAKP,2BACzCvB,KAAKqE,MAAM,wCAAwCvC,EAAKjC,SAExDiC,EAAKW,SAER,CAOD,mBAAAwC,CAAoBnD,GACdA,EAAKP,0BAA0BvB,MAAKgD,EAAM,aAC/C,CAOD,iBAAAkC,CAAkBpD,GACG,IAAfA,EAAKvB,OAAaP,MAAKgD,EAAM,aAClC,CAOD,qBAAAmC,CAAsBrD,GACpB,MAAM6D,EAAO7D,EAAKd,SACd2E,GAAQA,EAAKpF,QAAUuB,EAAKvB,QAAUuB,EAAKnB,UAC7CX,MAAKgD,EAAM,aACd,CAOD,oBAAAqC,CAAqBvD,GACdA,EAAKP,0BAA0BvB,MAAKgD,EAAM,eAChD,CAOD,uBAAAsC,CAAwBxD,GACjBA,EAAKZ,2BAA2BlB,MAAKgD,EAAM,aACjD,CAOD,kBAAAoC,CAAmBtD,GACjB,MAAM4D,EAAW5D,EAAKjB,aAEjB6E,EAEIA,EAASnF,MAAQuB,EAAKvB,MAAOP,MAAKgD,EAAM,YAExC0C,EAASnF,QAAUuB,EAAKvB,OAAUmF,EAAS/E,UAClDX,MAAKgD,EAAM,YALEhD,MAAKgD,EAAM,WAM3B,CAOD,sBAAAuC,CAAuBzD,GAChBA,EAAK7B,SAAU6B,EAAKP,0BAA0BvB,MAAKgD,EAAM,aAC/D,CAOD,sBAAAwC,CAAuB1D,GACjBA,EAAKP,0BAA0BvB,MAAKgD,EAAM,WAC/C,CAOD,EAAAA,CAAMD,GACJ/C,KAAKgF,MAAMjC,IAAQ,CACpB,EChFH,SAAS6C,EAAaC,GACpB,OAAO,IAAIpG,EAAKoG,EAAMC,OAAOC,QAAQ,uBACvC,CCsBA,SAASC,EAAKF,EAAQhE,GACpB,GAAKgE,GACDA,IAAWhE,EAAf,CAEA,GAAwB,OAApBgE,EAAOG,SAAmB,CAC5B,MAAMC,EAAqBJ,EAAOK,wBAAwBrE,GACtDoE,EAAqBE,KAAKC,4BAC5BP,EAAOjD,sBAAsB,cAAef,GACnCoE,EAAqBE,KAAKE,6BACnCR,EAAOjD,sBAAsB,WAAYf,EAE5C,CAEuB,OAApBgE,EAAOG,UACTH,EAAO7D,YAAYH,EAZO,CAc9B,CAiBA,SAASyE,EAAWzC,GAClB,OACEA,IACCA,EAAEiC,QAAQ,kDACTjC,EAAEiC,QAAQ,6CAEhB,CCnMA,MAAMS,EAAOC,OAAOD,KAWpBA,EAAKE,OAAOC,gBAA0B,SAAI,CACxCC,QAAS,KACTC,UAAU,EACVC,eAAe,EACfC,OAAO,UAIFP,EAAKE,OAAOC,gBAAgBK,SAiBnCR,EAAKE,OAAOO,QAAQC,eAAiB,KACnC,MAAMC,KAAEA,GAASX,EAAKE,OACtB,MAAO,qRAGoIS,EAAKC,uBAAuBD,EAAKC,iKAC7BD,EAAKE,yBAAyBF,EAAKE,iJACrDF,EAAKG,yBAAyBH,EAAKG,uLACGH,EAAKI,uBAAuBJ,EAAKI,uQAGlEJ,EAAKH,2BAA2BG,EAAKH,iJAC5CG,EAAKK,wBAAwBL,EAAKK,4IACpCL,EAAKM,uBAAuBN,EAAKM,oJACxBN,EAAKO,0BAA0BP,EAAKO,uJACpCP,EAAKQ,0BAA0BR,EAAKQ,6KACdR,EAAKS,0BAA0BT,EAAKS,6KACpCT,EAAKU,yBAAyBV,EAAKU,oQAG5DV,EAAKW,8BAA8BX,EAAKW,0UAI/BX,EAAKY,uBAAuBZ,EAAKY,gKAC3BZ,EAAKa,uBAAuBb,EAAKa,uWAM7Db,EAAKc,+BAA+Bd,EAAKe,sJAE/Ef,EAAKI,uHACLJ,EAAKgB,2FAKlF,EASD/F,SAASuB,iBAAiB,gBAAgB9B,SAASiC,IACjDA,EAAEsE,UAAY5B,EAAKE,OAAOO,QAAQC,gBAAgB,ICnF/C,MAACmB,EAAc,CAClB,CACEC,WAAY,6BACZC,sBHLW,cAAkCC,EAC/CpE,eAAiB,CAAC,aAElB,OAAAqE,GACEzI,KAAK4D,MAAQ5D,KAAK0I,UAAU9E,MAE5B5D,KAAKgE,SACN,CAED,aAAI0E,GACF,OAAO,IAAIlF,EAAUxD,KAAK2I,gBAC3B,CAED,OAAA3E,GACEhE,KAAK0I,UAAU1E,UACfhE,MAAK+E,GACN,CAED,KAAAd,GACEjE,KAAK0I,UAAUzE,OAChB,CAED,IAAA2E,CAAK/C,GACH7F,KAAK0I,UAAU1E,UAEf,MAAMlC,EAAO8D,EAAaC,GACpBH,EAAW5D,EAAKjB,aAEtB,IAAIgI,EAAQ,EAGVA,OAFeC,IAAbpD,GAEO5D,EAAKvB,MAEdmF,EAAS/E,UACTmB,EAAKd,UACLc,EAAKd,SAAST,MAAQmF,EAASnF,MAGvBmF,EAASnF,MAAQuB,EAAKvB,MAAQ,EAG9BmF,EAASnF,MAAQuB,EAAKvB,MAGhCuB,EAAKN,UAAUgB,IACbA,EAAMjC,OAASsI,CAAK,IAGtB7I,MAAK+E,IACLc,EAAMkD,gBACP,CAED,MAAAC,CAAOnD,GACQD,EAAaC,GAErB9F,KAAKiJ,SAEVhJ,MAAK+E,IACLc,EAAMkD,gBACP,CAED,IAAAE,CAAKpD,GACUD,EAAaC,GAErBrE,UAAUgB,IACbA,EAAMjC,OAAS,CAAC,IAGlBP,MAAK+E,IACLc,EAAMkD,gBACP,CAED,MAAAG,CAAOrD,GACQD,EAAaC,GAErBrE,UAAUgB,IACbA,EAAMjC,OAAS,CAAC,IAGlBP,MAAK+E,IACLc,EAAMkD,gBACP,CAED,QAAA7G,CAAS2D,GACMD,EAAaC,GAErB3D,WAELlC,MAAK+E,IACLc,EAAMkD,gBACP,CAED,MAAAtG,CAAOoD,GACQD,EAAaC,GAErBpD,SAELzC,MAAK+E,IACLc,EAAMkD,gBACP,CAKD,EAAAhE,GAEE/E,KAAKmJ,iBAAkB,EACvBC,YAAW,KACT,IAAKpJ,KAAKmJ,gBAAiB,OAE3BnJ,KAAKmJ,iBAAkB,EACvB,MAAME,EAAS,IAAIlF,EACnBnE,KAAK0I,UAAUjF,MAAM5B,SAASC,GAASuH,EAAO5E,UAAU3C,KACxD9B,KAAK0I,UAAUjF,MAAM5B,SAASC,GAASuH,EAAOtE,OAAOjD,KAErD9B,MAAKsJ,GAAe,GACnB,EACJ,CAED,EAAAA,GACEtJ,KAAKuJ,SAAS,SAAU,CACtBC,SAAS,EACTC,OAAQ,UACRC,OAAQ,CAAEC,MAAO3J,MAAK4J,MAEzB,CAED,EAAAA,GACE,OAAO5J,KAAK0I,UAAU9E,QAAU5D,KAAK4D,KACtC,IG1HD,CACE0E,WAAY,wBACZC,sBCZW,cAA6BC,EAC1C,QAAI1G,GACF,OAAO,IAAIrC,EAAKO,KAAK6J,GACtB,CAED,MAAIC,GACF,OAAO9J,KAAK+J,QAAQhE,QAAQ,KAC7B,CAED,MAAI8D,GACF,OAAO7J,KAAK+J,QAAQhE,QAAQ,KAC7B,CAED,OAAA0C,GACMzI,KAAK+J,QAAQ7J,QAAQ+C,eAAe,UACtCjD,KAAKgJ,SAGIhJ,KAAK8B,KAAKjC,OAAS,EAKrBG,KAAK8B,KAAKqB,qBACjBnD,KAAK8B,KAAKsB,oBACVpD,KAAKgE,WANLhE,KAAKgE,SAQR,CAED,MAAAgF,GAEahJ,KAAK8J,GAEhB9J,KAAK6J,GAAGb,SAERhJ,KAAKgE,SACN,CAED,OAAAA,GACEhE,KAAKuJ,SAAS,UAAW,CAAEC,SAAS,EAAMC,OAAQ,WACnD,ID1BD,CACEnB,WAAY,wBACZC,sBFjBW,cAA6BC,EAC1C,OAAAC,GACEzI,KAAKgK,WAAa,CACnB,CAWD,SAAAC,CAAUpE,GACR,GAAI7F,KAAK+J,UAAYlE,EAAMC,OAAOoE,cAAe,OAEjD,MAAMpE,EAASD,EAAMC,OACrBD,EAAMsE,aAAaC,cAAgB,OAGnCC,uBAAsB,IAAOvE,EAAO5F,QAAQoK,SAAW,IACxD,CAaD,QAAAC,CAAS1E,GACP,MAAM/D,EAAO9B,KAAKwK,SAClB,GAAK1I,EAKL,OAHAkE,EAAKO,EAAWV,EAAMC,QAAShE,GAE/B+D,EAAMkD,kBACC,CACR,CAYD,SAAA0B,CAAU5E,GAMR,GALAA,EAAMkD,iBAGN/I,KAAKgK,aA4HT,SAAqBnE,GACnB,MACuC,SAArCA,EAAMsE,aAAaC,eACkB,aAArCvE,EAAMsE,aAAaC,aAEvB,CA/HQM,CAAY7E,KAAW7F,KAAKwK,SAAU,CACxC,MAAM1I,EAAOM,SAASC,cAAc,MACpCP,EAAK5B,QAAQoK,SAAW,GACxBxI,EAAK5B,QAAQyK,QAAU,GACvB3K,KAAK+J,QAAQ9H,YAAYH,EAC1B,CACF,CAQD,SAAA8I,CAAU/E,GAGR7F,KAAKgK,aAGHhK,KAAKgK,YAAc,GACnBhK,KAAKwK,SAAStK,QAAQ+C,eAAe,aAErCjD,KAAKwK,SAASxB,SACdhJ,KAAKiE,QAER,CAUD,IAAA2E,CAAK/C,GACH,IAAI/D,EAAO9B,KAAKwK,SAEhB,GAAK1I,EAAL,CAMA,GAJA+D,EAAMkD,wBACCjH,EAAK5B,QAAQoK,SACpBtE,EAAKO,EAAWV,EAAMC,QAAShE,GAE3BA,EAAK5B,QAAQ+C,eAAe,WAAY,CAC1C,MAAM4H,EAAc/I,EACdgJ,EAAW1I,SAASC,cAAc,YACxCyI,EAAS1C,UAAYvC,EAAMsE,aAAaY,QAAQ,aAChDjJ,EAAOgJ,EAASE,QAAQ5K,cAAc,MAEtCJ,KAAK+J,QAAQkB,aAAanJ,EAAM+I,GAChCR,uBAAsB,IACpBvI,EAAK1B,cAAc,iCAAiC8K,SAEvD,CAEDlL,KAAKuJ,SAAS,OAAQ,CAAEzD,OAAQhE,EAAM0H,SAAS,EAAMC,OAAQ,WAlB3C,CAmBnB,CAMD,OAAA0B,GACE,MAAMrJ,EAAO9B,KAAKwK,SAEb1I,IACMA,EAAK5B,QAAQ+C,eAAe,WACrCnB,EAAKkH,iBAEElH,EAAK5B,QAAQoK,SACpBtK,KAAKiE,SAER,CAED,cAAImH,GACF,QAASpL,KAAKwK,QACf,CAED,YAAIA,GACF,OAAOxK,KAAK+J,QAAQ3J,cAAc,kBACnC,CAED,OAAA4D,GACEhE,KAAKuJ,SAAS,UAAW,CAAEC,SAAS,EAAMC,OAAQ,WACnD,CAED,KAAAxF,GACEjE,KAAKuJ,SAAS,QAAS,CAAEC,SAAS,EAAMC,OAAQ,WACjD,IEpID,CACEnB,WAAY,4BACZC,sBErBW,cAAgCC,EAC7CpE,eAAiB,CAAC,YAElB,SAAA6F,CAAUpE,GACJ7F,KAAK+J,UAAYlE,EAAMC,SAE3BD,EAAMsE,aAAakB,QAAQ,YAAarL,KAAKsL,eAAelD,WAC5DvC,EAAMsE,aAAaC,cAAgB,OACpC,IFeD,CACE9B,WAAY,8BACZC,sBGzBW,cAAkCC,EAC/C,OAAAC,GAEEzI,KAAKuL,aAAevL,KAAK+J,QAAQ7J,QAAQ0D,KAC1C,CAED,MAAA4H,CAAO1H,GACDA,EAAE4F,QAAU5F,EAAE4F,OAAOzG,eAAe,UACtCjD,KAAK+E,OAAOjB,EAAE4F,OAEjB,CAED,MAAA3E,EAAO4E,MAAEA,IAEL3J,KAAK+J,QAAQ7J,QAAQ0D,MADnB+F,EAC2B,QAEA3J,KAAKuL,YAErC,IHSD,CACEjD,WAAY,yBACZC,sBIrBW,cAA8BC,EAC3CpE,eAAiB,CAAC,QAAS,UAE3B,WAAAtE,CAAY4G,GACV+E,MAAM/E,GAEN1G,KAAK0L,SAAW,IAAIC,iBAAiB3L,KAAKwL,OAC3C,CAED,OAAA/C,GACE,MAAMqC,EAAW1I,SAASC,cAAc,YACxCyI,EAAS1C,UAnBE,sNAoBXpI,KAAKgL,QAAUF,EAASE,QAAQY,kBAChC5L,KAAKgL,QAAQ5C,UAAYpI,KAAK6L,YAAYvL,MAC1CN,KAAKgL,QAAQc,WAAa,IAAI9L,KAAK6L,YAAYC,YAC/C9L,KAAK6L,YAAYhJ,sBAAsB,cAAe7C,KAAKgL,SAC3DhL,KAAK6L,YAAYE,QAAS,EAE1B/L,KAAK0L,SAASM,QAAQhM,KAAKgL,QAAS,CAClCiB,YAAY,EACZC,WAAW,EACXC,eAAe,EACfC,SAAS,GAEZ,CAED,UAAAC,GACErM,KAAK0L,SAASW,aACdrM,KAAKgL,QAAQhC,gBACNhJ,KAAKgL,OACb,CAEDQ,OAAUc,IACRtM,KAAK6L,YAAYvL,MAAQN,KAAKuM,OAAOC,SAAS,EAGhDzH,OAAS,KACP/E,KAAKyM,aAAavB,OAAO,EAG3BwB,MAAS5I,KACyD,IAA5DA,EAAE6I,cAAc5B,QAAQ,aAAa6B,QAAQ,YAEjD9I,EAAEiF,iBAEF/I,KAAK6L,YAAYvL,MAAQwD,EAAE6I,cAAc5B,QAAQ,aAEjD/K,KAAK+E,SAAQ,EAMf,SAAIwH,GACF,OAAOvM,KAAKgL,QAAQ5K,cAAc,QACnC,IJhCD,CACEkI,WAAY,wBACZC,sBDzBW,cAA6BC,EAC1C,cAAAqE,CAAe/I,GAEd"}
@@ -6,6 +6,7 @@ module Katalyst
6
6
  before_action :set_container, only: %i[new create]
7
7
  before_action :set_item, except: %i[new create]
8
8
  before_action :set_editor_variant
9
+ before_action :require_kpop, only: %i[new edit]
9
10
 
10
11
  attr_reader :container, :item, :editor
11
12
 
@@ -103,6 +104,10 @@ module Katalyst
103
104
  def prefix_partial_path_with_controller_namespace
104
105
  false
105
106
  end
107
+
108
+ def kpop_fallback_location
109
+ main_app.root_path
110
+ end
106
111
  end
107
112
  end
108
113
  end
@@ -1,7 +1,15 @@
1
1
  import { Controller } from "@hotwired/stimulus";
2
2
 
3
+ const EDITOR = `
4
+ <div class="content--editor--table-editor"
5
+ contenteditable="true"
6
+ data-content--editor--table-target="content"
7
+ data-action="paste->content--editor--table#paste"
8
+ id="item-content-field">
9
+ </div>`;
10
+
3
11
  export default class TableController extends Controller {
4
- static targets = ["content", "input", "update"];
12
+ static targets = ["input", "update"];
5
13
 
6
14
  constructor(config) {
7
15
  super(config);
@@ -10,7 +18,15 @@ export default class TableController extends Controller {
10
18
  }
11
19
 
12
20
  connect() {
13
- this.observer.observe(this.contentTarget, {
21
+ const template = document.createElement("TEMPLATE");
22
+ template.innerHTML = EDITOR;
23
+ this.content = template.content.firstElementChild;
24
+ this.content.innerHTML = this.inputTarget.value;
25
+ this.content.className += ` ${this.inputTarget.className}`;
26
+ this.inputTarget.insertAdjacentElement("beforebegin", this.content);
27
+ this.inputTarget.hidden = true;
28
+
29
+ this.observer.observe(this.content, {
14
30
  attributes: true,
15
31
  childList: true,
16
32
  characterData: true,
@@ -20,10 +36,12 @@ export default class TableController extends Controller {
20
36
 
21
37
  disconnect() {
22
38
  this.observer.disconnect();
39
+ this.content.remove();
40
+ delete this.content;
23
41
  }
24
42
 
25
43
  change = (mutations) => {
26
- this.inputTarget.value = this.table.outerHTML;
44
+ this.inputTarget.value = this.table?.outerHTML;
27
45
  };
28
46
 
29
47
  update = () => {
@@ -31,6 +49,8 @@ export default class TableController extends Controller {
31
49
  };
32
50
 
33
51
  paste = (e) => {
52
+ if (e.clipboardData.getData("text/html").indexOf("<table") === -1) return;
53
+
34
54
  e.preventDefault();
35
55
 
36
56
  this.inputTarget.value = e.clipboardData.getData("text/html");
@@ -42,6 +62,6 @@ export default class TableController extends Controller {
42
62
  * @returns {HTMLTableElement} The table element from the content target
43
63
  */
44
64
  get table() {
45
- return this.contentTarget.querySelector("table");
65
+ return this.content.querySelector("table");
46
66
  }
47
67
  }
@@ -27,11 +27,6 @@
27
27
  <div class="field">
28
28
  <%= form.label :content %>
29
29
  <% content = sanitize_content_table(normalize_content_table(form.object, heading: false)) %>
30
- <div contenteditable="true"
31
- data-content--editor--table-target="content"
32
- data-action="paste->content--editor--table#paste">
33
- <%= content %>
34
- </div>
35
30
  <%= form.hidden_field :content, value: content, data: { content__editor__table_target: "input" } %>
36
31
  </div>
37
32
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: katalyst-content
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.3.0
4
+ version: 2.3.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Katalyst Interactive
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-03-13 00:00:00.000000000 Z
11
+ date: 2024-03-20 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: active_storage_validations