katalyst-tables 3.6.1 → 3.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f8f3e9232a9faeea1aafa1de62e46f2cda932ffae39d802b16e2d7c0a9a18fa2
4
- data.tar.gz: 889ff033c1c1cea7b544f23698b8849eef828597ddfd6a0cf1af19717fa88b38
3
+ metadata.gz: 5362e93821945472e9bc8c20574ab9325d6273f6f28f673722746ae9fec38f25
4
+ data.tar.gz: 36035838a96c61dab64a945dcee186771f5f83e74b2e28692d0a7da1558b9ef5
5
5
  SHA512:
6
- metadata.gz: 67d2150f8c35442ceb9443b02670293430f398c00b28457c9091d501ffa6f0d91c954350dc9a8fec7e6baa0028d39552647fcd6409decf6a068fbc4f5a590581
7
- data.tar.gz: fa0ead94e7f2116a76326eff10a868f675c307ac02c555c91cbdb6d873f040f4c3d171ee1b1d423843aa570fe47008710232a1fd2b93e63f2922c4511ace51b9
6
+ metadata.gz: 576d8272e2a6d5c9c8a8d043e2550191d7fc989f763876287db925b07c9b7336a9044e155ded05d48410331cb37b2bfeddae25dbe0b6e4e244c94932559b80bf
7
+ data.tar.gz: 6e198574c8eecd43ee24d042a2ef23669142a8c434637285471a7aef6d71f079b27b26e095a9b227356c2c4bfdb6b7cef97e187cd6735fb5596e3f16568fd81f
data/CHANGELOG.md CHANGED
@@ -1,3 +1,22 @@
1
+ ## [3.7.0]
2
+
3
+ Adds support for generating filter expressions for self-referencing models.
4
+
5
+ ## [3.6.0]
6
+
7
+ Keyboard navigation for query suggestions.
8
+
9
+ ## [3.5.0]
10
+
11
+ Adds a new query input for creating text-based filtering expressions.
12
+ See [query](docs/developers/collections/query.md) for collection extensions and
13
+ [filtering](docs/developers/frontend/filtering.md) for frontend support.
14
+
15
+ ## [3.4.0]
16
+
17
+ Support for selection columns and bulk actions.
18
+ See [docs](docs/developers/frontend/bulk-actions.md).
19
+
1
20
  ## [3.3.0]
2
21
  - Custom types for collections which support extensions for filtering with ranges and arrays.
3
22
 
@@ -264,17 +264,11 @@ class OrderableListController extends Controller {
264
264
  }
265
265
  }
266
266
 
267
- beforeMorphAttribute(e) {
268
- switch (e.detail.attributeName) {
269
- case "dragging": // set to track the item being dragged
270
- e.preventDefault();
271
- break;
272
- case "style": // used to animate rows moving up and down
273
- if (e.target.tagName === "TBODY" || e.target.tagName === "TR") {
274
- e.preventDefault();
275
- }
276
- break;
277
- }
267
+ beforeMorphElement(e) {
268
+ // Cancel morph if dragging to prevent swapping rows from under the user
269
+ // An alternative would be to require ids on rows so morph can accurately
270
+ // map before/after and avoid updating the row being dragged
271
+ if (this.isDragging) e.preventDefault();
278
272
  }
279
273
 
280
274
  //endregion
@@ -264,17 +264,11 @@ class OrderableListController extends Controller {
264
264
  }
265
265
  }
266
266
 
