katalyst-tables 2.3.1 → 2.5.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 +4 -4
- data/CHANGELOG.md +15 -0
- data/app/assets/builds/katalyst/tables.esm.js +7 -7
- data/app/assets/builds/katalyst/tables.js +7 -7
- data/app/assets/builds/katalyst/tables.min.js.map +1 -1
- data/app/components/concerns/katalyst/tables/configurable_component.rb +3 -3
- data/app/components/concerns/katalyst/tables/has_table_content.rb +16 -5
- data/app/components/concerns/katalyst/tables/row_renderer.rb +57 -0
- data/app/components/katalyst/table_component.rb +3 -2
- data/{lib → app/controllers/concerns}/katalyst/tables/backend.rb +4 -5
- data/{lib → app/helpers}/katalyst/tables/frontend.rb +0 -2
- data/app/javascript/tables/orderable/form_controller.js +1 -1
- data/app/javascript/tables/orderable/list_controller.js +6 -6
- data/app/models/concerns/katalyst/tables/collection/core.rb +2 -29
- data/app/models/concerns/katalyst/tables/collection/filtering.rb +23 -0
- data/app/models/concerns/katalyst/tables/collection/has_params.rb +43 -0
- data/app/models/concerns/katalyst/tables/collection/sorting.rb +2 -2
- data/app/models/katalyst/tables/{collection.rb → collection/base.rb} +27 -1
- data/app/models/katalyst/tables/collection/filter.rb +80 -0
- data/{lib/katalyst/tables/backend → app/models/katalyst/tables/collection}/sort_form.rb +13 -5
- data/lib/katalyst/tables.rb +0 -4
- metadata +18 -14
- /data/{lib → app/helpers}/katalyst/tables/frontend/helper.rb +0 -0
    
        checksums.yaml
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 2 | 
             
            SHA256:
         | 
| 3 | 
            -
              metadata.gz:  | 
| 4 | 
            -
              data.tar.gz:  | 
| 3 | 
            +
              metadata.gz: 73c920aef2dfd59566ab635a3b7f573a6bb6cc6b16548e9e198c23d021d571dd
         | 
| 4 | 
            +
              data.tar.gz: 2b2f8000946bda4871efe3ea052b29ff87fdb43cd1eaf1861fd5cdcb0cd52411
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 6 | 
            +
              metadata.gz: fe91356719cc1f290f90245cc22742c6d6a328818b42c95412baa10f8affe3a2d1e48e7733d439ec185c48bea7c4bc40f8eff9e986375200d37a3a020a063c75
         | 
| 7 | 
            +
              data.tar.gz: c4a65aac6559e0afb91cfde6f6efc4a4f1d06c1e4679fff3e903c94272b3c8f6f51005bd009013fbca60be7d08eb45edc3fba3e5926da15d28c78da449fa736a
         | 
    
        data/CHANGELOG.md
    CHANGED
    
    | @@ -1,5 +1,20 @@ | |
| 1 1 | 
             
            ## [Unreleased]
         | 
| 2 2 |  | 
| 3 | 
            +
            ## [2.5.0]
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            - Breaking change: use Rails' object lookup path to find row partials
         | 
| 6 | 
            +
              Previously: Nested::ResourceController would have looked for Nested::Model in
         | 
| 7 | 
            +
              the controller directory:
         | 
| 8 | 
            +
                app/views/nested/resources/_nested_model.html+row.erb
         | 
| 9 | 
            +
              After this change, uses Rails' polymorphic partials logic and looks in the
         | 
| 10 | 
            +
              model views directory:
         | 
| 11 | 
            +
                app/views/nested/models/_model.html+row.erb
         | 
| 12 | 
            +
             | 
| 13 | 
            +
            ## [2.4.0]
         | 
| 14 | 
            +
             | 
| 15 | 
            +
            - Internal refactor of filters to make it easier to add custom extensions
         | 
| 16 | 
            +
              and define nested attributes.
         | 
| 17 | 
            +
             | 
| 3 18 | 
             
            ## [2.3.0]
         | 
| 4 19 |  | 
| 5 20 | 
             
            - Remove support for Ruby < 3.0 (no longer used at Katalyst)
         | 
| @@ -198,7 +198,7 @@ class OrderableListController extends Controller { | |
| 198 198 |  | 
| 199 199 | 
             
                // reindex all items based on their new positions
         | 
| 200 200 | 
             
                this.tablesOrderableItemOutlets.forEach((item, index) =>
         | 
| 201 | 
            -
                  item.updateIndex(index)
         | 
| 201 | 
            +
                  item.updateIndex(index),
         | 
| 202 202 | 
             
                );
         | 
| 203 203 |  | 
| 204 204 | 
             
                // save the changes
         | 
| @@ -250,7 +250,7 @@ class OrderableListController extends Controller { | |
| 250 250 | 
             
                    this.element,
         | 
| 251 251 | 
             
                    this.dragItem.row,
         | 
| 252 252 | 
             
                    event,
         | 
| 253 | 
            -
                    this.animate
         | 
| 253 | 
            +
                    this.animate,
         | 
| 254 254 | 
             
                  );
         | 
| 255 255 | 
             
                });
         | 
| 256 256 | 
             
              };
         | 
| @@ -265,7 +265,7 @@ class OrderableListController extends Controller { | |
| 265 265 | 
             
                  this.dragState.updateScroll(
         | 
| 266 266 | 
             
                    this.element,
         | 
| 267 267 | 
             
                    this.dragItem.row,
         | 
| 268 | 
            -
                    this.animate
         | 
| 268 | 
            +
                    this.animate,
         | 
| 269 269 | 
             
                  );
         | 
| 270 270 | 
             
                });
         | 
| 271 271 | 
             
              };
         | 
| @@ -325,7 +325,7 @@ class OrderableListController extends Controller { | |
| 325 325 | 
             
                if (!this.isDragging) return null;
         | 
| 326 326 |  | 
| 327 327 | 
             
                return this.tablesOrderableItemOutlets.find(
         | 
| 328 | 
            -
                  (item) => item.id === this.dragState.targetId
         | 
| 328 | 
            +
                  (item) => item.id === this.dragState.targetId,
         | 
| 329 329 | 
             
                );
         | 
| 330 330 | 
             
              }
         | 
| 331 331 |  | 
| @@ -337,7 +337,7 @@ class OrderableListController extends Controller { | |
| 337 337 | 
             
               */
         | 
| 338 338 | 
             
              get #currentItems() {
         | 
| 339 339 | 
             
                return this.tablesOrderableItemOutlets.toSorted(
         | 
| 340 | 
            -
                  (a, b) => a.comparisonIndex - b.comparisonIndex
         | 
| 340 | 
            +
                  (a, b) => a.comparisonIndex - b.comparisonIndex,
         | 
| 341 341 | 
             
                );
         | 
| 342 342 | 
             
              }
         | 
| 343 343 |  | 
| @@ -349,7 +349,7 @@ class OrderableListController extends Controller { | |
| 349 349 | 
             
               */
         | 
| 350 350 | 
             
              #targetItem(element) {
         | 
| 351 351 | 
             
                return this.tablesOrderableItemOutlets.find(
         | 
| 352 | 
            -
                  (item) => item.element === element
         | 
| 352 | 
            +
                  (item) => item.element === element,
         | 
| 353 353 | 
             
                );
         | 
| 354 354 | 
             
              }
         | 
| 355 355 |  | 
| @@ -455,7 +455,7 @@ class OrderableFormController extends Controller { | |
| 455 455 | 
             
                this.element.insertAdjacentHTML(
         | 
| 456 456 | 
             
                  "beforeend",
         | 
| 457 457 | 
             
                  `<input type="hidden" name="${id_name}" value="${id_value}" data-generated>
         | 
| 458 | 
            -
                          <input type="hidden" name="${index_name}" value="${item.index}" data-generated | 
| 458 | 
            +
                          <input type="hidden" name="${index_name}" value="${item.index}" data-generated>`,
         | 
| 459 459 | 
             
                );
         | 
| 460 460 | 
             
              }
         | 
| 461 461 |  | 
| @@ -198,7 +198,7 @@ class OrderableListController extends Controller { | |
| 198 198 |  | 
| 199 199 | 
             
                // reindex all items based on their new positions
         | 
| 200 200 | 
             
                this.tablesOrderableItemOutlets.forEach((item, index) =>
         | 
| 201 | 
            -
                  item.updateIndex(index)
         | 
| 201 | 
            +
                  item.updateIndex(index),
         | 
| 202 202 | 
             
                );
         | 
| 203 203 |  | 
| 204 204 | 
             
                // save the changes
         | 
| @@ -250,7 +250,7 @@ class OrderableListController extends Controller { | |
| 250 250 | 
             
                    this.element,
         | 
| 251 251 | 
             
                    this.dragItem.row,
         | 
| 252 252 | 
             
                    event,
         | 
| 253 | 
            -
                    this.animate
         | 
| 253 | 
            +
                    this.animate,
         | 
| 254 254 | 
             
                  );
         | 
| 255 255 | 
             
                });
         | 
| 256 256 | 
             
              };
         | 
| @@ -265,7 +265,7 @@ class OrderableListController extends Controller { | |
| 265 265 | 
             
                  this.dragState.updateScroll(
         | 
| 266 266 | 
             
                    this.element,
         | 
| 267 267 | 
             
                    this.dragItem.row,
         | 
| 268 | 
            -
                    this.animate
         | 
| 268 | 
            +
                    this.animate,
         | 
| 269 269 | 
             
                  );
         | 
| 270 270 | 
             
                });
         | 
| 271 271 | 
             
              };
         | 
| @@ -325,7 +325,7 @@ class OrderableListController extends Controller { | |
| 325 325 | 
             
                if (!this.isDragging) return null;
         | 
| 326 326 |  | 
| 327 327 | 
             
                return this.tablesOrderableItemOutlets.find(
         | 
| 328 | 
            -
                  (item) => item.id === this.dragState.targetId
         | 
| 328 | 
            +
                  (item) => item.id === this.dragState.targetId,
         | 
| 329 329 | 
             
                );
         | 
| 330 330 | 
             
              }
         | 
| 331 331 |  | 
| @@ -337,7 +337,7 @@ class OrderableListController extends Controller { | |
| 337 337 | 
             
               */
         | 
| 338 338 | 
             
              get #currentItems() {
         | 
| 339 339 | 
             
                return this.tablesOrderableItemOutlets.toSorted(
         | 
| 340 | 
            -
                  (a, b) => a.comparisonIndex - b.comparisonIndex
         | 
| 340 | 
            +
                  (a, b) => a.comparisonIndex - b.comparisonIndex,
         | 
| 341 341 | 
             
                );
         | 
| 342 342 | 
             
              }
         | 
