katalyst-content 2.7.1 → 2.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: dd304c013caafd629c2337b31fb5f0d312a0788a849d837ce7af782a57a3323f
4
- data.tar.gz: fa5ebf0fc07717ad6342133019d98c8ee7c3fb7e1e10dc48da431eb800463ece
3
+ metadata.gz: 66041eb840d07d79378df3d2e9dd118b78c73b0360341f622cf62b8280c57deb
4
+ data.tar.gz: 4286fae6950b693ae85395efd7073644694b8e571d82a8f512eafb73698bea17
5
5
  SHA512:
6
- metadata.gz: a26484269d545c5e9be10a1c7f905ec79398c96d98274f135da46df72de6c76be552ec162aaa3707844b1a1ac6dac43cd7a2592f4f34d8e5d1f1c10310ad9bcf
7
- data.tar.gz: 9331d35d82ede880932a60c299cc2c6a525b46c4e972241d12c914507765ea38d2d3b9f686a027401a8e4871c67a9afb6bb471dd5fd2d910524426061fcc4ede
6
+ metadata.gz: d35c06d115c82bf4c3d31d8633da792dd498d9aa5949aa637df65e388bc2ce1a6c7a3c2e455baa00eb55d7a759d8fed75ac95b754b4297b1f10c2598c65fa719
7
+ data.tar.gz: 1b9bcea09d7a7b542afd2d645ef5778554795e5845d86cf61bc7c6b681239da7e37b5eeaddf1698d219b43a047809edf68d36d1e0defbc66e7751afa4e90cdd2
@@ -737,10 +737,6 @@ class ItemController extends Controller {
737
737
  }
738
738
 
