katalyst-koi 5.0.0.beta.3 → 5.0.1

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: 9bcc5dd5ebf6cb6ed2d0a989801f666af7e8bb0ab8eae889fbd12e8e6df8b5ac
4
- data.tar.gz: 25211eab3e9f3609d8b9923eac4408164b915873d625848050aa0f8b732deede
3
+ metadata.gz: 5820dfdebd095a698218f22c82418a8574a8f48ad4589454c175d91495b48f2a
4
+ data.tar.gz: 72cd699ccd493d6b4195fcad0cd064db46762b97681e3d23934eae580790443c
5
5
  SHA512:
6
- metadata.gz: '093d937e07a64eead13e4982b3155c83c91bcd9082683085786e38b294c061518dbcf00ec77f93645a9fd5d431802a7a329767fdea35fc52261aab6c20e4a18e'
7
- data.tar.gz: 87cb1bba9cf759973dce88c017701c91921f523f2d4945d13c3172bffc8173cf30399344b64170b93cd29fb5c57e01367146c38da6e92883b597b0c585a320ea
6
+ metadata.gz: 954f00403d6bc2361be663df10bd6cc0c24061675801ae9130133b293b85fcd7c30b84d152b500bb029595577a35015121aba334345ad470bb95d59eddf9d019
7
+ data.tar.gz: 9dd1b5da252025d2835f0777cec803c85a2c9bc1e707d23ed13b29a8a8649bcdcbc702668e9a7307624cb7ca6840546756dd7244be6849d774341a5f838f948f
@@ -7,8 +7,6 @@ import content from '@katalyst/content';
7
7
  import navigation from '@katalyst/navigation';
8
8
  import tables from '@katalyst/tables';
9
9
  import { get, parseRequestOptionsFromJSON, create, parseCreationOptionsFromJSON } from '@github/webauthn-json/browser-ponyfill';
10
- import HwComboboxController from 'controllers/hw_combobox_controller';
11
- import { eagerLoadControllersFrom } from '@hotwired/stimulus-loading';
12
10
 
13
11
  const application = Application.start();
14
12
 
@@ -766,10 +764,6 @@ const Definitions = [
766
764
  identifier: "form-request-submit",
767
765
  controllerConstructor: FormRequestSubmitController,
768
766
  },
769
- {
770
- identifier: "hw-combobox",
771
- controllerConstructor: HwComboboxController,
772
- },
773
767
  {
774
768
  identifier: "index-actions",
775
769
  controllerConstructor: IndexActionsController,
@@ -812,9 +806,17 @@ const Definitions = [
812
806
  },
813
807
  ];
814
808
 
815
- application.load(Definitions);
809
+ // dynamically attempt to load hw_combobox_controller, this is an optional dependency
810
+ await import('controllers/hw_combobox_controller')
811
+ .then(({ default: HwComboboxController }) => {
812
+ Definitions.push({
813
+ identifier: "hw-combobox",
814
+ controllerConstructor: HwComboboxController,
815
+ });
816
+ })
817
+ .catch(() => null);
816
818
 
817
- eagerLoadControllersFrom("admin/controllers", application);
819
+ application.load(Definitions);
818
820
 