| 343 343 |  | 
| @@ -349,7 +349,7 @@ class OrderableListController extends Controller { | |
| 349 349 | 
             
               */
         | 
| 350 350 | 
             
              #targetItem(element) {
         | 
| 351 351 | 
             
                return this.tablesOrderableItemOutlets.find(
         | 
| 352 | 
            -
                  (item) => item.element === element
         | 
| 352 | 
            +
                  (item) => item.element === element,
         | 
| 353 353 | 
             
                );
         | 
| 354 354 | 
             
              }
         | 
| 355 355 |  | 
| @@ -455,7 +455,7 @@ class OrderableFormController extends Controller { | |
| 455 455 | 
             
                this.element.insertAdjacentHTML(
         | 
| 456 456 | 
             
                  "beforeend",
         | 
| 457 457 | 
             
                  `<input type="hidden" name="${id_name}" value="${id_value}" data-generated>
         | 
| 458 | 
            -
                          <input type="hidden" name="${index_name}" value="${item.index}" data-generated | 
| 458 | 
            +
                          <input type="hidden" name="${index_name}" value="${item.index}" data-generated>`,
         | 
| 459 459 | 
             
                );
         | 
| 460 460 | 
             
              }
         | 
| 461 461 |  | 
| @@ -1 +1 @@ | |
| 1 | 
            -
            {"version":3,"file":"tables.min.js","sources":["../../../javascript/tables/orderable/list_controller.js","../../../javascript/tables/application.js","../../../javascript/tables/turbo/collection_controller.js","../../../javascript/tables/orderable/item_controller.js","../../../javascript/tables/orderable/form_controller.js"],"sourcesContent":["import { Controller } from \"@hotwired/stimulus\";\n\nexport default class OrderableListController extends Controller {\n  static outlets = [\"tables--orderable--item\", \"tables--orderable--form\"];\n\n  //region State transitions\n\n  startDragging(dragState) {\n    this.dragState = dragState;\n\n    document.addEventListener(\"mousemove\", this.mousemove);\n    document.addEventListener(\"mouseup\", this.mouseup);\n    window.addEventListener(\"scroll\", this.scroll, true);\n\n    this.element.style.position = \"relative\";\n  }\n\n  stopDragging() {\n    const dragState = this.dragState;\n    delete this.dragState;\n\n    document.removeEventListener(\"mousemove\", this.mousemove);\n    document.removeEventListener(\"mouseup\", this.mouseup);\n    window.removeEventListener(\"scroll\", this.scroll, true);\n\n    this.element.removeAttribute(\"style\");\n    this.tablesOrderableItemOutlets.forEach((item) => item.reset());\n\n    return dragState;\n  }\n\n  drop() {\n    // note: early returns guard against turbo updates that prevent us finding\n    // the right item to drop on. In this situation it's better to discard the\n    // drop than to drop in the wrong place.\n\n    const dragItem = this.dragItem;\n\n    if (!dragItem) return;\n\n    const newIndex = dragItem.dragIndex;\n    const targetItem = this.tablesOrderableItemOutlets[newIndex];\n\n    if (!targetItem) return;\n\n    // swap the dragged item into the correct position for its current offset\n    if (newIndex < dragItem.index) {\n      targetItem.row.insertAdjacentElement(\"beforebegin\", dragItem.row);\n    } else if (newIndex > dragItem.index) {\n      targetItem.row.insertAdjacentElement(\"afterend\", dragItem.row);\n    }\n\n    // reindex all items based on their new positions\n    this.tablesOrderableItemOutlets.forEach((item, index) =>\n      item.updateIndex(index)\n    );\n\n    // save the changes\n    this.commitChanges();\n  }\n\n  commitChanges() {\n    // clear any existing inputs to prevent duplicates\n    this.tablesOrderableFormOutlet.clear();\n\n    // insert any items that have changed position\n    this.tablesOrderableItemOutlets.forEach((item) => {\n      if (item.hasChanges) this.tablesOrderableFormOutlet.add(item);\n    });\n\n    this.tablesOrderableFormOutlet.submit();\n  }\n\n  //endregion\n\n  //region Events\n\n  mousedown(event) {\n    if (this.isDragging) return;\n\n    const target = this.#targetItem(event.target);\n\n    if (!target) return;\n\n    event.preventDefault(); // prevent built-in drag\n\n    this.startDragging(new DragState(this.element, event, target.id));\n\n    this.dragState.updateCursor(this.element, target.row, event, this.animate);\n  }\n\n  mousemove = (event) => {\n    if (!this.isDragging) return;\n\n    event.preventDefault(); // prevent build-in drag\n\n    if (this.ticking) return;\n\n    this.ticking = true;\n\n    window.requestAnimationFrame(() => {\n      this.ticking = false;\n      this.dragState.updateCursor(\n        this.element,\n        this.dragItem.row,\n        event,\n        this.animate\n      );\n    });\n  };\n\n  scroll = (event) => {\n    if (!this.isDragging || this.ticking) return;\n\n    this.ticking = true;\n\n    window.requestAnimationFrame(() => {\n      this.ticking = false;\n      this.dragState.updateScroll(\n        this.element,\n        this.dragItem.row,\n        this.animate\n      );\n    });\n  };\n\n  mouseup = (event) => {\n    if (!this.isDragging) return;\n\n    this.drop();\n    this.stopDragging();\n    this.tablesOrderableFormOutlets.forEach((form) => delete form.dragState);\n  };\n\n  tablesOrderableFormOutletConnected(form, element) {\n    if (form.dragState) {\n      // restore the previous controller's state\n      this.startDragging(form.dragState);\n    }\n  }\n\n  tablesOrderableFormOutletDisconnected(form, element) {\n    if (this.isDragging) {\n      // cache drag state in the form\n      form.dragState = this.stopDragging();\n    }\n  }\n\n  //endregion\n\n  //region Helpers\n\n  /**\n   * Updates the position of the drag item with a relative offset. Updates\n   * other items relative to the new position of the drag item, as required.\n   *\n   * @callback {OrderableListController~animate}\n   * @param {number} offset\n   */\n  animate = (offset) => {\n    const dragItem = this.dragItem;\n\n    // Visually update the dragItem so it follows the cursor\n    dragItem.dragUpdate(offset);\n\n    // Visually updates the position of all items in the list relative to the\n    // dragged item. No actual changes to orderings at this stage.\n    this.#currentItems.forEach((item, index) => {\n      if (item === dragItem) return;\n      item.updateVisually(index);\n    });\n  };\n\n  get isDragging() {\n    return !!this.dragState;\n  }\n\n  get dragItem() {\n    if (!this.isDragging) return null;\n\n    return this.tablesOrderableItemOutlets.find(\n      (item) => item.id === this.dragState.targetId\n    );\n  }\n\n  /**\n   * Returns the current items in the list, sorted by their current index.\n   * Current uses the drag index if the item is being dragged, if set.\n   *\n   * @returns {Array[OrderableRowController]}\n   */\n  get #currentItems() {\n    return this.tablesOrderableItemOutlets.toSorted(\n      (a, b) => a.comparisonIndex - b.comparisonIndex\n    );\n  }\n\n  /**\n   * Returns the item outlet that was clicked on, if any.\n   *\n   * @param element {HTMLElement} the clicked ordinal cell\n   * @returns {OrderableRowController}\n   */\n  #targetItem(element) {\n    return this.tablesOrderableItemOutlets.find(\n      (item) => item.element === element\n    );\n  }\n\n  //endregion\n}\n\n/**\n * During drag we want to be able to translate a document-relative coordinate\n * into a coordinate relative to the list element. This state object calculates\n * and stores internal state so that we can translate absolute page coordinates\n * from mouse events into relative offsets for the list items within the list\n * element.\n *\n * We also keep track of the drag target so that if the controller is attached\n * to a new element during the drag we can continue after the turbo update.\n */\nclass DragState {\n  /**\n   * @param list {HTMLElement} the list controller's element (tbody)\n   * @param event {MouseEvent} the initial event\n   * @param id {String} the id of the element being dragged\n   */\n  constructor(list, event, id) {\n    // cursor offset is the offset of the cursor relative to the drag item\n    this.cursorOffset = event.offsetY;\n\n    // initial offset is the offset position of the drag item at drag start\n    this.initialPosition = event.target.offsetTop - list.offsetTop;\n\n    // id of the item being dragged\n    this.targetId = id;\n  }\n\n  /**\n   * Calculates the offset of the drag item relative to its initial position.\n   *\n   * @param list {HTMLElement} the list controller's element (tbody)\n   * @param row {HTMLElement} the row being dragged\n   * @param event {MouseEvent} the current event\n   * @param callback {OrderableListController~animate} updates the drag item with a relative offset\n   */\n  updateCursor(list, row, event, callback) {\n    // Calculate and store the list offset relative to the viewport\n    // This value is cached so we can calculate the outcome of any scroll events\n    this.listOffset = list.getBoundingClientRect().top;\n\n    // Calculate the position of the cursor relative to the list.\n    // Accounts for scroll offsets by using the item's bounding client rect.\n    const cursorPosition = event.clientY - this.listOffset;\n\n    // intended item position relative to the list, from cursor position\n    let itemPosition = cursorPosition - this.cursorOffset;\n\n    this.#updateItemPosition(list, row, itemPosition, callback);\n  }\n\n  /**\n   * Animates the item's position as the list scrolls. Requires a previous call\n   * to set the scroll offset.\n   *\n   * @param list {HTMLElement} the list controller's element (tbody)\n   * @param row {HTMLElement} the row being dragged\n   * @param callback {OrderableListController~animate} updates the drag item with a relative offset\n   */\n  updateScroll(list, row, callback) {\n    const previousScrollOffset = this.listOffset;\n\n    // Calculate and store the list offset relative to the viewport\n    // This value is cached so we can calculate the outcome of any scroll events\n    this.listOffset = list.getBoundingClientRect().top;\n\n    // Calculate the change in scroll offset since the last update\n    const scrollDelta = previousScrollOffset - this.listOffset;\n\n    // intended item position relative to the list, from cursor position\n    const position = this.position + scrollDelta;\n\n    this.#updateItemPosition(list, row, position, callback);\n  }\n\n  #updateItemPosition(list, row, position, callback) {\n    // ensure itemPosition is within the bounds of the list (tbody)\n    position = Math.max(position, 0);\n    position = Math.min(position, list.offsetHeight - row.offsetHeight);\n\n    // cache the item's position relative to the list for use in scroll events\n    this.position = position;\n\n    // Item has position: relative, so we want to calculate the amount to move\n    // the item relative to it's DOM position to represent how much it has been\n    // dragged by.\n    const offset = position - this.initialPosition;\n\n    // Convert itemPosition from offset relative to list to offset relative to\n    // its position within the DOM (if it hadn't moved).\n    callback(offset);\n  }\n}\n","import TurboCollectionController from \"./turbo/collection_controller\";\nimport ItemController from \"./orderable/item_controller\";\nimport ListController from \"./orderable/list_controller\";\nimport FormController from \"./orderable/form_controller\";\n\nconst Definitions = [\n  {\n    identifier: \"tables--turbo--collection\",\n    controllerConstructor: TurboCollectionController,\n  },\n  {\n    identifier: \"tables--orderable--item\",\n    controllerConstructor: ItemController,\n  },\n  {\n    identifier: \"tables--orderable--list\",\n    controllerConstructor: ListController,\n  },\n  {\n    identifier: \"tables--orderable--form\",\n    controllerConstructor: FormController,\n  },\n];\n\nexport { Definitions as default };\n","import { Controller } from \"@hotwired/stimulus\";\nimport { Turbo } from \"@hotwired/turbo-rails\";\n\nexport default class TurboCollectionController extends Controller {\n  static values = {\n    query: String,\n    sort: String,\n  };\n\n  queryValueChanged(query) {\n    Turbo.navigator.history.replace(this.#url(query));\n  }\n\n  sortValueChanged(sort) {\n    document.querySelectorAll(this.#sortSelector).forEach((input) => {\n      if (input) input.value = sort;\n    });\n  }\n\n  get #sortSelector() {\n    return \"input[name='sort']\";\n  }\n\n  #url(query) {\n    const frame = this.element.closest(\"turbo-frame\");\n    let url;\n\n    if (frame) {\n      url = new URL(frame.baseURI);\n    } else {\n      url = new URL(window.location.href);\n    }\n\n    url.search = query;\n\n    return url;\n  }\n}\n","import { Controller } from \"@hotwired/stimulus\";\n\nexport default class OrderableRowController extends Controller {\n  static values = {\n    params: Object,\n  };\n\n  connect() {\n    // index from server may be inconsistent with the visual ordering,\n    // especially if this is a new node. Use positional indexes instead,\n    // as these are the values we will send on save.\n    this.index = domIndex(this.row);\n  }\n\n  paramsValueChanged(params) {\n    this.id = params.id_value;\n  }\n\n  dragUpdate(offset) {\n    this.dragOffset = offset;\n    this.row.style.position = \"relative\";\n    this.row.style.top = offset + \"px\";\n    this.row.style.zIndex = \"1\";\n    this.row.toggleAttribute(\"dragging\", true);\n  }\n\n  /**\n   * Called on items that are not the dragged item during drag. Updates the\n   * visual position of the item relative to the dragged item.\n   *\n   * @param index {number} intended index of the item during drag\n   */\n  updateVisually(index) {\n    this.row.style.position = \"relative\";\n    this.row.style.top = `${\n      this.row.offsetHeight * (index - this.dragIndex)\n    }px`;\n  }\n\n  /**\n   * Set the index value of the item. This is called on all items after a drop\n   * event. If the index is different to the params index then this item has\n   * changed.\n   *\n   * @param index {number} the new index value\n   */\n  updateIndex(index) {\n    this.index = index;\n  }\n\n  /**\n   * Restore any visual changes made during drag and remove the drag state.\n   */\n  reset() {\n    delete this.dragOffset;\n    this.row.removeAttribute(\"style\");\n    this.row.removeAttribute(\"dragging\");\n  }\n\n  /**\n   * @returns {boolean} true when the item has a change to its index value\n   */\n  get hasChanges() {\n    return this.paramsValue.index_value !== this.index;\n  }\n\n  /**\n   * Calculate the relative index of the item during drag. This is used to\n   * sort items during drag as it takes into account any uncommitted changes\n   * to index caused by the drag offset.\n   *\n   * @returns {number} index for the purposes of drag and drop ordering\n   */\n  get dragIndex() {\n    if (this.dragOffset && this.dragOffset !== 0) {\n      return this.index + Math.round(this.dragOffset / this.row.offsetHeight);\n    } else {\n      return this.index;\n    }\n  }\n\n  /**\n   * Index value for use in comparisons during drag. This is used to determine\n   * whether the dragged item is above or below another item. If this item is\n   * being dragged then we offset the index by 0.5 to ensure that it jumps up\n   * or down when it reaches the midpoint of the item above or below it.\n   *\n   * @returns {number}\n   */\n  get comparisonIndex() {\n    if (this.dragOffset) {\n      return this.dragIndex + (this.dragOffset > 0 ? 0.5 : -0.5);\n    } else {\n      return this.index;\n    }\n  }\n\n  /**\n   * The containing row element.\n   *\n   * @returns {HTMLElement}\n   */\n  get row() {\n    return this.element.parentElement;\n  }\n}\n\nfunction domIndex(element) {\n  return Array.from(element.parentElement.children).indexOf(element);\n}\n","import { Controller } from \"@hotwired/stimulus\";\n\nexport default class OrderableFormController extends Controller {\n  add(item) {\n    const { id_name, id_value, index_name } = item.paramsValue;\n    this.element.insertAdjacentHTML(\n      \"beforeend\",\n      `<input type=\"hidden\" name=\"${id_name}\" value=\"${id_value}\" data-generated>\n              <input type=\"hidden\" name=\"${index_name}\" value=\"${item.index}\" data-generated>`\n    );\n  }\n\n  submit() {\n    if (this.inputs.length === 0) return;\n\n    this.element.requestSubmit();\n  }\n\n  clear() {\n    this.inputs.forEach((input) => input.remove());\n  }\n\n  get inputs() {\n    return this.element.querySelectorAll(\"input[data-generated]\");\n  }\n}\n"],"names":["DragState","constructor","list","event","id","this","cursorOffset","offsetY","initialPosition","target","offsetTop","targetId","updateCursor","row","callback","listOffset","getBoundingClientRect","top","itemPosition","clientY","updateItemPosition","updateScroll","previousScrollOffset","scrollDelta","position","Math","max","min","offsetHeight","Definitions","identifier","controllerConstructor","Controller","static","query","String","sort","queryValueChanged","Turbo","navigator","history","replace","url","sortValueChanged","document","querySelectorAll","sortSelector","forEach","input","value","frame","element","closest","URL","baseURI","window","location","href","search","params","Object","connect","index","Array","from","parentElement","children","indexOf","paramsValueChanged","id_value","dragUpdate","offset","dragOffset","style","zIndex","toggleAttribute","updateVisually","dragIndex","updateIndex","reset","removeAttribute","hasChanges","paramsValue","index_value","round","comparisonIndex","startDragging","dragState","addEventListener","mousemove","mouseup","scroll","stopDragging","removeEventListener","tablesOrderableItemOutlets","item","drop","dragItem","newIndex","targetItem","insertAdjacentElement","commitChanges","tablesOrderableFormOutlet","clear","add","submit","mousedown","isDragging","preventDefault","animate","ticking","requestAnimationFrame","tablesOrderableFormOutlets","form","tablesOrderableFormOutletConnected","tablesOrderableFormOutletDisconnected","currentItems","find","toSorted","a","b","id_name","index_name","insertAdjacentHTML","inputs","length","requestSubmit","remove"],"mappings":"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"}
         | 
