katalyst-navigation 1.5.2 → 1.6.0

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: 4e5f480a3b37362c541fdc405d7ec260378be55458b0dbd88824e69440624268
4
- data.tar.gz: f662a3be9d829d081b4dceea36a9f699a02bd4b6e9a2e68a8999ad9aadbcfbc4
3
+ metadata.gz: 9d105afa8b02f8a188defa654988532ea041cbb437245e53ac3f2a049b0ef9d3
4
+ data.tar.gz: c561645ff7f288164f62356d2c9cd847b1a25d73fc44c8950b3e629db318dc42
5
5
  SHA512:
6
- metadata.gz: c9fffb2f84b729bbe3235cddbb70b828b841994ea03075d884e2a3a09e23b27cf0e60aa750f5d58f393341d9104fb1df3582decf8c97372709b2e1c3eae1cbef
7
- data.tar.gz: ee5f8d8695a8cbf074560efb47560b1a7e3bd6bb238d24972b55d5e62793df724253d67f08524ef63783dac73a5b707238f766dd08849d03f773e2c8ec981596
6
+ metadata.gz: 85d9f6b9cb21ab50299a5c8940627424643f905a08a1ad77b8a8f380eae2a85872b8fa8ce43cbd55ea31e14068d0184f1fa16c509e9625c3a1bc1709a0d66f74
7
+ data.tar.gz: 4cb2f1cdaec86b3399c5723a26a184cb1832a3d3e0dd1c8207c1335a0cc19f0ac32fab8307b2d4bf5681c6a30b8f49f00730e8088c46142a8fdbcdbf756bafe4
@@ -160,7 +160,7 @@ class Item {
160
160
  if (!listElement) listElement = createChildrenList(this.node);
161
161
 
162
162
  this.#expandedDescendants.forEach((child) =>
163
- listElement.appendChild(child.node)
163
+ listElement.appendChild(child.node),
164
164
  );
165
165
  }
166
166
 
@@ -251,7 +251,7 @@ class Item {
251
251
  if (!this.hasCollapsedDescendants()) return [];
252
252
 
253
253
  return Array.from(this.#childrenListElement.children).map(
254
- (node) => new Item(node)
254
+ (node) => new Item(node),
255
255
  );
256
256
  }
257
257
  }
