katalyst-tables 3.5.5 → 3.6.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -725,6 +725,7 @@ class QueryController extends Controller {
725
725
 
726
726
  closeModal() {
727
727
  delete this.modalTarget.dataset.open;
728
+ this.query.setAttribute("aria-expanded", false);
728
729
 
729
730
  if (document.activeElement === this.query) document.activeElement.blur();
730
731
 
@@ -733,6 +734,7 @@ class QueryController extends Controller {
733
734
 
734
735
  openModal() {
735
736
  this.modalTarget.dataset.open = true;
737
+ this.query.setAttribute("aria-expanded", true);
736
738
 
737
739
  document.addEventListener("selectionchange", this.selection);
738
740
  }
@@ -761,25 +763,26 @@ class QueryController extends Controller {
761
763
  delete this.pending;
762
764
  }
763
765
 
764
- // prevent an unnecessary `?q=` parameter from appearing in the URL
766
+ // add/remove current cursor position
767
+ if (hasFocus && this.query.value !== "") {
768
+ this.position.value = position;
769
+ this.position.disabled = false;
770
+ } else {
771
+ this.position.value = "";
772
+ this.position.disabled = true;
773
+ }
774
+
775
+ // prevent an unnecessary `?q=&p=0` parameter from appearing in the URL
765
776
  if (this.query.value === "") {
766
777
  this.query.disabled = true;
767
778
 
768
779
  // restore input and focus after form submission
769
780
  setTimeout(() => {
770
781
  this.query.disabled = false;
782
+ this.position.disabled = false;
771
783
  if (hasFocus) this.query.focus();
772
784
  }, 0);
773
785
  }
774
-
775
- // add/remove current cursor position
776
- if (hasFocus && position) {
777
- this.position.value = position;
778
- this.position.disabled = false;
779
- } else {
780
- this.position.value = "";
781
- this.position.disabled = true;
782
- }
783
786
  }
784
787
 
785
788
  update = () => {
@@ -801,8 +804,85 @@ class QueryController extends Controller {
801
804
  }
802
805
  }
803
806
 
807
+ moveToPreviousSuggestion() {
808
+ const prev = this.previousSuggestion || this.lastSuggestion;
809
+
810
+ if (prev) this.makeSuggestionActive(prev);
811
+ }
812
+
813
+ moveToNextSuggestion() {
814
+ const next = this.nextSuggestion || this.firstSuggestion;
815
+
816
+ if (next) this.makeSuggestionActive(next);
817
+ }
818
+
819
+ selectFirstSuggestion(e) {
820
+ // This is caused by pressing the tab key. We don't want to move focus.
821
+ // Ideally we don't want to always prevent the user from tabbing. We will address this later
822
+ e.preventDefault();
823
+
824
+ this.firstSuggestion?.dispatchEvent(new CustomEvent("query:select"));
825
+ }
826
+
827
+ selectActiveSuggestion() {
828
+ if (!this.activeSuggestion) {
829
+ this.closeModal();
830
+ return;
831
+ }
832
+
833
+ this.activeSuggestion.dispatchEvent(new CustomEvent("query:select"));
834
+ }
835
+
836
+ selectSuggestion(e) {
837
+ this.query.dispatchEvent(
838
+ new CustomEvent("replaceToken", {
839
+ detail: { token: e.params.value, position: this.query.selectionStart },
840
+ }),
841
+ );
842
+
843
+ this.clearActiveSuggestion();
844
+ }
845
+
846
+ makeSuggestionActive(node) {
847
+ if (this.activeSuggestion) {
848
+ this.activeSuggestion.setAttribute("aria-selected", "false");
849
+ }
850
+
851
+ this.query.setAttribute("aria-activedescendant", node.id);
852
+ node.setAttribute("aria-selected", "true");
853
+ }
854
+
855
+ clearActiveSuggestion() {
856
+ if (this.activeSuggestion) {
857
+ this.activeSuggestion.setAttribute("aria-selected", "false");
858
+ this.query.removeAttribute("aria-activedescendant");
859
+ }
860
+ }
861
+
862
+ get activeSuggestion() {
863
+ return this.modalTarget.querySelector(
864
+ `#${this.query.getAttribute("aria-activedescendant")}`,
865
+ );
866
+ }
867
+
868
+ get previousSuggestion() {
869
+ return this.activeSuggestion?.previousElementSibling;
870
+ }
871
+
872
+ get nextSuggestion() {
873
+ return this.activeSuggestion?.nextElementSibling;
874
+ }
875
+
876
+ get firstSuggestion() {
877
+ return this.modalTarget.querySelector("#suggestions li:first-of-type");
878
+ }
879
+
880
+ get lastSuggestion() {
881
+ return this.modalTarget.querySelector("#suggestions li:last-of-type");
882
+ }
883
+
804
884
  get query() {
805
- return this.element.querySelector("[role=searchbox]");
885
+ return this.element.querySelector("[role=combobox]");
806
886
  }
807
887
 
808
888
  get position() {
@@ -838,6 +918,49 @@ class QueryInputController extends Controller {
838
918
  this.highlightTarget.appendChild(token.render());
839
919
  });
840
920
  }
921
+
922
+ replaceToken(e) {
923
+ let tokenToAdd = e.detail.token.toString();
924
+
925
+ // wrap in quotes if it contains a spaces or special characters
926
+ if (/\s/.exec(tokenToAdd)) {
927
+ tokenToAdd = `"${tokenToAdd}"`;
928
+ }
929
+
930
+ const indexPosition = e.detail.position;
931
+ let caretPosition = indexPosition + tokenToAdd.length;
932
+ let sliceStart = indexPosition;
933
+ let sliceEnd = indexPosition;
934
+
935
+ // detect if position has a token already, if so, replace it
936
+ const existingToken = new Parser()
937
+ .parse(this.queryValue)
938
+ .tokenAtPosition(indexPosition);
939
+ if (existingToken) {
940
+ // We don't want to include the trailing space as we are replacing an existing value
941
+ tokenToAdd = tokenToAdd.trim();
942
+
943
+ // Slice up to the beginning of the tokens value (not the initial caret position)
944
+ sliceStart = existingToken.startOfValue();
945
+
946
+ // Slice after the end of the tokens value
947
+ sliceEnd = existingToken.endOfValue();
948
+
949
+ // The end position of the newly added token
950
+ caretPosition = sliceStart + tokenToAdd.length;
951
+ }
952
+
953
+ // Replace any text within sliceStart and sliceEnd with tokenToAdd
954
+ this.inputTarget.value =
955
+ this.queryValue.slice(0, sliceStart) +
956
+ tokenToAdd +
957
+ this.queryValue.slice(sliceEnd);
958
+
959
+ // Re focus the input at the end of the newly added token
960
+ this.update();
961
+ this.inputTarget.focus();
962
+ this.inputTarget.setSelectionRange(caretPosition, caretPosition);
963
+ }
841
964
  }