| 1 | 
            +
            {"version":3,"file":"tables.min.js","sources":["../../../javascript/tables/orderable/list_controller.js","../../../javascript/tables/application.js","../../../javascript/tables/turbo/collection_controller.js","../../../javascript/tables/orderable/item_controller.js","../../../javascript/tables/orderable/form_controller.js"],"sourcesContent":["import { Controller } from \"@hotwired/stimulus\";\n\nexport default class OrderableListController extends Controller {\n  static outlets = [\"tables--orderable--item\", \"tables--orderable--form\"];\n\n  //region State transitions\n\n  startDragging(dragState) {\n    this.dragState = dragState;\n\n    document.addEventListener(\"mousemove\", this.mousemove);\n    document.addEventListener(\"mouseup\", this.mouseup);\n    window.addEventListener(\"scroll\", this.scroll, true);\n\n    this.element.style.position = \"relative\";\n  }\n\n  stopDragging() {\n    const dragState = this.dragState;\n    delete this.dragState;\n\n    document.removeEventListener(\"mousemove\", this.mousemove);\n    document.removeEventListener(\"mouseup\", this.mouseup);\n    window.removeEventListener(\"scroll\", this.scroll, true);\n\n    this.element.removeAttribute(\"style\");\n    this.tablesOrderableItemOutlets.forEach((item) => item.reset());\n\n    return dragState;\n  }\n\n  drop() {\n    // note: early returns guard against turbo updates that prevent us finding\n    // the right item to drop on. In this situation it's better to discard the\n    // drop than to drop in the wrong place.\n\n    const dragItem = this.dragItem;\n\n    if (!dragItem) return;\n\n    const newIndex = dragItem.dragIndex;\n    const targetItem = this.tablesOrderableItemOutlets[newIndex];\n\n    if (!targetItem) return;\n\n    // swap the dragged item into the correct position for its current offset\n    if (newIndex < dragItem.index) {\n      targetItem.row.insertAdjacentElement(\"beforebegin\", dragItem.row);\n    } else if (newIndex > dragItem.index) {\n      targetItem.row.insertAdjacentElement(\"afterend\", dragItem.row);\n    }\n\n    // reindex all items based on their new positions\n    this.tablesOrderableItemOutlets.forEach((item, index) =>\n      item.updateIndex(index),\n    );\n\n    // save the changes\n    this.commitChanges();\n  }\n\n  commitChanges() {\n    // clear any existing inputs to prevent duplicates\n    this.tablesOrderableFormOutlet.clear();\n\n    // insert any items that have changed position\n    this.tablesOrderableItemOutlets.forEach((item) => {\n      if (item.hasChanges) this.tablesOrderableFormOutlet.add(item);\n    });\n\n    this.tablesOrderableFormOutlet.submit();\n  }\n\n  //endregion\n\n  //region Events\n\n  mousedown(event) {\n    if (this.isDragging) return;\n\n    const target = this.#targetItem(event.target);\n\n    if (!target) return;\n\n    event.preventDefault(); // prevent built-in drag\n\n    this.startDragging(new DragState(this.element, event, target.id));\n\n    this.dragState.updateCursor(this.element, target.row, event, this.animate);\n  }\n\n  mousemove = (event) => {\n    if (!this.isDragging) return;\n\n    event.preventDefault(); // prevent build-in drag\n\n    if (this.ticking) return;\n\n    this.ticking = true;\n\n    window.requestAnimationFrame(() => {\n      this.ticking = false;\n      this.dragState.updateCursor(\n        this.element,\n        this.dragItem.row,\n        event,\n        this.animate,\n      );\n    });\n  };\n\n  scroll = (event) => {\n    if (!this.isDragging || this.ticking) return;\n\n    this.ticking = true;\n\n    window.requestAnimationFrame(() => {\n      this.ticking = false;\n      this.dragState.updateScroll(\n        this.element,\n        this.dragItem.row,\n        this.animate,\n      );\n    });\n  };\n\n  mouseup = (event) => {\n    if (!this.isDragging) return;\n\n    this.drop();\n    this.stopDragging();\n    this.tablesOrderableFormOutlets.forEach((form) => delete form.dragState);\n  };\n\n  tablesOrderableFormOutletConnected(form, element) {\n    if (form.dragState) {\n      // restore the previous controller's state\n      this.startDragging(form.dragState);\n    }\n  }\n\n  tablesOrderableFormOutletDisconnected(form, element) {\n    if (this.isDragging) {\n      // cache drag state in the form\n      form.dragState = this.stopDragging();\n    }\n  }\n\n  //endregion\n\n  //region Helpers\n\n  /**\n   * Updates the position of the drag item with a relative offset. Updates\n   * other items relative to the new position of the drag item, as required.\n   *\n   * @callback {OrderableListController~animate}\n   * @param {number} offset\n   */\n  animate = (offset) => {\n    const dragItem = this.dragItem;\n\n    // Visually update the dragItem so it follows the cursor\n    dragItem.dragUpdate(offset);\n\n    // Visually updates the position of all items in the list relative to the\n    // dragged item. No actual changes to orderings at this stage.\n    this.#currentItems.forEach((item, index) => {\n      if (item === dragItem) return;\n      item.updateVisually(index);\n    });\n  };\n\n  get isDragging() {\n    return !!this.dragState;\n  }\n\n  get dragItem() {\n    if (!this.isDragging) return null;\n\n    return this.tablesOrderableItemOutlets.find(\n      (item) => item.id === this.dragState.targetId,\n    );\n  }\n\n  /**\n   * Returns the current items in the list, sorted by their current index.\n   * Current uses the drag index if the item is being dragged, if set.\n   *\n   * @returns {Array[OrderableRowController]}\n   */\n  get #currentItems() {\n    return this.tablesOrderableItemOutlets.toSorted(\n      (a, b) => a.comparisonIndex - b.comparisonIndex,\n    );\n  }\n\n  /**\n   * Returns the item outlet that was clicked on, if any.\n   *\n   * @param element {HTMLElement} the clicked ordinal cell\n   * @returns {OrderableRowController}\n   */\n  #targetItem(element) {\n    return this.tablesOrderableItemOutlets.find(\n      (item) => item.element === element,\n    );\n  }\n\n  //endregion\n}\n\n/**\n * During drag we want to be able to translate a document-relative coordinate\n * into a coordinate relative to the list element. This state object calculates\n * and stores internal state so that we can translate absolute page coordinates\n * from mouse events into relative offsets for the list items within the list\n * element.\n *\n * We also keep track of the drag target so that if the controller is attached\n * to a new element during the drag we can continue after the turbo update.\n */\nclass DragState {\n  /**\n   * @param list {HTMLElement} the list controller's element (tbody)\n   * @param event {MouseEvent} the initial event\n   * @param id {String} the id of the element being dragged\n   */\n  constructor(list, event, id) {\n    // cursor offset is the offset of the cursor relative to the drag item\n    this.cursorOffset = event.offsetY;\n\n    // initial offset is the offset position of the drag item at drag start\n    this.initialPosition = event.target.offsetTop - list.offsetTop;\n\n    // id of the item being dragged\n    this.targetId = id;\n  }\n\n  /**\n   * Calculates the offset of the drag item relative to its initial position.\n   *\n   * @param list {HTMLElement} the list controller's element (tbody)\n   * @param row {HTMLElement} the row being dragged\n   * @param event {MouseEvent} the current event\n   * @param callback {OrderableListController~animate} updates the drag item with a relative offset\n   */\n  updateCursor(list, row, event, callback) {\n    // Calculate and store the list offset relative to the viewport\n    // This value is cached so we can calculate the outcome of any scroll events\n    this.listOffset = list.getBoundingClientRect().top;\n\n    // Calculate the position of the cursor relative to the list.\n    // Accounts for scroll offsets by using the item's bounding client rect.\n    const cursorPosition = event.clientY - this.listOffset;\n\n    // intended item position relative to the list, from cursor position\n    let itemPosition = cursorPosition - this.cursorOffset;\n\n    this.#updateItemPosition(list, row, itemPosition, callback);\n  }\n\n  /**\n   * Animates the item's position as the list scrolls. Requires a previous call\n   * to set the scroll offset.\n   *\n   * @param list {HTMLElement} the list controller's element (tbody)\n   * @param row {HTMLElement} the row being dragged\n   * @param callback {OrderableListController~animate} updates the drag item with a relative offset\n   */\n  updateScroll(list, row, callback) {\n    const previousScrollOffset = this.listOffset;\n\n    // Calculate and store the list offset relative to the viewport\n    // This value is cached so we can calculate the outcome of any scroll events\n    this.listOffset = list.getBoundingClientRect().top;\n\n    // Calculate the change in scroll offset since the last update\n    const scrollDelta = previousScrollOffset - this.listOffset;\n\n    // intended item position relative to the list, from cursor position\n    const position = this.position + scrollDelta;\n\n    this.#updateItemPosition(list, row, position, callback);\n  }\n\n  #updateItemPosition(list, row, position, callback) {\n    // ensure itemPosition is within the bounds of the list (tbody)\n    position = Math.max(position, 0);\n    position = Math.min(position, list.offsetHeight - row.offsetHeight);\n\n    // cache the item's position relative to the list for use in scroll events\n    this.position = position;\n\n    // Item has position: relative, so we want to calculate the amount to move\n    // the item relative to it's DOM position to represent how much it has been\n    // dragged by.\n    const offset = position - this.initialPosition;\n\n    // Convert itemPosition from offset relative to list to offset relative to\n    // its position within the DOM (if it hadn't moved).\n    callback(offset);\n  }\n}\n","import TurboCollectionController from \"./turbo/collection_controller\";\nimport ItemController from \"./orderable/item_controller\";\nimport ListController from \"./orderable/list_controller\";\nimport FormController from \"./orderable/form_controller\";\n\nconst Definitions = [\n  {\n    identifier: \"tables--turbo--collection\",\n    controllerConstructor: TurboCollectionController,\n  },\n  {\n    identifier: \"tables--orderable--item\",\n    controllerConstructor: ItemController,\n  },\n  {\n    identifier: \"tables--orderable--list\",\n    controllerConstructor: ListController,\n  },\n  {\n    identifier: \"tables--orderable--form\",\n    controllerConstructor: FormController,\n  },\n];\n\nexport { Definitions as default };\n","import { Controller } from \"@hotwired/stimulus\";\nimport { Turbo } from \"@hotwired/turbo-rails\";\n\nexport default class TurboCollectionController extends Controller {\n  static values = {\n    query: String,\n    sort: String,\n  };\n\n  queryValueChanged(query) {\n    Turbo.navigator.history.replace(this.#url(query));\n  }\n\n  sortValueChanged(sort) {\n    document.querySelectorAll(this.#sortSelector).forEach((input) => {\n      if (input) input.value = sort;\n    });\n  }\n\n  get #sortSelector() {\n    return \"input[name='sort']\";\n  }\n\n  #url(query) {\n    const frame = this.element.closest(\"turbo-frame\");\n    let url;\n\n    if (frame) {\n      url = new URL(frame.baseURI);\n    } else {\n      url = new URL(window.location.href);\n    }\n\n    url.search = query;\n\n    return url;\n  }\n}\n","import { Controller } from \"@hotwired/stimulus\";\n\nexport default class OrderableRowController extends Controller {\n  static values = {\n    params: Object,\n  };\n\n  connect() {\n    // index from server may be inconsistent with the visual ordering,\n    // especially if this is a new node. Use positional indexes instead,\n    // as these are the values we will send on save.\n    this.index = domIndex(this.row);\n  }\n\n  paramsValueChanged(params) {\n    this.id = params.id_value;\n  }\n\n  dragUpdate(offset) {\n    this.dragOffset = offset;\n    this.row.style.position = \"relative\";\n    this.row.style.top = offset + \"px\";\n    this.row.style.zIndex = \"1\";\n    this.row.toggleAttribute(\"dragging\", true);\n  }\n\n  /**\n   * Called on items that are not the dragged item during drag. Updates the\n   * visual position of the item relative to the dragged item.\n   *\n   * @param index {number} intended index of the item during drag\n   */\n  updateVisually(index) {\n    this.row.style.position = \"relative\";\n    this.row.style.top = `${\n      this.row.offsetHeight * (index - this.dragIndex)\n    }px`;\n  }\n\n  /**\n   * Set the index value of the item. This is called on all items after a drop\n   * event. If the index is different to the params index then this item has\n   * changed.\n   *\n   * @param index {number} the new index value\n   */\n  updateIndex(index) {\n    this.index = index;\n  }\n\n  /**\n   * Restore any visual changes made during drag and remove the drag state.\n   */\n  reset() {\n    delete this.dragOffset;\n    this.row.removeAttribute(\"style\");\n    this.row.removeAttribute(\"dragging\");\n  }\n\n  /**\n   * @returns {boolean} true when the item has a change to its index value\n   */\n  get hasChanges() {\n    return this.paramsValue.index_value !== this.index;\n  }\n\n  /**\n   * Calculate the relative index of the item during drag. This is used to\n   * sort items during drag as it takes into account any uncommitted changes\n   * to index caused by the drag offset.\n   *\n   * @returns {number} index for the purposes of drag and drop ordering\n   */\n  get dragIndex() {\n    if (this.dragOffset && this.dragOffset !== 0) {\n      return this.index + Math.round(this.dragOffset / this.row.offsetHeight);\n    } else {\n      return this.index;\n    }\n  }\n\n  /**\n   * Index value for use in comparisons during drag. This is used to determine\n   * whether the dragged item is above or below another item. If this item is\n   * being dragged then we offset the index by 0.5 to ensure that it jumps up\n   * or down when it reaches the midpoint of the item above or below it.\n   *\n   * @returns {number}\n   */\n  get comparisonIndex() {\n    if (this.dragOffset) {\n      return this.dragIndex + (this.dragOffset > 0 ? 0.5 : -0.5);\n    } else {\n      return this.index;\n    }\n  }\n\n  /**\n   * The containing row element.\n   *\n   * @returns {HTMLElement}\n   */\n  get row() {\n    return this.element.parentElement;\n  }\n}\n\nfunction domIndex(element) {\n  return Array.from(element.parentElement.children).indexOf(element);\n}\n","import { Controller } from \"@hotwired/stimulus\";\n\nexport default class OrderableFormController extends Controller {\n  add(item) {\n    const { id_name, id_value, index_name } = item.paramsValue;\n    this.element.insertAdjacentHTML(\n      \"beforeend\",\n      `<input type=\"hidden\" name=\"${id_name}\" value=\"${id_value}\" data-generated>\n              <input type=\"hidden\" name=\"${index_name}\" value=\"${item.index}\" data-generated>`,\n    );\n  }\n\n  submit() {\n    if (this.inputs.length === 0) return;\n\n    this.element.requestSubmit();\n  }\n\n  clear() {\n    this.inputs.forEach((input) => input.remove());\n  }\n\n  get inputs() {\n    return this.element.querySelectorAll(\"input[data-generated]\");\n  }\n}\n"],"names":["DragState","constructor","list","event","id","this","cursorOffset","offsetY","initialPosition","target","offsetTop","targetId","updateCursor","row","callback","listOffset","getBoundingClientRect","top","itemPosition","clientY","updateItemPosition","updateScroll","previousScrollOffset","scrollDelta","position","Math","max","min","offsetHeight","Definitions","identifier","controllerConstructor","Controller","static","query","String","sort","queryValueChanged","Turbo","navigator","history","replace","url","sortValueChanged","document","querySelectorAll","sortSelector","forEach","input","value","frame","element","closest","URL","baseURI","window","location","href","search","params","Object","connect","index","Array","from","parentElement","children","indexOf","paramsValueChanged","id_value","dragUpdate","offset","dragOffset","style","zIndex","toggleAttribute","updateVisually","dragIndex","updateIndex","reset","removeAttribute","hasChanges","paramsValue","index_value","round","comparisonIndex","startDragging","dragState","addEventListener","mousemove","mouseup","scroll","stopDragging","removeEventListener","tablesOrderableItemOutlets","item","drop","dragItem","newIndex","targetItem","insertAdjacentElement","commitChanges","tablesOrderableFormOutlet","clear","add","submit","mousedown","isDragging","preventDefault","animate","ticking","requestAnimationFrame","tablesOrderableFormOutlets","form","tablesOrderableFormOutletConnected","tablesOrderableFormOutletDisconnected","currentItems","find","toSorted","a","b","id_name","index_name","insertAdjacentHTML","inputs","length","requestSubmit","remove"],"mappings":"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"}
         | 