@@ -294,7 +294,7 @@ class Menu {
294
294
  */
295
295
  get items() {
296
296
  return createItemList(
297
- this.node.querySelectorAll("[data-navigation-index]")
297
+ this.node.querySelectorAll("[data-navigation-index]"),
298
298
  );
299
299
  }
300
300
 
@@ -420,7 +420,7 @@ class RulesEngine {
420
420
  this.debug(
421
421
  `invalid depth on item ${item.index}: ${item.depth} => ${
422
422
  previous.depth + 1
423
- }`
423
+ }`,
424
424
  );
425
425
 
426
426
  item.depth = previous.depth + 1;
@@ -454,7 +454,7 @@ class RulesEngine {
454
454
  const previous = item.previousItem;
455
455
  if (previous && previous.depth < item.depth && !previous.isLayout) {
456
456
  this.debug(
457
- `invalid parent for item ${item.index}: ${item.depth} => ${previous.depth}`
457
+ `invalid parent for item ${item.index}: ${item.depth} => ${previous.depth}`,
458
458
  );
459
459
 
460
460
  item.depth = previous.depth;
@@ -856,7 +856,7 @@ class ListController extends Controller {
856
856
 
857
857
  this.element.replaceChild(item, placeholder);
858
858
  requestAnimationFrame(() =>
859
- item.querySelector("[role='button'][value='edit']").click()
859
+ item.querySelector("[role='button'][value='edit']").click(),
860
860
  );
861
861
  }
862
862
 
@@ -160,7 +160,7 @@ class Item {
160
160
  if (!listElement) listElement = createChildrenList(this.node);
161
161
 
162
162
  this.#expandedDescendants.forEach((child) =>
163
- listElement.appendChild(child.node)
163
+ listElement.appendChild(child.node),
164
164
  );
165
165
  }
166
166
 
@@ -251,7 +251,7 @@ class Item {
251
251
  if (!this.hasCollapsedDescendants()) return [];
252
252
 
253
253
  return Array.from(this.#childrenListElement.children).map(
254
- (node) => new Item(node)
254
+ (node) => new Item(node),
255
255
  );
256
256
  }
257
257
  }
@@ -294,7 +294,7 @@ class Menu {
294
294
  */
295
295
  get items() {
296
296
  return createItemList(
297
- this.node.querySelectorAll("[data-navigation-index]")
297
+ this.node.querySelectorAll("[data-navigation-index]"),
298
298
  );
299
299
  }
300
300
 
@@ -420,7 +420,7 @@ class RulesEngine {
420
420
  this.debug(
421
421
  `invalid depth on item ${item.index}: ${item.depth} => ${
422
422
  previous.depth + 1
423
- }`
423
+ }`,
424
424
  );
425
425
 
426
426
  item.depth = previous.depth + 1;
@@ -454,7 +454,7 @@ class RulesEngine {
454
454
  const previous = item.previousItem;
455
455
  if (previous && previous.depth < item.depth && !previous.isLayout) {
456
456
  this.debug(
457
- `invalid parent for item ${item.index}: ${item.depth} => ${previous.depth}`
457
+ `invalid parent for item ${item.index}: ${item.depth} => ${previous.depth}`,
458
458
  );
459
459
 
460
460
  item.depth = previous.depth;
@@ -856,7 +856,7 @@ class ListController extends Controller {
856
856
 
857
857
  this.element.replaceChild(item, placeholder);
858
858
  requestAnimationFrame(() =>
859
- item.querySelector("[role='button'][value='edit']").click()
859
+ item.querySelector("[role='button'][value='edit']").click(),
860
860
  );
861
861
  }
862
862
 
@@ -1 +1 @@
1
- {"version":3,"file":"navigation.min.js","sources":["../../../javascript/navigation/editor/item.js","../../../javascript/navigation/editor/menu.js","../../../javascript/navigation/editor/rules-engine.js","../../../javascript/navigation/editor/menu_controller.js","../../../javascript/navigation/editor/list_controller.js","../../../javascript/navigation/application.js","../../../javascript/navigation/editor/item_controller.js","../../../javascript/navigation/editor/new_item_controller.js","../../../javascript/navigation/editor/status_bar_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-navigation-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[`navigationItemId`];\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[`navigationItemId`] = `${id}`;\n this.#itemIdInput.value = `${id}`;\n }\n\n /**\n * @returns {number} logical nesting depth of node in menu\n */\n get depth() {\n return parseInt(this.node.dataset[`navigationDepth`]) || 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[`navigationDepth`] = `${depth}`;\n this.#depthInput.value = `${depth}`;\n }\n\n /**\n * @returns {number} logical index of node in menu (pre-order traversal)\n */\n get index() {\n return parseInt(this.node.dataset[`navigationIndex`]);\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[`navigationIndex`] = `${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 * 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 menu.\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-navigation-children]\n */\n get #childrenListElement() {\n return this.node.querySelector(`:scope > [data-navigation-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-navigation-index]\n * @returns {Element} ol[data-navigation-children]\n */\nfunction createChildrenList(node) {\n const childrenList = document.createElement(\"ol\");\n childrenList.setAttribute(\"class\", \"hidden\");\n\n childrenList.dataset[`navigationChildren`] = \"\";\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 Menu {\n /**\n * @param node {Element} navigation editor list\n */\n constructor(node) {\n this.node = node;\n }\n\n /**\n * @return {Item[]} an ordered list of all items in the menu\n */\n get items() {\n return createItemList(\n this.node.querySelectorAll(\"[data-navigation-index]\")\n );\n }\n\n /**\n * @return {String} a serialized description of the structure of the menu\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(maxDepth = null, debug = false) {\n this.maxDepth = maxDepth;\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.itemCannotExceedDepthLimit(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.nestingNeedsParent(item);\n this.nestingCannotExceedMaxDepth(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 * Depth must not exceed menu's depth limit.\n *\n * @param {Item} item\n */\n itemCannotExceedDepthLimit(item) {\n if (this.maxDepth > 0 && this.maxDepth <= item.depth) {\n // Note: this change can cause an issue where the previous item is treated\n // like a parent even though it no longer has children. This is because\n // items are processed in order. This issue does not seem worth solving\n // as it only occurs if the max depth is altered. The issue can be worked\n // around by saving the menu.\n item.depth = this.maxDepth - 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 * 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 nested (indented) if doing so would exceed the max depth.\n *\n * @param {Item} item\n */\n nestingCannotExceedMaxDepth(item) {\n if (this.maxDepth > 0 && this.maxDepth <= item.depth + 1) {\n this.#deny(\"denyNest\");\n }\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 Menu from \"./menu\";\nimport RulesEngine from \"./rules-engine\";\n\nexport default class MenuController extends Controller {\n static targets = [\"menu\"];\n static values = {\n maxDepth: Number,\n };\n\n connect() {\n this.state = this.menu.state;\n\n this.reindex();\n }\n\n get menu() {\n return new Menu(this.menuTarget);\n }\n\n reindex() {\n this.menu.reindex();\n this.#update();\n }\n\n reset() {\n this.menu.reset();\n }\n\n drop(event) {\n this.menu.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 (item.nextItem && item.nextItem.depth > previous.depth) {\n // if 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(this.maxDepthValue);\n this.menu.items.forEach((item) => engine.normalize(item));\n this.menu.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: \"navigation\",\n detail: { dirty: this.#isDirty() },\n });\n }\n\n #isDirty() {\n return this.menu.state !== this.state;\n }\n}\n\nfunction getEventItem(event) {\n return new Item(event.target.closest(\"[data-navigation-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.cancelDrag(event);\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\", {\n target: item,\n bubbles: true,\n prefix: \"navigation\",\n });\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: \"navigation\" });\n }\n\n reset() {\n this.dispatch(\"reset\", { bubbles: true, prefix: \"navigation\" });\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='navigation--editor--list'] > *\") ||\n e.closest(\"[data-controller='navigation--editor--list']\"))\n );\n}\n","import MenuController from \"./editor/menu_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\";\n\nconst Definitions = [\n {\n identifier: \"navigation--editor--menu\",\n controllerConstructor: MenuController,\n },\n {\n identifier: \"navigation--editor--item\",\n controllerConstructor: ItemController,\n },\n {\n identifier: \"navigation--editor--list\",\n controllerConstructor: ListController,\n },\n {\n identifier: \"navigation--editor--new-item\",\n controllerConstructor: NewItemController,\n },\n {\n identifier: \"navigation--editor--status-bar\",\n controllerConstructor: StatusBarController,\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: \"navigation\" });\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"],"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","collapse","listElement","document","createElement","setAttribute","appendChild","createChildrenList","child","expand","Array","from","reverse","insertAdjacentElement","toggleRule","rule","deny","hasOwnProperty","removeAttribute","hasItemIdChanged","updateAfterChange","descendants","push","map","Menu","items","nodes","querySelectorAll","state","inputs","e","join","reindex","reset","sort","RulesEngine","static","maxDepth","debug","args","console","log","normalize","firstItemDepthZero","depthMustBeSet","itemCannotHaveInvalidDepth","itemCannotExceedDepthLimit","parentMustBeLayout","parentCannotHaveExpandedAndCollapsedChildren","update","rules","parentsCannotDeNest","rootsCannotDeNest","nestingNeedsParent","nestingCannotExceedMaxDepth","leavesCannotCollapse","needHiddenItemsToExpand","parentsCannotBeDeleted","parentsCannotBeDragged","isNaN","previous","getEventItem","event","target","closest","swap","nodeName","positionComparison","compareDocumentPosition","Node","DOCUMENT_POSITION_FOLLOWING","DOCUMENT_POSITION_PRECEDING","dropTarget","Definitions","identifier","controllerConstructor","Controller","Number","connect","menu","menuTarget","drop","delta","undefined","preventDefault","remove","nest","deNest","updateRequested","setTimeout","engine","maxDepthValue","notifyChange","dispatch","bubbles","prefix","detail","dirty","isDirty","li","ol","element","enterCount","dragstart","parentElement","dataTransfer","effectAllowed","requestAnimationFrame","dragging","dragover","dragItem","dragenter","copyAllowed","newItem","dragleave","cancelDrag","placeholder","template","innerHTML","getData","content","replaceChild","click","dragend","isDragging","setData","templateTarget","versionState","change"],"mappings":"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"}
1
+ {"version":3,"file":"navigation.min.js","sources":["../../../javascript/navigation/editor/item.js","../../../javascript/navigation/editor/menu.js","../../../javascript/navigation/editor/rules-engine.js","../../../javascript/navigation/editor/menu_controller.js","../../../javascript/navigation/editor/list_controller.js","../../../javascript/navigation/application.js","../../../javascript/navigation/editor/item_controller.js","../../../javascript/navigation/editor/new_item_controller.js","../../../javascript/navigation/editor/status_bar_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-navigation-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[`navigationItemId`];\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[`navigationItemId`] = `${id}`;\n this.#itemIdInput.value = `${id}`;\n }\n\n /**\n * @returns {number} logical nesting depth of node in menu\n */\n get depth() {\n return parseInt(this.node.dataset[`navigationDepth`]) || 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[`navigationDepth`] = `${depth}`;\n this.#depthInput.value = `${depth}`;\n }\n\n /**\n * @returns {number} logical index of node in menu (pre-order traversal)\n */\n get index() {\n return parseInt(this.node.dataset[`navigationIndex`]);\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[`navigationIndex`] = `${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 * 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 menu.\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-navigation-children]\n */\n get #childrenListElement() {\n return this.node.querySelector(`:scope > [data-navigation-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-navigation-index]\n * @returns {Element} ol[data-navigation-children]\n */\nfunction createChildrenList(node) {\n const childrenList = document.createElement(\"ol\");\n childrenList.setAttribute(\"class\", \"hidden\");\n\n childrenList.dataset[`navigationChildren`] = \"\";\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 Menu {\n /**\n * @param node {Element} navigation editor list\n */\n constructor(node) {\n this.node = node;\n }\n\n /**\n * @return {Item[]} an ordered list of all items in the menu\n */\n get items() {\n return createItemList(\n this.node.querySelectorAll(\"[data-navigation-index]\"),\n );\n }\n\n /**\n * @return {String} a serialized description of the structure of the menu\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(maxDepth = null, debug = false) {\n this.maxDepth = maxDepth;\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.itemCannotExceedDepthLimit(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.nestingNeedsParent(item);\n this.nestingCannotExceedMaxDepth(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 * Depth must not exceed menu's depth limit.\n *\n * @param {Item} item\n */\n itemCannotExceedDepthLimit(item) {\n if (this.maxDepth > 0 && this.maxDepth <= item.depth) {\n // Note: this change can cause an issue where the previous item is treated\n // like a parent even though it no longer has children. This is because\n // items are processed in order. This issue does not seem worth solving\n // as it only occurs if the max depth is altered. The issue can be worked\n // around by saving the menu.\n item.depth = this.maxDepth - 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 * 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 nested (indented) if doing so would exceed the max depth.\n *\n * @param {Item} item\n */\n nestingCannotExceedMaxDepth(item) {\n if (this.maxDepth > 0 && this.maxDepth <= item.depth + 1) {\n this.#deny(\"denyNest\");\n }\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 Menu from \"./menu\";\nimport RulesEngine from \"./rules-engine\";\n\nexport default class MenuController extends Controller {\n static targets = [\"menu\"];\n static values = {\n maxDepth: Number,\n };\n\n connect() {\n this.state = this.menu.state;\n\n this.reindex();\n }\n\n get menu() {\n return new Menu(this.menuTarget);\n }\n\n reindex() {\n this.menu.reindex();\n this.#update();\n }\n\n reset() {\n this.menu.reset();\n }\n\n drop(event) {\n this.menu.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 (item.nextItem && item.nextItem.depth > previous.depth) {\n // if 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(this.maxDepthValue);\n this.menu.items.forEach((item) => engine.normalize(item));\n this.menu.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: \"navigation\",\n detail: { dirty: this.#isDirty() },\n });\n }\n\n #isDirty() {\n return this.menu.state !== this.state;\n }\n}\n\nfunction getEventItem(event) {\n return new Item(event.target.closest(\"[data-navigation-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.cancelDrag(event);\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\", {\n target: item,\n bubbles: true,\n prefix: \"navigation\",\n });\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: \"navigation\" });\n }\n\n reset() {\n this.dispatch(\"reset\", { bubbles: true, prefix: \"navigation\" });\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='navigation--editor--list'] > *\") ||\n e.closest(\"[data-controller='navigation--editor--list']\"))\n );\n}\n","import MenuController from \"./editor/menu_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\";\n\nconst Definitions = [\n {\n identifier: \"navigation--editor--menu\",\n controllerConstructor: MenuController,\n },\n {\n identifier: \"navigation--editor--item\",\n controllerConstructor: ItemController,\n },\n {\n identifier: \"navigation--editor--list\",\n controllerConstructor: ListController,\n },\n {\n identifier: \"navigation--editor--new-item\",\n controllerConstructor: NewItemController,\n },\n {\n identifier: \"navigation--editor--status-bar\",\n controllerConstructor: StatusBarController,\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: \"navigation\" });\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"],"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","collapse","listElement","document","createElement","setAttribute","appendChild","createChildrenList","child","expand","Array","from","reverse","insertAdjacentElement","toggleRule","rule","deny","hasOwnProperty","removeAttribute","hasItemIdChanged","updateAfterChange","descendants","push","map","Menu","items","nodes","querySelectorAll","state","inputs","e","join","reindex","reset","sort","RulesEngine","static","maxDepth","debug","args","console","log","normalize","firstItemDepthZero","depthMustBeSet","itemCannotHaveInvalidDepth","itemCannotExceedDepthLimit","parentMustBeLayout","parentCannotHaveExpandedAndCollapsedChildren","update","rules","parentsCannotDeNest","rootsCannotDeNest","nestingNeedsParent","nestingCannotExceedMaxDepth","leavesCannotCollapse","needHiddenItemsToExpand","parentsCannotBeDeleted","parentsCannotBeDragged","isNaN","previous","getEventItem","event","target","closest","swap","nodeName","positionComparison","compareDocumentPosition","Node","DOCUMENT_POSITION_FOLLOWING","DOCUMENT_POSITION_PRECEDING","dropTarget","Definitions","identifier","controllerConstructor","Controller","Number","connect","menu","menuTarget","drop","delta","undefined","preventDefault","remove","nest","deNest","updateRequested","setTimeout","engine","maxDepthValue","notifyChange","dispatch","bubbles","prefix","detail","dirty","isDirty","li","ol","element","enterCount","dragstart","parentElement","dataTransfer","effectAllowed","requestAnimationFrame","dragging","dragover","dragItem","dragenter","copyAllowed","newItem","dragleave","cancelDrag","placeholder","template","innerHTML","getData","content","replaceChild","click","dragend","isDragging","setData","templateTarget","versionState","change"],"mappings":"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"}
@@ -26,7 +26,9 @@
26
26
  }