842
965
 
843
966
  class Parser {
@@ -871,13 +994,13 @@ class Parser {
871
994
  skipWhitespace(query) {
872
995
  if (!query.scan(/\s+/)) return;
873
996
 
874
- return new Token(query.matched());
997
+ return new Token(query.matched(), query.position);
875
998
  }
876
999
 
877
1000
  takeUntagged(query) {
878
1001
  if (!query.scan(/\S+/)) return;
879
1002
 
880
- return new Untagged(query.matched());
1003
+ return new Untagged(query.matched(), query.position);
881
1004
  }
882
1005
 
883
1006
  takeTagged(query) {
@@ -889,13 +1012,13 @@ class Parser {
889
1012
  const value =
890
1013
  this.takeArrayValue(query) || this.takeSingleValue(query) || new Token();
891
1014
 
892
- return new Tagged(key, separator, value);
1015
+ return new Tagged(key, separator, value, query.position);
893
1016
  }
894
1017
 
895
1018
  takeArrayValue(query) {
896
1019
  if (!query.scan(/\[\s*/)) return;
897
1020
 
898
- const start = new Token(query.matched());
1021
+ const start = new Token(query.matched(), query.position);
899
1022
  const values = (this.values = []);
900
1023
 
901
1024
  while (!query.isEos()) {
@@ -904,17 +1027,17 @@ class Parser {
904
1027
  }
905
1028
 
906
1029
  query.scan(/\s*]/);
907
- const end = new Token(query.matched());
1030
+ const end = new Token(query.matched(), query.position);
908
1031
 
909
1032
  this.values = null;
910
1033
 
911
- return new Array$1(start, values, end);
1034
+ return new ArrayToken(start, values, end);
912
1035
  }
913
1036
 
914
1037
  takeDelimiter(query) {
915
1038
  if (!query.scan(/\s*,\s*/)) return;
916
1039
 
917
- return new Token(query.matched());
1040
+ return new Token(query.matched(), query.position);
918
1041
  }
919
1042
 
920
1043
  takeSingleValue(query) {
@@ -924,24 +1047,49 @@ class Parser {
924
1047
  takeQuotedValue(query) {
925
1048
  if (!query.scan(/"([^"]*)"/)) return;
926
1049
 
927
- return new Value(query.matched());
1050
+ return new Value(query.matched(), query.position);
928
1051
  }
929
1052
 
930
1053
  takeUnquotedValue(query) {
931
1054
  if (!query.scan(/[^ \],]*/)) return;
932
1055
 
933
- return new Value(query.matched());
1056
+ return new Value(query.matched(), query.position);
1057
+ }
1058
+
1059
+ tokenAtPosition(position) {
1060
+ return this.tokens
1061
+ .filter((t) => t instanceof Tagged || t instanceof Untagged)
1062
+ .find((t) => t.range.includes(position));
934
1063
  }
935
1064
  }
936
1065
 
937
1066
  class Token {
938
- constructor(value = "") {
1067
+ constructor(value = "", position) {
939
1068
  this.value = value;
1069
+ this.length = this.value.length;
1070
+ this.start = position - this.length;
1071
+ this.end = this.start + this.length;
1072
+ this.range = this.arrayRange(this.start, this.end);
940
1073
  }
941
1074
 
942
1075
  render() {
943
1076
  return document.createTextNode(this.value);
944
1077
  }
1078
+
1079
+ arrayRange(start, stop) {
1080
+ return Array.from(
1081
+ { length: stop - start + 1 },
1082
+ (value, index) => start + index,
1083
+ );
1084
+ }
1085
+
1086
+ startOfValue() {
1087
+ return this.start;
1088
+ }
1089
+
1090
+ endOfValue() {
1091
+ return this.end;
1092
+ }
945
1093
  }
946
1094
 
947
1095
  class Value extends Token {
@@ -955,12 +1103,16 @@ class Value extends Token {
955
1103
  }
956
1104
 
957
1105
  class Tagged extends Token {
958
- constructor(key, separator, value) {
1106
+ constructor(key, separator, value, position) {
959
1107
  super();
960
1108
 
961
1109
  this.key = key;
962
1110
  this.separator = separator;
963
1111
  this.value = value;
1112
+ this.length = key.length + separator.length + value.value.length;
1113
+ this.start = position - this.length;
1114
+ this.end = this.start + this.length;
1115
+ this.range = this.arrayRange(this.start, this.end);
964
1116
  }
965
1117
 
966
1118
  render() {
@@ -977,6 +1129,14 @@ class Tagged extends Token {
977
1129
 
978
1130
  return span;
979
1131
  }
1132
+
1133
+ startOfValue() {
1134
+ return this.value.startOfValue();
1135
+ }
1136
+
1137
+ endOfValue() {
1138
+ return this.value.endOfValue();
1139
+ }
980
1140
  }
981
1141
 
982
1142
  class Untagged extends Token {
@@ -988,13 +1148,18 @@ class Untagged extends Token {
988
1148
  }
989
1149
  }
990
1150
 
991
- let Array$1 = class Array extends Token {
1151
+ class ArrayToken extends Token {
992
1152
  constructor(start, values, end) {
993
1153
  super();
994
1154
 
995
1155
  this.start = start;
996
1156
  this.values = values;
997
1157
  this.end = end;
1158
+ this.range = this.arrayRange(start.start, end.range[end.length]);
1159
+ this.length =
1160
+ start.length +
1161
+ values.reduce((length, value) => length + value.length, 0) +
1162
+ end.length;
998
1163
  }
999
1164
 
1000
1165
  render() {
@@ -1012,7 +1177,15 @@ let Array$1 = class Array extends Token {
1012
1177
 
1013
1178
  return array;
1014
1179
  }
1015
- };
1180
+
1181
+ startOfValue() {
1182
+ return this.start.start;
1183
+ }
1184
+
1185
+ endOfValue() {
1186
+ return this.end.end;
1187
+ }
1188
+ }
1016
1189
 
1017
1190
  class StringScanner {
1018
1191
  constructor(input) {
@@ -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 a=s.clientY-this.listOffset-this.cursorOffset;this.#e(e,t,a,i)}updateScroll(e,t,s){const i=this.listOffset;this.listOffset=e.getBoundingClientRect().top;const a=i-this.listOffset,r=this.position+a;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 h(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 a(e.matched())}takeUntagged(e){if(e.scan(/\S+/))return new l(e.matched())}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 a;return new n(t,s,i)}takeArrayValue(e){if(!e.scan(/\[\s*/))return;const t=new a(e.matched()),s=this.values=[];for(;!e.isEos()&&this.push(this.takeSingleValue(e))&&this.push(this.takeDelimiter(e)););e.scan(/\s*]/);const i=new a(e.matched());return this.values=null,new o(t,s,i)}takeDelimiter(e){if(e.scan(/\s*,\s*/))return new a(e.matched())}takeSingleValue(e){return this.takeQuotedValue(e)||this.takeUnquotedValue(e)}takeQuotedValue(e){if(e.scan(/"([^"]*)"/))return new r(e.matched())}takeUnquotedValue(e){if(e.scan(/[^ \],]*/))return new r(e.matched())}}class a{constructor(e=""){this.value=e}render(){return document.createTextNode(this.value)}}class r extends a{render(){const e=document.createElement("span");return e.className="value",e.innerText=this.value,e}}class n extends a{constructor(e,t,s){super(),this.key=e,this.separator=t,this.value=s}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}}class l extends a{render(){const e=document.createElement("span");return e.className="untagged",e.innerText=this.value,e}}let o=class extends a{constructor(e,t,s){super(),this.start=e,this.values=t,this.end=s}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}};class h{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 u=[{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.#a(e))).filter((e=>e))}#a(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,document.activeElement===this.query&&document.activeElement.blur(),document.removeEventListener("selectionchange",this.selection)}openModal(){this.modalTarget.dataset.open=!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),""===this.query.value&&(this.query.disabled=!0,setTimeout((()=>{this.query.disabled=!1,e&&this.query.focus()}),0)),e&&t?(this.position.value=t,this.position.disabled=!1):(this.position.value="",this.position.disabled=!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()}get query(){return this.element.querySelector("[role=searchbox]")}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())}))}}}];export{u 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,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};
2
2
  //# sourceMappingURL=tables.min.js.map