katalyst-content 2.7.1 → 3.0.0.alpha.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (72) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +11 -2
  3. data/app/assets/builds/katalyst/content.esm.js +208 -110
  4. data/app/assets/builds/katalyst/content.js +208 -110
  5. data/app/assets/builds/katalyst/content.min.js +1 -1
  6. data/app/assets/builds/katalyst/content.min.js.map +1 -1
  7. data/app/assets/images/katalyst/content/icons/aside.svg +1 -0
  8. data/app/assets/images/katalyst/content/icons/collapse.svg +3 -0
  9. data/app/assets/images/katalyst/content/icons/column.svg +1 -0
  10. data/app/assets/images/katalyst/content/icons/content.svg +1 -0
  11. data/app/assets/images/katalyst/content/icons/edit.svg +1 -0
  12. data/app/assets/images/katalyst/content/icons/expand.svg +3 -0
  13. data/app/assets/images/katalyst/content/icons/figure.svg +1 -0
  14. data/app/assets/images/katalyst/content/icons/group.svg +1 -0
  15. data/app/assets/images/katalyst/content/icons/hidden.svg +1 -0
  16. data/app/assets/images/katalyst/content/icons/indent.svg +3 -0
  17. data/app/assets/images/katalyst/content/icons/outdent.svg +4 -0
  18. data/app/assets/images/katalyst/content/icons/remove.svg +1 -0
  19. data/app/assets/images/katalyst/content/icons/section.svg +1 -0
  20. data/app/assets/images/katalyst/content/icons/table.svg +1 -0
  21. data/app/assets/images/katalyst/content/icons/theme.svg +1 -0
  22. data/app/assets/stylesheets/katalyst/_content.scss +4 -0
  23. data/app/assets/stylesheets/katalyst/content/editor.css +196 -0
  24. data/app/assets/stylesheets/katalyst/content/icons.css +79 -0
  25. data/app/assets/stylesheets/katalyst/content/{editor/_status-bar.scss → status-bar.css} +31 -37
  26. data/app/assets/stylesheets/katalyst/content/{editor/_table.scss → table.css} +3 -5
  27. data/app/assets/stylesheets/katalyst/content.css +4 -0
  28. data/app/components/katalyst/content/editor/base_component.rb +0 -6
  29. data/app/components/katalyst/content/editor/item_component.html.erb +31 -15
  30. data/app/components/katalyst/content/editor/item_component.rb +1 -3
  31. data/app/components/katalyst/content/editor/item_editor_component.rb +8 -22
  32. data/app/components/katalyst/content/editor/new_item_component.html.erb +15 -22
  33. data/app/components/katalyst/content/editor/new_item_component.rb +7 -10
  34. data/app/components/katalyst/content/editor/new_items_component.html.erb +41 -2
  35. data/app/components/katalyst/content/editor/new_items_component.rb +0 -2
  36. data/app/components/katalyst/content/editor/row_component.html.erb +2 -1
  37. data/app/components/katalyst/content/editor/status_bar_component.rb +9 -11
  38. data/app/components/katalyst/content/editor/table_component.html.erb +0 -6
  39. data/app/components/katalyst/content/editor/table_component.rb +12 -14
  40. data/app/components/katalyst/content/editor_component.html.erb +7 -0
  41. data/app/components/katalyst/content/editor_component.rb +15 -12
  42. data/app/controllers/katalyst/content/application_controller.rb +1 -0
  43. data/app/controllers/katalyst/content/items_controller.rb +2 -3
  44. data/app/javascript/content/application.js +8 -3
  45. data/app/javascript/content/editor/item.js +1 -1
  46. data/app/javascript/content/editor/item_editor_controller.js +57 -0
  47. data/app/javascript/content/editor/list_controller.js +11 -104
  48. data/app/javascript/content/editor/new_items_controller.js +143 -0
  49. data/app/views/katalyst/content/asides/_aside.html+form.erb +22 -26
  50. data/app/views/katalyst/content/columns/_column.html+form.erb +18 -22
  51. data/app/views/katalyst/content/contents/_content.html+form.erb +22 -26
  52. data/app/views/katalyst/content/figures/_figure.html+form.erb +27 -31
  53. data/app/views/katalyst/content/groups/_group.html+form.erb +18 -22
  54. data/app/views/katalyst/content/items/_form.html.erb +6 -0
  55. data/app/views/katalyst/content/items/_item.html+form.erb +18 -22
  56. data/app/views/katalyst/content/items/edit.html.erb +40 -2
  57. data/app/views/katalyst/content/items/edit.turbo_stream.erb +2 -0
  58. data/app/views/katalyst/content/items/update.turbo_stream.erb +0 -1
  59. data/app/views/katalyst/content/sections/_section.html+form.erb +18 -22
  60. data/app/views/katalyst/content/tables/_table.html+form.erb +7 -9
  61. data/lib/katalyst/content/engine.rb +0 -1
  62. metadata +26 -28
  63. data/app/assets/stylesheets/katalyst/content/_index.scss +0 -1
  64. data/app/assets/stylesheets/katalyst/content/editor/_figure.scss +0 -12
  65. data/app/assets/stylesheets/katalyst/content/editor/_icon.scss +0 -17
  66. data/app/assets/stylesheets/katalyst/content/editor/_index.scss +0 -157
  67. data/app/assets/stylesheets/katalyst/content/editor/_item-actions.scss +0 -110
  68. data/app/assets/stylesheets/katalyst/content/editor/_item-rules.scss +0 -19
  69. data/app/assets/stylesheets/katalyst/content/editor/_new-items.scss +0 -83
  70. data/app/assets/stylesheets/katalyst/content/editor/_trix-rails.scss +0 -30
  71. data/app/assets/stylesheets/katalyst/content/editor/_variables.scss +0 -26
  72. data/app/javascript/content/editor/new_item_controller.js +0 -12