27
27
 
28
28
  &:hover {
29
- box-shadow: rgb(0 0 0 / 25%) 0 1px 2px, rgb(0 0 0 / 31%) 0 0 5px;
29
+ box-shadow:
30
+ rgb(0 0 0 / 25%) 0 1px 2px,
31
+ rgb(0 0 0 / 31%) 0 0 5px;
30
32
  }
31
33
 
32
34
  &::before {
@@ -8,8 +8,6 @@ module Katalyst
8
8
 
9
9
  attr_reader :menu, :item, :editor
10
10
 
11
- layout nil
12
-
13
11
  def new
14
12
  @item = @menu.items.build(new_item_params)
15
13
  @editor = Katalyst::Navigation::EditorComponent.new(menu:, item:)
@@ -28,7 +28,7 @@ module Katalyst
28
28
  return unless item.visible?
29
29
 
30
30
  tag.li(**item_attributes(item)) do
31
- concat public_send("render_#{item.model_name.param_key}", item)
31
+ concat public_send(:"render_#{item.model_name.param_key}", item)
32
32
  concat render_children(item) if item.children.any?
33
33
  end
34
34
  end
@@ -158,7 +158,7 @@ export default class Item {
158
158
  if (!listElement) listElement = createChildrenList(this.node);
159
159
 
160
160
  this.#expandedDescendants.forEach((child) =>
161
- listElement.appendChild(child.node)
161
+ listElement.appendChild(child.node),
162
162
  );
163
163
  }