819
821
  class KoiToolbarElement extends HTMLElement {
820
822
  constructor() {
@@ -826,12 +828,15 @@ class KoiToolbarElement extends HTMLElement {
826
828
 
827
829
  customElements.define("koi-toolbar", KoiToolbarElement);
828
830
 
829
- /** Let GOVUK know that we've got JS enabled */
830
- window.addEventListener("turbo:load", () => {
831
+ /** Initialize GOVUK */
832
+ function initGOVUK() {
831
833
  document.body.classList.toggle("js-enabled", true);
832
834
  document.body.classList.toggle(
833
835
  "govuk-frontend-supported",
834
836
  "noModule" in HTMLScriptElement.prototype,
835
837
  );
836
838
  initAll();
837
- });
839
+ }
840
+
841
+ window.addEventListener("turbo:load", initGOVUK);
842
+ if (window.Turbo) initGOVUK();
@@ -7,8 +7,6 @@ import content from '@katalyst/content';
7
7
  import navigation from '@katalyst/navigation';
8
8
  import tables from '@katalyst/tables';
9
9
  import { get, parseRequestOptionsFromJSON, create, parseCreationOptionsFromJSON } from '@github/webauthn-json/browser-ponyfill';
10
- import HwComboboxController from 'controllers/hw_combobox_controller';
11
- import { eagerLoadControllersFrom } from '@hotwired/stimulus-loading';
12
10
 
13
11
  const application = Application.start();
14
12
 
@@ -766,10 +764,6 @@ const Definitions = [
766
764
  identifier: "form-request-submit",
767
765
  controllerConstructor: FormRequestSubmitController,
768
766
  },
769
- {
770
- identifier: "hw-combobox",
771
- controllerConstructor: HwComboboxController,
772
- },
773
767
  {
774
768
  identifier: "index-actions",
775
769
  controllerConstructor: IndexActionsController,
@@ -812,9 +806,17 @@ const Definitions = [
812
806
  },
813
807
  ];
814
808
 
815
- application.load(Definitions);
809
+ // dynamically attempt to load hw_combobox_controller, this is an optional dependency
810
+ await import('controllers/hw_combobox_controller')
811
+ .then(({ default: HwComboboxController }) => {
812
+ Definitions.push({
813
+ identifier: "hw-combobox",
814
+ controllerConstructor: HwComboboxController,
815
+ });
816
+ })
817
+ .catch(() => null);
816
818
 
817
- eagerLoadControllersFrom("admin/controllers", application);
819
+ application.load(Definitions);
818
820
 
819
821
  class KoiToolbarElement extends HTMLElement {
820
822
  constructor() {
@@ -826,12 +828,15 @@ class KoiToolbarElement extends HTMLElement {
826
828
 
827
829
  customElements.define("koi-toolbar", KoiToolbarElement);
828
830
 
829
- /** Let GOVUK know that we've got JS enabled */
830
- window.addEventListener("turbo:load", () => {
831
+ /** Initialize GOVUK */
832
+ function initGOVUK() {
831
833
  document.body.classList.toggle("js-enabled", true);
832
834
  document.body.classList.toggle(
833
835
  "govuk-frontend-supported",
834
836
  "noModule" in HTMLScriptElement.prototype,
835
837
  );
836
838
  initAll();
837
- });
839
+ }
840
+
841
+ window.addEventListener("turbo:load", initGOVUK);
842
+ if (window.Turbo) initGOVUK();
@@ -1,2 +1,2 @@
1
- import"@hotwired/turbo-rails";import t,{initAll as e}from"@katalyst/govuk-formbuilder";import"@rails/actiontext";import"trix";import{Application as s,Controller as r}from"@hotwired/stimulus";import i from"@katalyst/content";import a from"@katalyst/navigation";import o from"@katalyst/tables";import{get as n,parseRequestOptionsFromJSON as l,create as c,parseCreationOptionsFromJSON as h}from"@github/webauthn-json/browser-ponyfill";import u from"controllers/hw_combobox_controller";import{eagerLoadControllersFrom as d}from"@hotwired/stimulus-loading";const g=s.start();class p{constructor(t,e){const{delay:s}=this._setDefaults(e);this.target=t,this.runner=new m(this,s),this.properties=[],this.startingCallbacks=[],this.startedCallbacks=[],this.completeCallbacks=[]}add(t){return this.properties.push(t),this}addCallback(t,e){switch(t){case"starting":this.startingCallbacks.push(e);break;case"started":this.startedCallbacks.push(e);break;case"complete":this.completeCallbacks.push(e)}return this}collapse(){return this.add(new f("max-height",`${this.target.scrollHeight}px`,"0px"))}expand(){return this.add(new f("max-height","0px",`${this.target.scrollHeight}px`))}slideOut(t){return this.add(new f(t,"0px",`-${this.target.scrollWidth}px`))}slideIn(t){return this.add(new f(t,`-${this.target.scrollWidth}px`,"0px"))}fadeOut(){return this.add(new f("opacity","100%","0%"))}fadeIn(){return this.add(new f("opacity","0%","100%"))}start(t=null){return requestAnimationFrame(()=>{this.runner.start(this.target),t&&t()}),this}cancel(){return this.runner.stop(this.target),this}_starting(){const t=new Event("transition:starting");this.startingCallbacks.forEach(e=>e(t)),this.target.dispatchEvent(t)}_started(){const t=new Event("transition:started");this.startedCallbacks.forEach(e=>e(t)),this.target.dispatchEvent(t)}_complete(){const t=new Event("transition:complete");this.completeCallbacks.forEach(e=>e(t)),this.target.dispatchEvent(t)}_setDefaults(t){return Object.assign({delay:250},t)}}class m{constructor(t,e){this.transition=t,this.running=null,this.delay=e}start(t){this.transition.properties.forEach(e=>e.onStarting(t)),requestAnimationFrame(()=>this.onStarted(t)),this.running=setTimeout(()=>this.stop(t,!0),this.delay),this.transition._starting()}onStarted(t){t.style.transitionProperty=this.transition.properties.map(t=>t.property).join(","),t.style.transitionDuration=`${this.delay}ms`,this.transition.properties.forEach(e=>e.onStarted(t)),this.transition._started()}stop(t,e=!1){this.running&&(e||clearTimeout(this.running),this.running=null,t.style.removeProperty("transition-property"),t.style.removeProperty("transition-duration"),this.transition.properties.forEach(e=>e.onComplete(t)),this.transition._complete())}}class f{constructor(t,e,s){this.property=t,this.from=e,this.to=s}onStarting(t){t.style.setProperty(this.property,this.from)}onStarted(t){t.style.setProperty(this.property,this.to)}onComplete(t){t.style.removeProperty(this.property)}}g.load(i),g.load(t),g.load(a),g.load(o);const b=[{identifier:"clipboard",controllerConstructor:class extends r{static targets=["source"];static classes=["supported"];connect(){"clipboard"in navigator&&this.element.classList.add(this.supportedClass)}copy(t){t.preventDefault(),navigator.clipboard.writeText(this.sourceTarget.value),this.element.classList.add("copied"),setTimeout(()=>{this.element.classList.remove("copied")},2e3)}}},{identifier:"flash",controllerConstructor:class extends r{close(t){t.target.closest("li").remove(),0===this.element.children.length&&this.element.remove()}}},{identifier:"form-request-submit",controllerConstructor:class extends r{requestSubmit(){this.element.requestSubmit()}}},{identifier:"hw-combobox",controllerConstructor:u},{identifier:"index-actions",controllerConstructor:class extends r{static targets=["create","search","sort"];initialize(){var t,e;this.update=(t=this,e=this.update,(...s)=>{clearTimeout(t.timer),t.timer=setTimeout(()=>{e.apply(t,...s)},300)})}disconnect(){clearTimeout(this.timer)}create(){this.createTarget.click()}search(){this.searchTarget.focus()}clear(){this.searchTarget.value="",this.searchTarget.closest("form").requestSubmit()}update(){this.searchTarget.closest("form").requestSubmit()}submit(){const t=document.activeElement===this.searchTarget;""===this.searchTarget.value&&(this.searchTarget.disabled=!0),""===this.sortTarget.value&&(this.sortTarget.disabled=!0),Promise.resolve().then(()=>{this.searchTarget.disabled=!1,this.sortTarget.disabled=!1,t&&this.searchTarget.focus()})}}},{identifier:"keyboard",controllerConstructor:class extends r{static values={mapping:String,depth:{type:Number,default:2}};event(t){if(function(t){if(!(t instanceof HTMLElement))return!1;const e=t.nodeName.toLowerCase(),s=(t.getAttribute("type")||"").toLowerCase();return"select"===e||"textarea"===e||"trix-editor"===e||"input"===e&&"submit"!==s&&"reset"!==s&&"checkbox"!==s&&"radio"!==s&&"file"!==s||t.isContentEditable}(t.target)||this.#t(t))return;const e=this.describeEvent(t);this.buffer=[...this.buffer||[],e].slice(0-this.depthValue);const s=this.buffer.reduceRight((t,e)=>"string"==typeof t||void 0===t?t:t[e],this.mappings);if("string"!=typeof s)return;this.buffer=[],t.preventDefault();const r=new CustomEvent(s,{detail:{cause:t},bubbles:!0});t.target.dispatchEvent(r)}describeEvent(t){return[t.ctrlKey&&"C",t.metaKey&&"M",t.altKey&&"A",t.shiftKey&&"S",t.code].filter(t=>t).join("-")}get mappings(){const t=this.mappingValue.replaceAll(/\s+/g," ").split(" ").filter(t=>t.length>0),e={};return t.forEach(t=>this.#e(e,t)),Object.defineProperty(this,"mappings",{value:e,writable:!1}),e}#e(t,e){const[s,r]=e.split("->"),i=s.split("+"),a=i.shift();(t=i.reduceRight((t,e)=>t[e]||={},t))[a]=r}#t(t){switch(t.code){case"ControlLeft":case"ControlRight":case"MetaLeft":case"MetaRight":case"ShiftLeft":case"ShiftRight":case"AltLeft":case"AltRight":return!0;default:return!1}}}},{identifier:"modal",controllerConstructor:class extends r{static targets=["dialog"];connect(){this.element.addEventListener("turbo:submit-end",this.onSubmit)}disconnect(){this.element.removeEventListener("turbo:submit-end",this.onSubmit)}outside(t){"DIALOG"===t.target.tagName&&this.dismiss()}dismiss(){this.dialogTarget&&(this.dialogTarget.open||this.dialogTarget.close(),this.element.removeAttribute("src"),this.dialogTarget.remove())}dialogTargetConnected(t){t.showModal()}onSubmit=t=>{t.detail.success&&"closeDialog"in t.detail.formSubmission?.submitter?.dataset&&(this.dialogTarget.close(),this.element.removeAttribute("src"),this.dialogTarget.remove())}}},{identifier:"navigation",controllerConstructor:class extends r{static targets=["filter"];filter(){const t=this.filterTarget.value;this.clearFilter(t),t.length>0&&this.applyFilter(t)}go(){this.element.querySelector("li:not([hidden]) > a").click()}clear(){0===this.filterTarget.value.length&&this.filterTarget.blur()}applyFilter(t){this.links.filter(e=>!this.prefixSearch(t.toLowerCase(),e.innerText.toLowerCase())).forEach(t=>{t.toggleAttribute("hidden",!0)}),this.menus.filter(t=>!t.matches("li:has(li:not([hidden]) > a)")).forEach(t=>{t.toggleAttribute("hidden",!0)})}clearFilter(t){this.element.querySelectorAll("li").forEach(t=>{t.toggleAttribute("hidden",!1)})}prefixSearch(t,e){const s=e.length,r=t.length;if(r>s)return!1;if(r===s)return t===e;t:for(let i=0,a=0;i<r;i++){const r=t.charCodeAt(i);if(32!==r){for(;a<s;){if(e.charCodeAt(a++)===r)continue t;for(;a<s&&32!==e.charCodeAt(a++););}return!1}for(;a<s&&32!==e.charCodeAt(a++););}return!0}toggle(){this.element.open?this.close():this.open()}open(){this.element.open||this.element.showModal()}close(){this.element.open&&this.element.close()}click(t){t.target===this.element&&this.close()}onMorphAttribute=t=>{if(t.target===this.element&&"open"===t.detail.attributeName)t.preventDefault()};get links(){return Array.from(this.element.querySelectorAll("li:has(> a)"))}get menus(){return Array.from(this.element.querySelectorAll("li:has(> ul)"))}}},{identifier:"navigation-toggle",controllerConstructor:class extends r{trigger(){this.dispatch("toggle",{prefix:"navigation",bubbles:!0})}}},{identifier:"pagy-nav",controllerConstructor:class extends r{connect(){document.addEventListener("shortcut:page-prev",this.prevPage),document.addEventListener("shortcut:page-next",this.nextPage)}disconnect(){document.removeEventListener("shortcut:page-prev",this.prevPage),document.removeEventListener("shortcut:page-next",this.nextPage)}nextPage=()=>{this.element.querySelector("a:last-child").click()};prevPage=()=>{this.element.querySelector("a:first-child").click()}}},{identifier:"show-hide",controllerConstructor:class extends r{static targets=["content"];toggle(){const t=this.contentTarget,e=t.toggleAttribute("data-collapsed");this.transition&&this.transition.cancel();const s=this.transition=new p(t).addCallback("starting",function(){t.setAttribute("data-collapsed-transitioning","true")}).addCallback("complete",function(){t.removeAttribute("data-collapsed-transitioning")});e?s.collapse():s.expand(),s.start()}}},{identifier:"sluggable",controllerConstructor:class extends r{static targets=["source","slug"];static values={slug:String};sourceChanged(t){""===this.slugValue&&(this.slugTarget.value=this.sourceTarget.value.toLowerCase().replace(/'/g,"-").replace(/[^-\w\s]/g,"").replace(/[^a-z0-9]+/g,"-").replace(/(^-|-$)/g,""))}slugChanged(t){this.slugValue=this.slugTarget.value}}},{identifier:"webauthn-authentication",controllerConstructor:class extends r{static targets=["response"];static values={options:Object};authenticate(){n(this.options).then(t=>{this.responseTarget.value=JSON.stringify(t),this.element.requestSubmit()})}get options(){return l(this.optionsValue)}}},{identifier:"webauthn-registration",controllerConstructor:class extends r{static values={options:Object,response:String};static targets=["intro","nickname","response"];submit(t){""===this.responseTarget.value&&"dialog"!==t.submitter.formMethod&&(t.preventDefault(),this.createCredential())}async createCredential(){const t=await c(this.options);this.responseValue=JSON.stringify(t),this.responseTarget.value=JSON.stringify(t)}responseValueChanged(t){const e=""!==t;this.introTarget.toggleAttribute("hidden",e),this.nicknameTarget.toggleAttribute("hidden",!e)}get options(){return h(this.optionsValue)}}}];g.load(b),d("admin/controllers",g);class v extends HTMLElement{constructor(){super(),this.setAttribute("role","toolbar")}}customElements.define("koi-toolbar",v),window.addEventListener("turbo:load",()=>{document.body.classList.toggle("js-enabled",!0),document.body.classList.toggle("govuk-frontend-supported","noModule"in HTMLScriptElement.prototype),e()});
1
+ import"@hotwired/turbo-rails";import t,{initAll as e}from"@katalyst/govuk-formbuilder";import"@rails/actiontext";import"trix";import{Application as s,Controller as r}from"@hotwired/stimulus";import i from"@katalyst/content";import a from"@katalyst/navigation";import o from"@katalyst/tables";import{get as n,parseRequestOptionsFromJSON as l,create as c,parseCreationOptionsFromJSON as h}from"@github/webauthn-json/browser-ponyfill";const u=s.start();class d{constructor(t,e){const{delay:s}=this._setDefaults(e);this.target=t,this.runner=new g(this,s),this.properties=[],this.startingCallbacks=[],this.startedCallbacks=[],this.completeCallbacks=[]}add(t){return this.properties.push(t),this}addCallback(t,e){switch(t){case"starting":this.startingCallbacks.push(e);break;case"started":this.startedCallbacks.push(e);break;case"complete":this.completeCallbacks.push(e)}return this}collapse(){return this.add(new p("max-height",`${this.target.scrollHeight}px`,"0px"))}expand(){return this.add(new p("max-height","0px",`${this.target.scrollHeight}px`))}slideOut(t){return this.add(new p(t,"0px",`-${this.target.scrollWidth}px`))}slideIn(t){return this.add(new p(t,`-${this.target.scrollWidth}px`,"0px"))}fadeOut(){return this.add(new p("opacity","100%","0%"))}fadeIn(){return this.add(new p("opacity","0%","100%"))}start(t=null){return requestAnimationFrame(()=>{this.runner.start(this.target),t&&t()}),this}cancel(){return this.runner.stop(this.target),this}_starting(){const t=new Event("transition:starting");this.startingCallbacks.forEach(e=>e(t)),this.target.dispatchEvent(t)}_started(){const t=new Event("transition:started");this.startedCallbacks.forEach(e=>e(t)),this.target.dispatchEvent(t)}_complete(){const t=new Event("transition:complete");this.completeCallbacks.forEach(e=>e(t)),this.target.dispatchEvent(t)}_setDefaults(t){return Object.assign({delay:250},t)}}class g{constructor(t,e){this.transition=t,this.running=null,this.delay=e}start(t){this.transition.properties.forEach(e=>e.onStarting(t)),requestAnimationFrame(()=>this.onStarted(t)),this.running=setTimeout(()=>this.stop(t,!0),this.delay),this.transition._starting()}onStarted(t){t.style.transitionProperty=this.transition.properties.map(t=>t.property).join(","),t.style.transitionDuration=`${this.delay}ms`,this.transition.properties.forEach(e=>e.onStarted(t)),this.transition._started()}stop(t,e=!1){this.running&&(e||clearTimeout(this.running),this.running=null,t.style.removeProperty("transition-property"),t.style.removeProperty("transition-duration"),this.transition.properties.forEach(e=>e.onComplete(t)),this.transition._complete())}}class p{constructor(t,e,s){this.property=t,this.from=e,this.to=s}onStarting(t){t.style.setProperty(this.property,this.from)}onStarted(t){t.style.setProperty(this.property,this.to)}onComplete(t){t.style.removeProperty(this.property)}}u.load(i),u.load(t),u.load(a),u.load(o);const m=[{identifier:"clipboard",controllerConstructor:class extends r{static targets=["source"];static classes=["supported"];connect(){"clipboard"in navigator&&this.element.classList.add(this.supportedClass)}copy(t){t.preventDefault(),navigator.clipboard.writeText(this.sourceTarget.value),this.element.classList.add("copied"),setTimeout(()=>{this.element.classList.remove("copied")},2e3)}}},{identifier:"flash",controllerConstructor:class extends r{close(t){t.target.closest("li").remove(),0===this.element.children.length&&this.element.remove()}}},{identifier:"form-request-submit",controllerConstructor:class extends r{requestSubmit(){this.element.requestSubmit()}}},{identifier:"index-actions",controllerConstructor:class extends r{static targets=["create","search","sort"];initialize(){var t,e;this.update=(t=this,e=this.update,(...s)=>{clearTimeout(t.timer),t.timer=setTimeout(()=>{e.apply(t,...s)},300)})}disconnect(){clearTimeout(this.timer)}create(){this.createTarget.click()}search(){this.searchTarget.focus()}clear(){this.searchTarget.value="",this.searchTarget.closest("form").requestSubmit()}update(){this.searchTarget.closest("form").requestSubmit()}submit(){const t=document.activeElement===this.searchTarget;""===this.searchTarget.value&&(this.searchTarget.disabled=!0),""===this.sortTarget.value&&(this.sortTarget.disabled=!0),Promise.resolve().then(()=>{this.searchTarget.disabled=!1,this.sortTarget.disabled=!1,t&&this.searchTarget.focus()})}}},{identifier:"keyboard",controllerConstructor:class extends r{static values={mapping:String,depth:{type:Number,default:2}};event(t){if(function(t){if(!(t instanceof HTMLElement))return!1;const e=t.nodeName.toLowerCase(),s=(t.getAttribute("type")||"").toLowerCase();return"select"===e||"textarea"===e||"trix-editor"===e||"input"===e&&"submit"!==s&&"reset"!==s&&"checkbox"!==s&&"radio"!==s&&"file"!==s||t.isContentEditable}(t.target)||this.#t(t))return;const e=this.describeEvent(t);this.buffer=[...this.buffer||[],e].slice(0-this.depthValue);const s=this.buffer.reduceRight((t,e)=>"string"==typeof t||void 0===t?t:t[e],this.mappings);if("string"!=typeof s)return;this.buffer=[],t.preventDefault();const r=new CustomEvent(s,{detail:{cause:t},bubbles:!0});t.target.dispatchEvent(r)}describeEvent(t){return[t.ctrlKey&&"C",t.metaKey&&"M",t.altKey&&"A",t.shiftKey&&"S",t.code].filter(t=>t).join("-")}get mappings(){const t=this.mappingValue.replaceAll(/\s+/g," ").split(" ").filter(t=>t.length>0),e={};return t.forEach(t=>this.#e(e,t)),Object.defineProperty(this,"mappings",{value:e,writable:!1}),e}#e(t,e){const[s,r]=e.split("->"),i=s.split("+"),a=i.shift();(t=i.reduceRight((t,e)=>t[e]||={},t))[a]=r}#t(t){switch(t.code){case"ControlLeft":case"ControlRight":case"MetaLeft":case"MetaRight":case"ShiftLeft":case"ShiftRight":case"AltLeft":case"AltRight":return!0;default:return!1}}}},{identifier:"modal",controllerConstructor:class extends r{static targets=["dialog"];connect(){this.element.addEventListener("turbo:submit-end",this.onSubmit)}disconnect(){this.element.removeEventListener("turbo:submit-end",this.onSubmit)}outside(t){"DIALOG"===t.target.tagName&&this.dismiss()}dismiss(){this.dialogTarget&&(this.dialogTarget.open||this.dialogTarget.close(),this.element.removeAttribute("src"),this.dialogTarget.remove())}dialogTargetConnected(t){t.showModal()}onSubmit=t=>{t.detail.success&&"closeDialog"in t.detail.formSubmission?.submitter?.dataset&&(this.dialogTarget.close(),this.element.removeAttribute("src"),this.dialogTarget.remove())}}},{identifier:"navigation",controllerConstructor:class extends r{static targets=["filter"];filter(){const t=this.filterTarget.value;this.clearFilter(t),t.length>0&&this.applyFilter(t)}go(){this.element.querySelector("li:not([hidden]) > a").click()}clear(){0===this.filterTarget.value.length&&this.filterTarget.blur()}applyFilter(t){this.links.filter(e=>!this.prefixSearch(t.toLowerCase(),e.innerText.toLowerCase())).forEach(t=>{t.toggleAttribute("hidden",!0)}),this.menus.filter(t=>!t.matches("li:has(li:not([hidden]) > a)")).forEach(t=>{t.toggleAttribute("hidden",!0)})}clearFilter(t){this.element.querySelectorAll("li").forEach(t=>{t.toggleAttribute("hidden",!1)})}prefixSearch(t,e){const s=e.length,r=t.length;if(r>s)return!1;if(r===s)return t===e;t:for(let i=0,a=0;i<r;i++){const r=t.charCodeAt(i);if(32!==r){for(;a<s;){if(e.charCodeAt(a++)===r)continue t;for(;a<s&&32!==e.charCodeAt(a++););}return!1}for(;a<s&&32!==e.charCodeAt(a++););}return!0}toggle(){this.element.open?this.close():this.open()}open(){this.element.open||this.element.showModal()}close(){this.element.open&&this.element.close()}click(t){t.target===this.element&&this.close()}onMorphAttribute=t=>{if(t.target===this.element&&"open"===t.detail.attributeName)t.preventDefault()};get links(){return Array.from(this.element.querySelectorAll("li:has(> a)"))}get menus(){return Array.from(this.element.querySelectorAll("li:has(> ul)"))}}},{identifier:"navigation-toggle",controllerConstructor:class extends r{trigger(){this.dispatch("toggle",{prefix:"navigation",bubbles:!0})}}},{identifier:"pagy-nav",controllerConstructor:class extends r{connect(){document.addEventListener("shortcut:page-prev",this.prevPage),document.addEventListener("shortcut:page-next",this.nextPage)}disconnect(){document.removeEventListener("shortcut:page-prev",this.prevPage),document.removeEventListener("shortcut:page-next",this.nextPage)}nextPage=()=>{this.element.querySelector("a:last-child").click()};prevPage=()=>{this.element.querySelector("a:first-child").click()}}},{identifier:"show-hide",controllerConstructor:class extends r{static targets=["content"];toggle(){const t=this.contentTarget,e=t.toggleAttribute("data-collapsed");this.transition&&this.transition.cancel();const s=this.transition=new d(t).addCallback("starting",function(){t.setAttribute("data-collapsed-transitioning","true")}).addCallback("complete",function(){t.removeAttribute("data-collapsed-transitioning")});e?s.collapse():s.expand(),s.start()}}},{identifier:"sluggable",controllerConstructor:class extends r{static targets=["source","slug"];static values={slug:String};sourceChanged(t){""===this.slugValue&&(this.slugTarget.value=this.sourceTarget.value.toLowerCase().replace(/'/g,"-").replace(/[^-\w\s]/g,"").replace(/[^a-z0-9]+/g,"-").replace(/(^-|-$)/g,""))}slugChanged(t){this.slugValue=this.slugTarget.value}}},{identifier:"webauthn-authentication",controllerConstructor:class extends r{static targets=["response"];static values={options:Object};authenticate(){n(this.options).then(t=>{this.responseTarget.value=JSON.stringify(t),this.element.requestSubmit()})}get options(){return l(this.optionsValue)}}},{identifier:"webauthn-registration",controllerConstructor:class extends r{static values={options:Object,response:String};static targets=["intro","nickname","response"];submit(t){""===this.responseTarget.value&&"dialog"!==t.submitter.formMethod&&(t.preventDefault(),this.createCredential())}async createCredential(){const t=await c(this.options);this.responseValue=JSON.stringify(t),this.responseTarget.value=JSON.stringify(t)}responseValueChanged(t){const e=""!==t;this.introTarget.toggleAttribute("hidden",e),this.nicknameTarget.toggleAttribute("hidden",!e)}get options(){return h(this.optionsValue)}}}];await import("controllers/hw_combobox_controller").then(({default:t})=>{m.push({identifier:"hw-combobox",controllerConstructor:t})}).catch(()=>null),u.load(m);class f extends HTMLElement{constructor(){super(),this.setAttribute("role","toolbar")}}function b(){document.body.classList.toggle("js-enabled",!0),document.body.classList.toggle("govuk-frontend-supported","noModule"in HTMLScriptElement.prototype),e()}customElements.define("koi-toolbar",f),window.addEventListener("turbo:load",b),window.Turbo&&b();
2
2
  //# sourceMappingURL=koi.min.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"koi.min.js","sources":["../../../javascript/koi/controllers/application.js","../../../javascript/koi/utils/transition.js","../../../javascript/koi/controllers/index.js","../../../javascript/koi/controllers/clipboard_controller.js","../../../javascript/koi/controllers/flash_controller.js","../../../javascript/koi/controllers/form_request_submit_controller.js","../../../javascript/koi/controllers/index_actions_controller.js","../../../javascript/koi/controllers/keyboard_controller.js","../../../javascript/koi/controllers/modal_controller.js","../../../javascript/koi/controllers/navigation_controller.js","../../../javascript/koi/controllers/navigation_toggle_controller.js","../../../javascript/koi/controllers/pagy_nav_controller.js","../../../javascript/koi/controllers/show_hide_controller.js","../../../javascript/koi/controllers/sluggable_controller.js","../../../javascript/koi/controllers/webauthn_authentication_controller.js","../../../javascript/koi/controllers/webauthn_registration_controller.js","../../../javascript/koi/elements/toolbar.js","../../../javascript/koi/application.js"],"sourcesContent":["import { Application } from \"@hotwired/stimulus\";\n\nconst application = Application.start();\n\nexport { application };\n","const DEFAULT_DELAY = 250;\n\n/**\n * A utility class for managing CSS transition animations.\n *\n * Transition uses Javascript timers to track state instead of relying on\n * CSS transition events, which is a more complicated API. Please call `cancel`\n * when the node being animated is detached from the DOM to avoid unexpected\n * errors or animation glitches.\n *\n * Transition assumes that CSS already specifies styles to achieve the expected\n * start and end states. Transition adds temporary overrides and then animates\n * between those values using CSS transitions. For example, to use the collapse\n * transition:\n *\n * @example\n * // CSS:\n * target {\n * max-height: unset;\n * overflow: 0;\n * }\n * target.hidden {\n * max-height: 0;\n * }\n *\n * @example\n * // Javascript\n * target.addClass(\"hidden\");\n * new Transition(target).collapse().start();\n */\nclass Transition {\n constructor(target, options) {\n const { delay } = this._setDefaults(options);\n\n this.target = target;\n this.runner = new Runner(this, delay);\n this.properties = [];\n\n this.startingCallbacks = [];\n this.startedCallbacks = [];\n this.completeCallbacks = [];\n }\n\n add(property) {\n this.properties.push(property);\n return this;\n }\n\n /** Adds callback for transition events */\n addCallback(type, callback) {\n switch (type) {\n case \"starting\":\n this.startingCallbacks.push(callback);\n break;\n case \"started\":\n this.startedCallbacks.push(callback);\n break;\n case \"complete\":\n this.completeCallbacks.push(callback);\n break;\n }\n return this;\n }\n\n /** Collapse an element in place, assumes overflow is set appropriately, margin is not collapsed */\n collapse() {\n return this.add(\n new PropertyTransition(\n \"max-height\",\n `${this.target.scrollHeight}px`,\n \"0px\",\n ),\n );\n }\n\n /** Restore a collapsed element */\n expand() {\n return this.add(\n new PropertyTransition(\n \"max-height\",\n \"0px\",\n `${this.target.scrollHeight}px`,\n ),\n );\n }\n\n /** Slide an element left or right by its scroll width, assumes position relative */\n slideOut(direction) {\n return this.add(\n new PropertyTransition(direction, \"0px\", `-${this.target.scrollWidth}px`),\n );\n }\n\n /** Restore an element that has been slid */\n slideIn(direction) {\n return this.add(\n new PropertyTransition(direction, `-${this.target.scrollWidth}px`, \"0px\"),\n );\n }\n\n /** Cause an element to become transparent by transforming opacity */\n fadeOut() {\n return this.add(new PropertyTransition(\"opacity\", \"100%\", \"0%\"));\n }\n\n /** Cause a transparent element to become visible again */\n fadeIn() {\n return this.add(new PropertyTransition(\"opacity\", \"0%\", \"100%\"));\n }\n\n start(callback = null) {\n // start the runner on next tick so that any side-effects of the current execution can occur first\n requestAnimationFrame(() => {\n this.runner.start(this.target);\n if (callback) callback();\n });\n return this;\n }\n\n cancel() {\n this.runner.stop(this.target);\n return this;\n }\n\n _starting() {\n const event = new Event(\"transition:starting\");\n this.startingCallbacks.forEach((cb) => cb(event));\n this.target.dispatchEvent(event);\n }\n\n _started() {\n const event = new Event(\"transition:started\");\n this.startedCallbacks.forEach((cb) => cb(event));\n this.target.dispatchEvent(event);\n }\n\n _complete() {\n const event = new Event(\"transition:complete\");\n this.completeCallbacks.forEach((cb) => cb(event));\n this.target.dispatchEvent(event);\n }\n\n _setDefaults(options) {\n return Object.assign({ delay: DEFAULT_DELAY }, options);\n }\n}\n\n/**\n * Encapsulates internal execution and timing functionality for `Transition`\n */\nclass Runner {\n constructor(transition, delay) {\n this.transition = transition;\n this.running = null;\n this.delay = delay;\n }\n\n start(target) {\n // 1. Set the initial state(s)\n this.transition.properties.forEach((t) => t.onStarting(target));\n\n // 2. On next update, set transition and final state(s)\n requestAnimationFrame(() => this.onStarted(target));\n\n // 3. After transition has finished, clean up\n this.running = setTimeout(() => this.stop(target, true), this.delay);\n\n this.transition._starting();\n }\n\n onStarted(target) {\n target.style.transitionProperty = this.transition.properties\n .map((t) => t.property)\n .join(\",\");\n target.style.transitionDuration = `${this.delay}ms`;\n this.transition.properties.forEach((t) => t.onStarted(target));\n\n this.transition._started();\n }\n\n stop(target, timeout = false) {\n if (!this.running) return;\n if (!timeout) clearTimeout(this.running);\n\n this.running = null;\n\n target.style.removeProperty(\"transition-property\");\n target.style.removeProperty(\"transition-duration\");\n this.transition.properties.forEach((t) => t.onComplete(target));\n\n this.transition._complete();\n }\n}\n\n/**\n * Represents animation of a single CSS property. Currently only CSS animations\n * are supported, but this could be a natural extension point for Javascript\n * animations in the future.\n */\nclass PropertyTransition {\n constructor(property, from, to) {\n this.property = property;\n this.from = from;\n this.to = to;\n }\n\n onStarting(target) {\n target.style.setProperty(this.property, this.from);\n }\n\n onStarted(target) {\n target.style.setProperty(this.property, this.to);\n }\n\n onComplete(target) {\n target.style.removeProperty(this.property);\n }\n}\n\nexport { Transition };\n","import { application } from \"./application\";\n\nimport content from \"@katalyst/content\";\napplication.load(content);\n\nimport govuk from \"@katalyst/govuk-formbuilder\";\napplication.load(govuk);\n\nimport navigation from \"@katalyst/navigation\";\napplication.load(navigation);\n\nimport tables from \"@katalyst/tables\";\napplication.load(tables);\n\nimport ClipboardController from \"./clipboard_controller\";\nimport FlashController from \"./flash_controller\";\nimport FormRequestSubmitController from \"./form_request_submit_controller\";\nimport IndexActionsController from \"./index_actions_controller\";\nimport KeyboardController from \"./keyboard_controller\";\nimport ModalController from \"./modal_controller\";\nimport NavigationController from \"./navigation_controller\";\nimport NavigationToggleController from \"./navigation_toggle_controller\";\nimport PagyNavController from \"./pagy_nav_controller\";\nimport ShowHideController from \"./show_hide_controller\";\nimport SluggableController from \"./sluggable_controller\";\nimport WebauthnAuthenticationController from \"./webauthn_authentication_controller\";\nimport WebauthnRegistrationController from \"./webauthn_registration_controller\";\n\n// Third party controllers\nimport HwComboboxController from \"controllers/hw_combobox_controller\";\n\nconst Definitions = [\n {\n identifier: \"clipboard\",\n controllerConstructor: ClipboardController,\n },\n {\n identifier: \"flash\",\n controllerConstructor: FlashController,\n },\n {\n identifier: \"form-request-submit\",\n controllerConstructor: FormRequestSubmitController,\n },\n {\n identifier: \"hw-combobox\",\n controllerConstructor: HwComboboxController,\n },\n {\n identifier: \"index-actions\",\n controllerConstructor: IndexActionsController,\n },\n {\n identifier: \"keyboard\",\n controllerConstructor: KeyboardController,\n },\n {\n identifier: \"modal\",\n controllerConstructor: ModalController,\n },\n {\n identifier: \"navigation\",\n controllerConstructor: NavigationController,\n },\n {\n identifier: \"navigation-toggle\",\n controllerConstructor: NavigationToggleController,\n },\n {\n identifier: \"pagy-nav\",\n controllerConstructor: PagyNavController,\n },\n {\n identifier: \"show-hide\",\n controllerConstructor: ShowHideController,\n },\n {\n identifier: \"sluggable\",\n controllerConstructor: SluggableController,\n },\n {\n identifier: \"webauthn-authentication\",\n controllerConstructor: WebauthnAuthenticationController,\n },\n {\n identifier: \"webauthn-registration\",\n controllerConstructor: WebauthnRegistrationController,\n },\n];\n\napplication.load(Definitions);\n\n// Eager load all controllers defined in the import map under controllers/admin/**/*_controller\nimport { eagerLoadControllersFrom } from \"@hotwired/stimulus-loading\";\n\neagerLoadControllersFrom(\"admin/controllers\", application);\n","import { Controller } from \"@hotwired/stimulus\";\n\nexport default class ClipboardController extends Controller {\n static targets = [\"source\"];\n\n static classes = [\"supported\"];\n\n connect() {\n if (\"clipboard\" in navigator) {\n this.element.classList.add(this.supportedClass);\n }\n }\n\n copy(event) {\n event.preventDefault();\n navigator.clipboard.writeText(this.sourceTarget.value);\n\n this.element.classList.add(\"copied\");\n setTimeout(() => {\n this.element.classList.remove(\"copied\");\n }, 2000);\n }\n}\n","import { Controller } from \"@hotwired/stimulus\";\n\nexport default class FlashController extends Controller {\n close(e) {\n e.target.closest(\"li\").remove();\n\n // remove the flash container if there are no more flashes\n if (this.element.children.length === 0) {\n this.element.remove();\n }\n }\n}\n","import { Controller } from \"@hotwired/stimulus\";\n\n/**\n A stimulus controller to request form submissions.\n This controller should be attached to a form element.\n */\nexport default class FormRequestSubmitController extends Controller {\n requestSubmit() {\n this.element.requestSubmit();\n }\n}\n","import { Controller } from \"@hotwired/stimulus\";\n\nexport default class IndexActionsController extends Controller {\n static targets = [\"create\", \"search\", \"sort\"];\n\n initialize() {\n // debounce search\n this.update = debounce(this, this.update);\n }\n\n disconnect() {\n clearTimeout(this.timer);\n }\n\n create() {\n this.createTarget.click();\n }\n\n search() {\n this.searchTarget.focus();\n }\n\n clear() {\n this.searchTarget.value = \"\";\n this.searchTarget.closest(\"form\").requestSubmit();\n }\n\n update() {\n this.searchTarget.closest(\"form\").requestSubmit();\n }\n\n submit() {\n const shouldFocus = document.activeElement === this.searchTarget;\n\n if (this.searchTarget.value === \"\") {\n this.searchTarget.disabled = true;\n }\n if (this.sortTarget.value === \"\") {\n this.sortTarget.disabled = true;\n }\n\n // restore state and focus after submit\n Promise.resolve().then(() => {\n this.searchTarget.disabled = false;\n this.sortTarget.disabled = false;\n if (shouldFocus) {\n this.searchTarget.focus();\n }\n });\n }\n}\n\nfunction debounce(self, f) {\n return (...args) => {\n clearTimeout(self.timer);\n self.timer = setTimeout(() => {\n f.apply(self, ...args);\n }, 300);\n };\n}\n","import { Controller } from \"@hotwired/stimulus\";\n\nconst DEBUG = false;\n\nexport default class KeyboardController extends Controller {\n static values = {\n mapping: String,\n depth: { type: Number, default: 2 },\n };\n\n event(cause) {\n if (isFormField(cause.target) || this.#ignore(cause)) return;\n\n const key = this.describeEvent(cause);\n\n this.buffer = [...(this.buffer || []), key].slice(0 - this.depthValue);\n\n if (DEBUG) console.debug(\"[keyboard] buffer:\", ...this.buffer);\n\n // test whether the tail of the buffer matches any of the configured chords\n const action = this.buffer.reduceRight((mapping, key) => {\n if (typeof mapping === \"string\" || typeof mapping === \"undefined\") {\n return mapping;\n } else {\n return mapping[key];\n }\n }, this.mappings);\n\n // if we don't have a string we may have a miss or an incomplete chord\n if (typeof action !== \"string\") return;\n\n // clear the buffer and prevent the key from being consumed elsewhere\n this.buffer = [];\n cause.preventDefault();\n\n if (DEBUG) console.debug(\"[keyboard] event: %s\", action);\n\n // fire the configured event\n const event = new CustomEvent(action, {\n detail: { cause: cause },\n bubbles: true,\n });\n cause.target.dispatchEvent(event);\n }\n\n /**\n * @param event KeyboardEvent input event to describe\n * @return String description of keyboard event, e.g. 'C-KeyV' (CTRL+V)\n */\n describeEvent(event) {\n return [\n event.ctrlKey && \"C\",\n event.metaKey && \"M\",\n event.altKey && \"A\",\n event.shiftKey && \"S\",\n event.code,\n ]\n .filter((w) => w)\n .join(\"-\");\n }\n\n /**\n * Build a tree for efficiently looking up key chords, where the last key in the sequence\n * is the first key in tree.\n */\n get mappings() {\n const inputs = this.mappingValue\n .replaceAll(/\\s+/g, \" \")\n .split(\" \")\n .filter((f) => f.length > 0);\n const mappings = {};\n\n inputs.forEach((mapping) => this.#parse(mappings, mapping));\n\n // memoize the result\n Object.defineProperty(this, \"mappings\", {\n value: mappings,\n writable: false,\n });\n\n return mappings;\n }\n\n /**\n * Parse a key chord pattern and an event and store it in the inverted tree lookup structure.\n *\n * @param mappings inverted tree lookup for key chords\n * @param mapping input definition, e.g. \"C-KeyC+C-KeyV->paste\"\n */\n #parse(mappings, mapping) {\n const [pattern, event] = mapping.split(\"->\");\n const keys = pattern.split(\"+\");\n const first = keys.shift();\n\n mappings = keys.reduceRight(\n (mappings, key) => (mappings[key] ||= {}),\n mappings,\n );\n mappings[first] = event;\n }\n\n /**\n * Ignore modifier keys, as they will be captured in normal key presses.\n *\n * @param event KeyboardEvent\n * @returns {boolean} true if key event should be ignored\n */\n #ignore(event) {\n switch (event.code) {\n case \"ControlLeft\":\n case \"ControlRight\":\n case \"MetaLeft\":\n case \"MetaRight\":\n case \"ShiftLeft\":\n case \"ShiftRight\":\n case \"AltLeft\":\n case \"AltRight\":\n return true;\n default:\n return false;\n }\n }\n}\n\n/**\n * Detect input nodes where we should not listen for events.\n *\n * Credit: github.com\n */\nfunction isFormField(element) {\n if (!(element instanceof HTMLElement)) {\n return false;\n }\n\n const name = element.nodeName.toLowerCase();\n const type = (element.getAttribute(\"type\") || \"\").toLowerCase();\n return (\n name === \"select\" ||\n name === \"textarea\" ||\n name === \"trix-editor\" ||\n (name === \"input\" &&\n type !== \"submit\" &&\n type !== \"reset\" &&\n type !== \"checkbox\" &&\n type !== \"radio\" &&\n type !== \"file\") ||\n element.isContentEditable\n );\n}\n","import { Controller } from \"@hotwired/stimulus\";\n\nexport default class ModalController extends Controller {\n static targets = [\"dialog\"];\n\n connect() {\n this.element.addEventListener(\"turbo:submit-end\", this.onSubmit);\n }\n\n disconnect() {\n this.element.removeEventListener(\"turbo:submit-end\", this.onSubmit);\n }\n\n outside(e) {\n if (e.target.tagName === \"DIALOG\") this.dismiss();\n }\n\n dismiss() {\n if (!this.dialogTarget) return;\n if (!this.dialogTarget.open) this.dialogTarget.close();\n\n this.element.removeAttribute(\"src\");\n this.dialogTarget.remove();\n }\n\n dialogTargetConnected(dialog) {\n dialog.showModal();\n }\n\n onSubmit = (event) => {\n if (\n event.detail.success &&\n \"closeDialog\" in event.detail.formSubmission?.submitter?.dataset\n ) {\n this.dialogTarget.close();\n this.element.removeAttribute(\"src\");\n this.dialogTarget.remove();\n }\n };\n}\n","import { Controller } from \"@hotwired/stimulus\";\n\nexport default class NavigationController extends Controller {\n static targets = [\"filter\"];\n\n filter() {\n const filter = this.filterTarget.value;\n this.clearFilter(filter);\n\n if (filter.length > 0) {\n this.applyFilter(filter);\n }\n }\n\n go() {\n this.element.querySelector(\"li:not([hidden]) > a\").click();\n }\n\n clear() {\n if (this.filterTarget.value.length === 0) this.filterTarget.blur();\n }\n\n applyFilter(filter) {\n // hide items that don't match the search filter\n this.links\n .filter(\n (li) =>\n !this.prefixSearch(filter.toLowerCase(), li.innerText.toLowerCase()),\n )\n .forEach((li) => {\n li.toggleAttribute(\"hidden\", true);\n });\n\n this.menus\n .filter((li) => !li.matches(\"li:has(li:not([hidden]) > a)\"))\n .forEach((li) => {\n li.toggleAttribute(\"hidden\", true);\n });\n }\n\n clearFilter(filter) {\n this.element.querySelectorAll(\"li\").forEach((li) => {\n li.toggleAttribute(\"hidden\", false);\n });\n }\n\n prefixSearch(needle, haystack) {\n const haystackLength = haystack.length;\n const needleLength = needle.length;\n if (needleLength > haystackLength) {\n return false;\n }\n if (needleLength === haystackLength) {\n return needle === haystack;\n }\n outer: for (let i = 0, j = 0; i < needleLength; i++) {\n const needleChar = needle.charCodeAt(i);\n if (needleChar === 32) {\n // skip ahead to next space in the haystack\n while (j < haystackLength && haystack.charCodeAt(j++) !== 32) {}\n continue;\n }\n while (j < haystackLength) {\n if (haystack.charCodeAt(j++) === needleChar) continue outer;\n // skip ahead to the next space in the haystack\n while (j < haystackLength && haystack.charCodeAt(j++) !== 32) {}\n }\n return false;\n }\n return true;\n }\n\n toggle() {\n this.element.open ? this.close() : this.open();\n }\n\n open() {\n if (!this.element.open) this.element.showModal();\n }\n\n close() {\n if (this.element.open) this.element.close();\n }\n\n click(e) {\n if (e.target === this.element) this.close();\n }\n\n onMorphAttribute = (e) => {\n if (e.target !== this.element) return;\n\n switch (e.detail.attributeName) {\n case \"open\":\n e.preventDefault();\n }\n };\n\n get links() {\n return Array.from(this.element.querySelectorAll(\"li:has(> a)\"));\n }\n\n get menus() {\n return Array.from(this.element.querySelectorAll(\"li:has(> ul)\"));\n }\n}\n","import { Controller } from \"@hotwired/stimulus\";\n\nexport default class NavigationToggleController extends Controller {\n trigger() {\n this.dispatch(\"toggle\", { prefix: \"navigation\", bubbles: true });\n }\n}\n","import { Controller } from \"@hotwired/stimulus\";\n\nexport default class PagyNavController extends Controller {\n connect() {\n document.addEventListener(\"shortcut:page-prev\", this.prevPage);\n document.addEventListener(\"shortcut:page-next\", this.nextPage);\n }\n\n disconnect() {\n document.removeEventListener(\"shortcut:page-prev\", this.prevPage);\n document.removeEventListener(\"shortcut:page-next\", this.nextPage);\n }\n\n nextPage = () => {\n this.element.querySelector(\"a:last-child\").click();\n };\n\n prevPage = () => {\n this.element.querySelector(\"a:first-child\").click();\n };\n}\n","import { Controller } from \"@hotwired/stimulus\";\nimport { Transition } from \"../utils/transition\";\n\nexport default class ShowHideController extends Controller {\n static targets = [\"content\"];\n\n toggle() {\n const element = this.contentTarget;\n const hide = element.toggleAttribute(\"data-collapsed\");\n\n // cancel previous animation, if any\n if (this.transition) this.transition.cancel();\n\n const transition = (this.transition = new Transition(element)\n .addCallback(\"starting\", function () {\n element.setAttribute(\"data-collapsed-transitioning\", \"true\");\n })\n .addCallback(\"complete\", function () {\n element.removeAttribute(\"data-collapsed-transitioning\");\n }));\n hide ? transition.collapse() : transition.expand();\n\n transition.start();\n }\n}\n","import { Controller } from \"@hotwired/stimulus\";\n\n/**\n * Connect an input (e.g. title) to slug.\n */\nexport default class SluggableController extends Controller {\n static targets = [\"source\", \"slug\"];\n static values = {\n slug: String,\n };\n\n sourceChanged(e) {\n if (this.slugValue === \"\") {\n this.slugTarget.value = parameterize(this.sourceTarget.value);\n }\n }\n\n slugChanged(e) {\n this.slugValue = this.slugTarget.value;\n }\n}\n\nfunction parameterize(input) {\n return input\n .toLowerCase()\n .replace(/'/g, \"-\")\n .replace(/[^-\\w\\s]/g, \"\")\n .replace(/[^a-z0-9]+/g, \"-\")\n .replace(/(^-|-$)/g, \"\");\n}\n","import { Controller } from \"@hotwired/stimulus\";\n\nimport {\n get,\n parseRequestOptionsFromJSON,\n} from \"@github/webauthn-json/browser-ponyfill\";\n\nexport default class WebauthnAuthenticationController extends Controller {\n static targets = [\"response\"];\n static values = { options: Object };\n\n authenticate() {\n get(this.options).then((response) => {\n this.responseTarget.value = JSON.stringify(response);\n\n this.element.requestSubmit();\n });\n }\n\n get options() {\n return parseRequestOptionsFromJSON(this.optionsValue);\n }\n}\n","import { Controller } from \"@hotwired/stimulus\";\n\nimport {\n create,\n parseCreationOptionsFromJSON,\n} from \"@github/webauthn-json/browser-ponyfill\";\n\nexport default class WebauthnRegistrationController extends Controller {\n static values = {\n options: Object,\n response: String,\n };\n static targets = [\"intro\", \"nickname\", \"response\"];\n\n submit(e) {\n if (\n this.responseTarget.value === \"\" &&\n e.submitter.formMethod !== \"dialog\"\n ) {\n e.preventDefault();\n this.createCredential();\n }\n }\n\n async createCredential() {\n const response = await create(this.options);\n\n this.responseValue = JSON.stringify(response);\n this.responseTarget.value = JSON.stringify(response);\n }\n\n responseValueChanged(response) {\n const responsePresent = response !== \"\";\n this.introTarget.toggleAttribute(\"hidden\", responsePresent);\n this.nicknameTarget.toggleAttribute(\"hidden\", !responsePresent);\n }\n\n get options() {\n return parseCreationOptionsFromJSON(this.optionsValue);\n }\n}\n","class KoiToolbarElement extends HTMLElement {\n constructor() {\n super();\n\n this.setAttribute(\"role\", \"toolbar\");\n }\n}\n\ncustomElements.define(\"koi-toolbar\", KoiToolbarElement);\n","import \"@hotwired/turbo-rails\";\nimport { initAll } from \"@katalyst/govuk-formbuilder\";\nimport \"@rails/actiontext\";\nimport \"trix\";\n\nimport \"./controllers\";\nimport \"./elements\";\n\n/** Let GOVUK know that we've got JS enabled */\nwindow.addEventListener(\"turbo:load\", () => {\n document.body.classList.toggle(\"js-enabled\", true);\n document.body.classList.toggle(\n \"govuk-frontend-supported\",\n \"noModule\" in HTMLScriptElement.prototype,\n );\n initAll();\n});\n"],"names":["application","Application","start","Transition","constructor","target","options","delay","this","_setDefaults","runner","Runner","properties","startingCallbacks","startedCallbacks","completeCallbacks","add","property","push","addCallback","type","callback","collapse","PropertyTransition","scrollHeight","expand","slideOut","direction","scrollWidth","slideIn","fadeOut","fadeIn","requestAnimationFrame","cancel","stop","_starting","event","Event","forEach","cb","dispatchEvent","_started","_complete","Object","assign","transition","running","t","onStarting","onStarted","setTimeout","style","transitionProperty","map","join","transitionDuration","timeout","clearTimeout","removeProperty","onComplete","from","to","setProperty","load","content","govuk","navigation","tables","Definitions","identifier","controllerConstructor","Controller","static","connect","navigator","element","classList","supportedClass","copy","preventDefault","clipboard","writeText","sourceTarget","value","remove","close","e","closest","children","length","requestSubmit","HwComboboxController","initialize","self","f","update","args","timer","apply","disconnect","create","createTarget","click","search","searchTarget","focus","clear","submit","shouldFocus","document","activeElement","disabled","sortTarget","Promise","resolve","then","mapping","String","depth","Number","default","cause","HTMLElement","name","nodeName","toLowerCase","getAttribute","isContentEditable","isFormField","ignore","key","describeEvent","buffer","slice","depthValue","action","reduceRight","mappings","CustomEvent","detail","bubbles","ctrlKey","metaKey","altKey","shiftKey","code","filter","w","inputs","mappingValue","replaceAll","split","parse","defineProperty","writable","pattern","keys","first","shift","addEventListener","onSubmit","removeEventListener","outside","tagName","dismiss","dialogTarget","open","removeAttribute","dialogTargetConnected","dialog","showModal","success","formSubmission","submitter","dataset","filterTarget","clearFilter","applyFilter","go","querySelector","blur","links","li","prefixSearch","innerText","toggleAttribute","menus","matches","querySelectorAll","needle","haystack","haystackLength","needleLength","outer","i","j","needleChar","charCodeAt","toggle","onMorphAttribute","attributeName","Array","trigger","dispatch","prefix","prevPage","nextPage","contentTarget","hide","setAttribute","slug","sourceChanged","slugValue","slugTarget","replace","slugChanged","authenticate","get","response","responseTarget","JSON","stringify","parseRequestOptionsFromJSON","optionsValue","formMethod","createCredential","responseValue","responseValueChanged","responsePresent","introTarget","nicknameTarget","parseCreationOptionsFromJSON","eagerLoadControllersFrom","KoiToolbarElement","super","customElements","define","window","body","HTMLScriptElement","prototype","initAll"],"mappings":"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"}
1
+ {"version":3,"file":"koi.min.js","sources":["../../../javascript/koi/controllers/application.js","../../../javascript/koi/utils/transition.js","../../../javascript/koi/controllers/index.js","../../../javascript/koi/controllers/clipboard_controller.js","../../../javascript/koi/controllers/flash_controller.js","../../../javascript/koi/controllers/form_request_submit_controller.js","../../../javascript/koi/controllers/index_actions_controller.js","../../../javascript/koi/controllers/keyboard_controller.js","../../../javascript/koi/controllers/modal_controller.js","../../../javascript/koi/controllers/navigation_controller.js","../../../javascript/koi/controllers/navigation_toggle_controller.js","../../../javascript/koi/controllers/pagy_nav_controller.js","../../../javascript/koi/controllers/show_hide_controller.js","../../../javascript/koi/controllers/sluggable_controller.js","../../../javascript/koi/controllers/webauthn_authentication_controller.js","../../../javascript/koi/controllers/webauthn_registration_controller.js","../../../javascript/koi/elements/toolbar.js","../../../javascript/koi/application.js"],"sourcesContent":["import { Application } from \"@hotwired/stimulus\";\n\nconst application = Application.start();\n\nexport { application };\n","const DEFAULT_DELAY = 250;\n\n/**\n * A utility class for managing CSS transition animations.\n *\n * Transition uses Javascript timers to track state instead of relying on\n * CSS transition events, which is a more complicated API. Please call `cancel`\n * when the node being animated is detached from the DOM to avoid unexpected\n * errors or animation glitches.\n *\n * Transition assumes that CSS already specifies styles to achieve the expected\n * start and end states. Transition adds temporary overrides and then animates\n * between those values using CSS transitions. For example, to use the collapse\n * transition:\n *\n * @example\n * // CSS:\n * target {\n * max-height: unset;\n * overflow: 0;\n * }\n * target.hidden {\n * max-height: 0;\n * }\n *\n * @example\n * // Javascript\n * target.addClass(\"hidden\");\n * new Transition(target).collapse().start();\n */\nclass Transition {\n constructor(target, options) {\n const { delay } = this._setDefaults(options);\n\n this.target = target;\n this.runner = new Runner(this, delay);\n this.properties = [];\n\n this.startingCallbacks = [];\n this.startedCallbacks = [];\n this.completeCallbacks = [];\n }\n\n add(property) {\n this.properties.push(property);\n return this;\n }\n\n /** Adds callback for transition events */\n addCallback(type, callback) {\n switch (type) {\n case \"starting\":\n this.startingCallbacks.push(callback);\n break;\n case \"started\":\n this.startedCallbacks.push(callback);\n break;\n case \"complete\":\n this.completeCallbacks.push(callback);\n break;\n }\n return this;\n }\n\n /** Collapse an element in place, assumes overflow is set appropriately, margin is not collapsed */\n collapse() {\n return this.add(\n new PropertyTransition(\n \"max-height\",\n `${this.target.scrollHeight}px`,\n \"0px\",\n ),\n );\n }\n\n /** Restore a collapsed element */\n expand() {\n return this.add(\n new PropertyTransition(\n \"max-height\",\n \"0px\",\n `${this.target.scrollHeight}px`,\n ),\n );\n }\n\n /** Slide an element left or right by its scroll width, assumes position relative */\n slideOut(direction) {\n return this.add(\n new PropertyTransition(direction, \"0px\", `-${this.target.scrollWidth}px`),\n );\n }\n\n /** Restore an element that has been slid */\n slideIn(direction) {\n return this.add(\n new PropertyTransition(direction, `-${this.target.scrollWidth}px`, \"0px\"),\n );\n }\n\n /** Cause an element to become transparent by transforming opacity */\n fadeOut() {\n return this.add(new PropertyTransition(\"opacity\", \"100%\", \"0%\"));\n }\n\n /** Cause a transparent element to become visible again */\n fadeIn() {\n return this.add(new PropertyTransition(\"opacity\", \"0%\", \"100%\"));\n }\n\n start(callback = null) {\n // start the runner on next tick so that any side-effects of the current execution can occur first\n requestAnimationFrame(() => {\n this.runner.start(this.target);\n if (callback) callback();\n });\n return this;\n }\n\n cancel() {\n this.runner.stop(this.target);\n return this;\n }\n\n _starting() {\n const event = new Event(\"transition:starting\");\n this.startingCallbacks.forEach((cb) => cb(event));\n this.target.dispatchEvent(event);\n }\n\n _started() {\n const event = new Event(\"transition:started\");\n this.startedCallbacks.forEach((cb) => cb(event));\n this.target.dispatchEvent(event);\n }\n\n _complete() {\n const event = new Event(\"transition:complete\");\n this.completeCallbacks.forEach((cb) => cb(event));\n this.target.dispatchEvent(event);\n }\n\n _setDefaults(options) {\n return Object.assign({ delay: DEFAULT_DELAY }, options);\n }\n}\n\n/**\n * Encapsulates internal execution and timing functionality for `Transition`\n */\nclass Runner {\n constructor(transition, delay) {\n this.transition = transition;\n this.running = null;\n this.delay = delay;\n }\n\n start(target) {\n // 1. Set the initial state(s)\n this.transition.properties.forEach((t) => t.onStarting(target));\n\n // 2. On next update, set transition and final state(s)\n requestAnimationFrame(() => this.onStarted(target));\n\n // 3. After transition has finished, clean up\n this.running = setTimeout(() => this.stop(target, true), this.delay);\n\n this.transition._starting();\n }\n\n onStarted(target) {\n target.style.transitionProperty = this.transition.properties\n .map((t) => t.property)\n .join(\",\");\n target.style.transitionDuration = `${this.delay}ms`;\n this.transition.properties.forEach((t) => t.onStarted(target));\n\n this.transition._started();\n }\n\n stop(target, timeout = false) {\n if (!this.running) return;\n if (!timeout) clearTimeout(this.running);\n\n this.running = null;\n\n target.style.removeProperty(\"transition-property\");\n target.style.removeProperty(\"transition-duration\");\n this.transition.properties.forEach((t) => t.onComplete(target));\n\n this.transition._complete();\n }\n}\n\n/**\n * Represents animation of a single CSS property. Currently only CSS animations\n * are supported, but this could be a natural extension point for Javascript\n * animations in the future.\n */\nclass PropertyTransition {\n constructor(property, from, to) {\n this.property = property;\n this.from = from;\n this.to = to;\n }\n\n onStarting(target) {\n target.style.setProperty(this.property, this.from);\n }\n\n onStarted(target) {\n target.style.setProperty(this.property, this.to);\n }\n\n onComplete(target) {\n target.style.removeProperty(this.property);\n }\n}\n\nexport { Transition };\n","import { application } from \"./application\";\n\nimport content from \"@katalyst/content\";\napplication.load(content);\n\nimport govuk from \"@katalyst/govuk-formbuilder\";\napplication.load(govuk);\n\nimport navigation from \"@katalyst/navigation\";\napplication.load(navigation);\n\nimport tables from \"@katalyst/tables\";\napplication.load(tables);\n\nimport ClipboardController from \"./clipboard_controller\";\nimport FlashController from \"./flash_controller\";\nimport FormRequestSubmitController from \"./form_request_submit_controller\";\nimport IndexActionsController from \"./index_actions_controller\";\nimport KeyboardController from \"./keyboard_controller\";\nimport ModalController from \"./modal_controller\";\nimport NavigationController from \"./navigation_controller\";\nimport NavigationToggleController from \"./navigation_toggle_controller\";\nimport PagyNavController from \"./pagy_nav_controller\";\nimport ShowHideController from \"./show_hide_controller\";\nimport SluggableController from \"./sluggable_controller\";\nimport WebauthnAuthenticationController from \"./webauthn_authentication_controller\";\nimport WebauthnRegistrationController from \"./webauthn_registration_controller\";\n\nconst Definitions = [\n {\n identifier: \"clipboard\",\n controllerConstructor: ClipboardController,\n },\n {\n identifier: \"flash\",\n controllerConstructor: FlashController,\n },\n {\n identifier: \"form-request-submit\",\n controllerConstructor: FormRequestSubmitController,\n },\n {\n identifier: \"index-actions\",\n controllerConstructor: IndexActionsController,\n },\n {\n identifier: \"keyboard\",\n controllerConstructor: KeyboardController,\n },\n {\n identifier: \"modal\",\n controllerConstructor: ModalController,\n },\n {\n identifier: \"navigation\",\n controllerConstructor: NavigationController,\n },\n {\n identifier: \"navigation-toggle\",\n controllerConstructor: NavigationToggleController,\n },\n {\n identifier: \"pagy-nav\",\n controllerConstructor: PagyNavController,\n },\n {\n identifier: \"show-hide\",\n controllerConstructor: ShowHideController,\n },\n {\n identifier: \"sluggable\",\n controllerConstructor: SluggableController,\n },\n {\n identifier: \"webauthn-authentication\",\n controllerConstructor: WebauthnAuthenticationController,\n },\n {\n identifier: \"webauthn-registration\",\n controllerConstructor: WebauthnRegistrationController,\n },\n];\n\n// dynamically attempt to load hw_combobox_controller, this is an optional dependency\nawait import(\"controllers/hw_combobox_controller\")\n .then(({ default: HwComboboxController }) => {\n Definitions.push({\n identifier: \"hw-combobox\",\n controllerConstructor: HwComboboxController,\n });\n })\n .catch(() => null);\n\napplication.load(Definitions);\n","import { Controller } from \"@hotwired/stimulus\";\n\nexport default class ClipboardController extends Controller {\n static targets = [\"source\"];\n\n static classes = [\"supported\"];\n\n connect() {\n if (\"clipboard\" in navigator) {\n this.element.classList.add(this.supportedClass);\n }\n }\n\n copy(event) {\n event.preventDefault();\n navigator.clipboard.writeText(this.sourceTarget.value);\n\n this.element.classList.add(\"copied\");\n setTimeout(() => {\n this.element.classList.remove(\"copied\");\n }, 2000);\n }\n}\n","import { Controller } from \"@hotwired/stimulus\";\n\nexport default class FlashController extends Controller {\n close(e) {\n e.target.closest(\"li\").remove();\n\n // remove the flash container if there are no more flashes\n if (this.element.children.length === 0) {\n this.element.remove();\n }\n }\n}\n","import { Controller } from \"@hotwired/stimulus\";\n\n/**\n A stimulus controller to request form submissions.\n This controller should be attached to a form element.\n */\nexport default class FormRequestSubmitController extends Controller {\n requestSubmit() {\n this.element.requestSubmit();\n }\n}\n","import { Controller } from \"@hotwired/stimulus\";\n\nexport default class IndexActionsController extends Controller {\n static targets = [\"create\", \"search\", \"sort\"];\n\n initialize() {\n // debounce search\n this.update = debounce(this, this.update);\n }\n\n disconnect() {\n clearTimeout(this.timer);\n }\n\n create() {\n this.createTarget.click();\n }\n\n search() {\n this.searchTarget.focus();\n }\n\n clear() {\n this.searchTarget.value = \"\";\n this.searchTarget.closest(\"form\").requestSubmit();\n }\n\n update() {\n this.searchTarget.closest(\"form\").requestSubmit();\n }\n\n submit() {\n const shouldFocus = document.activeElement === this.searchTarget;\n\n if (this.searchTarget.value === \"\") {\n this.searchTarget.disabled = true;\n }\n if (this.sortTarget.value === \"\") {\n this.sortTarget.disabled = true;\n }\n\n // restore state and focus after submit\n Promise.resolve().then(() => {\n this.searchTarget.disabled = false;\n this.sortTarget.disabled = false;\n if (shouldFocus) {\n this.searchTarget.focus();\n }\n });\n }\n}\n\nfunction debounce(self, f) {\n return (...args) => {\n clearTimeout(self.timer);\n self.timer = setTimeout(() => {\n f.apply(self, ...args);\n }, 300);\n };\n}\n","import { Controller } from \"@hotwired/stimulus\";\n\nconst DEBUG = false;\n\nexport default class KeyboardController extends Controller {\n static values = {\n mapping: String,\n depth: { type: Number, default: 2 },\n };\n\n event(cause) {\n if (isFormField(cause.target) || this.#ignore(cause)) return;\n\n const key = this.describeEvent(cause);\n\n this.buffer = [...(this.buffer || []), key].slice(0 - this.depthValue);\n\n if (DEBUG) console.debug(\"[keyboard] buffer:\", ...this.buffer);\n\n // test whether the tail of the buffer matches any of the configured chords\n const action = this.buffer.reduceRight((mapping, key) => {\n if (typeof mapping === \"string\" || typeof mapping === \"undefined\") {\n return mapping;\n } else {\n return mapping[key];\n }\n }, this.mappings);\n\n // if we don't have a string we may have a miss or an incomplete chord\n if (typeof action !== \"string\") return;\n\n // clear the buffer and prevent the key from being consumed elsewhere\n this.buffer = [];\n cause.preventDefault();\n\n if (DEBUG) console.debug(\"[keyboard] event: %s\", action);\n\n // fire the configured event\n const event = new CustomEvent(action, {\n detail: { cause: cause },\n bubbles: true,\n });\n cause.target.dispatchEvent(event);\n }\n\n /**\n * @param event KeyboardEvent input event to describe\n * @return String description of keyboard event, e.g. 'C-KeyV' (CTRL+V)\n */\n describeEvent(event) {\n return [\n event.ctrlKey && \"C\",\n event.metaKey && \"M\",\n event.altKey && \"A\",\n event.shiftKey && \"S\",\n event.code,\n ]\n .filter((w) => w)\n .join(\"-\");\n }\n\n /**\n * Build a tree for efficiently looking up key chords, where the last key in the sequence\n * is the first key in tree.\n */\n get mappings() {\n const inputs = this.mappingValue\n .replaceAll(/\\s+/g, \" \")\n .split(\" \")\n .filter((f) => f.length > 0);\n const mappings = {};\n\n inputs.forEach((mapping) => this.#parse(mappings, mapping));\n\n // memoize the result\n Object.defineProperty(this, \"mappings\", {\n value: mappings,\n writable: false,\n });\n\n return mappings;\n }\n\n /**\n * Parse a key chord pattern and an event and store it in the inverted tree lookup structure.\n *\n * @param mappings inverted tree lookup for key chords\n * @param mapping input definition, e.g. \"C-KeyC+C-KeyV->paste\"\n */\n #parse(mappings, mapping) {\n const [pattern, event] = mapping.split(\"->\");\n const keys = pattern.split(\"+\");\n const first = keys.shift();\n\n mappings = keys.reduceRight(\n (mappings, key) => (mappings[key] ||= {}),\n mappings,\n );\n mappings[first] = event;\n }\n\n /**\n * Ignore modifier keys, as they will be captured in normal key presses.\n *\n * @param event KeyboardEvent\n * @returns {boolean} true if key event should be ignored\n */\n #ignore(event) {\n switch (event.code) {\n case \"ControlLeft\":\n case \"ControlRight\":\n case \"MetaLeft\":\n case \"MetaRight\":\n case \"ShiftLeft\":\n case \"ShiftRight\":\n case \"AltLeft\":\n case \"AltRight\":\n return true;\n default:\n return false;\n }\n }\n}\n\n/**\n * Detect input nodes where we should not listen for events.\n *\n * Credit: github.com\n */\nfunction isFormField(element) {\n if (!(element instanceof HTMLElement)) {\n return false;\n }\n\n const name = element.nodeName.toLowerCase();\n const type = (element.getAttribute(\"type\") || \"\").toLowerCase();\n return (\n name === \"select\" ||\n name === \"textarea\" ||\n name === \"trix-editor\" ||\n (name === \"input\" &&\n type !== \"submit\" &&\n type !== \"reset\" &&\n type !== \"checkbox\" &&\n type !== \"radio\" &&\n type !== \"file\") ||\n element.isContentEditable\n );\n}\n","import { Controller } from \"@hotwired/stimulus\";\n\nexport default class ModalController extends Controller {\n static targets = [\"dialog\"];\n\n connect() {\n this.element.addEventListener(\"turbo:submit-end\", this.onSubmit);\n }\n\n disconnect() {\n this.element.removeEventListener(\"turbo:submit-end\", this.onSubmit);\n }\n\n outside(e) {\n if (e.target.tagName === \"DIALOG\") this.dismiss();\n }\n\n dismiss() {\n if (!this.dialogTarget) return;\n if (!this.dialogTarget.open) this.dialogTarget.close();\n\n this.element.removeAttribute(\"src\");\n this.dialogTarget.remove();\n }\n\n dialogTargetConnected(dialog) {\n dialog.showModal();\n }\n\n onSubmit = (event) => {\n if (\n event.detail.success &&\n \"closeDialog\" in event.detail.formSubmission?.submitter?.dataset\n ) {\n this.dialogTarget.close();\n this.element.removeAttribute(\"src\");\n this.dialogTarget.remove();\n }\n };\n}\n","import { Controller } from \"@hotwired/stimulus\";\n\nexport default class NavigationController extends Controller {\n static targets = [\"filter\"];\n\n filter() {\n const filter = this.filterTarget.value;\n this.clearFilter(filter);\n\n if (filter.length > 0) {\n this.applyFilter(filter);\n }\n }\n\n go() {\n this.element.querySelector(\"li:not([hidden]) > a\").click();\n }\n\n clear() {\n if (this.filterTarget.value.length === 0) this.filterTarget.blur();\n }\n\n applyFilter(filter) {\n // hide items that don't match the search filter\n this.links\n .filter(\n (li) =>\n !this.prefixSearch(filter.toLowerCase(), li.innerText.toLowerCase()),\n )\n .forEach((li) => {\n li.toggleAttribute(\"hidden\", true);\n });\n\n this.menus\n .filter((li) => !li.matches(\"li:has(li:not([hidden]) > a)\"))\n .forEach((li) => {\n li.toggleAttribute(\"hidden\", true);\n });\n }\n\n clearFilter(filter) {\n this.element.querySelectorAll(\"li\").forEach((li) => {\n li.toggleAttribute(\"hidden\", false);\n });\n }\n\n prefixSearch(needle, haystack) {\n const haystackLength = haystack.length;\n const needleLength = needle.length;\n if (needleLength > haystackLength) {\n return false;\n }\n if (needleLength === haystackLength) {\n return needle === haystack;\n }\n outer: for (let i = 0, j = 0; i < needleLength; i++) {\n const needleChar = needle.charCodeAt(i);\n if (needleChar === 32) {\n // skip ahead to next space in the haystack\n while (j < haystackLength && haystack.charCodeAt(j++) !== 32) {}\n continue;\n }\n while (j < haystackLength) {\n if (haystack.charCodeAt(j++) === needleChar) continue outer;\n // skip ahead to the next space in the haystack\n while (j < haystackLength && haystack.charCodeAt(j++) !== 32) {}\n }\n return false;\n }\n return true;\n }\n\n toggle() {\n this.element.open ? this.close() : this.open();\n }\n\n open() {\n if (!this.element.open) this.element.showModal();\n }\n\n close() {\n if (this.element.open) this.element.close();\n }\n\n click(e) {\n if (e.target === this.element) this.close();\n }\n\n onMorphAttribute = (e) => {\n if (e.target !== this.element) return;\n\n switch (e.detail.attributeName) {\n case \"open\":\n e.preventDefault();\n }\n };\n\n get links() {\n return Array.from(this.element.querySelectorAll(\"li:has(> a)\"));\n }\n\n get menus() {\n return Array.from(this.element.querySelectorAll(\"li:has(> ul)\"));\n }\n}\n","import { Controller } from \"@hotwired/stimulus\";\n\nexport default class NavigationToggleController extends Controller {\n trigger() {\n this.dispatch(\"toggle\", { prefix: \"navigation\", bubbles: true });\n }\n}\n","import { Controller } from \"@hotwired/stimulus\";\n\nexport default class PagyNavController extends Controller {\n connect() {\n document.addEventListener(\"shortcut:page-prev\", this.prevPage);\n document.addEventListener(\"shortcut:page-next\", this.nextPage);\n }\n\n disconnect() {\n document.removeEventListener(\"shortcut:page-prev\", this.prevPage);\n document.removeEventListener(\"shortcut:page-next\", this.nextPage);\n }\n\n nextPage = () => {\n this.element.querySelector(\"a:last-child\").click();\n };\n\n prevPage = () => {\n this.element.querySelector(\"a:first-child\").click();\n };\n}\n","import { Controller } from \"@hotwired/stimulus\";\nimport { Transition } from \"../utils/transition\";\n\nexport default class ShowHideController extends Controller {\n static targets = [\"content\"];\n\n toggle() {\n const element = this.contentTarget;\n const hide = element.toggleAttribute(\"data-collapsed\");\n\n // cancel previous animation, if any\n if (this.transition) this.transition.cancel();\n\n const transition = (this.transition = new Transition(element)\n .addCallback(\"starting\", function () {\n element.setAttribute(\"data-collapsed-transitioning\", \"true\");\n })\n .addCallback(\"complete\", function () {\n element.removeAttribute(\"data-collapsed-transitioning\");\n }));\n hide ? transition.collapse() : transition.expand();\n\n transition.start();\n }\n}\n","import { Controller } from \"@hotwired/stimulus\";\n\n/**\n * Connect an input (e.g. title) to slug.\n */\nexport default class SluggableController extends Controller {\n static targets = [\"source\", \"slug\"];\n static values = {\n slug: String,\n };\n\n sourceChanged(e) {\n if (this.slugValue === \"\") {\n this.slugTarget.value = parameterize(this.sourceTarget.value);\n }\n }\n\n slugChanged(e) {\n this.slugValue = this.slugTarget.value;\n }\n}\n\nfunction parameterize(input) {\n return input\n .toLowerCase()\n .replace(/'/g, \"-\")\n .replace(/[^-\\w\\s]/g, \"\")\n .replace(/[^a-z0-9]+/g, \"-\")\n .replace(/(^-|-$)/g, \"\");\n}\n","import { Controller } from \"@hotwired/stimulus\";\n\nimport {\n get,\n parseRequestOptionsFromJSON,\n} from \"@github/webauthn-json/browser-ponyfill\";\n\nexport default class WebauthnAuthenticationController extends Controller {\n static targets = [\"response\"];\n static values = { options: Object };\n\n authenticate() {\n get(this.options).then((response) => {\n this.responseTarget.value = JSON.stringify(response);\n\n this.element.requestSubmit();\n });\n }\n\n get options() {\n return parseRequestOptionsFromJSON(this.optionsValue);\n }\n}\n","import { Controller } from \"@hotwired/stimulus\";\n\nimport {\n create,\n parseCreationOptionsFromJSON,\n} from \"@github/webauthn-json/browser-ponyfill\";\n\nexport default class WebauthnRegistrationController extends Controller {\n static values = {\n options: Object,\n response: String,\n };\n static targets = [\"intro\", \"nickname\", \"response\"];\n\n submit(e) {\n if (\n this.responseTarget.value === \"\" &&\n e.submitter.formMethod !== \"dialog\"\n ) {\n e.preventDefault();\n this.createCredential();\n }\n }\n\n async createCredential() {\n const response = await create(this.options);\n\n this.responseValue = JSON.stringify(response);\n this.responseTarget.value = JSON.stringify(response);\n }\n\n responseValueChanged(response) {\n const responsePresent = response !== \"\";\n this.introTarget.toggleAttribute(\"hidden\", responsePresent);\n this.nicknameTarget.toggleAttribute(\"hidden\", !responsePresent);\n }\n\n get options() {\n return parseCreationOptionsFromJSON(this.optionsValue);\n }\n}\n","class KoiToolbarElement extends HTMLElement {\n constructor() {\n super();\n\n this.setAttribute(\"role\", \"toolbar\");\n }\n}\n\ncustomElements.define(\"koi-toolbar\", KoiToolbarElement);\n","import \"@hotwired/turbo-rails\";\nimport { initAll } from \"@katalyst/govuk-formbuilder\";\nimport \"@rails/actiontext\";\nimport \"trix\";\n\nimport \"./controllers\";\nimport \"./elements\";\n\n/** Initialize GOVUK */\nfunction initGOVUK() {\n document.body.classList.toggle(\"js-enabled\", true);\n document.body.classList.toggle(\n \"govuk-frontend-supported\",\n \"noModule\" in HTMLScriptElement.prototype,\n );\n initAll();\n}\n\nwindow.addEventListener(\"turbo:load\", initGOVUK);\nif (window.Turbo) initGOVUK();\n"],"names":["application","Application","start","Transition","constructor","target","options","delay","this","_setDefaults","runner","Runner","properties","startingCallbacks","startedCallbacks","completeCallbacks","add","property","push","addCallback","type","callback","collapse","PropertyTransition","scrollHeight","expand","slideOut","direction","scrollWidth","slideIn","fadeOut","fadeIn","requestAnimationFrame","cancel","stop","_starting","event","Event","forEach","cb","dispatchEvent","_started","_complete","Object","assign","transition","running","t","onStarting","onStarted","setTimeout","style","transitionProperty","map","join","transitionDuration","timeout","clearTimeout","removeProperty","onComplete","from","to","setProperty","load","content","govuk","navigation","tables","Definitions","identifier","controllerConstructor","Controller","static","connect","navigator","element","classList","supportedClass","copy","preventDefault","clipboard","writeText","sourceTarget","value","remove","close","e","closest","children","length","requestSubmit","initialize","self","f","update","args","timer","apply","disconnect","create","createTarget","click","search","searchTarget","focus","clear","submit","shouldFocus","document","activeElement","disabled","sortTarget","Promise","resolve","then","mapping","String","depth","Number","default","cause","HTMLElement","name","nodeName","toLowerCase","getAttribute","isContentEditable","isFormField","ignore","key","describeEvent","buffer","slice","depthValue","action","reduceRight","mappings","CustomEvent","detail","bubbles","ctrlKey","metaKey","altKey","shiftKey","code","filter","w","inputs","mappingValue","replaceAll","split","parse","defineProperty","writable","pattern","keys","first","shift","addEventListener","onSubmit","removeEventListener","outside","tagName","dismiss","dialogTarget","open","removeAttribute","dialogTargetConnected","dialog","showModal","success","formSubmission","submitter","dataset","filterTarget","clearFilter","applyFilter","go","querySelector","blur","links","li","prefixSearch","innerText","toggleAttribute","menus","matches","querySelectorAll","needle","haystack","haystackLength","needleLength","outer","i","j","needleChar","charCodeAt","toggle","onMorphAttribute","attributeName","Array","trigger","dispatch","prefix","prevPage","nextPage","contentTarget","hide","setAttribute","slug","sourceChanged","slugValue","slugTarget","replace","slugChanged","authenticate","get","response","responseTarget","JSON","stringify","parseRequestOptionsFromJSON","optionsValue","formMethod","createCredential","responseValue","responseValueChanged","responsePresent","introTarget","nicknameTarget","parseCreationOptionsFromJSON","import","HwComboboxController","catch","KoiToolbarElement","super","initGOVUK","body","HTMLScriptElement","prototype","initAll","customElements","define","window","Turbo"],"mappings":"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"}
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 16 16"><path stroke="#000" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.333" d="M8.026 6.6c-.372 0-.73.147-.993.41A1.4 1.4 0 0 0 6.62 8c0 .714-.07 1.757-.183 2.8m2.993-2.016c0 1.666 0 4.466-.702 6.216m3.014-.686c.084-.42.302-1.61.351-2.114M1 8c0-1.47.464-2.901 1.326-4.093a7.02 7.02 0 0 1 3.478-2.548 7.05 7.05 0 0 1 4.317-.04A7.03 7.03 0 0 1 13.647 3.8M1 10.8h.007m13.905 0c.14-1.4.092-3.748 0-4.2M3.108 13.25c.351-1.05.702-3.15.702-5.25 0-.477.08-.95.24-1.4M5.671 15c.148-.462.317-.924.4-1.4m-.154-9.24a4.23 4.23 0 0 1 5.76 1.54c.37.638.564 1.363.564 2.1v1.4"/></svg>
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" fill="#EC662B" viewBox="0 0 256 256"><path d="M133.708 138.489 256 256H11.508zM0 146.043l51.437 49.448L0 244.939zm3.038-18.049 59.905-57.588 59.318 57.024-59.941 57.589zM81.727 67.49H184.57l-51.407 49.48zM0 0h113.167L.615 108.218H0zm136.155 0h118.623l-54.429 52.364H81.725z"/></svg>
@@ -11,5 +11,10 @@
11
11
  .brand {
12
12
  color: white;
13
13
  text-decoration: none;
14
+
15
+ .icon {
16
+ --scale: 1.3;
17
+ margin-inline-end: var(--space-3xs);
18
+ }
14
19
  }
15
20
  }
@@ -32,6 +32,8 @@
32
32
  grid-area: input;
33
33
  margin-block-start: calc(-0.5 * var(--input-size));
34
34
  translate: 0 calc(var(--stroke-input-width) + 0.25 * var(--input-size));
35
+ /* Firefox fix - unable to calculate baseline from dynamic height */
36
+ min-height: var(--input-size);
35
37
  }
36
38
 
37
39
  .govuk-checkboxes__item::after {
@@ -5,9 +5,15 @@ form:not([class]),
5
5
  margin-top: var(--flow-space, var(--space-m));
6
6
  }
7
7
 
8
+ /* if the first element in the form is hidden, create negative space to consume the next child's flow margin */
8
9
  &:has(> [type="hidden"]:first-child) {
9
10
  margin-top: calc(-1 * var(--flow-space, var(--space-m)));
10
11
  }
12
+
13
+ /* if we're flowing ourselves then removing our flow margin is sufficient */
14
+ .flow > * + &:has(> [type="hidden"]:first-child) {
15
+ margin-top: 0;
16
+ }
11
17
  }
12
18
 
13
19
  .govuk-form-group {
@@ -32,6 +32,8 @@
32
32
  grid-area: input;
33
33
  margin-block-start: calc(-0.5 * var(--input-size));
34
34
  translate: 0 calc(var(--stroke-input-width) + 0.25 * var(--input-size));
35
+ /* Firefox fix - unable to calculate baseline from dynamic height */
36
+ min-height: var(--input-size);
35
37
  }
36
38
 
37
39
  .govuk-radios__item::after {
@@ -6,6 +6,7 @@
6
6
  --color-light: #ffffff;
7
7
  --color-primary: #266dd3;
8
8
  --color-tint: #f0ecf3;
9
+ --color-brand: #ec662b;
9
10
  --focus-color: #fd0;
10
11
 
11
12
  /* alerts */
@@ -8,7 +8,13 @@
8
8
  mask: url("icons/close.svg");
9
9
  }
10
10
 
11
+ [data-icon="fingerprint"] {
12
+ -webkit-mask: url("icons/fingerprint.svg");
13
+ mask: url("icons/fingerprint.svg");
14
+ }
15
+
11
16
  [data-icon="koi"] {
12
- -webkit-mask: url("koi.png") center/cover no-repeat;
13
- mask: url("koi.png") center/cover no-repeat;
17
+ -webkit-mask: url("logo.svg");
18
+ mask: url("logo.svg");
19
+ color: var(--color-brand);
14
20
  }
@@ -4,23 +4,25 @@
4
4
  grid-template-areas: "logo header" "logo site-name";
5
5
  grid-template-columns: auto 1fr;
6
6
  grid-template-rows: auto auto;
7
- column-gap: var(--space-m);
8
- }
7
+ column-gap: var(--space-s);
9
8
 
10
- h1 {
11
- grid-area: header;
12
- font-weight: var(--font-light);
13
- }
9
+ .icon {
10
+ --scale: 4;
11
+ --offset: 2px;
12
+ grid-area: logo;
13
+ align-self: center;
14
+ }
14
15
 
15
- h2 {
16
- grid-area: site-name;
17
- font-weight: var(--font-medium);
18
- font-size: var(--size-m);
19
- }
16
+ h1 {
17
+ grid-area: header;
18
+ font-weight: var(--font-bold);
19
+ }
20
20
 
21
- img {
22
- max-height: 4rem;
23
- grid-area: logo;
24
- align-self: center;
21
+ h2 {
22
+ grid-area: site-name;
23
+ font-weight: var(--font-medium);
24
+ font-size: var(--size-step-1);
25
+ color: var(--color-mid);
26
+ }
25
27
  }
26
28
  }
@@ -6,12 +6,15 @@ import "trix";
6
6
  import "./controllers";
7
7
  import "./elements";
8
8
 
9
- /** Let GOVUK know that we've got JS enabled */
10
- window.addEventListener("turbo:load", () => {
9
+ /** Initialize GOVUK */
10
+ function initGOVUK() {
11
11
  document.body.classList.toggle("js-enabled", true);
12
12
  document.body.classList.toggle(
13
13
  "govuk-frontend-supported",
14
14
  "noModule" in HTMLScriptElement.prototype,
15
15
  );
16
16
  initAll();
17
- });
17
+ }
18
+
19
+ window.addEventListener("turbo:load", initGOVUK);
20
+ if (window.Turbo) initGOVUK();
@@ -26,9 +26,6 @@ import SluggableController from "./sluggable_controller";
26
26
  import WebauthnAuthenticationController from "./webauthn_authentication_controller";
27
27
  import WebauthnRegistrationController from "./webauthn_registration_controller";
28
28
 
29
- // Third party controllers
30
- import HwComboboxController from "controllers/hw_combobox_controller";
31
-
32
29
  const Definitions = [
33
30
  {
34
31
  identifier: "clipboard",
@@ -42,10 +39,6 @@ const Definitions = [
42
39
  identifier: "form-request-submit",
43
40
  controllerConstructor: FormRequestSubmitController,
44
41
  },
45
- {
46
- identifier: "hw-combobox",
47
- controllerConstructor: HwComboboxController,
48
- },
49
42
  {
50
43
  identifier: "index-actions",
51
44
  controllerConstructor: IndexActionsController,
@@ -88,9 +81,14 @@ const Definitions = [
88
81
  },
89
82
  ];
90
83
 
91
- application.load(Definitions);
92
-
93
- // Eager load all controllers defined in the import map under controllers/admin/**/*_controller
94
- import { eagerLoadControllersFrom } from "@hotwired/stimulus-loading";
84
+ // dynamically attempt to load hw_combobox_controller, this is an optional dependency
85
+ await import("controllers/hw_combobox_controller")
86
+ .then(({ default: HwComboboxController }) => {
87
+ Definitions.push({
88
+ identifier: "hw-combobox",
89
+ controllerConstructor: HwComboboxController,
90
+ });
91
+ })
92
+ .catch(() => null);
95
93
 
96
- eagerLoadControllersFrom("admin/controllers", application);
94
+ application.load(Definitions);
@@ -22,4 +22,8 @@ class WellKnown < ApplicationRecord
22
22
  def format
23
23
  content_type.to_sym
24
24
  end
25
+
26
+ def to_s
27
+ name
28
+ end
25
29
  end
@@ -25,6 +25,8 @@
25
25
  <%= hidden_field_tag(:redirect, redirect) %>
26
26
  <div class="actions">
27
27
  <%= form.admin_save "Next" %>
28
- <%= form.button "🔑", type: :button, class: "button button--secondary", data: { action: "webauthn-authentication#authenticate" } %>
28
+ <%= form.button(type: :button, class: "button button--secondary", data: { action: "webauthn-authentication#authenticate" }) do %>
29
+ <icon class="icon" data-icon="fingerprint" aria-label="Passkey">&nbsp;</icon>
30
+ <% end %>
29
31
  </div>
30
32
  <% end %>
@@ -3,6 +3,7 @@
3
3
  data-action="shortcut:go@document->navigation#toggle
4
4
  navigation:toggle@document->navigation#toggle
5
5
  shortcut:nav-toggle@document->navigation#toggle
6
+ turbo:before-cache@document->navigation#close
6
7
  turbo:before-morph-attribute->navigation#onMorphAttribute
7
8
  click->navigation#click">
8
9
  <nav aria-label="Main menu" role="navigation" class="flow">
@@ -6,7 +6,7 @@
6
6
  <!-- title -->
7
7
  <title><%= Koi.config.admin_name %><%= " - #{yield :title}" if content_for? :title %></title>
8
8
 
9
- <!-- META -->
9
+ <!-- meta -->
10
10
  <%= csrf_meta_tags %>
11
11
  <%= csp_meta_tag %>
12
12
  <meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=0.6667">
@@ -17,10 +17,13 @@
17
17
  <meta name="turbo-refresh-scroll" content="preserve">
18
18
  <%= yield :head %>
19
19
 
20
- <!-- STYLES -->
20
+ <!-- icons -->
21
+ <link rel="icon" sizes="any" type="image/svg+xml" href="<%= path_to_image("koi/logo.svg") %>">
22
+
23
+ <!-- styles -->
21
24
  <%= stylesheet_link_tag Koi.config.admin_stylesheet, "data-turbo-track": "reload" %>
22
25
 
23
- <!-- SCRIPTS -->
26
+ <!-- scripts -->
24
27
  <%= javascript_importmap_tags Koi.config.admin_javascript_entry_point %>
25
28
  </head>
26
29
  <body data-controller="keyboard"
@@ -1,35 +1,44 @@
1
1
  <!DOCTYPE html>
2
2
  <html lang="en">
3
3
  <head>
4
- <!-- meta -->
5
4
  <meta charset="UTF-8">
6
5
 
7
6
  <!-- title -->
8
- <title>Koi</title>
7
+ <title><%= Koi.config.admin_name %></title>
9
8
 
10
- <!-- META -->
9
+ <!-- meta -->
11
10
  <%= csrf_meta_tags %>
11
+ <%= csp_meta_tag %>
12
12
  <meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=0.6667">
13
13
  <meta name="robots" content="noindex,nofollow">
14
- <%= yield :meta %>
14
+ <%= Koi::Release.meta_tags(self) %>
15
+
16
+ <meta name="turbo-refresh-method" content="morph">
17
+ <meta name="turbo-refresh-scroll" content="preserve">
18
+ <%= yield :head %>
19
+
20
+ <!-- icons -->
21
+ <link rel="icon" sizes="any" type="image/svg+xml" href="<%= path_to_image("koi/logo.svg") %>">
15
22
 
16
- <!-- STYLES -->
23
+ <!-- styles -->
17
24
  <%= stylesheet_link_tag path_to_stylesheet("koi/login.css"), "data-turbo-track": "reload" %>
18
25
  <%= stylesheet_link_tag Koi.config.admin_stylesheet, "data-turbo-track": "reload" %>
19
26
 
20
- <!-- SCRIPTS -->
27
+ <!-- scripts -->
21
28
  <%= javascript_importmap_tags Koi.config.admin_javascript_entry_point %>
22
29
  </head>
23
30
  <body>
24
31
  <main class="cover" data-centered>
25
32
  <div class="login | modal">
26
- <header>
27
- <img src="<%= path_to_image("koi/koi.png") %>" alt="Koi" aria-hidden>
28
- <h1>Koi</h1>
29
- <h2 class="site-name"><%= URI.parse(root_url).host %></h2>
30
- </header>
33
+ <div class="wrapper flow">
34
+ <header>
35
+ <icon aria-hidden="true" class="icon" data-icon="koi">&nbsp;</icon>
36
+ <h1>Koi</h1>
37
+ <h2 class="site-name"><%= URI.parse(root_url).host %></h2>
38
+ </header>
31
39
 
32
- <%= yield %>
40
+ <%= yield %>
41
+ </div>
33
42
  </div>
34
43
  </main>
35
44
  </body>
@@ -0,0 +1,27 @@
1
+ {
2
+ "ignored_warnings": [
3
+ {
4
+ "warning_type": "Cross-Site Request Forgery",
5
+ "warning_code": 7,
6
+ "fingerprint": "bffc2950c37b9c59fe52697d8d7c5c859c70ca98dd67f33cf8e522bdcc4bff33",
7
+ "check_name": "ForgerySetting",
8
+ "message": "`protect_from_forgery` should be called in `Admin::ApplicationController`",
9
+ "file": "app/controllers/admin/application_controller.rb",
10
+ "line": 4,
11
+ "link": "https://brakemanscanner.org/docs/warning_types/cross-site_request_forgery/",
12
+ "code": null,
13
+ "render_path": null,
14
+ "location": {
15
+ "type": "controller",
16
+ "controller": "Admin::ApplicationController"
17
+ },
18
+ "user_input": null,
19
+ "confidence": "High",
20
+ "cwe_id": [
21
+ 352
22
+ ],
23
+ "note": "Koi::Controller includes protect_from_forgery with: :exception"
24
+ }
25
+ ],
26
+ "brakeman_version": "7.0.2"
27
+ }
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: katalyst-koi
3
3
  version: !ruby/object:Gem::Version
4
- version: 5.0.0.beta.3
4
+ version: 5.0.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Katalyst Interactive
@@ -263,7 +263,8 @@ files:
263
263
  - app/assets/images/koi/application/sort-descending.png
264
264
  - app/assets/images/koi/icons/add.svg
265
265
  - app/assets/images/koi/icons/close.svg
266
- - app/assets/images/koi/koi.png
266
+ - app/assets/images/koi/icons/fingerprint.svg
267
+ - app/assets/images/koi/logo.svg
267
268
  - app/assets/stylesheets/koi/blocks/actions.css
268
269
  - app/assets/stylesheets/koi/blocks/application-header.css
269
270
  - app/assets/stylesheets/koi/blocks/application-navigation.css
@@ -429,11 +430,11 @@ files:
429
430
  - app/views/layouts/koi/_application_header.html.erb
430
431
  - app/views/layouts/koi/_application_navigation.html.erb
431
432
  - app/views/layouts/koi/_flash.html.erb
432
- - app/views/layouts/koi/_navigation_header.html.erb
433
433
  - app/views/layouts/koi/_navigation_item.html.erb
434
434
  - app/views/layouts/koi/application.html.erb
435
435
  - app/views/layouts/koi/frame.html.erb
436
436
  - app/views/layouts/koi/login.html.erb
437
+ - config/brakeman.ignore
437
438
  - config/importmap.rb
438
439
  - config/initializers/extensions.rb
439
440
  - config/initializers/flipper.rb
Binary file
@@ -1,9 +0,0 @@
1
- <header>
2
- <h2 class="site-name"><%= URI.parse(root_url).host %></h2>
3
- <%# show username on nav header and Koi Admin on login page %>
4
- <% if local_assigns[:admin].present? %>
5
- <%= link_to admin.name, main_app.admin_admin_user_path(admin), class: "admin-name" %>
6
- <% else %>
7
- <h3 class="admin-name">Koi Admin</h3>
8
- <% end %>
9
- </header>