| @@ -24,9 +24,9 @@ module Katalyst | |
| 24 24 | 
             
                    # other tables.
         | 
| 25 25 | 
             
                    def config_component(name, component_name: "#{name}_component", default: nil) # rubocop:disable Metrics/MethodLength
         | 
| 26 26 | 
             
                      config_accessor(name)
         | 
| 27 | 
            -
                      config.public_send("#{name}=", default)
         | 
| 27 | 
            +
                      config.public_send(:"#{name}=", default)
         | 
| 28 28 | 
             
                      define_method(component_name) do
         | 
| 29 | 
            -
                        return instance_variable_get("@#{component_name}") if instance_variable_defined?("@#{component_name}")
         | 
| 29 | 
            +
                        return instance_variable_get(:"@#{component_name}") if instance_variable_defined?(:"@#{component_name}")
         | 
| 30 30 |  | 
| 31 31 | 
             
                        klass     = config.public_send(name)
         | 
| 32 32 | 
             
                        component = klass ? self.class.const_get(klass) : nil
         | 
| @@ -37,7 +37,7 @@ module Katalyst | |
| 37 37 | 
             
                          component.extend(HiddenSubcomponent)
         | 
| 38 38 | 
             
                        end
         | 
| 39 39 |  | 
| 40 | 
            -
                        instance_variable_set("@#{component_name}", component) if component
         | 