@@ -275,7 +275,7 @@ class Item {
275
275
  */
276
276
  function createChildrenList(node) {
277
277
  const childrenList = document.createElement("ol");
278
- childrenList.setAttribute("class", "hidden");
278
+ childrenList.toggleAttribute("hidden", true);
279
279
 
280
280
  // if objectType is "rich-content" set richContentChildren as a data attribute
281
281
  childrenList.dataset[`contentChildren`] = "";
@@ -736,11 +736,62 @@ class ItemController extends Controller {
736
736
  }
737
737
  }
738
738
 
739
- class ListController extends Controller {
739
+ class ItemEditorController extends Controller {
740
+ static targets = ["dialog"];
741
+
740
742
  connect() {
741
- this.enterCount = 0;
743
+ this.element.addEventListener("turbo:submit-end", this.onSubmit);
744
+ }
745
+
746
+ disconnect() {
747
+ this.element.removeEventListener("turbo:submit-end", this.onSubmit);
748
+ }
749
+
750
+ dismiss() {
751
+ if (!this.dialogTarget) return;
752
+ if (!this.dialogTarget.open) this.dialogTarget.close();
753
+
754
+ if (!("itemPersisted" in this.dialogTarget.dataset)) {
755
+ this.#removeTargetItem();
756
+ }
757
+
758
+ this.element.removeAttribute("src");
759
+ this.dialogTarget.remove();
760
+ }
761
+
762
+ dialogTargetConnected(dialog) {
763
+ dialog.showModal();
764
+ }
765
+
766
+ onSubmit = (event) => {
767
+ if (
768
+ event.detail.success &&
769
+ "closeDialog" in event.detail.formSubmission?.submitter?.dataset
770
+ ) {
771
+ this.dialogTarget.close();
772
+ this.element.removeAttribute("src");
773
+ this.dialogTarget.remove();
774
+ }
775
+ };
776
+
777
+ noop() {}
778
+
779
+ #removeTargetItem() {
780
+ const el = document.getElementById(this.dialogTarget.dataset.itemId);
781
+ const item = new Item(el.closest("[data-content-item]"));
782
+ const list = item.node.parentElement;
783
+
784
+ item.node.remove();
785
+
786
+ this.dispatch("reindex", {
787
+ target: list,
788
+ bubbles: true,
789
+ prefix: "content",
790
+ });
742
791
  }
792
+ }
743
793
 
794
+ class ListController extends Controller {
744
795
  /**
745
796
  * When the user starts a drag within the list, set the item's dataTransfer
746
797
  * properties to indicate that it's being dragged and update its style.
@@ -764,11 +815,6 @@ class ListController extends Controller {
764
815
  * When the user drags an item over another item in the last, swap the
765
816
  * dragging item with the item under the cursor.
766
817
  *
767
- * As a special case, if the item is dragged over placeholder space at the end
768
- * of the list, move the item to the bottom of the list instead. This allows
769
- * users to hit the list element more easily when adding new items to an empty
770
- * list.
771
- *
772
818
  * @param event {DragEvent}
773
819
  */
774
820
  dragover(event) {
@@ -782,54 +828,7 @@ class ListController extends Controller {
782
828
  }
783
829
 
784
830
  /**
785
- * When the user drags an item into the list, create a placeholder item to
786
- * represent the new item. Note that we can't access the drag data
787
- * until drop, so we assume that this is our template item for now.
788
- *
789
- * Users can cancel the drag by dragging the item out of the list or by
790
- * pressing escape. Both are handled by `cancelDrag`.
791
- *
792
- * @param event {DragEvent}
793
- */
794
- dragenter(event) {
795
- event.preventDefault();
796
-
797
- // Safari doesn't support relatedTarget, so we count enter/leave pairs
798
- this.enterCount++;
799
-
800
- if (copyAllowed(event) && !this.dragItem) {
801
- const item = document.createElement("li");
802
- item.dataset.dragging = "";
803
- item.dataset.newItem = "";
804
- this.element.appendChild(item);
805
- }
806
- }
807
-
808
- /**
809
- * When the user drags the item out of the list, remove the placeholder.
810
- * This allows users to cancel the drag by dragging the item out of the list.
811
- *
812
- * @param event {DragEvent}
813
- */
814
- dragleave(event) {
815
- // Safari doesn't support relatedTarget, so we count enter/leave pairs
816
- // https://bugs.webkit.org/show_bug.cgi?id=66547
817
- this.enterCount--;
818
-
819
- if (
820
- this.enterCount <= 0 &&
821
- this.dragItem?.dataset.hasOwnProperty("newItem")
822
- ) {
823
- this.dragItem.remove();
824
- this.reset();
825
- }
826
- }
827
-
828
- /**
829
- * When the user drops an item into the list, end the drag and reindex the list.
830
- *
831
- * If the item is a new item, we replace the placeholder with the template
832
- * item data from the dataTransfer API.
831
+ * When the user drops an item, end the drag and reindex the list.
833
832
  *
834
833
  * @param event {DragEvent}
835
834
  */
@@ -842,31 +841,17 @@ class ListController extends Controller {
842
841
  delete item.dataset.dragging;
843
842
  swap(dropTarget(event.target), item);
844
843
 
845
- if (item.dataset.hasOwnProperty("newItem")) {
846
- const placeholder = item;
847
- const template = document.createElement("template");
848
- template.innerHTML = event.dataTransfer.getData("text/html");
849
- item = template.content.querySelector("li");
850
-
851
- this.element.replaceChild(item, placeholder);
852
- requestAnimationFrame(() =>
853
- item.querySelector("[role='button'][value='edit']").click(),
854
- );
855
- }
856
-
857
844
  this.dispatch("drop", { target: item, bubbles: true, prefix: "content" });
858
845
  }
859
846
 
860
847
  /**
861
- * End an in-progress drag. If the item is a new item, remove it, otherwise
862
- * reset the item's style and restore its original position in the list.
848
+ * End an in-progress drag by resetting the item's style and restoring its
849
+ * original position in the list.
863
850
  */
864
851
  dragend() {
865
852
  const item = this.dragItem;
866
853
 
867
- if (!item) ; else if (item.dataset.hasOwnProperty("newItem")) {
868
- item.remove();
869
- } else {
854
+ if (item) {
870
855
  delete item.dataset.dragging;
871
856
  this.reset();
872
857
  }
@@ -890,7 +875,7 @@ class ListController extends Controller {
890
875
  }
891
876
 
892
877
  /**
893
- * Swaps two list items. If target is a list, the item is appended.
878
+ * Swaps two list items.
894
879
  *
895
880
  * @param target the target element to swap with
896
881
  * @param item the item the user is dragging
@@ -899,51 +884,160 @@ function swap(target, item) {
899
884
  if (!target) return;
900
885
  if (target === item) return;
901
886
 
902
- if (target.nodeName === "LI") {
903
- const positionComparison = target.compareDocumentPosition(item);
904
- if (positionComparison & Node.DOCUMENT_POSITION_FOLLOWING) {
905
- target.insertAdjacentElement("beforebegin", item);
906
- } else if (positionComparison & Node.DOCUMENT_POSITION_PRECEDING) {
907
- target.insertAdjacentElement("afterend", item);
908
- }
909
- }
910
-
911
- if (target.nodeName === "OL") {
912
- target.appendChild(item);
887
+ const positionComparison = target.compareDocumentPosition(item);
888
+ if (positionComparison & Node.DOCUMENT_POSITION_FOLLOWING) {
889
+ target.insertAdjacentElement("beforebegin", item);
890
+ } else if (positionComparison & Node.DOCUMENT_POSITION_PRECEDING) {
891
+ target.insertAdjacentElement("afterend", item);
913
892
  }
914
893
  }
915
894
 
916
- /**
917
- * Returns true if the event supports copy or copy move.
918
- *
919
- * Chrome and Firefox use copy, but Safari only supports copyMove.
920
- */
921
- function copyAllowed(event) {
922
- return (
923
- event.dataTransfer.effectAllowed === "copy" ||
924
- event.dataTransfer.effectAllowed === "copyMove"
925
- );
926
- }
927
-
928
895
  /**
929
896
  * Given an event target, return the closest drop target, if any.
930
897
  */
931
898
  function dropTarget(e) {
932
- return (
933
- e &&
934
- (e.closest("[data-controller='content--editor--list'] > *") ||
935
- e.closest("[data-controller='content--editor--list']"))
936
- );
899
+ return e && e.closest("[data-controller='content--editor--list'] > *");
937
900
  }
938
901
 
939
- class NewItemController extends Controller {
940
- static targets = ["template"];
902
+ const EDGE_AREA = 24;
941
903
 
942
- dragstart(event) {
943
- if (this.element !== event.target) return;
904
+ class NewItemsController extends Controller {
905
+ static targets = ["inline"];
944
906
 
945
- event.dataTransfer.setData("text/html", this.templateTarget.innerHTML);
946
- event.dataTransfer.effectAllowed = "copy";
907
+ connect() {
908
+ this.form.addEventListener("mousemove", this.move);
909
+ }
910
+
911
+ disconnect() {
912
+ this.form?.removeEventListener("mousemove", this.move);
913
+ delete this.currentItem;
914
+ }
915
+
916
+ open(e) {
917
+ e.preventDefault();
918
+ this.dialog.showModal();
919
+ }
920
+
921
+ close(e) {
922
+ e.preventDefault();
923
+ this.dialog.close();
924
+ }
925
+
926
+ noop(e) {}
927
+
928
+ /**
929
+ * Add the selected item to the DOM at the current position or the end of the list.
930
+ */
931
+ add(e) {
932
+ e.preventDefault();
933
+
934
+ const template = e.target.closest("li").querySelector("template");
935
+ const item = template.content.querySelector("li").cloneNode(true);
936
+ const target = this.currentItem;
937
+
938
+ if (target) {
939
+ target.insertAdjacentElement("beforebegin", item);
940
+ } else {
941
+ this.list.insertAdjacentElement("beforeend", item);
942
+ }
943
+
944
+ this.toggleInline(false);
945
+ this.dialog.close();
946
+
947
+ requestAnimationFrame(() => {
948
+ item.querySelector(`[value="edit"]`).click();
949
+ });
950
+ }
951
+
952
+ morph(e) {
953
+ e.preventDefault();
954
+ this.dialog.close();
955
+ }
956
+
957
+ move = (e) => {
958
+ if (this.isOverInlineTarget(e)) return;
959
+ if (this.dialog.open) return;
960
+
961
+ const target = this.getCurrentItem(e);
962
+
963
+ // return if we're already showing this item
964
+ if (this.currentItem === target) return;
965
+
966
+ // hide the button if it's already visible
967
+ if (this.currentItem) this.toggleInline(false);
968
+
969
+ this.currentItem = target;
970
+
971
+ // clear any previously set timer
972
+ if (this.timer) clearTimeout(this.timer);
973
+
974
+ // show the button after a debounce pause
975
+ this.timer = setTimeout(() => {
976
+ delete this.timer;
977
+ this.toggleInline();
978
+ }, 100);
979
+ };
980
+
981
+ toggleInline(show = !!this.currentItem) {
982
+ if (show) {
983
+ this.inlineTarget.style.top = `${this.currentItem.offsetTop}px`;
984
+ this.inlineTarget.toggleAttribute("hidden", false);
985
+ } else {
986
+ this.inlineTarget.toggleAttribute("hidden", true);
987
+ }
988
+ }
989
+
990
+ get dialog() {
991
+ return this.element.querySelector("dialog");
992
+ }
993
+
994
+ /**
995
+ * @returns {HTMLFormElement}
996
+ */
997
+ get form() {
998
+ return this.element.closest("form");
999
+ }
1000
+
1001
+ /**
1002
+ * @returns {HTMLUListElement,null}
1003
+ */
1004
+ get list() {
1005
+ return this.form.querySelector(`[data-controller="content--editor--list"]`);
1006
+ }
1007
+
1008
+ /**
1009
+ * @param {MouseEvent} e
1010
+ * @returns {HTMLLIElement,null}
1011
+ */
1012
+ getCurrentItem(e) {
1013
+ const item = document.elementFromPoint(e.clientX, e.clientY).closest("li");
1014
+ if (!item) return null;
1015
+
1016
+ const bounds = item.getBoundingClientRect();
1017
+
1018
+ // check X for center(ish) mouse position
1019
+ if (e.clientX < bounds.left + bounds.width / 2 - 2 * EDGE_AREA) return null;
1020
+ if (e.clientX > bounds.left + bounds.width / 2 + 2 * EDGE_AREA) return null;
1021
+
1022
+ // check Y for hits on this item or it's next sibling
1023
+ if (e.clientY - bounds.y <= EDGE_AREA) {
1024
+ return item;
1025
+ } else if (bounds.y + bounds.height - e.clientY <= EDGE_AREA) {
1026
+ return item.nextElementSibling;
1027
+ } else {
1028
+ return null;
1029
+ }
1030
+ }
1031
+
1032
+ /**
1033
+ * @param {MouseEvent} e
1034
+ * @returns {Boolean} true when the target of the event is the floating button
1035
+ */
1036
+ isOverInlineTarget(e) {
1037
+ return (
1038
+ this.inlineTarget ===
1039
+ document.elementFromPoint(e.clientX, e.clientY).closest("div")
1040
+ );
947
1041
  }
948
1042
  }
949
1043
 
@@ -1194,13 +1288,17 @@ const Definitions = [
1194
1288
  identifier: "content--editor--item",
1195
1289
  controllerConstructor: ItemController,
1196
1290
  },
1291
+ {
1292
+ identifier: "content--editor--item-editor",
1293
+ controllerConstructor: ItemEditorController,
1294
+ },
1197
1295
  {
1198
1296
  identifier: "content--editor--list",
1199
1297
  controllerConstructor: ListController,
1200
1298
  },
1201
1299
  {
1202
- identifier: "content--editor--new-item",
1203
- controllerConstructor: NewItemController,
1300
+ identifier: "content--editor--new-items",
1301
+ controllerConstructor: NewItemsController,
1204
1302
  },
1205
1303
  {
1206
1304
  identifier: "content--editor--status-bar",
@@ -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.#s;t(this),this.#r(t),e.forEach((e=>e.#r(t)))}#r(t){this.hasCollapsedDescendants()&&this.#a.forEach((e=>{t(e),e.#r(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.#s.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#s(){const t=[];let e=this.nextItem;for(;e&&e.depth>this.depth;)t.push(e),e=e.nextItem;return t}get#a(){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 s(t){return new e(t.target.closest("[data-content-item]"))}function r(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 a(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=s(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){s(t).node.remove(),this.#d(),t.preventDefault()}nest(t){s(t).traverse((t=>{t.depth+=1})),this.#d(),t.preventDefault()}deNest(t){s(t).traverse((t=>{t.depth-=1})),this.#d(),t.preventDefault()}collapse(t){s(t).collapse(),this.#d(),t.preventDefault()}expand(t){s(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 r(a(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,r(a(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}morph(t){t.target===this.element&&(this.versionState=this.element.dataset.state,this.update({dirty:!1}))}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){this.element.addEventListener("turbo:before-morph-attribute",this.suppressMorph),this.element.addEventListener("turbo:before-morph-element",this.suppressMorph),this.element.toolbarElement&&(this.element.toolbarElement.addEventListener("turbo:before-morph-attribute",this.suppressMorph),this.element.toolbarElement.addEventListener("turbo:before-morph-element",this.suppressMorph))}disconnect(){this.element.removeEventListener("turbo:before-morph-attribute",this.suppressMorph),this.element.removeEventListener("turbo:before-morph-element",this.suppressMorph),this.element.toolbarElement&&(this.element.toolbarElement.removeEventListener("turbo:before-morph-attribute",this.suppressMorph),this.element.toolbarElement.removeEventListener("turbo:before-morph-element",this.suppressMorph))}suppressMorph=t=>{"TRIX-EDITOR"!==t.target.tagName&&"TRIX-TOOLBAR"!==t.target.tagName||t.preventDefault()}}}];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.#s;t(this),this.#r(t),e.forEach((e=>e.#r(t)))}#r(t){this.hasCollapsedDescendants()&&this.#o.forEach((e=>{t(e),e.#r(t)}))}collapseChild(t){this.#i.appendChild(t.node)}collapse(){let t=this.#i;t||(t=function(t){const e=document.createElement("ol");return e.toggleAttribute("hidden",!0),e.dataset.contentChildren="",t.appendChild(e),e}(this.node)),this.#s.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#s(){const t=[];let e=this.nextItem;for(;e&&e.depth>this.depth;)t.push(e),e=e.nextItem;return t}get#o(){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.#a("denyDeNest")}rootsCannotDeNest(t){0===t.depth&&this.#a("denyDeNest")}onlyLastItemCanDeNest(t){const e=t.nextItem;e&&e.depth===t.depth&&!t.isLayout&&this.#a("denyDeNest")}leavesCannotCollapse(t){t.hasExpandedDescendants()||this.#a("denyCollapse")}needHiddenItemsToExpand(t){t.hasCollapsedDescendants()||this.#a("denyExpand")}nestingNeedsParent(t){const e=t.previousItem;e?e.depth<t.depth?this.#a("denyNest"):e.depth!==t.depth||e.isLayout||this.#a("denyNest"):this.#a("denyNest")}parentsCannotBeDeleted(t){t.itemId&&!t.hasExpandedDescendants()||this.#a("denyRemove")}parentsCannotBeDragged(t){t.hasExpandedDescendants()&&this.#a("denyDrag")}#a(t){this.rules[t]=!0}}function s(t){return new e(t.target.closest("[data-content-item]"))}function r(t,e){if(!t)return;if(t===e)return;const n=t.compareDocumentPosition(e);n&Node.DOCUMENT_POSITION_FOLLOWING?t.insertAdjacentElement("beforebegin",e):n&Node.DOCUMENT_POSITION_PRECEDING&&t.insertAdjacentElement("afterend",e)}function o(t){return t&&t.closest("[data-controller='content--editor--list'] > *")}const a=window.Trix;a.config.blockAttributes.heading4={tagName:"h4",terminal:!0,breakOnReturn:!0,group:!1},delete a.config.blockAttributes.heading1;a.config.toolbar.getDefaultHTML=()=>{const{lang:t}=a.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=a.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=s(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){s(t).node.remove(),this.#d(),t.preventDefault()}nest(t){s(t).traverse((t=>{t.depth+=1})),this.#d(),t.preventDefault()}deNest(t){s(t).traverse((t=>{t.depth-=1})),this.#d(),t.preventDefault()}collapse(t){s(t).collapse(),this.#d(),t.preventDefault()}expand(t){s(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--item-editor",controllerConstructor:class extends t{static targets=["dialog"];connect(){this.element.addEventListener("turbo:submit-end",this.onSubmit)}disconnect(){this.element.removeEventListener("turbo:submit-end",this.onSubmit)}dismiss(){this.dialogTarget&&(this.dialogTarget.open||this.dialogTarget.close(),"itemPersisted"in this.dialogTarget.dataset||this.#h(),this.element.removeAttribute("src"),this.dialogTarget.remove())}dialogTargetConnected(t){t.showModal()}onSubmit=t=>{t.detail.success&&"closeDialog"in t.detail.formSubmission?.submitter?.dataset&&(this.dialogTarget.close(),this.element.removeAttribute("src"),this.dialogTarget.remove())};noop(){}#h(){const t=document.getElementById(this.dialogTarget.dataset.itemId),n=new e(t.closest("[data-content-item]")),i=n.node.parentElement;n.node.remove(),this.dispatch("reindex",{target:i,bubbles:!0,prefix:"content"})}}},{identifier:"content--editor--list",controllerConstructor:class extends t{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 r(o(t.target),e),t.preventDefault(),!0}drop(t){let e=this.dragItem;e&&(t.preventDefault(),delete e.dataset.dragging,r(o(t.target),e),this.dispatch("drop",{target:e,bubbles:!0,prefix:"content"}))}dragend(){const t=this.dragItem;t&&(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-items",controllerConstructor:class extends t{static targets=["inline"];connect(){this.form.addEventListener("mousemove",this.move)}disconnect(){this.form?.removeEventListener("mousemove",this.move),delete this.currentItem}open(t){t.preventDefault(),this.dialog.showModal()}close(t){t.preventDefault(),this.dialog.close()}noop(t){}add(t){t.preventDefault();const e=t.target.closest("li").querySelector("template").content.querySelector("li").cloneNode(!0),n=this.currentItem;n?n.insertAdjacentElement("beforebegin",e):this.list.insertAdjacentElement("beforeend",e),this.toggleInline(!1),this.dialog.close(),requestAnimationFrame((()=>{e.querySelector('[value="edit"]').click()}))}morph(t){t.preventDefault(),this.dialog.close()}move=t=>{if(this.isOverInlineTarget(t))return;if(this.dialog.open)return;const e=this.getCurrentItem(t);this.currentItem!==e&&(this.currentItem&&this.toggleInline(!1),this.currentItem=e,this.timer&&clearTimeout(this.timer),this.timer=setTimeout((()=>{delete this.timer,this.toggleInline()}),100))};toggleInline(t=!!this.currentItem){t?(this.inlineTarget.style.top=`${this.currentItem.offsetTop}px`,this.inlineTarget.toggleAttribute("hidden",!1)):this.inlineTarget.toggleAttribute("hidden",!0)}get dialog(){return this.element.querySelector("dialog")}get form(){return this.element.closest("form")}get list(){return this.form.querySelector('[data-controller="content--editor--list"]')}getCurrentItem(t){const e=document.elementFromPoint(t.clientX,t.clientY).closest("li");if(!e)return null;const n=e.getBoundingClientRect();return t.clientX<n.left+n.width/2-48||t.clientX>n.left+n.width/2+48?null:t.clientY-n.y<=24?e:n.y+n.height-t.clientY<=24?e.nextElementSibling:null}isOverInlineTarget(t){return this.inlineTarget===document.elementFromPoint(t.clientX,t.clientY).closest("div")}}},{identifier:"content--editor--status-bar",controllerConstructor:class extends t{connect(){this.versionState=this.element.dataset.state}morph(t){t.target===this.element&&(this.versionState=this.element.dataset.state,this.update({dirty:!1}))}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){this.element.addEventListener("turbo:before-morph-attribute",this.suppressMorph),this.element.addEventListener("turbo:before-morph-element",this.suppressMorph),this.element.toolbarElement&&(this.element.toolbarElement.addEventListener("turbo:before-morph-attribute",this.suppressMorph),this.element.toolbarElement.addEventListener("turbo:before-morph-element",this.suppressMorph))}disconnect(){this.element.removeEventListener("turbo:before-morph-attribute",this.suppressMorph),this.element.removeEventListener("turbo:before-morph-element",this.suppressMorph),this.element.toolbarElement&&(this.element.toolbarElement.removeEventListener("turbo:before-morph-attribute",this.suppressMorph),this.element.toolbarElement.removeEventListener("turbo:before-morph-element",this.suppressMorph))}suppressMorph=t=>{"TRIX-EDITOR"!==t.target.tagName&&"TRIX-TOOLBAR"!==t.target.tagName||t.preventDefault()}}}];export{d as default};
2
2
  //# sourceMappingURL=content.min.js.map