267
- beforeMorphAttribute(e) {
268
- switch (e.detail.attributeName) {
269
- case "dragging": // set to track the item being dragged
270
- e.preventDefault();
271
- break;
272
- case "style": // used to animate rows moving up and down
273
- if (e.target.tagName === "TBODY" || e.target.tagName === "TR") {
274
- e.preventDefault();
275
- }
276
- break;
277
- }
267
+ beforeMorphElement(e) {
268
+ // Cancel morph if dragging to prevent swapping rows from under the user
269
+ // An alternative would be to require ids on rows so morph can accurately
270
+ // map before/after and avoid updating the row being dragged
271
+ if (this.isDragging) e.preventDefault();
278
272
  }
279
273
 
280
274
  //endregion
@@ -1,2 +1,2 @@
1
- import{Controller as e}from"@hotwired/stimulus";class t{constructor(e,t,s){this.cursorOffset=t.offsetY,this.initialPosition=t.target.offsetTop-e.offsetTop,this.targetId=s}updateCursor(e,t,s,i){this.listOffset=e.getBoundingClientRect().top;let n=s.clientY-this.listOffset-this.cursorOffset;this.#e(e,t,n,i)}updateScroll(e,t,s){const i=this.listOffset;this.listOffset=e.getBoundingClientRect().top;const n=i-this.listOffset,a=this.position+n;this.#e(e,t,a,s)}#e(e,t,s,i){s=Math.max(s,0),s=Math.min(s,e.offsetHeight-t.offsetHeight),this.position=s;i(s-this.initialPosition)}}class s extends e{static outlets=["tables--selection--form"];static values={params:Object,checked:Boolean};tablesSelectionFormOutletConnected(e){e.visible(this.id,!0),this.checkedValue=e.isSelected(this.id)}disconnect(){this.hasTablesSelectionFormOutlet&&this.tablesSelectionFormOutlet.visible(this.id,!1)}change(e){e.preventDefault(),this.checkedValue=this.tablesSelectionFormOutlet.toggle(this.id)}get id(){return this.paramsValue.id}paramsValueChanged(e,t){this.hasTablesSelectionFormOutlet&&(t.id!==e.id&&this.tablesSelectionFormOutlet.visible(t.id,!1),this.tablesSelectionFormOutlet.visible(e.id,!0),this.checkedValue=this.tablesSelectionFormOutlet.isSelected(e.id),this.update())}checkedValueChanged(){this.hasTablesSelectionFormOutlet&&(this.checkedValue=this.tablesSelectionFormOutlet.isSelected(this.id),this.update())}async update(){return this.updating||=Promise.resolve().then((()=>{this.#t(),delete this.updating})),this.updating}#t(){this.element.querySelector("input").checked=this.checkedValue,this.dispatch("select",{detail:{id:this.id,selected:this.checkedValue}})}}class i{constructor(){this.tokens=[],this.values=null}parse(e){const t=new u(e);for(;!t.isEos();){this.push(this.skipWhitespace(t));const e=this.takeTagged(t)||this.takeUntagged(t);if(!this.push(e))break}return this}push(e){return e&&(this.values?this.values.push(e):this.tokens.push(e)),!!e}skipWhitespace(e){if(e.scan(/\s+/))return new n(e.matched(),e.position)}takeUntagged(e){if(e.scan(/\S+/))return new l(e.matched(),e.position)}takeTagged(e){if(!e.scan(/(\w+(?:\.\w+)?)(:\s*)/))return;const t=e.valueAt(1),s=e.valueAt(2),i=this.takeArrayValue(e)||this.takeSingleValue(e)||new n;return new r(t,s,i,e.position)}takeArrayValue(e){if(!e.scan(/\[\s*/))return;const t=new n(e.matched(),e.position),s=this.values=[];for(;!e.isEos()&&this.push(this.takeSingleValue(e))&&this.push(this.takeDelimiter(e)););e.scan(/\s*]/);const i=new n(e.matched(),e.position);return this.values=null,new o(t,s,i)}takeDelimiter(e){if(e.scan(/\s*,\s*/))return new n(e.matched(),e.position)}takeSingleValue(e){return this.takeQuotedValue(e)||this.takeUnquotedValue(e)}takeQuotedValue(e){if(e.scan(/"([^"]*)"/))return new a(e.matched(),e.position)}takeUnquotedValue(e){if(e.scan(/[^ \],]*/))return new a(e.matched(),e.position)}tokenAtPosition(e){return this.tokens.filter((e=>e instanceof r||e instanceof l)).find((t=>t.range.includes(e)))}}class n{constructor(e="",t){this.value=e,this.length=this.value.length,this.start=t-this.length,this.end=this.start+this.length,this.range=this.arrayRange(this.start,this.end)}render(){return document.createTextNode(this.value)}arrayRange(e,t){return Array.from({length:t-e+1},((t,s)=>e+s))}startOfValue(){return this.start}endOfValue(){return this.end}}class a extends n{render(){const e=document.createElement("span");return e.className="value",e.innerText=this.value,e}}class r extends n{constructor(e,t,s,i){super(),this.key=e,this.separator=t,this.value=s,this.length=e.length+t.length+s.value.length,this.start=i-this.length,this.end=this.start+this.length,this.range=this.arrayRange(this.start,this.end)}render(){const e=document.createElement("span");e.className="tag";const t=document.createElement("span");return t.className="key",t.innerText=this.key,e.appendChild(t),e.appendChild(document.createTextNode(this.separator)),e.appendChild(this.value.render()),e}startOfValue(){return this.value.startOfValue()}endOfValue(){return this.value.endOfValue()}}class l extends n{render(){const e=document.createElement("span");return e.className="untagged",e.innerText=this.value,e}}class o extends n{constructor(e,t,s){super(),this.start=e,this.values=t,this.end=s,this.range=this.arrayRange(e.start,s.range[s.length]),this.length=e.length+t.reduce(((e,t)=>e+t.length),0)+s.length}render(){const e=document.createElement("span");return e.className="array-values",e.appendChild(this.start.render()),this.values.forEach((t=>{const s=document.createElement("span");s.appendChild(t.render()),e.appendChild(s)})),e.appendChild(this.end.render()),e}startOfValue(){return this.start.start}endOfValue(){return this.end.end}}class u{constructor(e){this.input=e,this.position=0,this.last=null}isEos(){return this.position>=this.input.length}scan(e){const t=e.exec(this.input.substring(this.position));return 0===t?.index?(this.last=t,this.position+=t[0].length,!0):(this.last={},!1)}matched(){return this.last&&this.last[0]}valueAt(e){return this.last&&this.last[e]}}const h=[{identifier:"tables--orderable--item",controllerConstructor:class extends e{static values={params:Object};connect(){var e;this.index=(e=this.row,Array.from(e.parentElement.children).indexOf(e))}paramsValueChanged(e){this.id=e.id_value}dragUpdate(e){this.dragOffset=e,this.row.style.position="relative",this.row.style.top=e+"px",this.row.style.zIndex="1",this.row.toggleAttribute("dragging",!0)}updateVisually(e){this.row.style.position="relative",this.row.style.top=this.row.offsetHeight*(e-this.dragIndex)+"px"}updateIndex(e){this.index=e}params(e){const{id_name:t,id_value:s,index_name:i}=this.paramsValue;return[{name:`${e}[${s}][${t}]`,value:this.id},{name:`${e}[${s}][${i}]`,value:this.index}]}reset(){delete this.dragOffset,this.row.removeAttribute("style"),this.row.removeAttribute("dragging")}get hasChanges(){return this.paramsValue.index_value!==this.index}get dragIndex(){return this.dragOffset&&0!==this.dragOffset?this.index+Math.round(this.dragOffset/this.row.offsetHeight):this.index}get comparisonIndex(){return this.dragOffset?this.dragIndex+(this.dragOffset>0?.5:-.5):this.index}get row(){return this.element.parentElement}}},{identifier:"tables--orderable--list",controllerConstructor:class extends e{static outlets=["tables--orderable--item","tables--orderable--form"];startDragging(e){this.dragState=e,document.addEventListener("mousemove",this.mousemove),document.addEventListener("mouseup",this.mouseup),window.addEventListener("scroll",this.scroll,!0),this.element.style.position="relative"}stopDragging(){const e=this.dragState;return delete this.dragState,document.removeEventListener("mousemove",this.mousemove),document.removeEventListener("mouseup",this.mouseup),window.removeEventListener("scroll",this.scroll,!0),this.element.removeAttribute("style"),this.tablesOrderableItemOutlets.forEach((e=>e.reset())),e}drop(){const e=this.dragItem;if(!e)return;const t=e.dragIndex,s=this.tablesOrderableItemOutlets[t];s&&(t<e.index?s.row.insertAdjacentElement("beforebegin",e.row):t>e.index&&s.row.insertAdjacentElement("afterend",e.row),this.tablesOrderableItemOutlets.forEach(((e,t)=>e.updateIndex(t))),this.commitChanges())}commitChanges(){this.tablesOrderableFormOutlet.clear(),this.tablesOrderableItemOutlets.forEach((e=>{e.hasChanges&&this.tablesOrderableFormOutlet.add(e)})),this.tablesOrderableFormOutlet.submit()}mousedown(e){if(this.isDragging)return;const s=this.#s(e.target);s&&(e.preventDefault(),this.startDragging(new t(this.element,e,s.id)),this.dragState.updateCursor(this.element,s.row,e,this.animate))}mousemove=e=>{this.isDragging&&(e.preventDefault(),this.ticking||(this.ticking=!0,window.requestAnimationFrame((()=>{this.ticking=!1,this.dragState?.updateCursor(this.element,this.dragItem.row,e,this.animate)}))))};scroll=e=>{this.isDragging&&!this.ticking&&(this.ticking=!0,window.requestAnimationFrame((()=>{this.ticking=!1,this.dragState?.updateScroll(this.element,this.dragItem.row,this.animate)})))};mouseup=e=>{this.isDragging&&(this.drop(),this.stopDragging(),this.tablesOrderableFormOutlets.forEach((e=>delete e.dragState)))};tablesOrderableFormOutletConnected(e,t){e.dragState&&this.startDragging(e.dragState)}tablesOrderableFormOutletDisconnected(e,t){this.isDragging&&(e.dragState=this.stopDragging())}beforeMorphAttribute(e){switch(e.detail.attributeName){case"dragging":e.preventDefault();break;case"style":"TBODY"!==e.target.tagName&&"TR"!==e.target.tagName||e.preventDefault()}}animate=e=>{const t=this.dragItem;t.dragUpdate(e),this.#i.forEach(((e,s)=>{e!==t&&e.updateVisually(s)}))};get isDragging(){return!!this.dragState}get dragItem(){return this.isDragging?this.tablesOrderableItemOutlets.find((e=>e.id===this.dragState.targetId)):null}get#i(){return this.tablesOrderableItemOutlets.toSorted(((e,t)=>e.comparisonIndex-t.comparisonIndex))}#s(e){return this.tablesOrderableItemOutlets.find((t=>t.element===e))}}},{identifier:"tables--orderable--form",controllerConstructor:class extends e{static values={scope:String};add(e){e.params(this.scopeValue).forEach((({name:e,value:t})=>{this.element.insertAdjacentHTML("beforeend",`<input type="hidden" name="${e}" value="${t}" data-generated>`)}))}submit(){0!==this.inputs.length&&this.element.requestSubmit()}clear(){this.inputs.forEach((e=>e.remove()))}get inputs(){return this.element.querySelectorAll("input[data-generated]")}}},{identifier:"tables--selection--form",controllerConstructor:class extends e{static values={count:Number,primaryKey:{type:String,default:"id"}};static targets=["count","singular","plural"];connect(){this.countValue=this.inputs.length}toggle(e){const t=this.input(e);return t?t.remove():this.element.insertAdjacentHTML("beforeend",`<input type="hidden" name="${this.primaryKeyValue}[]" value="${e}">`),this.countValue=this.visibleInputs.length,!t}visible(e,t){const s=this.input(e);return s&&(s.disabled=!t),this.countValue=this.visibleInputs.length,!s}isSelected(e){return!!this.input(e)}get inputs(){return this.element.querySelectorAll(`input[name="${this.primaryKeyValue}[]"]`)}get visibleInputs(){return Array.from(this.inputs).filter((e=>!e.disabled))}input(e){return this.element.querySelector(`input[name="${this.primaryKeyValue}[]"][value="${e}"]`)}countValueChanged(e){this.element.toggleAttribute("hidden",0===e),this.countTarget.textContent=e,this.singularTarget.toggleAttribute("hidden",1!==e),this.pluralTarget.toggleAttribute("hidden",1===e)}}},{identifier:"tables--selection--item",controllerConstructor:s},{identifier:"tables--selection--table",controllerConstructor:class extends e{static targets=["header","item"];static outlets=["tables--selection--form"];itemTargetConnected(e){this.update()}itemTargetDisconnected(e){this.update()}toggleHeader(e){this.items.forEach((t=>{t.checkedValue!==e.target.checked&&(t.checkedValue=this.tablesSelectionFormOutlet.toggle(t.id))}))}async update(){return this.updating||=Promise.resolve().then((()=>{this.#t(),delete this.updating})),this.updating}#t(){let e=0,t=0;this.items.forEach((s=>{e++,s.checkedValue&&t++})),this.headerInput.checked=e>0&&t===e,this.headerInput.indeterminate=t>0&&t!==e}get headerInput(){return this.headerTarget.querySelector("input")}get items(){return this.itemTargets.map((e=>this.#n(e))).filter((e=>e))}#n(e){return this.application.getControllerForElementAndIdentifier(e,"tables--selection--item")}}},{identifier:"tables--query",controllerConstructor:class extends e{static targets=["modal"];disconnect(){delete this.pending,document.removeEventListener("selectionchange",this.selection)}focus(){document.activeElement!==this.query&&(this.query.addEventListener("focusin",(e=>{e.target.setSelectionRange(-1,-1)}),{once:!0}),this.query.focus())}closeModal(){delete this.modalTarget.dataset.open,this.query.setAttribute("aria-expanded",!1),document.activeElement===this.query&&document.activeElement.blur(),document.removeEventListener("selectionchange",this.selection)}openModal(){this.modalTarget.dataset.open=!0,this.query.setAttribute("aria-expanded",!0),document.addEventListener("selectionchange",this.selection)}clear(){""===this.query.value?this.closeModal():(this.query.value="",this.query.dispatchEvent(new Event("input")),this.query.dispatchEvent(new Event("change")),this.update())}submit(){const e=this.isFocused,t=e&&this.query.selectionStart;this.pending&&(clearTimeout(this.pending),delete this.pending),e&&""!==this.query.value?(this.position.value=t,this.position.disabled=!1):(this.position.value="",this.position.disabled=!0),""===this.query.value&&(this.query.disabled=!0,setTimeout((()=>{this.query.disabled=!1,this.position.disabled=!1,e&&this.query.focus()}),0))}update=()=>{this.pending&&clearTimeout(this.pending),this.pending=setTimeout((()=>{this.element.requestSubmit()}),300)};selection=()=>{this.isFocused&&this.query.value.length>0&&this.update()};beforeMorphAttribute(e){if("data-open"===e.detail.attributeName)e.preventDefault()}moveToPreviousSuggestion(){const e=this.previousSuggestion||this.lastSuggestion;e&&this.makeSuggestionActive(e)}moveToNextSuggestion(){const e=this.nextSuggestion||this.firstSuggestion;e&&this.makeSuggestionActive(e)}selectFirstSuggestion(e){e.preventDefault(),this.firstSuggestion?.dispatchEvent(new CustomEvent("query:select"))}selectActiveSuggestion(){this.activeSuggestion?this.activeSuggestion.dispatchEvent(new CustomEvent("query:select")):this.closeModal()}selectSuggestion(e){this.query.dispatchEvent(new CustomEvent("replaceToken",{detail:{token:e.params.value,position:this.query.selectionStart}})),this.clearActiveSuggestion()}makeSuggestionActive(e){this.activeSuggestion&&this.activeSuggestion.setAttribute("aria-selected","false"),this.query.setAttribute("aria-activedescendant",e.id),e.setAttribute("aria-selected","true")}clearActiveSuggestion(){this.activeSuggestion&&(this.activeSuggestion.setAttribute("aria-selected","false"),this.query.removeAttribute("aria-activedescendant"))}get activeSuggestion(){return this.modalTarget.querySelector(`#${this.query.getAttribute("aria-activedescendant")}`)}get previousSuggestion(){return this.activeSuggestion?.previousElementSibling}get nextSuggestion(){return this.activeSuggestion?.nextElementSibling}get firstSuggestion(){return this.modalTarget.querySelector("#suggestions li:first-of-type")}get lastSuggestion(){return this.modalTarget.querySelector("#suggestions li:last-of-type")}get query(){return this.element.querySelector("[role=combobox]")}get position(){return this.element.querySelector("input[name=p]")}get isFocused(){return this.query===document.activeElement}}},{identifier:"tables--query-input",controllerConstructor:class extends e{static targets=["input","highlight"];static values={query:String};connect(){this.queryValue=this.inputTarget.value,this.element.dataset.connected=""}disconnect(){delete this.element.dataset.connected}update(){this.queryValue=this.inputTarget.value}queryValueChanged(e){this.highlightTarget.innerHTML="",(new i).parse(e).tokens.forEach((e=>{this.highlightTarget.appendChild(e.render())}))}replaceToken(e){let t=e.detail.token.toString();/\s/.exec(t)&&(t=`"${t}"`);const s=e.detail.position;let n=s+t.length,a=s,r=s;const l=(new i).parse(this.queryValue).tokenAtPosition(s);l&&(t=t.trim(),a=l.startOfValue(),r=l.endOfValue(),n=a+t.length),this.inputTarget.value=this.queryValue.slice(0,a)+t+this.queryValue.slice(r),this.update(),this.inputTarget.focus(),this.inputTarget.setSelectionRange(n,n)}}}];export{h as default};
1
+ import{Controller as e}from"@hotwired/stimulus";class t{constructor(e,t,s){this.cursorOffset=t.offsetY,this.initialPosition=t.target.offsetTop-e.offsetTop,this.targetId=s}updateCursor(e,t,s,i){this.listOffset=e.getBoundingClientRect().top;let n=s.clientY-this.listOffset-this.cursorOffset;this.#e(e,t,n,i)}updateScroll(e,t,s){const i=this.listOffset;this.listOffset=e.getBoundingClientRect().top;const n=i-this.listOffset,r=this.position+n;this.#e(e,t,r,s)}#e(e,t,s,i){s=Math.max(s,0),s=Math.min(s,e.offsetHeight-t.offsetHeight),this.position=s;i(s-this.initialPosition)}}class s extends e{static outlets=["tables--selection--form"];static values={params:Object,checked:Boolean};tablesSelectionFormOutletConnected(e){e.visible(this.id,!0),this.checkedValue=e.isSelected(this.id)}disconnect(){this.hasTablesSelectionFormOutlet&&this.tablesSelectionFormOutlet.visible(this.id,!1)}change(e){e.preventDefault(),this.checkedValue=this.tablesSelectionFormOutlet.toggle(this.id)}get id(){return this.paramsValue.id}paramsValueChanged(e,t){this.hasTablesSelectionFormOutlet&&(t.id!==e.id&&this.tablesSelectionFormOutlet.visible(t.id,!1),this.tablesSelectionFormOutlet.visible(e.id,!0),this.checkedValue=this.tablesSelectionFormOutlet.isSelected(e.id),this.update())}checkedValueChanged(){this.hasTablesSelectionFormOutlet&&(this.checkedValue=this.tablesSelectionFormOutlet.isSelected(this.id),this.update())}async update(){return this.updating||=Promise.resolve().then((()=>{this.#t(),delete this.updating})),this.updating}#t(){this.element.querySelector("input").checked=this.checkedValue,this.dispatch("select",{detail:{id:this.id,selected:this.checkedValue}})}}class i{constructor(){this.tokens=[],this.values=null}parse(e){const t=new u(e);for(;!t.isEos();){this.push(this.skipWhitespace(t));const e=this.takeTagged(t)||this.takeUntagged(t);if(!this.push(e))break}return this}push(e){return e&&(this.values?this.values.push(e):this.tokens.push(e)),!!e}skipWhitespace(e){if(e.scan(/\s+/))return new n(e.matched(),e.position)}takeUntagged(e){if(e.scan(/\S+/))return new l(e.matched(),e.position)}takeTagged(e){if(!e.scan(/(\w+(?:\.\w+)?)(:\s*)/))return;const t=e.valueAt(1),s=e.valueAt(2),i=this.takeArrayValue(e)||this.takeSingleValue(e)||new n;return new a(t,s,i,e.position)}takeArrayValue(e){if(!e.scan(/\[\s*/))return;const t=new n(e.matched(),e.position),s=this.values=[];for(;!e.isEos()&&this.push(this.takeSingleValue(e))&&this.push(this.takeDelimiter(e)););e.scan(/\s*]/);const i=new n(e.matched(),e.position);return this.values=null,new o(t,s,i)}takeDelimiter(e){if(e.scan(/\s*,\s*/))return new n(e.matched(),e.position)}takeSingleValue(e){return this.takeQuotedValue(e)||this.takeUnquotedValue(e)}takeQuotedValue(e){if(e.scan(/"([^"]*)"/))return new r(e.matched(),e.position)}takeUnquotedValue(e){if(e.scan(/[^ \],]*/))return new r(e.matched(),e.position)}tokenAtPosition(e){return this.tokens.filter((e=>e instanceof a||e instanceof l)).find((t=>t.range.includes(e)))}}class n{constructor(e="",t){this.value=e,this.length=this.value.length,this.start=t-this.length,this.end=this.start+this.length,this.range=this.arrayRange(this.start,this.end)}render(){return document.createTextNode(this.value)}arrayRange(e,t){return Array.from({length:t-e+1},((t,s)=>e+s))}startOfValue(){return this.start}endOfValue(){return this.end}}class r extends n{render(){const e=document.createElement("span");return e.className="value",e.innerText=this.value,e}}class a extends n{constructor(e,t,s,i){super(),this.key=e,this.separator=t,this.value=s,this.length=e.length+t.length+s.value.length,this.start=i-this.length,this.end=this.start+this.length,this.range=this.arrayRange(this.start,this.end)}render(){const e=document.createElement("span");e.className="tag";const t=document.createElement("span");return t.className="key",t.innerText=this.key,e.appendChild(t),e.appendChild(document.createTextNode(this.separator)),e.appendChild(this.value.render()),e}startOfValue(){return this.value.startOfValue()}endOfValue(){return this.value.endOfValue()}}class l extends n{render(){const e=document.createElement("span");return e.className="untagged",e.innerText=this.value,e}}class o extends n{constructor(e,t,s){super(),this.start=e,this.values=t,this.end=s,this.range=this.arrayRange(e.start,s.range[s.length]),this.length=e.length+t.reduce(((e,t)=>e+t.length),0)+s.length}render(){const e=document.createElement("span");return e.className="array-values",e.appendChild(this.start.render()),this.values.forEach((t=>{const s=document.createElement("span");s.appendChild(t.render()),e.appendChild(s)})),e.appendChild(this.end.render()),e}startOfValue(){return this.start.start}endOfValue(){return this.end.end}}class u{constructor(e){this.input=e,this.position=0,this.last=null}isEos(){return this.position>=this.input.length}scan(e){const t=e.exec(this.input.substring(this.position));return 0===t?.index?(this.last=t,this.position+=t[0].length,!0):(this.last={},!1)}matched(){return this.last&&this.last[0]}valueAt(e){return this.last&&this.last[e]}}const h=[{identifier:"tables--orderable--item",controllerConstructor:class extends e{static values={params:Object};connect(){var e;this.index=(e=this.row,Array.from(e.parentElement.children).indexOf(e))}paramsValueChanged(e){this.id=e.id_value}dragUpdate(e){this.dragOffset=e,this.row.style.position="relative",this.row.style.top=e+"px",this.row.style.zIndex="1",this.row.toggleAttribute("dragging",!0)}updateVisually(e){this.row.style.position="relative",this.row.style.top=this.row.offsetHeight*(e-this.dragIndex)+"px"}updateIndex(e){this.index=e}params(e){const{id_name:t,id_value:s,index_name:i}=this.paramsValue;return[{name:`${e}[${s}][${t}]`,value:this.id},{name:`${e}[${s}][${i}]`,value:this.index}]}reset(){delete this.dragOffset,this.row.removeAttribute("style"),this.row.removeAttribute("dragging")}get hasChanges(){return this.paramsValue.index_value!==this.index}get dragIndex(){return this.dragOffset&&0!==this.dragOffset?this.index+Math.round(this.dragOffset/this.row.offsetHeight):this.index}get comparisonIndex(){return this.dragOffset?this.dragIndex+(this.dragOffset>0?.5:-.5):this.index}get row(){return this.element.parentElement}}},{identifier:"tables--orderable--list",controllerConstructor:class extends e{static outlets=["tables--orderable--item","tables--orderable--form"];startDragging(e){this.dragState=e,document.addEventListener("mousemove",this.mousemove),document.addEventListener("mouseup",this.mouseup),window.addEventListener("scroll",this.scroll,!0),this.element.style.position="relative"}stopDragging(){const e=this.dragState;return delete this.dragState,document.removeEventListener("mousemove",this.mousemove),document.removeEventListener("mouseup",this.mouseup),window.removeEventListener("scroll",this.scroll,!0),this.element.removeAttribute("style"),this.tablesOrderableItemOutlets.forEach((e=>e.reset())),e}drop(){const e=this.dragItem;if(!e)return;const t=e.dragIndex,s=this.tablesOrderableItemOutlets[t];s&&(t<e.index?s.row.insertAdjacentElement("beforebegin",e.row):t>e.index&&s.row.insertAdjacentElement("afterend",e.row),this.tablesOrderableItemOutlets.forEach(((e,t)=>e.updateIndex(t))),this.commitChanges())}commitChanges(){this.tablesOrderableFormOutlet.clear(),this.tablesOrderableItemOutlets.forEach((e=>{e.hasChanges&&this.tablesOrderableFormOutlet.add(e)})),this.tablesOrderableFormOutlet.submit()}mousedown(e){if(this.isDragging)return;const s=this.#s(e.target);s&&(e.preventDefault(),this.startDragging(new t(this.element,e,s.id)),this.dragState.updateCursor(this.element,s.row,e,this.animate))}mousemove=e=>{this.isDragging&&(e.preventDefault(),this.ticking||(this.ticking=!0,window.requestAnimationFrame((()=>{this.ticking=!1,this.dragState?.updateCursor(this.element,this.dragItem.row,e,this.animate)}))))};scroll=e=>{this.isDragging&&!this.ticking&&(this.ticking=!0,window.requestAnimationFrame((()=>{this.ticking=!1,this.dragState?.updateScroll(this.element,this.dragItem.row,this.animate)})))};mouseup=e=>{this.isDragging&&(this.drop(),this.stopDragging(),this.tablesOrderableFormOutlets.forEach((e=>delete e.dragState)))};tablesOrderableFormOutletConnected(e,t){e.dragState&&this.startDragging(e.dragState)}tablesOrderableFormOutletDisconnected(e,t){this.isDragging&&(e.dragState=this.stopDragging())}beforeMorphElement(e){this.isDragging&&e.preventDefault()}animate=e=>{const t=this.dragItem;t.dragUpdate(e),this.#i.forEach(((e,s)=>{e!==t&&e.updateVisually(s)}))};get isDragging(){return!!this.dragState}get dragItem(){return this.isDragging?this.tablesOrderableItemOutlets.find((e=>e.id===this.dragState.targetId)):null}get#i(){return this.tablesOrderableItemOutlets.toSorted(((e,t)=>e.comparisonIndex-t.comparisonIndex))}#s(e){return this.tablesOrderableItemOutlets.find((t=>t.element===e))}}},{identifier:"tables--orderable--form",controllerConstructor:class extends e{static values={scope:String};add(e){e.params(this.scopeValue).forEach((({name:e,value:t})=>{this.element.insertAdjacentHTML("beforeend",`<input type="hidden" name="${e}" value="${t}" data-generated>`)}))}submit(){0!==this.inputs.length&&this.element.requestSubmit()}clear(){this.inputs.forEach((e=>e.remove()))}get inputs(){return this.element.querySelectorAll("input[data-generated]")}}},{identifier:"tables--selection--form",controllerConstructor:class extends e{static values={count:Number,primaryKey:{type:String,default:"id"}};static targets=["count","singular","plural"];connect(){this.countValue=this.inputs.length}toggle(e){const t=this.input(e);return t?t.remove():this.element.insertAdjacentHTML("beforeend",`<input type="hidden" name="${this.primaryKeyValue}[]" value="${e}">`),this.countValue=this.visibleInputs.length,!t}visible(e,t){const s=this.input(e);return s&&(s.disabled=!t),this.countValue=this.visibleInputs.length,!s}isSelected(e){return!!this.input(e)}get inputs(){return this.element.querySelectorAll(`input[name="${this.primaryKeyValue}[]"]`)}get visibleInputs(){return Array.from(this.inputs).filter((e=>!e.disabled))}input(e){return this.element.querySelector(`input[name="${this.primaryKeyValue}[]"][value="${e}"]`)}countValueChanged(e){this.element.toggleAttribute("hidden",0===e),this.countTarget.textContent=e,this.singularTarget.toggleAttribute("hidden",1!==e),this.pluralTarget.toggleAttribute("hidden",1===e)}}},{identifier:"tables--selection--item",controllerConstructor:s},{identifier:"tables--selection--table",controllerConstructor:class extends e{static targets=["header","item"];static outlets=["tables--selection--form"];itemTargetConnected(e){this.update()}itemTargetDisconnected(e){this.update()}toggleHeader(e){this.items.forEach((t=>{t.checkedValue!==e.target.checked&&(t.checkedValue=this.tablesSelectionFormOutlet.toggle(t.id))}))}async update(){return this.updating||=Promise.resolve().then((()=>{this.#t(),delete this.updating})),this.updating}#t(){let e=0,t=0;this.items.forEach((s=>{e++,s.checkedValue&&t++})),this.headerInput.checked=e>0&&t===e,this.headerInput.indeterminate=t>0&&t!==e}get headerInput(){return this.headerTarget.querySelector("input")}get items(){return this.itemTargets.map((e=>this.#n(e))).filter((e=>e))}#n(e){return this.application.getControllerForElementAndIdentifier(e,"tables--selection--item")}}},{identifier:"tables--query",controllerConstructor:class extends e{static targets=["modal"];disconnect(){delete this.pending,document.removeEventListener("selectionchange",this.selection)}focus(){document.activeElement!==this.query&&(this.query.addEventListener("focusin",(e=>{e.target.setSelectionRange(-1,-1)}),{once:!0}),this.query.focus())}closeModal(){delete this.modalTarget.dataset.open,this.query.setAttribute("aria-expanded",!1),document.activeElement===this.query&&document.activeElement.blur(),document.removeEventListener("selectionchange",this.selection)}openModal(){this.modalTarget.dataset.open=!0,this.query.setAttribute("aria-expanded",!0),document.addEventListener("selectionchange",this.selection)}clear(){""===this.query.value?this.closeModal():(this.query.value="",this.query.dispatchEvent(new Event("input")),this.query.dispatchEvent(new Event("change")),this.update())}submit(){const e=this.isFocused,t=e&&this.query.selectionStart;this.pending&&(clearTimeout(this.pending),delete this.pending),e&&""!==this.query.value?(this.position.value=t,this.position.disabled=!1):(this.position.value="",this.position.disabled=!0),""===this.query.value&&(this.query.disabled=!0,setTimeout((()=>{this.query.disabled=!1,this.position.disabled=!1,e&&this.query.focus()}),0))}update=()=>{this.pending&&clearTimeout(this.pending),this.pending=setTimeout((()=>{this.element.requestSubmit()}),300)};selection=()=>{this.isFocused&&this.query.value.length>0&&this.update()};beforeMorphAttribute(e){if("data-open"===e.detail.attributeName)e.preventDefault()}moveToPreviousSuggestion(){const e=this.previousSuggestion||this.lastSuggestion;e&&this.makeSuggestionActive(e)}moveToNextSuggestion(){const e=this.nextSuggestion||this.firstSuggestion;e&&this.makeSuggestionActive(e)}selectFirstSuggestion(e){e.preventDefault(),this.firstSuggestion?.dispatchEvent(new CustomEvent("query:select"))}selectActiveSuggestion(){this.activeSuggestion?this.activeSuggestion.dispatchEvent(new CustomEvent("query:select")):this.closeModal()}selectSuggestion(e){this.query.dispatchEvent(new CustomEvent("replaceToken",{detail:{token:e.params.value,position:this.query.selectionStart}})),this.clearActiveSuggestion()}makeSuggestionActive(e){this.activeSuggestion&&this.activeSuggestion.setAttribute("aria-selected","false"),this.query.setAttribute("aria-activedescendant",e.id),e.setAttribute("aria-selected","true")}clearActiveSuggestion(){this.activeSuggestion&&(this.activeSuggestion.setAttribute("aria-selected","false"),this.query.removeAttribute("aria-activedescendant"))}get activeSuggestion(){return this.modalTarget.querySelector(`#${this.query.getAttribute("aria-activedescendant")}`)}get previousSuggestion(){return this.activeSuggestion?.previousElementSibling}get nextSuggestion(){return this.activeSuggestion?.nextElementSibling}get firstSuggestion(){return this.modalTarget.querySelector("#suggestions li:first-of-type")}get lastSuggestion(){return this.modalTarget.querySelector("#suggestions li:last-of-type")}get query(){return this.element.querySelector("[role=combobox]")}get position(){return this.element.querySelector("input[name=p]")}get isFocused(){return this.query===document.activeElement}}},{identifier:"tables--query-input",controllerConstructor:class extends e{static targets=["input","highlight"];static values={query:String};connect(){this.queryValue=this.inputTarget.value,this.element.dataset.connected=""}disconnect(){delete this.element.dataset.connected}update(){this.queryValue=this.inputTarget.value}queryValueChanged(e){this.highlightTarget.innerHTML="",(new i).parse(e).tokens.forEach((e=>{this.highlightTarget.appendChild(e.render())}))}replaceToken(e){let t=e.detail.token.toString();/\s/.exec(t)&&(t=`"${t}"`);const s=e.detail.position;let n=s+t.length,r=s,a=s;const l=(new i).parse(this.queryValue).tokenAtPosition(s);l&&(t=t.trim(),r=l.startOfValue(),a=l.endOfValue(),n=r+t.length),this.inputTarget.value=this.queryValue.slice(0,r)+t+this.queryValue.slice(a),this.update(),this.inputTarget.focus(),this.inputTarget.setSelectionRange(n,n)}}}];export{h as default};
2
2
  //# sourceMappingURL=tables.min.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"tables.min.js","sources":["../../../javascript/tables/orderable/list_controller.js","../../../javascript/tables/selection/item_controller.js","../../../javascript/tables/query_input_controller.js","../../../javascript/tables/application.js","../../../javascript/tables/orderable/item_controller.js","../../../javascript/tables/orderable/form_controller.js","../../../javascript/tables/selection/form_controller.js","../../../javascript/tables/selection/table_controller.js","../../../javascript/tables/query_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 beforeMorphAttribute(e) {\n switch (e.detail.attributeName) {\n case \"dragging\": // set to track the item being dragged\n e.preventDefault();\n break;\n case \"style\": // used to animate rows moving up and down\n if (e.target.tagName === \"TBODY\" || e.target.tagName === \"TR\") {\n e.preventDefault();\n }\n break;\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 { Controller } from \"@hotwired/stimulus\";\n\n/**\n * Couples an input element in a row to the selection form which is turbo-permanent and outside the table.\n * When the input is toggled, the form will create/destroy hidden inputs. The checkbox inside this cell will follow\n * the hidden inputs.\n *\n * Cell value may change when:\n * * cell connects, e.g. when the user paginates\n * * cell is re-used by turbo-morph, e.g. pagination\n * * cell is toggled\n * * select-all/de-select-all on table header\n */\nexport default class SelectionItemController extends Controller {\n static outlets = [\"tables--selection--form\"];\n static values = {\n params: Object,\n checked: Boolean,\n };\n\n tablesSelectionFormOutletConnected(form) {\n form.visible(this.id, true);\n this.checkedValue = form.isSelected(this.id);\n }\n\n disconnect() {\n // Remove from form's list of visible selections.\n // This should be an outlet disconnect, but those events are not reliable in turbo 8.0\n if (this.hasTablesSelectionFormOutlet) {\n this.tablesSelectionFormOutlet.visible(this.id, false);\n }\n }\n\n change(e) {\n e.preventDefault();\n\n this.checkedValue = this.tablesSelectionFormOutlet.toggle(this.id);\n }\n\n get id() {\n return this.paramsValue.id;\n }\n\n /**\n * Update checked to match match selection form. This occurs when the item is re-used by turbo-morph.\n */\n paramsValueChanged(params, previous) {\n if (!this.hasTablesSelectionFormOutlet) return;\n\n // if id is changing (e.g. morph) then let the form know that the previous id is now not visible\n if (previous.id !== params.id) {\n this.tablesSelectionFormOutlet.visible(previous.id, false);\n }\n\n // tell form that our id is now visible in the table\n this.tablesSelectionFormOutlet.visible(params.id, true);\n\n // id has changed, so update checked from form\n this.checkedValue = this.tablesSelectionFormOutlet.isSelected(params.id);\n\n // propagate changes\n this.update();\n }\n\n /**\n * Update input to match checked. This occurs when the item is toggled, connected, or morphed.\n */\n checkedValueChanged() {\n if (!this.hasTablesSelectionFormOutlet) return;\n\n // ensure that checked matches the form, i.e. if morphed\n this.checkedValue = this.tablesSelectionFormOutlet.isSelected(this.id);\n\n // propagate changes\n this.update();\n }\n\n /**\n * Notify table that id or value may have changed. Note that this may fire when nothing has changed.\n *\n * Debouncing to minimise dom updates.\n */\n async update() {\n this.updating ||= Promise.resolve().then(() => {\n this.#update();\n delete this.updating;\n });\n\n return this.updating;\n }\n\n #update() {\n this.element.querySelector(\"input\").checked = this.checkedValue;\n this.dispatch(\"select\", {\n detail: { id: this.id, selected: this.checkedValue },\n });\n }\n}\n","import { Controller } from \"@hotwired/stimulus\";\n\nexport default class QueryInputController extends Controller {\n static targets = [\"input\", \"highlight\"];\n static values = { query: String };\n\n connect() {\n this.queryValue = this.inputTarget.value;\n this.element.dataset.connected = \"\";\n }\n\n disconnect() {\n delete this.element.dataset.connected;\n }\n\n update() {\n this.queryValue = this.inputTarget.value;\n }\n\n queryValueChanged(query) {\n this.highlightTarget.innerHTML = \"\";\n\n new Parser().parse(query).tokens.forEach((token) => {\n this.highlightTarget.appendChild(token.render());\n });\n }\n\n replaceToken(e) {\n let tokenToAdd = e.detail.token.toString();\n\n // wrap in quotes if it contains a spaces or special characters\n if (/\\s/.exec(tokenToAdd)) {\n tokenToAdd = `\"${tokenToAdd}\"`;\n }\n\n const indexPosition = e.detail.position;\n let caretPosition = indexPosition + tokenToAdd.length;\n let sliceStart = indexPosition;\n let sliceEnd = indexPosition;\n\n // detect if position has a token already, if so, replace it\n const existingToken = new Parser()\n .parse(this.queryValue)\n .tokenAtPosition(indexPosition);\n if (existingToken) {\n // We don't want to include the trailing space as we are replacing an existing value\n tokenToAdd = tokenToAdd.trim();\n\n // Slice up to the beginning of the tokens value (not the initial caret position)\n sliceStart = existingToken.startOfValue();\n\n // Slice after the end of the tokens value\n sliceEnd = existingToken.endOfValue();\n\n // The end position of the newly added token\n caretPosition = sliceStart + tokenToAdd.length;\n }\n\n // Replace any text within sliceStart and sliceEnd with tokenToAdd\n this.inputTarget.value =\n this.queryValue.slice(0, sliceStart) +\n tokenToAdd +\n this.queryValue.slice(sliceEnd);\n\n // Re focus the input at the end of the newly added token\n this.update();\n this.inputTarget.focus();\n this.inputTarget.setSelectionRange(caretPosition, caretPosition);\n }\n}\n\nclass Parser {\n constructor() {\n this.tokens = [];\n this.values = null;\n }\n\n parse(input) {\n const query = new StringScanner(input);\n\n while (!query.isEos()) {\n this.push(this.skipWhitespace(query));\n\n const value = this.takeTagged(query) || this.takeUntagged(query);\n\n if (!this.push(value)) break;\n }\n\n return this;\n }\n\n push(token) {\n if (token) {\n this.values ? this.values.push(token) : this.tokens.push(token);\n }\n\n return !!token;\n }\n\n skipWhitespace(query) {\n if (!query.scan(/\\s+/)) return;\n\n return new Token(query.matched(), query.position);\n }\n\n takeUntagged(query) {\n if (!query.scan(/\\S+/)) return;\n\n return new Untagged(query.matched(), query.position);\n }\n\n takeTagged(query) {\n if (!query.scan(/(\\w+(?:\\.\\w+)?)(:\\s*)/)) return;\n\n const key = query.valueAt(1);\n const separator = query.valueAt(2);\n\n const value =\n this.takeArrayValue(query) || this.takeSingleValue(query) || new Token();\n\n return new Tagged(key, separator, value, query.position);\n }\n\n takeArrayValue(query) {\n if (!query.scan(/\\[\\s*/)) return;\n\n const start = new Token(query.matched(), query.position);\n const values = (this.values = []);\n\n while (!query.isEos()) {\n if (!this.push(this.takeSingleValue(query))) break;\n if (!this.push(this.takeDelimiter(query))) break;\n }\n\n query.scan(/\\s*]/);\n const end = new Token(query.matched(), query.position);\n\n this.values = null;\n\n return new ArrayToken(start, values, end);\n }\n\n takeDelimiter(query) {\n if (!query.scan(/\\s*,\\s*/)) return;\n\n return new Token(query.matched(), query.position);\n }\n\n takeSingleValue(query) {\n return this.takeQuotedValue(query) || this.takeUnquotedValue(query);\n }\n\n takeQuotedValue(query) {\n if (!query.scan(/\"([^\"]*)\"/)) return;\n\n return new Value(query.matched(), query.position);\n }\n\n takeUnquotedValue(query) {\n if (!query.scan(/[^ \\],]*/)) return;\n\n return new Value(query.matched(), query.position);\n }\n\n tokenAtPosition(position) {\n return this.tokens\n .filter((t) => t instanceof Tagged || t instanceof Untagged)\n .find((t) => t.range.includes(position));\n }\n}\n\nclass Token {\n constructor(value = \"\", position) {\n this.value = value;\n this.length = this.value.length;\n this.start = position - this.length;\n this.end = this.start + this.length;\n this.range = this.arrayRange(this.start, this.end);\n }\n\n render() {\n return document.createTextNode(this.value);\n }\n\n arrayRange(start, stop) {\n return Array.from(\n { length: stop - start + 1 },\n (value, index) => start + index,\n );\n }\n\n startOfValue() {\n return this.start;\n }\n\n endOfValue() {\n return this.end;\n }\n}\n\nclass Value extends Token {\n render() {\n const span = document.createElement(\"span\");\n span.className = \"value\";\n span.innerText = this.value;\n\n return span;\n }\n}\n\nclass Tagged extends Token {\n constructor(key, separator, value, position) {\n super();\n\n this.key = key;\n this.separator = separator;\n this.value = value;\n this.length = key.length + separator.length + value.value.length;\n this.start = position - this.length;\n this.end = this.start + this.length;\n this.range = this.arrayRange(this.start, this.end);\n }\n\n render() {\n const span = document.createElement(\"span\");\n span.className = \"tag\";\n\n const key = document.createElement(\"span\");\n key.className = \"key\";\n key.innerText = this.key;\n\n span.appendChild(key);\n span.appendChild(document.createTextNode(this.separator));\n span.appendChild(this.value.render());\n\n return span;\n }\n\n startOfValue() {\n return this.value.startOfValue();\n }\n\n endOfValue() {\n return this.value.endOfValue();\n }\n}\n\nclass Untagged extends Token {\n render() {\n const span = document.createElement(\"span\");\n span.className = \"untagged\";\n span.innerText = this.value;\n return span;\n }\n}\n\nclass ArrayToken extends Token {\n constructor(start, values, end) {\n super();\n\n this.start = start;\n this.values = values;\n this.end = end;\n this.range = this.arrayRange(start.start, end.range[end.length]);\n this.length =\n start.length +\n values.reduce((length, value) => length + value.length, 0) +\n end.length;\n }\n\n render() {\n const array = document.createElement(\"span\");\n array.className = \"array-values\";\n array.appendChild(this.start.render());\n\n this.values.forEach((value) => {\n const span = document.createElement(\"span\");\n span.appendChild(value.render());\n array.appendChild(span);\n });\n\n array.appendChild(this.end.render());\n\n return array;\n }\n\n startOfValue() {\n return this.start.start;\n }\n\n endOfValue() {\n return this.end.end;\n }\n}\n\nclass StringScanner {\n constructor(input) {\n this.input = input;\n this.position = 0;\n this.last = null;\n }\n\n isEos() {\n return this.position >= this.input.length;\n }\n\n scan(regex) {\n const match = regex.exec(this.input.substring(this.position));\n if (match?.index === 0) {\n this.last = match;\n this.position += match[0].length;\n return true;\n } else {\n this.last = {};\n return false;\n }\n }\n\n matched() {\n return this.last && this.last[0];\n }\n\n valueAt(index) {\n return this.last && this.last[index];\n }\n}\n","import OrderableItemController from \"./orderable/item_controller\";\nimport OrderableListController from \"./orderable/list_controller\";\nimport OrderableFormController from \"./orderable/form_controller\";\nimport SelectionFormController from \"./selection/form_controller\";\nimport SelectionItemController from \"./selection/item_controller\";\nimport SelectionTableController from \"./selection/table_controller\";\nimport QueryController from \"./query_controller\";\nimport QueryInputController from \"./query_input_controller\";\n\nconst Definitions = [\n {\n identifier: \"tables--orderable--item\",\n controllerConstructor: OrderableItemController,\n },\n {\n identifier: \"tables--orderable--list\",\n controllerConstructor: OrderableListController,\n },\n {\n identifier: \"tables--orderable--form\",\n controllerConstructor: OrderableFormController,\n },\n {\n identifier: \"tables--selection--form\",\n controllerConstructor: SelectionFormController,\n },\n {\n identifier: \"tables--selection--item\",\n controllerConstructor: SelectionItemController,\n },\n {\n identifier: \"tables--selection--table\",\n controllerConstructor: SelectionTableController,\n },\n {\n identifier: \"tables--query\",\n controllerConstructor: QueryController,\n },\n {\n identifier: \"tables--query-input\",\n controllerConstructor: QueryInputController,\n },\n];\n\nexport { Definitions as default };\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 /** Retrieve params for use in the form */\n params(scope) {\n const { id_name, id_value, index_name } = this.paramsValue;\n return [\n { name: `${scope}[${id_value}][${id_name}]`, value: this.id },\n { name: `${scope}[${id_value}][${index_name}]`, value: this.index },\n ];\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 static values = { scope: String };\n\n add(item) {\n item.params(this.scopeValue).forEach(({ name, value }) => {\n this.element.insertAdjacentHTML(\n \"beforeend\",\n `<input type=\"hidden\" name=\"${name}\" value=\"${value}\" data-generated>`,\n );\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","import { Controller } from \"@hotwired/stimulus\";\n\nexport default class SelectionFormController extends Controller {\n static values = {\n count: Number,\n primaryKey: { type: String, default: \"id\" },\n };\n static targets = [\"count\", \"singular\", \"plural\"];\n\n connect() {\n this.countValue = this.inputs.length;\n }\n\n /**\n * @param id to toggle\n * @return {boolean} true if selected, false if unselected\n */\n toggle(id) {\n const input = this.input(id);\n\n if (input) {\n input.remove();\n } else {\n this.element.insertAdjacentHTML(\n \"beforeend\",\n `<input type=\"hidden\" name=\"${this.primaryKeyValue}[]\" value=\"${id}\">`,\n );\n }\n\n this.countValue = this.visibleInputs.length;\n\n return !input;\n }\n\n /**\n * @param id to toggle visibility\n * @return {boolean} true if visible, false if not visible\n */\n visible(id, visible) {\n const input = this.input(id);\n\n if (input) {\n input.disabled = !visible;\n }\n\n this.countValue = this.visibleInputs.length;\n\n return !input;\n }\n\n /**\n * @returns {boolean} true if the given id is currently selected\n */\n isSelected(id) {\n return !!this.input(id);\n }\n\n get inputs() {\n return this.element.querySelectorAll(\n `input[name=\"${this.primaryKeyValue}[]\"]`,\n );\n }\n\n get visibleInputs() {\n return Array.from(this.inputs).filter((i) => !i.disabled);\n }\n\n input(id) {\n return this.element.querySelector(\n `input[name=\"${this.primaryKeyValue}[]\"][value=\"${id}\"]`,\n );\n }\n\n countValueChanged(count) {\n this.element.toggleAttribute(\"hidden\", count === 0);\n this.countTarget.textContent = count;\n this.singularTarget.toggleAttribute(\"hidden\", count !== 1);\n this.pluralTarget.toggleAttribute(\"hidden\", count === 1);\n }\n}\n","import { Controller } from \"@hotwired/stimulus\";\n\nexport default class SelectionTableController extends Controller {\n static targets = [\"header\", \"item\"];\n static outlets = [\"tables--selection--form\"];\n\n itemTargetConnected(item) {\n this.update();\n }\n\n itemTargetDisconnected(item) {\n this.update();\n }\n\n toggleHeader(e) {\n this.items.forEach((item) => {\n if (item.checkedValue === e.target.checked) return;\n\n item.checkedValue = this.tablesSelectionFormOutlet.toggle(item.id);\n });\n }\n\n async update() {\n this.updating ||= Promise.resolve().then(() => {\n this.#update();\n delete this.updating;\n });\n\n return this.updating;\n }\n\n #update() {\n let present = 0;\n let checked = 0;\n\n this.items.forEach((item) => {\n present++;\n if (item.checkedValue) checked++;\n });\n\n this.headerInput.checked = present > 0 && checked === present;\n this.headerInput.indeterminate = checked > 0 && checked !== present;\n }\n\n get headerInput() {\n return this.headerTarget.querySelector(\"input\");\n }\n\n get items() {\n return this.itemTargets.map((el) => this.#itemOutlet(el)).filter((c) => c);\n }\n\n /**\n * Ideally we would be using outlets, but as of turbo 8.0.4 outlets do not fire disconnect events when morphing.\n *\n * Instead, we're using the targets to finds the controller.\n */\n #itemOutlet(el) {\n return this.application.getControllerForElementAndIdentifier(\n el,\n \"tables--selection--item\",\n );\n }\n}\n","import { Controller } from \"@hotwired/stimulus\";\n\nexport default class QueryController extends Controller {\n static targets = [\"modal\"];\n\n disconnect() {\n delete this.pending;\n\n document.removeEventListener(\"selectionchange\", this.selection);\n }\n\n focus() {\n if (document.activeElement === this.query) return;\n\n this.query.addEventListener(\n \"focusin\",\n (e) => {\n e.target.setSelectionRange(-1, -1);\n },\n { once: true },\n );\n\n this.query.focus();\n }\n\n closeModal() {\n delete this.modalTarget.dataset.open;\n this.query.setAttribute(\"aria-expanded\", false);\n\n if (document.activeElement === this.query) document.activeElement.blur();\n\n document.removeEventListener(\"selectionchange\", this.selection);\n }\n\n openModal() {\n this.modalTarget.dataset.open = true;\n this.query.setAttribute(\"aria-expanded\", true);\n\n document.addEventListener(\"selectionchange\", this.selection);\n }\n\n /**\n * If the user presses escape once, clear the input.\n * If the user presses escape again, get them out of here.\n */\n clear() {\n if (this.query.value === \"\") {\n this.closeModal();\n } else {\n this.query.value = \"\";\n this.query.dispatchEvent(new Event(\"input\"));\n this.query.dispatchEvent(new Event(\"change\"));\n this.update();\n }\n }\n\n submit() {\n const hasFocus = this.isFocused;\n const position = hasFocus && this.query.selectionStart;\n\n if (this.pending) {\n clearTimeout(this.pending);\n delete this.pending;\n }\n\n // add/remove current cursor position\n if (hasFocus && this.query.value !== \"\") {\n this.position.value = position;\n this.position.disabled = false;\n } else {\n this.position.value = \"\";\n this.position.disabled = true;\n }\n\n // prevent an unnecessary `?q=&p=0` parameter from appearing in the URL\n if (this.query.value === \"\") {\n this.query.disabled = true;\n\n // restore input and focus after form submission\n setTimeout(() => {\n this.query.disabled = false;\n this.position.disabled = false;\n if (hasFocus) this.query.focus();\n }, 0);\n }\n }\n\n update = () => {\n if (this.pending) clearTimeout(this.pending);\n this.pending = setTimeout(() => {\n this.element.requestSubmit();\n }, 300);\n };\n\n selection = () => {\n if (this.isFocused && this.query.value.length > 0) this.update();\n };\n\n beforeMorphAttribute(e) {\n switch (e.detail.attributeName) {\n case \"data-open\":\n e.preventDefault();\n break;\n }\n }\n\n moveToPreviousSuggestion() {\n const prev = this.previousSuggestion || this.lastSuggestion;\n\n if (prev) this.makeSuggestionActive(prev);\n }\n\n moveToNextSuggestion() {\n const next = this.nextSuggestion || this.firstSuggestion;\n\n if (next) this.makeSuggestionActive(next);\n }\n\n selectFirstSuggestion(e) {\n // This is caused by pressing the tab key. We don't want to move focus.\n // Ideally we don't want to always prevent the user from tabbing. We will address this later\n e.preventDefault();\n\n this.firstSuggestion?.dispatchEvent(new CustomEvent(\"query:select\"));\n }\n\n selectActiveSuggestion() {\n if (!this.activeSuggestion) {\n this.closeModal();\n return;\n }\n\n this.activeSuggestion.dispatchEvent(new CustomEvent(\"query:select\"));\n }\n\n selectSuggestion(e) {\n this.query.dispatchEvent(\n new CustomEvent(\"replaceToken\", {\n detail: { token: e.params.value, position: this.query.selectionStart },\n }),\n );\n\n this.clearActiveSuggestion();\n }\n\n makeSuggestionActive(node) {\n if (this.activeSuggestion) {\n this.activeSuggestion.setAttribute(\"aria-selected\", \"false\");\n }\n\n this.query.setAttribute(\"aria-activedescendant\", node.id);\n node.setAttribute(\"aria-selected\", \"true\");\n }\n\n clearActiveSuggestion() {\n if (this.activeSuggestion) {\n this.activeSuggestion.setAttribute(\"aria-selected\", \"false\");\n this.query.removeAttribute(\"aria-activedescendant\");\n }\n }\n\n get activeSuggestion() {\n return this.modalTarget.querySelector(\n `#${this.query.getAttribute(\"aria-activedescendant\")}`,\n );\n }\n\n get previousSuggestion() {\n return this.activeSuggestion?.previousElementSibling;\n }\n\n get nextSuggestion() {\n return this.activeSuggestion?.nextElementSibling;\n }\n\n get firstSuggestion() {\n return this.modalTarget.querySelector(\"#suggestions li:first-of-type\");\n }\n\n get lastSuggestion() {\n return this.modalTarget.querySelector(\"#suggestions li:last-of-type\");\n }\n\n get query() {\n return this.element.querySelector(\"[role=combobox]\");\n }\n\n get position() {\n return this.element.querySelector(\"input[name=p]\");\n }\n\n get isFocused() {\n return this.query === document.activeElement;\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","SelectionItemController","Controller","static","params","Object","checked","Boolean","tablesSelectionFormOutletConnected","form","visible","checkedValue","isSelected","disconnect","hasTablesSelectionFormOutlet","tablesSelectionFormOutlet","change","e","preventDefault","toggle","paramsValue","paramsValueChanged","previous","update","checkedValueChanged","updating","Promise","resolve","then","element","querySelector","dispatch","detail","selected","Parser","tokens","values","parse","input","query","StringScanner","isEos","push","skipWhitespace","value","takeTagged","takeUntagged","token","scan","Token","matched","Untagged","key","valueAt","separator","takeArrayValue","takeSingleValue","Tagged","start","takeDelimiter","end","ArrayToken","takeQuotedValue","takeUnquotedValue","Value","tokenAtPosition","filter","t","find","range","includes","length","arrayRange","render","document","createTextNode","stop","Array","from","index","startOfValue","endOfValue","span","createElement","className","innerText","super","appendChild","reduce","array","forEach","last","regex","match","exec","substring","Definitions","identifier","controllerConstructor","connect","parentElement","children","indexOf","id_value","dragUpdate","offset","dragOffset","style","zIndex","toggleAttribute","updateVisually","dragIndex","updateIndex","scope","id_name","index_name","name","reset","removeAttribute","hasChanges","index_value","round","comparisonIndex","startDragging","dragState","addEventListener","mousemove","mouseup","window","scroll","stopDragging","removeEventListener","tablesOrderableItemOutlets","item","drop","dragItem","newIndex","targetItem","insertAdjacentElement","commitChanges","tablesOrderableFormOutlet","clear","add","submit","mousedown","isDragging","animate","ticking","requestAnimationFrame","tablesOrderableFormOutlets","tablesOrderableFormOutletConnected","tablesOrderableFormOutletDisconnected","beforeMorphAttribute","attributeName","tagName","currentItems","toSorted","a","b","String","scopeValue","insertAdjacentHTML","inputs","requestSubmit","remove","querySelectorAll","count","Number","primaryKey","type","default","countValue","primaryKeyValue","visibleInputs","disabled","i","countValueChanged","countTarget","textContent","singularTarget","pluralTarget","itemTargetConnected","itemTargetDisconnected","toggleHeader","items","present","headerInput","indeterminate","headerTarget","itemTargets","map","el","itemOutlet","c","application","getControllerForElementAndIdentifier","pending","selection","focus","activeElement","setSelectionRange","once","closeModal","modalTarget","dataset","open","setAttribute","blur","openModal","dispatchEvent","Event","hasFocus","isFocused","selectionStart","clearTimeout","setTimeout","moveToPreviousSuggestion","prev","previousSuggestion","lastSuggestion","makeSuggestionActive","moveToNextSuggestion","next","nextSuggestion","firstSuggestion","selectFirstSuggestion","CustomEvent","selectActiveSuggestion","activeSuggestion","selectSuggestion","clearActiveSuggestion","node","getAttribute","previousElementSibling","nextElementSibling","queryValue","inputTarget","connected","queryValueChanged","highlightTarget","innerHTML","replaceToken","tokenToAdd","toString","indexPosition","caretPosition","sliceStart","sliceEnd","existingToken","trim","slice"],"mappings":"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"}
1
+ {"version":3,"file":"tables.min.js","sources":["../../../javascript/tables/orderable/list_controller.js","../../../javascript/tables/selection/item_controller.js","../../../javascript/tables/query_input_controller.js","../../../javascript/tables/application.js","../../../javascript/tables/orderable/item_controller.js","../../../javascript/tables/orderable/form_controller.js","../../../javascript/tables/selection/form_controller.js","../../../javascript/tables/selection/table_controller.js","../../../javascript/tables/query_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 beforeMorphElement(e) {\n // Cancel morph if dragging to prevent swapping rows from under the user\n // An alternative would be to require ids on rows so morph can accurately\n // map before/after and avoid updating the row being dragged\n if (this.isDragging) e.preventDefault();\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 { Controller } from \"@hotwired/stimulus\";\n\n/**\n * Couples an input element in a row to the selection form which is turbo-permanent and outside the table.\n * When the input is toggled, the form will create/destroy hidden inputs. The checkbox inside this cell will follow\n * the hidden inputs.\n *\n * Cell value may change when:\n * * cell connects, e.g. when the user paginates\n * * cell is re-used by turbo-morph, e.g. pagination\n * * cell is toggled\n * * select-all/de-select-all on table header\n */\nexport default class SelectionItemController extends Controller {\n static outlets = [\"tables--selection--form\"];\n static values = {\n params: Object,\n checked: Boolean,\n };\n\n tablesSelectionFormOutletConnected(form) {\n form.visible(this.id, true);\n this.checkedValue = form.isSelected(this.id);\n }\n\n disconnect() {\n // Remove from form's list of visible selections.\n // This should be an outlet disconnect, but those events are not reliable in turbo 8.0\n if (this.hasTablesSelectionFormOutlet) {\n this.tablesSelectionFormOutlet.visible(this.id, false);\n }\n }\n\n change(e) {\n e.preventDefault();\n\n this.checkedValue = this.tablesSelectionFormOutlet.toggle(this.id);\n }\n\n get id() {\n return this.paramsValue.id;\n }\n\n /**\n * Update checked to match match selection form. This occurs when the item is re-used by turbo-morph.\n */\n paramsValueChanged(params, previous) {\n if (!this.hasTablesSelectionFormOutlet) return;\n\n // if id is changing (e.g. morph) then let the form know that the previous id is now not visible\n if (previous.id !== params.id) {\n this.tablesSelectionFormOutlet.visible(previous.id, false);\n }\n\n // tell form that our id is now visible in the table\n this.tablesSelectionFormOutlet.visible(params.id, true);\n\n // id has changed, so update checked from form\n this.checkedValue = this.tablesSelectionFormOutlet.isSelected(params.id);\n\n // propagate changes\n this.update();\n }\n\n /**\n * Update input to match checked. This occurs when the item is toggled, connected, or morphed.\n */\n checkedValueChanged() {\n if (!this.hasTablesSelectionFormOutlet) return;\n\n // ensure that checked matches the form, i.e. if morphed\n this.checkedValue = this.tablesSelectionFormOutlet.isSelected(this.id);\n\n // propagate changes\n this.update();\n }\n\n /**\n * Notify table that id or value may have changed. Note that this may fire when nothing has changed.\n *\n * Debouncing to minimise dom updates.\n */\n async update() {\n this.updating ||= Promise.resolve().then(() => {\n this.#update();\n delete this.updating;\n });\n\n return this.updating;\n }\n\n #update() {\n this.element.querySelector(\"input\").checked = this.checkedValue;\n this.dispatch(\"select\", {\n detail: { id: this.id, selected: this.checkedValue },\n });\n }\n}\n","import { Controller } from \"@hotwired/stimulus\";\n\nexport default class QueryInputController extends Controller {\n static targets = [\"input\", \"highlight\"];\n static values = { query: String };\n\n connect() {\n this.queryValue = this.inputTarget.value;\n this.element.dataset.connected = \"\";\n }\n\n disconnect() {\n delete this.element.dataset.connected;\n }\n\n update() {\n this.queryValue = this.inputTarget.value;\n }\n\n queryValueChanged(query) {\n this.highlightTarget.innerHTML = \"\";\n\n new Parser().parse(query).tokens.forEach((token) => {\n this.highlightTarget.appendChild(token.render());\n });\n }\n\n replaceToken(e) {\n let tokenToAdd = e.detail.token.toString();\n\n // wrap in quotes if it contains a spaces or special characters\n if (/\\s/.exec(tokenToAdd)) {\n tokenToAdd = `\"${tokenToAdd}\"`;\n }\n\n const indexPosition = e.detail.position;\n let caretPosition = indexPosition + tokenToAdd.length;\n let sliceStart = indexPosition;\n let sliceEnd = indexPosition;\n\n // detect if position has a token already, if so, replace it\n const existingToken = new Parser()\n .parse(this.queryValue)\n .tokenAtPosition(indexPosition);\n if (existingToken) {\n // We don't want to include the trailing space as we are replacing an existing value\n tokenToAdd = tokenToAdd.trim();\n\n // Slice up to the beginning of the tokens value (not the initial caret position)\n sliceStart = existingToken.startOfValue();\n\n // Slice after the end of the tokens value\n sliceEnd = existingToken.endOfValue();\n\n // The end position of the newly added token\n caretPosition = sliceStart + tokenToAdd.length;\n }\n\n // Replace any text within sliceStart and sliceEnd with tokenToAdd\n this.inputTarget.value =\n this.queryValue.slice(0, sliceStart) +\n tokenToAdd +\n this.queryValue.slice(sliceEnd);\n\n // Re focus the input at the end of the newly added token\n this.update();\n this.inputTarget.focus();\n this.inputTarget.setSelectionRange(caretPosition, caretPosition);\n }\n}\n\nclass Parser {\n constructor() {\n this.tokens = [];\n this.values = null;\n }\n\n parse(input) {\n const query = new StringScanner(input);\n\n while (!query.isEos()) {\n this.push(this.skipWhitespace(query));\n\n const value = this.takeTagged(query) || this.takeUntagged(query);\n\n if (!this.push(value)) break;\n }\n\n return this;\n }\n\n push(token) {\n if (token) {\n this.values ? this.values.push(token) : this.tokens.push(token);\n }\n\n return !!token;\n }\n\n skipWhitespace(query) {\n if (!query.scan(/\\s+/)) return;\n\n return new Token(query.matched(), query.position);\n }\n\n takeUntagged(query) {\n if (!query.scan(/\\S+/)) return;\n\n return new Untagged(query.matched(), query.position);\n }\n\n takeTagged(query) {\n if (!query.scan(/(\\w+(?:\\.\\w+)?)(:\\s*)/)) return;\n\n const key = query.valueAt(1);\n const separator = query.valueAt(2);\n\n const value =\n this.takeArrayValue(query) || this.takeSingleValue(query) || new Token();\n\n return new Tagged(key, separator, value, query.position);\n }\n\n takeArrayValue(query) {\n if (!query.scan(/\\[\\s*/)) return;\n\n const start = new Token(query.matched(), query.position);\n const values = (this.values = []);\n\n while (!query.isEos()) {\n if (!this.push(this.takeSingleValue(query))) break;\n if (!this.push(this.takeDelimiter(query))) break;\n }\n\n query.scan(/\\s*]/);\n const end = new Token(query.matched(), query.position);\n\n this.values = null;\n\n return new ArrayToken(start, values, end);\n }\n\n takeDelimiter(query) {\n if (!query.scan(/\\s*,\\s*/)) return;\n\n return new Token(query.matched(), query.position);\n }\n\n takeSingleValue(query) {\n return this.takeQuotedValue(query) || this.takeUnquotedValue(query);\n }\n\n takeQuotedValue(query) {\n if (!query.scan(/\"([^\"]*)\"/)) return;\n\n return new Value(query.matched(), query.position);\n }\n\n takeUnquotedValue(query) {\n if (!query.scan(/[^ \\],]*/)) return;\n\n return new Value(query.matched(), query.position);\n }\n\n tokenAtPosition(position) {\n return this.tokens\n .filter((t) => t instanceof Tagged || t instanceof Untagged)\n .find((t) => t.range.includes(position));\n }\n}\n\nclass Token {\n constructor(value = \"\", position) {\n this.value = value;\n this.length = this.value.length;\n this.start = position - this.length;\n this.end = this.start + this.length;\n this.range = this.arrayRange(this.start, this.end);\n }\n\n render() {\n return document.createTextNode(this.value);\n }\n\n arrayRange(start, stop) {\n return Array.from(\n { length: stop - start + 1 },\n (value, index) => start + index,\n );\n }\n\n startOfValue() {\n return this.start;\n }\n\n endOfValue() {\n return this.end;\n }\n}\n\nclass Value extends Token {\n render() {\n const span = document.createElement(\"span\");\n span.className = \"value\";\n span.innerText = this.value;\n\n return span;\n }\n}\n\nclass Tagged extends Token {\n constructor(key, separator, value, position) {\n super();\n\n this.key = key;\n this.separator = separator;\n this.value = value;\n this.length = key.length + separator.length + value.value.length;\n this.start = position - this.length;\n this.end = this.start + this.length;\n this.range = this.arrayRange(this.start, this.end);\n }\n\n render() {\n const span = document.createElement(\"span\");\n span.className = \"tag\";\n\n const key = document.createElement(\"span\");\n key.className = \"key\";\n key.innerText = this.key;\n\n span.appendChild(key);\n span.appendChild(document.createTextNode(this.separator));\n span.appendChild(this.value.render());\n\n return span;\n }\n\n startOfValue() {\n return this.value.startOfValue();\n }\n\n endOfValue() {\n return this.value.endOfValue();\n }\n}\n\nclass Untagged extends Token {\n render() {\n const span = document.createElement(\"span\");\n span.className = \"untagged\";\n span.innerText = this.value;\n return span;\n }\n}\n\nclass ArrayToken extends Token {\n constructor(start, values, end) {\n super();\n\n this.start = start;\n this.values = values;\n this.end = end;\n this.range = this.arrayRange(start.start, end.range[end.length]);\n this.length =\n start.length +\n values.reduce((length, value) => length + value.length, 0) +\n end.length;\n }\n\n render() {\n const array = document.createElement(\"span\");\n array.className = \"array-values\";\n array.appendChild(this.start.render());\n\n this.values.forEach((value) => {\n const span = document.createElement(\"span\");\n span.appendChild(value.render());\n array.appendChild(span);\n });\n\n array.appendChild(this.end.render());\n\n return array;\n }\n\n startOfValue() {\n return this.start.start;\n }\n\n endOfValue() {\n return this.end.end;\n }\n}\n\nclass StringScanner {\n constructor(input) {\n this.input = input;\n this.position = 0;\n this.last = null;\n }\n\n isEos() {\n return this.position >= this.input.length;\n }\n\n scan(regex) {\n const match = regex.exec(this.input.substring(this.position));\n if (match?.index === 0) {\n this.last = match;\n this.position += match[0].length;\n return true;\n } else {\n this.last = {};\n return false;\n }\n }\n\n matched() {\n return this.last && this.last[0];\n }\n\n valueAt(index) {\n return this.last && this.last[index];\n }\n}\n","import OrderableItemController from \"./orderable/item_controller\";\nimport OrderableListController from \"./orderable/list_controller\";\nimport OrderableFormController from \"./orderable/form_controller\";\nimport SelectionFormController from \"./selection/form_controller\";\nimport SelectionItemController from \"./selection/item_controller\";\nimport SelectionTableController from \"./selection/table_controller\";\nimport QueryController from \"./query_controller\";\nimport QueryInputController from \"./query_input_controller\";\n\nconst Definitions = [\n {\n identifier: \"tables--orderable--item\",\n controllerConstructor: OrderableItemController,\n },\n {\n identifier: \"tables--orderable--list\",\n controllerConstructor: OrderableListController,\n },\n {\n identifier: \"tables--orderable--form\",\n controllerConstructor: OrderableFormController,\n },\n {\n identifier: \"tables--selection--form\",\n controllerConstructor: SelectionFormController,\n },\n {\n identifier: \"tables--selection--item\",\n controllerConstructor: SelectionItemController,\n },\n {\n identifier: \"tables--selection--table\",\n controllerConstructor: SelectionTableController,\n },\n {\n identifier: \"tables--query\",\n controllerConstructor: QueryController,\n },\n {\n identifier: \"tables--query-input\",\n controllerConstructor: QueryInputController,\n },\n];\n\nexport { Definitions as default };\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 /** Retrieve params for use in the form */\n params(scope) {\n const { id_name, id_value, index_name } = this.paramsValue;\n return [\n { name: `${scope}[${id_value}][${id_name}]`, value: this.id },\n { name: `${scope}[${id_value}][${index_name}]`, value: this.index },\n ];\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 static values = { scope: String };\n\n add(item) {\n item.params(this.scopeValue).forEach(({ name, value }) => {\n this.element.insertAdjacentHTML(\n \"beforeend\",\n `<input type=\"hidden\" name=\"${name}\" value=\"${value}\" data-generated>`,\n );\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","import { Controller } from \"@hotwired/stimulus\";\n\nexport default class SelectionFormController extends Controller {\n static values = {\n count: Number,\n primaryKey: { type: String, default: \"id\" },\n };\n static targets = [\"count\", \"singular\", \"plural\"];\n\n connect() {\n this.countValue = this.inputs.length;\n }\n\n /**\n * @param id to toggle\n * @return {boolean} true if selected, false if unselected\n */\n toggle(id) {\n const input = this.input(id);\n\n if (input) {\n input.remove();\n } else {\n this.element.insertAdjacentHTML(\n \"beforeend\",\n `<input type=\"hidden\" name=\"${this.primaryKeyValue}[]\" value=\"${id}\">`,\n );\n }\n\n this.countValue = this.visibleInputs.length;\n\n return !input;\n }\n\n /**\n * @param id to toggle visibility\n * @return {boolean} true if visible, false if not visible\n */\n visible(id, visible) {\n const input = this.input(id);\n\n if (input) {\n input.disabled = !visible;\n }\n\n this.countValue = this.visibleInputs.length;\n\n return !input;\n }\n\n /**\n * @returns {boolean} true if the given id is currently selected\n */\n isSelected(id) {\n return !!this.input(id);\n }\n\n get inputs() {\n return this.element.querySelectorAll(\n `input[name=\"${this.primaryKeyValue}[]\"]`,\n );\n }\n\n get visibleInputs() {\n return Array.from(this.inputs).filter((i) => !i.disabled);\n }\n\n input(id) {\n return this.element.querySelector(\n `input[name=\"${this.primaryKeyValue}[]\"][value=\"${id}\"]`,\n );\n }\n\n countValueChanged(count) {\n this.element.toggleAttribute(\"hidden\", count === 0);\n this.countTarget.textContent = count;\n this.singularTarget.toggleAttribute(\"hidden\", count !== 1);\n this.pluralTarget.toggleAttribute(\"hidden\", count === 1);\n }\n}\n","import { Controller } from \"@hotwired/stimulus\";\n\nexport default class SelectionTableController extends Controller {\n static targets = [\"header\", \"item\"];\n static outlets = [\"tables--selection--form\"];\n\n itemTargetConnected(item) {\n this.update();\n }\n\n itemTargetDisconnected(item) {\n this.update();\n }\n\n toggleHeader(e) {\n this.items.forEach((item) => {\n if (item.checkedValue === e.target.checked) return;\n\n item.checkedValue = this.tablesSelectionFormOutlet.toggle(item.id);\n });\n }\n\n async update() {\n this.updating ||= Promise.resolve().then(() => {\n this.#update();\n delete this.updating;\n });\n\n return this.updating;\n }\n\n #update() {\n let present = 0;\n let checked = 0;\n\n this.items.forEach((item) => {\n present++;\n if (item.checkedValue) checked++;\n });\n\n this.headerInput.checked = present > 0 && checked === present;\n this.headerInput.indeterminate = checked > 0 && checked !== present;\n }\n\n get headerInput() {\n return this.headerTarget.querySelector(\"input\");\n }\n\n get items() {\n return this.itemTargets.map((el) => this.#itemOutlet(el)).filter((c) => c);\n }\n\n /**\n * Ideally we would be using outlets, but as of turbo 8.0.4 outlets do not fire disconnect events when morphing.\n *\n * Instead, we're using the targets to finds the controller.\n */\n #itemOutlet(el) {\n return this.application.getControllerForElementAndIdentifier(\n el,\n \"tables--selection--item\",\n );\n }\n}\n","import { Controller } from \"@hotwired/stimulus\";\n\nexport default class QueryController extends Controller {\n static targets = [\"modal\"];\n\n disconnect() {\n delete this.pending;\n\n document.removeEventListener(\"selectionchange\", this.selection);\n }\n\n focus() {\n if (document.activeElement === this.query) return;\n\n this.query.addEventListener(\n \"focusin\",\n (e) => {\n e.target.setSelectionRange(-1, -1);\n },\n { once: true },\n );\n\n this.query.focus();\n }\n\n closeModal() {\n delete this.modalTarget.dataset.open;\n this.query.setAttribute(\"aria-expanded\", false);\n\n if (document.activeElement === this.query) document.activeElement.blur();\n\n document.removeEventListener(\"selectionchange\", this.selection);\n }\n\n openModal() {\n this.modalTarget.dataset.open = true;\n this.query.setAttribute(\"aria-expanded\", true);\n\n document.addEventListener(\"selectionchange\", this.selection);\n }\n\n /**\n * If the user presses escape once, clear the input.\n * If the user presses escape again, get them out of here.\n */\n clear() {\n if (this.query.value === \"\") {\n this.closeModal();\n } else {\n this.query.value = \"\";\n this.query.dispatchEvent(new Event(\"input\"));\n this.query.dispatchEvent(new Event(\"change\"));\n this.update();\n }\n }\n\n submit() {\n const hasFocus = this.isFocused;\n const position = hasFocus && this.query.selectionStart;\n\n if (this.pending) {\n clearTimeout(this.pending);\n delete this.pending;\n }\n\n // add/remove current cursor position\n if (hasFocus && this.query.value !== \"\") {\n this.position.value = position;\n this.position.disabled = false;\n } else {\n this.position.value = \"\";\n this.position.disabled = true;\n }\n\n // prevent an unnecessary `?q=&p=0` parameter from appearing in the URL\n if (this.query.value === \"\") {\n this.query.disabled = true;\n\n // restore input and focus after form submission\n setTimeout(() => {\n this.query.disabled = false;\n this.position.disabled = false;\n if (hasFocus) this.query.focus();\n }, 0);\n }\n }\n\n update = () => {\n if (this.pending) clearTimeout(this.pending);\n this.pending = setTimeout(() => {\n this.element.requestSubmit();\n }, 300);\n };\n\n selection = () => {\n if (this.isFocused && this.query.value.length > 0) this.update();\n };\n\n beforeMorphAttribute(e) {\n switch (e.detail.attributeName) {\n case \"data-open\":\n e.preventDefault();\n break;\n }\n }\n\n moveToPreviousSuggestion() {\n const prev = this.previousSuggestion || this.lastSuggestion;\n\n if (prev) this.makeSuggestionActive(prev);\n }\n\n moveToNextSuggestion() {\n const next = this.nextSuggestion || this.firstSuggestion;\n\n if (next) this.makeSuggestionActive(next);\n }\n\n selectFirstSuggestion(e) {\n // This is caused by pressing the tab key. We don't want to move focus.\n // Ideally we don't want to always prevent the user from tabbing. We will address this later\n e.preventDefault();\n\n this.firstSuggestion?.dispatchEvent(new CustomEvent(\"query:select\"));\n }\n\n selectActiveSuggestion() {\n if (!this.activeSuggestion) {\n this.closeModal();\n return;\n }\n\n this.activeSuggestion.dispatchEvent(new CustomEvent(\"query:select\"));\n }\n\n selectSuggestion(e) {\n this.query.dispatchEvent(\n new CustomEvent(\"replaceToken\", {\n detail: { token: e.params.value, position: this.query.selectionStart },\n }),\n );\n\n this.clearActiveSuggestion();\n }\n\n makeSuggestionActive(node) {\n if (this.activeSuggestion) {\n this.activeSuggestion.setAttribute(\"aria-selected\", \"false\");\n }\n\n this.query.setAttribute(\"aria-activedescendant\", node.id);\n node.setAttribute(\"aria-selected\", \"true\");\n }\n\n clearActiveSuggestion() {\n if (this.activeSuggestion) {\n this.activeSuggestion.setAttribute(\"aria-selected\", \"false\");\n this.query.removeAttribute(\"aria-activedescendant\");\n }\n }\n\n get activeSuggestion() {\n return this.modalTarget.querySelector(\n `#${this.query.getAttribute(\"aria-activedescendant\")}`,\n );\n }\n\n get previousSuggestion() {\n return this.activeSuggestion?.previousElementSibling;\n }\n\n get nextSuggestion() {\n return this.activeSuggestion?.nextElementSibling;\n }\n\n get firstSuggestion() {\n return this.modalTarget.querySelector(\"#suggestions li:first-of-type\");\n }\n\n get lastSuggestion() {\n return this.modalTarget.querySelector(\"#suggestions li:last-of-type\");\n }\n\n get query() {\n return this.element.querySelector(\"[role=combobox]\");\n }\n\n get position() {\n return this.element.querySelector(\"input[name=p]\");\n }\n\n get isFocused() {\n return this.query === document.activeElement;\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","SelectionItemController","Controller","static","params","Object","checked","Boolean","tablesSelectionFormOutletConnected","form","visible","checkedValue","isSelected","disconnect","hasTablesSelectionFormOutlet","tablesSelectionFormOutlet","change","e","preventDefault","toggle","paramsValue","paramsValueChanged","previous","update","checkedValueChanged","updating","Promise","resolve","then","element","querySelector","dispatch","detail","selected","Parser","tokens","values","parse","input","query","StringScanner","isEos","push","skipWhitespace","value","takeTagged","takeUntagged","token","scan","Token","matched","Untagged","key","valueAt","separator","takeArrayValue","takeSingleValue","Tagged","start","takeDelimiter","end","ArrayToken","takeQuotedValue","takeUnquotedValue","Value","tokenAtPosition","filter","t","find","range","includes","length","arrayRange","render","document","createTextNode","stop","Array","from","index","startOfValue","endOfValue","span","createElement","className","innerText","super","appendChild","reduce","array","forEach","last","regex","match","exec","substring","Definitions","identifier","controllerConstructor","connect","parentElement","children","indexOf","id_value","dragUpdate","offset","dragOffset","style","zIndex","toggleAttribute","updateVisually","dragIndex","updateIndex","scope","id_name","index_name","name","reset","removeAttribute","hasChanges","index_value","round","comparisonIndex","startDragging","dragState","addEventListener","mousemove","mouseup","window","scroll","stopDragging","removeEventListener","tablesOrderableItemOutlets","item","drop","dragItem","newIndex","targetItem","insertAdjacentElement","commitChanges","tablesOrderableFormOutlet","clear","add","submit","mousedown","isDragging","animate","ticking","requestAnimationFrame","tablesOrderableFormOutlets","tablesOrderableFormOutletConnected","tablesOrderableFormOutletDisconnected","beforeMorphElement","currentItems","toSorted","a","b","String","scopeValue","insertAdjacentHTML","inputs","requestSubmit","remove","querySelectorAll","count","Number","primaryKey","type","default","countValue","primaryKeyValue","visibleInputs","disabled","i","countValueChanged","countTarget","textContent","singularTarget","pluralTarget","itemTargetConnected","itemTargetDisconnected","toggleHeader","items","present","headerInput","indeterminate","headerTarget","itemTargets","map","el","itemOutlet","c","application","getControllerForElementAndIdentifier","pending","selection","focus","activeElement","setSelectionRange","once","closeModal","modalTarget","dataset","open","setAttribute","blur","openModal","dispatchEvent","Event","hasFocus","isFocused","selectionStart","clearTimeout","setTimeout","beforeMorphAttribute","attributeName","moveToPreviousSuggestion","prev","previousSuggestion","lastSuggestion","makeSuggestionActive","moveToNextSuggestion","next","nextSuggestion","firstSuggestion","selectFirstSuggestion","CustomEvent","selectActiveSuggestion","activeSuggestion","selectSuggestion","clearActiveSuggestion","node","getAttribute","previousElementSibling","nextElementSibling","queryValue","inputTarget","connected","queryValueChanged","highlightTarget","innerHTML","replaceToken","tokenToAdd","toString","indexPosition","caretPosition","sliceStart","sliceEnd","existingToken","trim","slice"],"mappings":"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"}
@@ -53,7 +53,7 @@ module Katalyst
53
53
  data: {
54
54
  controller: LIST_CONTROLLER,
55
55
  action: %W[mousedown->#{LIST_CONTROLLER}#mousedown
56
- turbo:before-morph-attribute->#{LIST_CONTROLLER}#beforeMorphAttribute],
56
+ turbo:before-morph-element->#{LIST_CONTROLLER}#beforeMorphElement:self],
57
57
  "#{LIST_CONTROLLER}-#{FORM_CONTROLLER}-outlet" => "##{Orderable.default_form_id(collection)}",
58
58
  "#{LIST_CONTROLLER}-#{ITEM_CONTROLLER}-outlet" => "td.ordinal",
59
59
  },
@@ -146,17 +146,11 @@ export default class OrderableListController extends Controller {
146
146
  }
147
147
  }
148
148
 
149
- beforeMorphAttribute(e) {
150
- switch (e.detail.attributeName) {
151
- case "dragging": // set to track the item being dragged
152
- e.preventDefault();
153
- break;
154
- case "style": // used to animate rows moving up and down
155
- if (e.target.tagName === "TBODY" || e.target.tagName === "TR") {
156
- e.preventDefault();
157
- }
158
- break;
159
- }
149
+ beforeMorphElement(e) {
150
+ // Cancel morph if dragging to prevent swapping rows from under the user
151
+ // An alternative would be to require ids on rows so morph can accurately
152
+ // map before/after and avoid updating the row being dragged
153
+ if (this.isDragging) e.preventDefault();
160
154
  }
161
155
 
162
156
  //endregion
@@ -6,12 +6,10 @@ module Katalyst
6
6
  class ConstantValue < Base
7
7
  delegate :to_param, to: :@attribute_type
8
8
 
9
- def initialize(name:, type:, model:, column:, value:)
9
+ def initialize(name:, type:, value:)
10
10
  super(value)
11
11
 
12
12
  @attribute_type = type
13
- @model = model
14
- @column = column
15
13
  @name = name
16
14
  end
17
15
 
@@ -4,16 +4,12 @@ module Katalyst
4
4
  module Tables
5
5
  module Suggestions
6
6
  class DatabaseValue < Base
7
- attr_reader :model, :column
8
-
9
7
  delegate :to_param, to: :@attribute_type
10
8
 
11
- def initialize(name:, type:, model:, column:, value:)
9
+ def initialize(name:, type:, value:)
12
10
  super(value)
13
11
 
14
12
  @attribute_type = type
15
- @model = model
16
- @column = column
17
13
  @name = name
18
14
  end
19
15
 
@@ -22,16 +22,14 @@ module Katalyst
22
22
  end
23
23
  end
24
24
 
25
- def suggestions(scope, attribute)
26
- _, model, column = model_and_column_for(scope, attribute)
27
-
25
+ def suggestions(_scope, attribute)
28
26
  values = %w[true false]
29
27
 
30
28
  if attribute.value_before_type_cast.present?
31
29
  values = values.select { |value| value.include?(attribute.value_before_type_cast) }
32
30
  end
33
31
 
34
- values.map { |v| constant_suggestion(attribute:, model:, column:, value: deserialize(v)) }
32
+ values.map { |v| constant_suggestion(attribute:, value: deserialize(v)) }
35
33
  end
36
34
  end
37
35
  end
@@ -23,14 +23,12 @@ module Katalyst
23
23
  end
24
24
 
25
25
  def suggestions(scope, attribute)
26
- _, model, column = model_and_column_for(scope, attribute)
27
-
28
26
  [
29
27
  *super(scope, attribute, limit: 6, order: :desc),
30
- database_suggestion(attribute:, model:, column:, value: ::Date.current.beginning_of_week..),
31
- database_suggestion(attribute:, model:, column:, value: ::Date.current.beginning_of_month..),
32
- database_suggestion(attribute:, model:, column:, value: 1.month.ago.all_month),
33
- database_suggestion(attribute:, model:, column:, value: 1.year.ago.all_year),
28
+ database_suggestion(attribute:, value: ::Date.current.beginning_of_week..),
29
+ database_suggestion(attribute:, value: ::Date.current.beginning_of_month..),
30
+ database_suggestion(attribute:, value: 1.month.ago.all_month),
31
+ database_suggestion(attribute:, value: 1.year.ago.all_year),
34
32
  ]
35
33
  end
36
34
 
@@ -16,7 +16,15 @@ module Katalyst
16
16
  end
17
17
 
18
18
  def suggestions(scope, attribute)
19
- _, model, column = model_and_column_for(scope, attribute)
19
+ model = scope.model
20
+ column = attribute.name
21
+
22
+ if attribute.name.include?(".")
23
+ table_name, column = attribute.name.split(".")
24
+ model = scope.model.reflections[table_name].klass
25
+
26
+ raise(ArgumentError, "Unknown association '#{table_name}' for #{scope.model}") unless model
27
+ end
20
28
 
21
29
  raise ArgumentError, "Unknown enum #{column} for #{model}" unless model.defined_enums.has_key?(column)
22
30
 
@@ -26,7 +34,7 @@ module Katalyst
26
34
  values = values.select { |key| key.include?(attribute.value_before_type_cast) }
27
35
  end
28
36
 
29
- values.map { |value| constant_suggestion(attribute:, model:, column:, value:) }
37
+ values.map { |value| constant_suggestion(attribute:, value:) }
30
38
  end
31
39
 
32
40
  private
@@ -5,8 +5,6 @@ module Katalyst
5
5
  module Collection
6
6
  module Type
7
7
  class String < Value
8
- include ActiveRecord::Sanitization::ClassMethods
9
-
10
8
  attr_reader :exact
11
9
  alias_method :exact?, :exact
12
10
 
@@ -21,11 +19,32 @@ module Katalyst
21
19
 
22
20
  private
23
21
 
24
- def filter_condition(model, column, value)
25
- if exact? || scope
22
+ class Match
23
+ include ActiveRecord::Sanitization::ClassMethods
24
+
25
+ attr_reader :value
26
+
27
+ def initialize(value)
28
+ @value = value
29
+ end
30
+
31
+ def to_sql
32
+ "%#{sanitize_sql_like(value)}%"
33
+ end
34
+ end
35
+
36
+ class MatchHandler
37
+ def call(attribute, value)
38
+ attribute.matches(value.to_sql)
39
+ end
40
+ end
41
+
42
+ def apply_filter(scope, model, attribute, value)
43
+ if exact?
26
44
  super
27
45
  else
28
- model.where(model.arel_table[column].matches("%#{sanitize_sql_like(value)}%"))
46
+ model.predicate_builder.register_handler(Match, MatchHandler.new)
47
+ scope.where(attribute.name => Match.new(value))
29
48
  end
30
49
  end
31
50
  end
@@ -33,10 +33,18 @@ module Katalyst
33
33
  def filter(scope, attribute, value: filter_value(attribute))
34
34
  return scope unless filter?(attribute, value)
35
35
 
36
- scope, model, column = model_and_column_for(scope, attribute)
37
- condition = filter_condition(model, column, value)
36
+ if self.scope.present?
37
+ scope.public_send(self.scope, value)
38
+ elsif attribute.name.include?(".")
39
+ table_name, = attribute.name.split(".")
40
+ association = scope.model.reflections[table_name]
38
41
 
39
- scope.merge(condition)
42
+ raise(ArgumentError, "Unknown association '#{table_name}' for #{scope.model}") unless association
43
+
44
+ apply_filter(scope.joins(table_name.to_sym), association.klass, attribute, value)
45
+ else
46
+ apply_filter(scope, scope.model, attribute, value)
47
+ end
40
48
  end
41
49
 
42
50
  def to_param(value)
@@ -44,54 +52,51 @@ module Katalyst
44
52
  end
45
53
 
46
54
  def suggestions(scope, attribute, limit: 10, order: :asc)
47
- scope, model, column = model_and_column_for(scope, attribute)
55
+ model = scope.model
56
+ column = attribute.name
57
+
58
+ if attribute.name.include?(".")
59
+ table_name, column = attribute.name.split(".")
60
+ model = scope.model.reflections[table_name].klass
61
+
62
+ raise(ArgumentError, "Unknown association '#{table_name}' for #{scope.model}") unless model
63
+
64
+ scope = scope.joins(table_name.to_sym)
65
+ end
48
66
 
49
67
  unless model.attribute_types.has_key?(column)
50
68
  raise(ArgumentError, "Unknown column '#{column}' for #{model}. " \
51
69
  "Consider defining '#{attribute.name.parameterize.underscore}_suggestions'")
52
70
  end
53
71
 
54
- arel_column = model.arel_table[column]
55
-
56
72
  filter(scope, attribute)
57
- .group(arel_column)
73
+ .group(attribute.name)
58
74
  .distinct
59
75
  .limit(limit)
60
- .reorder(arel_column => order)
61
- .pluck(arel_column)
62
- .map { |v| database_suggestion(attribute:, model:, column:, value: deserialize(v)) }
76
+ .reorder(attribute.name => order)
77
+ .pluck(attribute.name)
78
+ .map { |v| database_suggestion(attribute:, value: deserialize(v)) }
63
79
  end
64
80
 
65
81
  private
66
82
 
67
- def constant_suggestion(attribute:, model:, column:, value:)
68
- Tables::Suggestions::ConstantValue.new(name: attribute.name, type: attribute.type, model:, column:, value:)
83
+ def constant_suggestion(attribute:, value:)
84
+ Tables::Suggestions::ConstantValue.new(name: attribute.name, type: attribute.type, value:)
69
85
  end
70
86
 
71
- def database_suggestion(attribute:, model:, column:, value:)
72
- Tables::Suggestions::DatabaseValue.new(name: attribute.name, type: attribute.type, model:, column:, value:)
87
+ def database_suggestion(attribute:, value:)
88
+ Tables::Suggestions::DatabaseValue.new(name: attribute.name, type: attribute.type, value:)
73
89
  end
74
90
 
75
91
  def filter_value(attribute)
76
92
  attribute.value
77
93
  end
78
94
 
79
- def filter_condition(model, column, value)
95
+ def apply_filter(scope, _model, attribute, value)
80
96
  if value.nil?
81
- model.none
82
- elsif scope
83
- model.public_send(scope, value)
84
- else
85
- model.where(column => serialize(value))
86
- end
87
- end
88
-
89
- def model_and_column_for(scope, attribute)
90
- if attribute.name.include?(".")
91
- table, column = attribute.name.split(".")
92
- [scope.joins(table.to_sym), scope.model.reflections[table].klass, column]
97
+ scope.none
93
98
  else
94
- [scope, scope.model, attribute.name]
99
+ scope.where(attribute.name => serialize(value))
95
100
  end
96
101
  end
97
102
  end
metadata CHANGED
@@ -1,14 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: katalyst-tables
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.6.1
4
+ version: 3.7.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Katalyst Interactive
8
- autorequire:
9
8
  bindir: bin
10
9
  cert_chain: []
11
- date: 2024-10-09 00:00:00.000000000 Z
10
+ date: 2025-01-13 00:00:00.000000000 Z
12
11
  dependencies:
13
12
  - !ruby/object:Gem::Dependency
14
13
  name: katalyst-html-attributes
@@ -175,7 +174,6 @@ metadata:
175
174
  homepage_uri: https://github.com/katalyst/tables
176
175
  source_code_uri: https://github.com/katalyst/tables
177
176
  changelog_uri: https://github.com/katalyst/tables/blobs/main/CHANGELOG.md
178
- post_install_message:
179
177
  rdoc_options: []
180
178
  require_paths:
181
179
  - lib
@@ -190,8 +188,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
190
188
  - !ruby/object:Gem::Version
191
189
  version: '0'
192
190
  requirements: []
193
- rubygems_version: 3.5.16
194
- signing_key:
191
+ rubygems_version: 3.6.2
195
192
  specification_version: 4
196
193
  summary: HTML table generator for Rails views
197
194
  test_files: []