| 40 | 
            +
                        instance_variable_set(:"@#{component_name}", component) if component
         | 
| 41 41 | 
             
                      end
         | 
| 42 42 | 
             
                    end
         | 
| 43 43 | 
             
                  end
         | 
| @@ -20,13 +20,24 @@ module Katalyst | |
| 20 20 | 
             
                  private
         | 
| 21 21 |  | 
| 22 22 | 
             
                  def row_proc
         | 
| 23 | 
            -
                    @row_proc | 
| 23 | 
            +
                    if @row_proc
         | 
| 24 | 
            +
                      @row_proc
         | 
| 25 | 
            +
                    elsif @__vc_render_in_block
         | 
| 26 | 
            +
                      @row_proc = @__vc_render_in_block
         | 
| 27 | 
            +
                    else
         | 
| 28 | 
            +
                      @row_proc = Proc.new do |row, object|
         | 
| 29 | 
            +
                        row_renderer.render_row(row, object, view_context)
         | 
| 30 | 
            +
                      end
         | 
| 31 | 
            +
                    end
         | 
| 24 32 | 
             
                  end
         | 
| 25 33 |  | 
| 26 | 
            -
                  def  | 
| 27 | 
            -
                     | 
| 28 | 
            -
             | 
| 29 | 
            -
             | 
| 34 | 
            +
                  def row_renderer
         | 
| 35 | 
            +
                    @row_renderer ||= RowRenderer.new(@lookup_context,
         | 
| 36 | 
            +
                                                      collection: collection,
         | 
| 37 | 
            +
                                                      as:         @as,
         | 
| 38 | 
            +
                                                      partial:    @partial,
         | 
| 39 | 
            +
                                                      variants:   [:row],
         | 
| 40 | 
            +
                                                      formats:    [:html])
         | 
| 30 41 | 
             
                  end
         | 
| 31 42 | 
             
                end
         | 
| 32 43 | 
             
              end
         | 
| @@ -0,0 +1,57 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            module Katalyst
         | 
| 4 | 
            +
              module Tables
         | 
| 5 | 
            +
                class RowRenderer < ActionView::PartialRenderer # :nodoc:
         | 
| 6 | 
            +
                  include ObjectRendering
         | 
| 7 | 
            +
             | 
| 8 | 
            +
                  def initialize(lookup_context, collection:, partial:, **options)
         | 
| 9 | 
            +
                    super(lookup_context, options)
         | 
| 10 | 
            +
             | 
| 11 | 
            +
                    @collection = collection
         | 
| 12 | 
            +
                    @partial    = partial
         | 
| 13 | 
            +
                  end
         | 
| 14 | 
            +
             | 
| 15 | 
            +
                  def render_row(row, object, view_context)
         | 
| 16 | 
            +
                    @row    = row
         | 
| 17 | 
            +
                    @object = object
         | 
| 18 | 
            +
             | 
| 19 | 
            +
                    if @partial.blank?
         | 
| 20 | 
            +
                      example  = example_for(@collection)
         | 
| 21 | 
            +
                      @partial = partial_path(example, view_context) if example.present?
         | 
| 22 | 
            +
                    end
         | 
| 23 | 
            +
             | 
| 24 | 
            +
                    # if we still cannot find an example return an empty table (no header row)
         | 
| 25 | 
            +
                    return "" if @partial.blank?
         | 
| 26 | 
            +
             | 
| 27 | 
            +
                    @local_name ||= local_variable(@partial)
         | 
| 28 | 
            +
                    render(@partial, view_context, nil)
         | 
| 29 | 
            +
                  end
         | 
| 30 | 
            +
             | 
| 31 | 
            +
                  private
         | 
| 32 | 
            +
             | 
| 33 | 
            +
                  def example_for(collection)
         | 
| 34 | 
            +
                    if collection.respond_to?(:items)
         | 
| 35 | 
            +
                      example_for(collection.items)
         | 
| 36 | 
            +
                    elsif collection.respond_to?(:any?) && collection.any?
         | 
| 37 | 
            +
                      collection.first
         | 
| 38 | 
            +
                    elsif collection.respond_to?(:model)
         | 
| 39 | 
            +
                      collection.model.new
         | 
| 40 | 
            +
                    end
         | 
| 41 | 
            +
                    # if none of the above strategies match, return nil
         | 
| 42 | 
            +
                  rescue ArgumentError
         | 
| 43 | 
            +
                    nil # if we could not construct an example without passing arguments, return nil
         | 
| 44 | 
            +
                  end
         | 
| 45 | 
            +
             | 
| 46 | 
            +
                  def template_keys(path)
         | 
| 47 | 
            +
                    super + [@local_name, :row]
         | 
| 48 | 
            +
                  end
         | 
| 49 | 
            +
             | 
| 50 | 
            +
                  def render_partial_template(view, locals, template, layout, block)
         | 
| 51 | 
            +
                    locals[@local_name || template.variable] = @object
         | 
| 52 | 
            +
                    locals[:row]                             = @row
         | 
| 53 | 
            +
                    super(view, locals, template, layout, block)
         | 
| 54 | 
            +
                  end
         | 
| 55 | 
            +
                end
         | 
| 56 | 
            +
              end
         | 
| 57 | 
            +
            end
         | 
| @@ -30,7 +30,7 @@ module Katalyst | |
| 30 30 | 
             
                # - `header`: whether to render the header row (defaults to true, supports options)
         | 
| 31 31 | 
             
                # - `caption`: whether to render the caption (defaults to true, supports options)
         | 
| 32 32 | 
             
                # - `object_name`: the name of the object to use for partial rendering (defaults to collection.model_name.i18n_key)
         | 
| 33 | 
            -
                # - `partial`: the name of the partial to use for rendering each row (defaults to  | 
| 33 | 
            +
                # - `partial`: the name of the partial to use for rendering each row (defaults to to_partial_path on the object)
         | 
| 34 34 | 
             
                # - `as`: the name of the local variable to use for rendering each row (defaults to collection.model_name.param_key)
         | 