739
739
  class ListController extends Controller {
740
- connect() {
741
- this.enterCount = 0;
742
- }
743
-
744
740
  /**
745
741
  * When the user starts a drag within the list, set the item's dataTransfer
746
742
  * properties to indicate that it's being dragged and update its style.
@@ -764,11 +760,6 @@ class ListController extends Controller {
764
760
  * When the user drags an item over another item in the last, swap the
765
761
  * dragging item with the item under the cursor.
766
762
  *
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
763
  * @param event {DragEvent}
773
764
  */
774
765
  dragover(event) {
@@ -782,54 +773,7 @@ class ListController extends Controller {
782
773
  }
783
774
 
784
775
  /**
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.
776
+ * When the user drops an item, end the drag and reindex the list.
833
777
  *
834
778
  * @param event {DragEvent}
835
779
  */
@@ -842,31 +786,17 @@ class ListController extends Controller {
842
786
  delete item.dataset.dragging;
843
787
  swap(dropTarget(event.target), item);
844
788
 
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
789
  this.dispatch("drop", { target: item, bubbles: true, prefix: "content" });
858
790
  }
859
791
 
860
792
  /**
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.
793
+ * End an in-progress drag by resetting the item's style and restoring its
794
+ * original position in the list.
863
795
  */
864
796
  dragend() {
865
797
  const item = this.dragItem;
866
798
 
867
- if (!item) ; else if (item.dataset.hasOwnProperty("newItem")) {
868
- item.remove();
869
- } else {
799
+ if (item) {
870
800
  delete item.dataset.dragging;
871
801
  this.reset();
872
802
  }
@@ -890,7 +820,7 @@ class ListController extends Controller {
890
820
  }
891
821
 
892
822
  /**
893
- * Swaps two list items. If target is a list, the item is appended.
823
+ * Swaps two list items.
894
824
  *
895
825
  * @param target the target element to swap with
896
826
  * @param item the item the user is dragging
@@ -899,51 +829,160 @@ function swap(target, item) {
899
829
  if (!target) return;
900
830
  if (target === item) return;
901
831
 
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
- }
832
+ const positionComparison = target.compareDocumentPosition(item);
833
+ if (positionComparison & Node.DOCUMENT_POSITION_FOLLOWING) {
834
+ target.insertAdjacentElement("beforebegin", item);
835
+ } else if (positionComparison & Node.DOCUMENT_POSITION_PRECEDING) {
836
+ target.insertAdjacentElement("afterend", item);
909
837
  }
910
-
911
- if (target.nodeName === "OL") {
912
- target.appendChild(item);
913
- }
914
- }
915
-
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
838
  }
927
839
 
928
840
  /**
929
841
  * Given an event target, return the closest drop target, if any.
930
842
  */
931
843
  function dropTarget(e) {
932
- return (
933
- e &&
934
- (e.closest("[data-controller='content--editor--list'] > *") ||
935
- e.closest("[data-controller='content--editor--list']"))
936
- );
844
+ return e && e.closest("[data-controller='content--editor--list'] > *");
937
845
  }
938
846
 
939
- class NewItemController extends Controller {
940
- static targets = ["template"];
847
+ const EDGE_AREA = 24;
941
848
 
942
- dragstart(event) {
943
- if (this.element !== event.target) return;
849
+ class NewItemsController extends Controller {
850
+ static targets = ["inline"];
851
+
852
+ connect() {
853
+ this.form.addEventListener("mousemove", this.move);
854
+ }
855
+
856
+ disconnect() {
857
+ this.form?.removeEventListener("mousemove", this.move);
858
+ delete this.currentItem;
859
+ }
860
+
861
+ open(e) {
862
+ e.preventDefault();
863
+ this.dialog.showModal();
864
+ }
865
+
866
+ close(e) {
867
+ e.preventDefault();
868
+ this.dialog.close();
869
+ }
870
+
871
+ noop(e) {}
872
+
873
+ /**
874
+ * Add the selected item to the DOM at the current position or the end of the list.
875
+ */
876
+ add(e) {
877
+ e.preventDefault();
878
+
879
+ const template = e.target.querySelector("template");
880
+ const item = template.content.querySelector("li").cloneNode(true);
881
+ const target = this.currentItem;
882
+
883
+ if (target) {
884
+ target.insertAdjacentElement("beforebegin", item);
885
+ } else {
886
+ this.list.insertAdjacentElement("beforeend", item);
887
+ }
888
+
889
+ this.toggleInline(false);
890
+ this.dialog.close();
891
+
892
+ requestAnimationFrame(() => {
893
+ item.querySelector(`[value="edit"]`).click();
894
+ });
895
+ }
896
+
897
+ morph(e) {
898
+ e.preventDefault();
899
+ this.dialog.close();
900
+ }
901
+
902
+ move = (e) => {
903
+ if (this.isOverInlineTarget(e)) return;
904
+ if (this.dialog.open) return;
905
+
906
+ const target = this.getCurrentItem(e);
907
+
908
+ // return if we're already showing this item
909
+ if (this.currentItem === target) return;
910
+
911
+ // hide the button if it's already visible
912
+ if (this.currentItem) this.toggleInline(false);
913
+
914
+ this.currentItem = target;
915
+
916
+ // clear any previously set timer
917
+ if (this.timer) clearTimeout(this.timer);
918
+
919
+ // show the button after a debounce pause
920
+ this.timer = setTimeout(() => {
921
+ delete this.timer;
922
+ this.toggleInline();
923
+ }, 100);
924
+ };
944
925
 
945
- event.dataTransfer.setData("text/html", this.templateTarget.innerHTML);
946
- event.dataTransfer.effectAllowed = "copy";
926
+ toggleInline(show = !!this.currentItem) {
927
+ if (show) {
928
+ this.inlineTarget.style.top = `${this.currentItem.offsetTop}px`;
929
+ this.inlineTarget.toggleAttribute("hidden", false);
930
+ } else {
931
+ this.inlineTarget.toggleAttribute("hidden", true);
932
+ }
933
+ }
934
+
935
+ get dialog() {
936
+ return this.element.querySelector("dialog");
937
+ }
938
+
939
+ /**
940
+ * @returns {HTMLFormElement}
941
+ */
942
+ get form() {
943
+ return this.element.closest("form");
944
+ }
945
+
946
+ /**
947
+ * @returns {HTMLUListElement,null}
948
+ */
949
+ get list() {
950
+ return this.form.querySelector(`[data-controller="content--editor--list"]`);
951
+ }
952
+
953
+ /**
954
+ * @param {MouseEvent} e
955
+ * @returns {HTMLLIElement,null}
956
+ */
957
+ getCurrentItem(e) {
958
+ const item = document.elementFromPoint(e.clientX, e.clientY).closest("li");
959
+ if (!item) return null;
960
+
961
+ const bounds = item.getBoundingClientRect();
962
+
963
+ // check X for center(ish) mouse position
964
+ if (e.clientX < bounds.left + bounds.width / 2 - 2 * EDGE_AREA) return null;
965
+ if (e.clientX > bounds.left + bounds.width / 2 + 2 * EDGE_AREA) return null;
966
+
967
+ // check Y for hits on this item or it's next sibling
968
+ if (e.clientY - bounds.y <= EDGE_AREA) {
969
+ return item;
970
+ } else if (bounds.y + bounds.height - e.clientY <= EDGE_AREA) {
971
+ return item.nextElementSibling;
972
+ } else {
973
+ return null;
974
+ }
975
+ }
976
+
977
+ /**
978
+ * @param {MouseEvent} e
979
+ * @returns {Boolean} true when the target of the event is the floating button
980
+ */
981
+ isOverInlineTarget(e) {
982
+ return (
983
+ this.inlineTarget ===
984
+ document.elementFromPoint(e.clientX, e.clientY).closest("div")
985
+ );
947
986
  }
948
987
  }
949
988
 
@@ -1199,8 +1238,8 @@ const Definitions = [
1199
1238
  controllerConstructor: ListController,
1200
1239
  },
1201
1240
  {
1202
- identifier: "content--editor--new-item",
1203
- controllerConstructor: NewItemController,
1241
+ identifier: "content--editor--new-items",
1242
+ controllerConstructor: NewItemsController,
1204
1243
  },
1205
1244
  {
1206
1245
  identifier: "content--editor--status-bar",
@@ -737,10 +737,6 @@ class ItemController extends Controller {
737
737
  }
738
738
 
739
739
  class ListController extends Controller {
740
- connect() {
741
- this.enterCount = 0;
742
- }
743
-
744
740
  /**
745
741
  * When the user starts a drag within the list, set the item's dataTransfer
746
742
  * properties to indicate that it's being dragged and update its style.
@@ -764,11 +760,6 @@ class ListController extends Controller {
764
760
  * When the user drags an item over another item in the last, swap the
765
761
  * dragging item with the item under the cursor.
766
762
  *
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
763
  * @param event {DragEvent}
773
764
  */
774
765
  dragover(event) {
@@ -782,54 +773,7 @@ class ListController extends Controller {
782
773
  }
783
774
 
784
775
  /**
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.
776
+ * When the user drops an item, end the drag and reindex the list.
833
777
  *
834
778
  * @param event {DragEvent}
835
779
  */
@@ -842,31 +786,17 @@ class ListController extends Controller {
842
786
  delete item.dataset.dragging;
843
787
  swap(dropTarget(event.target), item);
844
788
 
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
789
  this.dispatch("drop", { target: item, bubbles: true, prefix: "content" });
858
790
  }
859
791
 
860
792
  /**
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.
793
+ * End an in-progress drag by resetting the item's style and restoring its
794
+ * original position in the list.
863
795
  */
864
796
  dragend() {
865
797
  const item = this.dragItem;
866
798
 
867
- if (!item) ; else if (item.dataset.hasOwnProperty("newItem")) {
868
- item.remove();
869
- } else {
799
+ if (item) {
870
800
  delete item.dataset.dragging;
871
801
  this.reset();
872
802
  }
@@ -890,7 +820,7 @@ class ListController extends Controller {
890
820
  }
891
821
 
892
822
  /**
893
- * Swaps two list items. If target is a list, the item is appended.
823
+ * Swaps two list items.
894
824
  *
895
825
  * @param target the target element to swap with
896
826
  * @param item the item the user is dragging
@@ -899,51 +829,160 @@ function swap(target, item) {
899
829
  if (!target) return;
900
830
  if (target === item) return;
901
831
 
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
- }
832
+ const positionComparison = target.compareDocumentPosition(item);
833
+ if (positionComparison & Node.DOCUMENT_POSITION_FOLLOWING) {
834
+ target.insertAdjacentElement("beforebegin", item);
835
+ } else if (positionComparison & Node.DOCUMENT_POSITION_PRECEDING) {
836
+ target.insertAdjacentElement("afterend", item);
909
837
  }
910
-
911
- if (target.nodeName === "OL") {
912
- target.appendChild(item);
913
- }
914
- }
915
-
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
838
  }
927
839
 
928
840
  /**
929
841
  * Given an event target, return the closest drop target, if any.
930
842
  */
931
843
  function dropTarget(e) {
932
- return (
933
- e &&
934
- (e.closest("[data-controller='content--editor--list'] > *") ||
935
- e.closest("[data-controller='content--editor--list']"))
936
- );
844
+ return e && e.closest("[data-controller='content--editor--list'] > *");
937
845
  }
938
846
 
939
- class NewItemController extends Controller {
940
- static targets = ["template"];
847
+ const EDGE_AREA = 24;
941
848
 
942
- dragstart(event) {
943
- if (this.element !== event.target) return;
849
+ class NewItemsController extends Controller {
850
+ static targets = ["inline"];
851
+
852
+ connect() {
853
+ this.form.addEventListener("mousemove", this.move);
854
+ }
855
+
856
+ disconnect() {
857
+ this.form?.removeEventListener("mousemove", this.move);
858
+ delete this.currentItem;
859
+ }
860
+
861
+ open(e) {
862
+ e.preventDefault();
863
+ this.dialog.showModal();
864
+ }
865
+
866
+ close(e) {
867
+ e.preventDefault();
868
+ this.dialog.close();
869
+ }
870
+
871
+ noop(e) {}
872
+
873
+ /**
874
+ * Add the selected item to the DOM at the current position or the end of the list.
875
+ */
876
+ add(e) {
877
+ e.preventDefault();
878
+
879
+ const template = e.target.querySelector("template");
880
+ const item = template.content.querySelector("li").cloneNode(true);
881
+ const target = this.currentItem;
882
+
883
+ if (target) {
884
+ target.insertAdjacentElement("beforebegin", item);
885
+ } else {
886
+ this.list.insertAdjacentElement("beforeend", item);
887
+ }
888
+
889
+ this.toggleInline(false);
890
+ this.dialog.close();
891
+
892
+ requestAnimationFrame(() => {
893
+ item.querySelector(`[value="edit"]`).click();
894
+ });
895
+ }
896
+
897
+ morph(e) {
898
+ e.preventDefault();
899
+ this.dialog.close();
900
+ }
901
+
902
+ move = (e) => {
903
+ if (this.isOverInlineTarget(e)) return;
904
+ if (this.dialog.open) return;
905
+
906
+ const target = this.getCurrentItem(e);
907
+
908
+ // return if we're already showing this item
909
+ if (this.currentItem === target) return;
910
+
911
+ // hide the button if it's already visible
912
+ if (this.currentItem) this.toggleInline(false);
913
+
914
+ this.currentItem = target;
915
+
916
+ // clear any previously set timer
917
+ if (this.timer) clearTimeout(this.timer);
918
+
919
+ // show the button after a debounce pause
920
+ this.timer = setTimeout(() => {
921
+ delete this.timer;
922
+ this.toggleInline();
923
+ }, 100);
924
+ };
944
925
 
945
- event.dataTransfer.setData("text/html", this.templateTarget.innerHTML);
946
- event.dataTransfer.effectAllowed = "copy";
926
+ toggleInline(show = !!this.currentItem) {
927
+ if (show) {
928
+ this.inlineTarget.style.top = `${this.currentItem.offsetTop}px`;
929
+ this.inlineTarget.toggleAttribute("hidden", false);
930
+ } else {
931
+ this.inlineTarget.toggleAttribute("hidden", true);
932
+ }
933
+ }
934
+
935
+ get dialog() {
936
+ return this.element.querySelector("dialog");
937
+ }
938
+
939
+ /**
940
+ * @returns {HTMLFormElement}
941
+ */
942
+ get form() {
943
+ return this.element.closest("form");
944
+ }
945
+
946
+ /**
947
+ * @returns {HTMLUListElement,null}
948
+ */
949
+ get list() {
950
+ return this.form.querySelector(`[data-controller="content--editor--list"]`);
951
+ }
952
+
953
+ /**
954
+ * @param {MouseEvent} e
955
+ * @returns {HTMLLIElement,null}
956
+ */
957
+ getCurrentItem(e) {
958
+ const item = document.elementFromPoint(e.clientX, e.clientY).closest("li");
959
+ if (!item) return null;
960
+
961
+ const bounds = item.getBoundingClientRect();
962
+
963
+ // check X for center(ish) mouse position
964
+ if (e.clientX < bounds.left + bounds.width / 2 - 2 * EDGE_AREA) return null;
965
+ if (e.clientX > bounds.left + bounds.width / 2 + 2 * EDGE_AREA) return null;
966
+
967
+ // check Y for hits on this item or it's next sibling
968
+ if (e.clientY - bounds.y <= EDGE_AREA) {
969
+ return item;
970
+ } else if (bounds.y + bounds.height - e.clientY <= EDGE_AREA) {
971
+ return item.nextElementSibling;
972
+ } else {
973
+ return null;
974
+ }
975
+ }
976
+
977
+ /**
978
+ * @param {MouseEvent} e
979
+ * @returns {Boolean} true when the target of the event is the floating button
980
+ */
981
+ isOverInlineTarget(e) {
982
+ return (
983
+ this.inlineTarget ===
984
+ document.elementFromPoint(e.clientX, e.clientY).closest("div")
985
+ );
947
986
  }
948
987
  }
949
988
 
@@ -1199,8 +1238,8 @@ const Definitions = [
1199
1238
  controllerConstructor: ListController,
1200
1239
  },
1201
1240
  {
1202
- identifier: "content--editor--new-item",
1203
- controllerConstructor: NewItemController,
1241
+ identifier: "content--editor--new-items",
1242
+ controllerConstructor: NewItemsController,
1204
1243
  },
1205
1244
  {
1206
1245
  identifier: "content--editor--status-bar",