164
164
 
@@ -249,7 +249,7 @@ export default class Item {
249
249
  if (!this.hasCollapsedDescendants()) return [];
250
250
 
251
251
  return Array.from(this.#childrenListElement.children).map(
252
- (node) => new Item(node)
252
+ (node) => new Item(node),
253
253
  );
254
254
  }
255
255
  }
@@ -113,7 +113,7 @@ export default class ListController extends Controller {
113
113
 
114
114
  this.element.replaceChild(item, placeholder);
115
115
  requestAnimationFrame(() =>
116
- item.querySelector("[role='button'][value='edit']").click()
116
+ item.querySelector("[role='button'][value='edit']").click(),
117
117
  );
118
118
  }
119
119
 
@@ -21,7 +21,7 @@ export default class Menu {
21
21
  */
22
22
  get items() {
23
23
  return createItemList(
24
- this.node.querySelectorAll("[data-navigation-index]")
24
+ this.node.querySelectorAll("[data-navigation-index]"),
25
25
  );
26
26
  }
27
27
 
@@ -92,7 +92,7 @@ export default class RulesEngine {
92
92
  this.debug(
93
93
  `invalid depth on item ${item.index}: ${item.depth} => ${
94
94
  previous.depth + 1
95
- }`
95
+ }`,
96
96
  );
97
97
 
98
98
  item.depth = previous.depth + 1;
@@ -126,7 +126,7 @@ export default class RulesEngine {
126
126
  const previous = item.previousItem;
127
127
  if (previous && previous.depth < item.depth && !previous.isLayout) {
128
128
  this.debug(
129
- `invalid parent for item ${item.index}: ${item.depth} => ${previous.depth}`
129
+ `invalid parent for item ${item.index}: ${item.depth} => ${previous.depth}`,
130
130
  );
131
131
 
132
132
  item.depth = previous.depth;
@@ -1,5 +1,3 @@
1
- <%= render Kpop::FrameComponent.new do %>
2
- <%= render Kpop::ModalComponent.new(title: item_editor.title, layout: "side-panel") do %>
3
- <%= render item_editor %>
4
- <% end %>
1
+ <%= render Kpop::ModalComponent.new(title: item_editor.title, layout: "side-panel") do %>
2
+ <%= render item_editor %>
5
3
  <% end %>
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: katalyst-navigation
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.5.2
4
+ version: 1.6.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Katalyst Interactive
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-12-20 00:00:00.000000000 Z
11
+ date: 2024-02-21 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: katalyst-html-attributes
@@ -172,7 +172,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
172
172
  - !ruby/object:Gem::Version
173
173
  version: '0'
174
174
  requirements: []
175
- rubygems_version: 3.4.10
175
+ rubygems_version: 3.4.19
176
176
  signing_key:
177
177
  specification_version: 4
178
178
  summary: Navigation generator and editor