| 35 35 | 
             
                # In addition to these options, standard HTML attributes can be passed which will be added to the table tag.
         | 
| 36 36 | 
             
                def initialize(collection:,
         | 
| @@ -40,7 +40,8 @@ module Katalyst | |
| 40 40 | 
             
                               **html_attributes)
         | 
| 41 41 | 
             
                  @collection = collection
         | 
| 42 42 |  | 
| 43 | 
            -
                  # sorting: instance of Katalyst::Tables:: | 
| 43 | 
            +
                  # sorting: instance of Katalyst::Tables::Collection::SortForm.
         | 
| 44 | 
            +
                  # If not provided will be inferred from the collection.
         | 
| 44 45 | 
             
                  @sorting = sorting || html_attributes.delete(:sort) # backwards compatibility with old `sort` option
         | 
| 45 46 |  | 
| 46 47 | 
             
                  # header: true means render the header row, header: false means no header row, if a hash, passes as options
         | 
| @@ -1,10 +1,5 @@ | |
| 1 1 | 
             
            # frozen_string_literal: true
         | 
| 2 2 |  | 
| 3 | 
            -
            require "active_support"
         | 
| 4 | 
            -
            require "active_support/concern"
         | 
| 5 | 
            -
             | 
| 6 | 
            -
            require_relative "backend/sort_form"
         | 
| 7 | 
            -
             | 
| 8 3 | 
             
            module Katalyst
         | 
| 9 4 | 
             
              module Tables
         | 
| 10 5 | 
             
                # Utilities for controllers that are generating collections for visualisation
         | 
| @@ -14,6 +9,10 @@ module Katalyst | |
| 14 9 | 
             
                module Backend
         | 
| 15 10 | 
             
                  extend ActiveSupport::Concern
         | 
| 16 11 |  | 
| 12 | 
            +
                  # @deprecated backwards compatibility
         | 
| 13 | 
            +
                  class SortForm < Katalyst::Tables::Collection::SortForm
         | 
| 14 | 
            +
                  end
         | 
| 15 | 
            +
             | 
| 17 16 | 
             
                  # Sort the given collection by params[:sort], which is set when a user
         | 
| 18 17 | 
             
                  # interacts with a column header in a frontend table view.
         | 
| 19 18 | 
             
                  #
         | 
| @@ -6,7 +6,7 @@ export default class OrderableFormController extends Controller { | |
| 6 6 | 
             
                this.element.insertAdjacentHTML(
         | 
| 7 7 | 
             
                  "beforeend",
         | 
| 8 8 | 
             
                  `<input type="hidden" name="${id_name}" value="${id_value}" data-generated>
         | 
| 9 | 
            -
                          <input type="hidden" name="${index_name}" value="${item.index}" data-generated | 
| 9 | 
            +
                          <input type="hidden" name="${index_name}" value="${item.index}" data-generated>`,
         | 
| 10 10 | 
             
                );
         | 
| 11 11 | 
             
              }
         | 
| 12 12 |  | 
| @@ -52,7 +52,7 @@ export default class OrderableListController extends Controller { | |
| 52 52 |  | 
| 53 53 | 
             
                // reindex all items based on their new positions
         | 
| 54 54 | 
             
                this.tablesOrderableItemOutlets.forEach((item, index) =>
         | 
| 55 | 
            -
                  item.updateIndex(index)
         | 
| 55 | 
            +
                  item.updateIndex(index),
         | 
| 56 56 | 
             
                );
         | 
| 57 57 |  | 
| 58 58 | 
             
                // save the changes
         | 
| @@ -104,7 +104,7 @@ export default class OrderableListController extends Controller { | |
| 104 104 | 
             
                    this.element,
         | 
| 105 105 | 
             
                    this.dragItem.row,
         | 
| 106 106 | 
             
                    event,
         | 
| 107 | 
            -
                    this.animate
         | 
| 107 | 
            +
                    this.animate,
         | 
| 108 108 | 
             
                  );
         | 
| 109 109 | 
             
                });
         | 
| 110 110 | 
             
              };
         | 
| @@ -119,7 +119,7 @@ export default class OrderableListController extends Controller { | |
| 119 119 | 
             
                  this.dragState.updateScroll(
         | 
| 120 120 | 
             
                    this.element,
         | 
| 121 121 | 
             
                    this.dragItem.row,
         | 
| 122 | 
            -
                    this.animate
         | 
| 122 | 
            +
                    this.animate,
         | 
| 123 123 | 
             
                  );
         | 
| 124 124 | 
             
                });
         | 
| 125 125 | 
             
              };
         | 
| @@ -179,7 +179,7 @@ export default class OrderableListController extends Controller { | |
| 179 179 | 
             
                if (!this.isDragging) return null;
         | 
| 180 180 |  | 
| 181 181 | 
             
                return this.tablesOrderableItemOutlets.find(
         | 
| 182 | 
            -
                  (item) => item.id === this.dragState.targetId
         | 
| 182 | 
            +
                  (item) => item.id === this.dragState.targetId,
         | 
| 183 183 | 
             
                );
         | 
| 184 184 | 
             
              }
         | 
| 185 185 |  | 
| @@ -191,7 +191,7 @@ export default class OrderableListController extends Controller { | |
| 191 191 | 
             
               */
         | 
| 192 192 | 
             
              get #currentItems() {
         | 
| 193 193 | 
             
                return this.tablesOrderableItemOutlets.toSorted(
         | 
| 194 | 
            -
                  (a, b) => a.comparisonIndex - b.comparisonIndex
         | 
| 194 | 
            +
                  (a, b) => a.comparisonIndex - b.comparisonIndex,
         | 
| 195 195 | 
             
                );
         | 
| 196 196 | 
             
              }
         | 
| 197 197 |  | 
| @@ -203,7 +203,7 @@ export default class OrderableListController extends Controller { | |
| 203 203 | 
             
               */
         | 
| 204 204 | 
             
              #targetItem(element) {
         | 
| 205 205 | 
             
                return this.tablesOrderableItemOutlets.find(
         | 
| 206 | 
            -
                  (item) => item.element === element
         | 
| 206 | 
            +
                  (item) => item.element === element,
         | 
| 207 207 | 
             
                );
         | 
| 208 208 | 
             
              }
         | 
| 209 209 |  | 
| @@ -11,6 +11,7 @@ module Katalyst | |
| 11 11 | 
             
                    include ActiveModel::Dirty
         | 
| 12 12 | 
             
                    include ActiveSupport::Configurable
         | 
| 13 13 |  | 
| 14 | 
            +
                    include HasParams
         | 
| 14 15 | 
             
                    include Reducers
         | 
| 15 16 |  | 
| 16 17 | 
             
                    class_methods do
         | 
| @@ -29,8 +30,7 @@ module Katalyst | |
| 29 30 | 
             
                    included do
         | 
| 30 31 | 
             
                      attr_accessor :items
         | 
| 31 32 |  | 
| 32 | 
            -
                      delegate : | 
| 33 | 
            -
                      delegate :model_name, to: :model, allow_nil: true
         | 
| 33 | 
            +
                      delegate :each, :count, :empty?, to: :items, allow_nil: true
         | 
| 34 34 | 
             
                    end
         | 
| 35 35 |  | 
| 36 36 | 
             
                    def initialize(**options)
         | 
| @@ -39,18 +39,6 @@ module Katalyst | |
| 39 39 | 
             
                      clear_changes_information
         | 
| 40 40 | 
             
                    end
         | 
| 41 41 |  | 
| 42 | 
            -
                    def filter
         | 
| 43 | 
            -
                      # no-op by default
         | 
| 44 | 
            -
                    end
         | 
| 45 | 
            -
             | 
| 46 | 
            -
                    def filtered?
         | 
| 47 | 
            -
                      self.class.new.filters != filters
         | 
| 48 | 
            -
                    end
         | 
| 49 | 
            -
             | 
| 50 | 
            -
                    def filters
         | 
| 51 | 
            -
                      attributes.except("page", "sort")
         | 
| 52 | 
            -
                    end
         | 
| 53 | 
            -
             | 
| 54 42 | 
             
                    def apply(items)
         | 
| 55 43 | 
             
                      @items = items
         | 
| 56 44 | 
             
                      reducers.build do |_|
         | 
| @@ -59,21 +47,6 @@ module Katalyst | |
| 59 47 | 
             
                      end.call(self)
         | 
| 60 48 | 
             
                      self
         | 
| 61 49 | 
             
                    end
         | 
| 62 | 
            -
             | 
| 63 | 
            -
                    def with_params(params)
         | 
| 64 | 
            -
                      self.attributes = params.permit(self.class.permitted_params)
         | 
| 65 | 
            -
             | 
| 66 | 
            -
                      self
         | 
| 67 | 
            -
                    end
         | 
| 68 | 
            -
             | 
| 69 | 
            -
                    # Returns a hash of the current attributes that have changed from defaults.
         | 
| 70 | 
            -
                    def to_params
         | 
| 71 | 
            -
                      attributes.slice(*changed)
         | 
| 72 | 
            -
                    end
         | 
| 73 | 
            -
             | 
| 74 | 
            -
                    def inspect
         | 
| 75 | 
            -
                      "#<#{self.class.name} @attributes=#{attributes.inspect} @model=\"#{model}\" @count=#{items&.count}>"
         | 
| 76 | 
            -
                    end
         | 
| 77 50 | 
             
                  end
         | 
| 78 51 | 
             
                end
         | 
| 79 52 | 
             
              end
         | 
| @@ -0,0 +1,23 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            module Katalyst
         | 
| 4 | 
            +
              module Tables
         | 
| 5 | 
            +
                module Collection
         | 
| 6 | 
            +
                  using HasParams
         | 
| 7 | 
            +
             | 
| 8 | 
            +
                  module Filtering # :nodoc:
         | 
| 9 | 
            +
                    def filter
         | 
| 10 | 
            +
                      # no-op by default
         | 
| 11 | 
            +
                    end
         | 
| 12 | 
            +
             | 
| 13 | 
            +
                    def filtered?
         | 
| 14 | 
            +
                      filters.any?
         | 
| 15 | 
            +
                    end
         | 
| 16 | 
            +
             | 
| 17 | 
            +
                    def filters
         | 
| 18 | 
            +
                      changed_attributes.except("sort", "page")
         | 
| 19 | 
            +
                    end
         | 
| 20 | 
            +
                  end
         | 
| 21 | 
            +
                end
         | 
| 22 | 
            +
              end
         | 
| 23 | 
            +
            end
         | 
| @@ -0,0 +1,43 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            module Katalyst
         | 
| 4 | 
            +
              module Tables
         | 
| 5 | 
            +
                module Collection
         | 
| 6 | 
            +
                  module HasParams # :nodoc:
         | 
| 7 | 
            +
                    extend ActiveSupport::Concern
         | 
| 8 | 
            +
             | 
| 9 | 
            +
                    refine Object do
         | 
| 10 | 
            +
                      def to_params
         | 
| 11 | 
            +
                        as_json
         | 
| 12 | 
            +
                      end
         | 
| 13 | 
            +
                    end
         | 
| 14 | 
            +
             | 
| 15 | 
            +
                    refine ActiveModel::AttributeSet do
         | 
| 16 | 
            +
                      def to_params
         | 
| 17 | 
            +
                        to_h.transform_values(&:to_params).as_json
         | 
| 18 | 
            +
                      end
         | 
| 19 | 
            +
                    end
         | 
| 20 | 
            +
             | 
| 21 | 
            +
                    refine ActiveModel::Attributes do
         | 
| 22 | 
            +
                      def to_params
         | 
| 23 | 
            +
                        if respond_to?(:changed)
         | 
| 24 | 
            +
                          @attributes.to_params.slice(*changed)
         | 
| 25 | 
            +
                        else
         | 
| 26 | 
            +
                          @attributes.to_params
         | 
| 27 | 
            +
                        end
         | 
| 28 | 
            +
                      end
         | 
| 29 | 
            +
                    end
         | 
| 30 | 
            +
             | 
| 31 | 
            +
                    using HasParams
         | 
| 32 | 
            +
             | 
| 33 | 
            +
                    # Returns a hash of the current attributes that have changed from defaults.
         | 
| 34 | 
            +
                    # This uses Refinements internally so it needs to be exposed publicly with this super call.
         | 
| 35 | 
            +
                    # rubocop:disable Lint/UselessMethodDefinition
         | 
| 36 | 
            +
                    def to_params
         | 
| 37 | 
            +
                      super
         | 
| 38 | 
            +
                    end
         | 
| 39 | 
            +
                    # rubocop:enable Lint/UselessMethodDefinition
         | 
| 40 | 
            +
                  end
         | 
| 41 | 
            +
                end
         | 
| 42 | 
            +
              end
         | 
| 43 | 
            +
            end
         | 
| @@ -22,7 +22,7 @@ module Katalyst | |
| 22 22 | 
             
                    end
         | 
| 23 23 |  | 
| 24 24 | 
             
                    def initialize(sorting: config.sorting, **options)
         | 
| 25 | 
            -
                      @sorting =  | 
| 25 | 
            +
                      @sorting = SortForm.parse(sorting) if sorting
         | 
| 26 26 |  | 
| 27 27 | 
             
                      super(sort: sorting, **options) # set default sort based on config
         | 
| 28 28 | 
             
                    end
         | 
| @@ -31,7 +31,7 @@ module Katalyst | |
| 31 31 | 
             
                      return unless @sorting
         | 
| 32 32 |  | 
| 33 33 | 
             
                      # update internal proxy
         | 
| 34 | 
            -
                      @sorting =  | 
| 34 | 
            +
                      @sorting = SortForm.parse(value, default: attribute_was(:sort))
         | 
| 35 35 |  | 
| 36 36 | 
             
                      # update attribute based on normalized value
         | 
| 37 37 | 
             
                      super(@sorting.to_param)
         | 
| @@ -3,7 +3,9 @@ | |
| 3 3 | 
             
            module Katalyst
         | 
| 4 4 | 
             
              module Tables
         | 
| 5 5 | 
             
                module Collection
         | 
| 6 | 
            -
                  # Entry point for creating a collection for use with table components | 
| 6 | 
            +
                  # Entry point for creating a collection for use with table components
         | 
| 7 | 
            +
                  # where filter params are flat, e.g. ?search=query
         | 
| 8 | 
            +
                  #
         | 
| 7 9 | 
             
                  # This class is intended to be subclassed, i.e.:
         | 
| 8 10 | 
             
                  #
         | 
| 9 11 | 
             
                  # class ApplicationController < ActionController::Base
         | 
| @@ -21,11 +23,35 @@ module Katalyst | |
| 21 23 | 
             
                  # ````
         | 
| 22 24 | 
             
                  class Base
         | 
| 23 25 | 
             
                    include Core
         | 
| 26 | 
            +
                    include Filtering
         | 
| 24 27 | 
             
                    include Pagination
         | 
| 25 28 | 
             
                    include Sorting
         | 
| 26 29 |  | 
| 27 30 | 
             
                    use(Sorting::Sort)
         | 
| 28 31 | 
             
                    use(Pagination::Paginate)
         | 
| 32 | 
            +
             | 
| 33 | 
            +
                    def self.with_params(params)
         | 
| 34 | 
            +
                      new.with_params(params)
         | 
| 35 | 
            +
                    end
         | 
| 36 | 
            +
             | 
| 37 | 
            +
                    def model_name
         | 
| 38 | 
            +
                      @model_name ||= items.model_name.dup.tap do |name|
         | 
| 39 | 
            +
                        name.param_key = ""
         | 
| 40 | 
            +
                      end
         | 
| 41 | 
            +
                    end
         | 
| 42 | 
            +
             | 
| 43 | 
            +
                    def with_params(params)
         | 
| 44 | 
            +
                      # test support
         | 
| 45 | 
            +
                      params = ActionController::Parameters.new(params) unless params.is_a?(ActionController::Parameters)
         | 
| 46 | 
            +
             | 
| 47 | 
            +
                      self.attributes = params.permit(self.class.permitted_params)
         | 
| 48 | 
            +
             | 
| 49 | 
            +
                      self
         | 
| 50 | 
            +
                    end
         | 
| 51 | 
            +
             | 
| 52 | 
            +
                    def inspect
         | 
| 53 | 
            +
                      "#<#{self.class.name} @attributes=#{attributes.inspect} @model_name=\"#{model_name}\" @count=#{items&.count}>"
         | 
| 54 | 
            +
                    end
         | 
| 29 55 | 
             
                  end
         | 
| 30 56 | 
             
                end
         | 
| 31 57 | 
             
              end
         | 
| @@ -0,0 +1,80 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            module Katalyst
         | 
| 4 | 
            +
              module Tables
         | 
| 5 | 
            +
                module Collection
         | 
| 6 | 
            +
                  # Entry point for creating a collection for use with table components
         | 
| 7 | 
            +
                  # where filter params are nested, e.g. ?filters[search]=query
         | 
| 8 | 
            +
                  #
         | 
| 9 | 
            +
                  # This class is intended to be subclassed, i.e.:
         | 
| 10 | 
            +
                  #
         | 
| 11 | 
            +
                  # class ApplicationController < ActionController::Base
         | 
| 12 | 
            +
                  #   class Collection < Katalyst::Tables::Collection::Base
         | 
| 13 | 
            +
                  #     ...
         | 
| 14 | 
            +
                  #   end
         | 
| 15 | 
            +
                  # end
         | 
| 16 | 
            +
                  #
         | 
| 17 | 
            +
                  # In the context of a controller action, construct a collection, apply it
         | 
| 18 | 
            +
                  # to a model, then pass the result to the view component:
         | 
| 19 | 
            +
                  # ```
         | 
| 20 | 
            +
                  # collection = Collection.new.with_params(params).apply(People.all)
         | 
| 21 | 
            +
                  # table = Katalyst::TableComponent.new(collection: collection)
         | 
| 22 | 
            +
                  # render table
         | 
| 23 | 
            +
                  # ````
         | 
| 24 | 
            +
                  class Filter
         | 
| 25 | 
            +
                    include Core
         | 
| 26 | 
            +
                    include Filtering
         | 
| 27 | 
            +
                    include Pagination
         | 
| 28 | 
            +
                    include Sorting
         | 
| 29 | 
            +
             | 
| 30 | 
            +
                    use(Sorting::Sort)
         | 
| 31 | 
            +
                    use(Pagination::Paginate)
         | 
| 32 | 
            +
             | 
| 33 | 
            +
                    def self.with_params(params)
         | 
| 34 | 
            +
                      new.with_params(params)
         | 
| 35 | 
            +
                    end
         | 
| 36 | 
            +
             | 
| 37 | 
            +
                    def self.permitted_params
         | 
| 38 | 
            +
                      super.excluding("sort", "page")
         | 
| 39 | 
            +
                    end
         | 
| 40 | 
            +
             | 
| 41 | 
            +
                    attr_reader :param_key
         | 
| 42 | 
            +
             | 
| 43 | 
            +
                    def initialize(param_key: :filters, **options)
         | 
| 44 | 
            +
                      super(**options)
         | 
| 45 | 
            +
             | 
| 46 | 
            +
                      @param_key = param_key.to_sym
         | 
| 47 | 
            +
                    end
         | 
| 48 | 
            +
             | 
| 49 | 
            +
                    def model_name
         | 
| 50 | 
            +
                      @model_name ||= items.model_name.tap do |name|
         | 
| 51 | 
            +
                        name.param_key = param_key
         | 
| 52 | 
            +
                      end
         | 
| 53 | 
            +
                    end
         | 
| 54 | 
            +
             | 
| 55 | 
            +
                    def with_params(params)
         | 
| 56 | 
            +
                      params  = params.permit(:sort, :page, param_key => self.class.permitted_params)
         | 
| 57 | 
            +
                      filters = params[param_key]
         | 
| 58 | 
            +
             | 
| 59 | 
            +
                      self.attributes = filters if filters.present?
         | 
| 60 | 
            +
                      self.attributes = params.slice("page", "sort")
         | 
| 61 | 
            +
             | 
| 62 | 
            +
                      self
         | 
| 63 | 
            +
                    end
         | 
| 64 | 
            +
             | 
| 65 | 
            +
                    def to_params
         | 
| 66 | 
            +
                      if filtered?
         | 
| 67 | 
            +
                        { param_key.to_s => super.except("sort", "page") }.merge(super.slice("sort", "page"))
         | 
| 68 | 
            +
                      else
         | 
| 69 | 
            +
                        super.slice("sort", "page")
         | 
| 70 | 
            +
                      end
         | 
| 71 | 
            +
                    end
         | 
| 72 | 
            +
             | 
| 73 | 
            +
                    def inspect
         | 
| 74 | 
            +
                      "#<#{self.class.name} @param_key=#{param_key.inspect} " +
         | 
| 75 | 
            +
                        "@attributes=#{attributes.inspect} @model=\"#{model}\" @count=#{items&.count}>"
         | 
| 76 | 
            +
                    end
         | 
| 77 | 
            +
                  end
         | 
| 78 | 
            +
                end
         | 
| 79 | 
            +
              end
         | 
| 80 | 
            +
            end
         | 
| @@ -2,7 +2,7 @@ | |
| 2 2 |  | 
| 3 3 | 
             
            module Katalyst
         | 
| 4 4 | 
             
              module Tables
         | 
| 5 | 
            -
                module  | 
| 5 | 
            +
                module Collection
         | 
| 6 6 | 
             
                  # A FormObject (model) representing the sort state of controller for a given
         | 
| 7 7 | 
             
                  # collection/parameter.
         | 
| 8 8 | 
             
                  class SortForm
         | 
| @@ -37,8 +37,8 @@ module Katalyst | |
| 37 37 | 
             
                    # @param column [String, Symbol]
         | 
| 38 38 | 
             
                    # @return [true, false]
         | 
| 39 39 | 
             
                    def supports?(collection, column)
         | 
| 40 | 
            -
                      collection.respond_to?("order_by_#{column}") ||
         | 
| 41 | 
            -
                        collection. | 
| 40 | 
            +
                      scope_for(collection).respond_to?(:"order_by_#{column}") ||
         | 
| 41 | 
            +
                        model_for(collection).has_attribute?(column.to_s)
         | 
| 42 42 | 
             
                    end
         | 
| 43 43 |  | 
| 44 44 | 
             
                    # Returns the current sort behaviour of the given column, for use as a
         | 
| @@ -72,8 +72,8 @@ module Katalyst | |
| 72 72 | 
             
                    def apply(collection)
         | 
| 73 73 | 
             
                      return [self, collection] if column.nil?
         | 
| 74 74 |  | 
| 75 | 
            -
                      if collection.respond_to?("order_by_#{column}")
         | 
| 76 | 
            -
                        collection = collection.reorder(nil).public_send("order_by_#{column}", direction.to_sym)
         | 
| 75 | 
            +
                      if collection.respond_to?(:"order_by_#{column}")
         | 
| 76 | 
            +
                        collection = collection.reorder(nil).public_send(:"order_by_#{column}", direction.to_sym)
         | 
| 77 77 | 
             
                      elsif collection.model.has_attribute?(column)
         | 
| 78 78 | 
             
                        collection = collection.reorder(column => direction)
         | 
| 79 79 | 
             
                      else
         | 
| @@ -88,6 +88,14 @@ module Katalyst | |
| 88 88 | 
             
                    def clear!
         | 
| 89 89 | 
             
                      self.column = self.direction = nil
         | 
| 90 90 | 
             
                    end
         | 
| 91 | 
            +
             | 
| 92 | 
            +
                    def scope_for(collection)
         | 
| 93 | 
            +
                      collection.is_a?(Core) ? collection.items : collection
         | 
| 94 | 
            +
                    end
         | 
| 95 | 
            +
             | 
| 96 | 
            +
                    def model_for(collection)
         | 
| 97 | 
            +
                      scope_for(collection).model
         | 
| 98 | 
            +
                    end
         | 
| 91 99 | 
             
                  end
         | 
| 92 100 | 
             
                end
         | 
| 93 101 | 
             
              end
         | 
    
        data/lib/katalyst/tables.rb
    CHANGED
    
    | @@ -3,11 +3,7 @@ | |
| 3 3 | 
             
            require "view_component"
         | 
| 4 4 | 
             
            require "katalyst/html_attributes"
         | 
| 5 5 |  | 
| 6 | 
            -
            require_relative "tables/backend"
         | 
| 7 6 | 
             
            require_relative "tables/engine"
         | 
| 8 | 
            -
            require_relative "tables/frontend"
         | 
| 9 | 
            -
             | 
| 10 | 
            -
            require_relative "tables/engine" if Object.const_defined?(:Rails)
         | 
| 11 7 |  | 
| 12 8 | 
             
            module Katalyst
         | 
| 13 9 | 
             
              module Tables
         | 
    
        metadata
    CHANGED
    
    | @@ -1,14 +1,14 @@ | |
| 1 1 | 
             
            --- !ruby/object:Gem::Specification
         | 
| 2 2 | 
             
            name: katalyst-tables
         | 
| 3 3 | 
             
            version: !ruby/object:Gem::Version
         | 
| 4 | 
            -
              version: 2. | 
| 4 | 
            +
              version: 2.5.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:  | 
| 11 | 
            +
            date: 2024-01-30 00:00:00.000000000 Z
         | 
| 12 12 | 
             
            dependencies:
         | 
| 13 13 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 14 14 | 
             
              name: katalyst-html-attributes
         | 
| @@ -38,8 +38,8 @@ dependencies: | |
| 38 38 | 
             
                - - ">="
         | 
| 39 39 | 
             
                  - !ruby/object:Gem::Version
         | 
| 40 40 | 
             
                    version: '0'
         | 
| 41 | 
            -
            description:  | 
| 42 | 
            -
               | 
| 41 | 
            +
            description: HTML table generator for building tabular index views with filtering,
         | 
| 42 | 
            +
              sorting, and pagination.
         | 
| 43 43 | 
             
            email:
         | 
| 44 44 | 
             
            - devs@katalyst.com.au
         | 
| 45 45 | 
             
            executables: []
         | 
| @@ -57,6 +57,7 @@ files: | |
| 57 57 | 
             
            - app/components/concerns/katalyst/tables/configurable_component.rb
         | 
| 58 58 | 
             
            - app/components/concerns/katalyst/tables/has_table_content.rb
         | 
| 59 59 | 
             
            - app/components/concerns/katalyst/tables/orderable.rb
         | 
| 60 | 
            +
            - app/components/concerns/katalyst/tables/row_renderer.rb
         | 
| 60 61 | 
             
            - app/components/concerns/katalyst/tables/sortable.rb
         | 
| 61 62 | 
             
            - app/components/concerns/katalyst/tables/turbo_replaceable.rb
         | 
| 62 63 | 
             
            - app/components/katalyst/table_component.html.erb
         | 
| @@ -70,33 +71,36 @@ files: | |
| 70 71 | 
             
            - app/components/katalyst/tables/pagy_nav_component.rb
         | 
| 71 72 | 
             
            - app/components/katalyst/turbo/pagy_nav_component.rb
         | 
| 72 73 | 
             
            - app/components/katalyst/turbo/table_component.rb
         | 
| 74 | 
            +
            - app/controllers/concerns/katalyst/tables/backend.rb
         | 
| 75 | 
            +
            - app/helpers/katalyst/tables/frontend.rb
         | 
| 76 | 
            +
            - app/helpers/katalyst/tables/frontend/helper.rb
         | 
| 73 77 | 
             
            - app/javascript/tables/application.js
         | 
| 74 78 | 
             
            - app/javascript/tables/orderable/form_controller.js
         | 
| 75 79 | 
             
            - app/javascript/tables/orderable/item_controller.js
         | 
| 76 80 | 
             
            - app/javascript/tables/orderable/list_controller.js
         | 
| 77 81 | 
             
            - app/javascript/tables/turbo/collection_controller.js
         | 
| 78 82 | 
             
            - app/models/concerns/katalyst/tables/collection/core.rb
         | 
| 83 | 
            +
            - app/models/concerns/katalyst/tables/collection/filtering.rb
         | 
| 84 | 
            +
            - app/models/concerns/katalyst/tables/collection/has_params.rb
         | 
| 79 85 | 
             
            - app/models/concerns/katalyst/tables/collection/pagination.rb
         | 
| 80 86 | 
             
            - app/models/concerns/katalyst/tables/collection/reducers.rb
         | 
| 81 87 | 
             
            - app/models/concerns/katalyst/tables/collection/sorting.rb
         | 
| 82 | 
            -
            - app/models/katalyst/tables/collection.rb
         | 
| 88 | 
            +
            - app/models/katalyst/tables/collection/base.rb
         | 
| 89 | 
            +
            - app/models/katalyst/tables/collection/filter.rb
         | 
| 90 | 
            +
            - app/models/katalyst/tables/collection/sort_form.rb
         | 
| 83 91 | 
             
            - config/importmap.rb
         | 
| 84 92 | 
             
            - config/locales/tables.en.yml
         | 
| 85 93 | 
             
            - lib/katalyst/tables.rb
         | 
| 86 | 
            -
            - lib/katalyst/tables/backend.rb
         | 
| 87 | 
            -
            - lib/katalyst/tables/backend/sort_form.rb
         | 
| 88 94 | 
             
            - lib/katalyst/tables/engine.rb
         | 
| 89 | 
            -
             | 
| 90 | 
            -
            - lib/katalyst/tables/frontend/helper.rb
         | 
| 91 | 
            -
            homepage: https://github.com/katalyst/katalyst-tables
         | 
| 95 | 
            +
            homepage: https://github.com/katalyst/tables
         | 
| 92 96 | 
             
            licenses:
         | 
| 93 97 | 
             
            - MIT
         | 
| 94 98 | 
             
            metadata:
         | 
| 95 99 | 
             
              allowed_push_host: https://rubygems.org
         | 
| 96 100 | 
             
              rubygems_mfa_required: 'true'
         | 
| 97 | 
            -
              homepage_uri: https://github.com/katalyst/ | 
| 98 | 
            -
              source_code_uri: https://github.com/katalyst/ | 
| 99 | 
            -
              changelog_uri: https://github.com/katalyst/ | 
| 101 | 
            +
              homepage_uri: https://github.com/katalyst/tables
         | 
| 102 | 
            +
              source_code_uri: https://github.com/katalyst/tables
         | 
| 103 | 
            +
              changelog_uri: https://github.com/katalyst/tables/blobs/main/CHANGELOG.md
         | 
| 100 104 | 
             
            post_install_message:
         | 
| 101 105 | 
             
            rdoc_options: []
         | 
| 102 106 | 
             
            require_paths:
         | 
| @@ -112,7 +116,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement | |
| 112 116 | 
             
                - !ruby/object:Gem::Version
         | 
| 113 117 | 
             
                  version: '0'
         | 
| 114 118 | 
             
            requirements: []
         | 
| 115 | 
            -
            rubygems_version: 3.4. | 
| 119 | 
            +
            rubygems_version: 3.4.19
         | 
| 116 120 | 
             
            signing_key:
         | 
| 117 121 | 
             
            specification_version: 4
         | 
| 118 122 | 
             
            summary: HTML table generator for Rails views
         | 
| 
            File without changes
         |