{"version":3,"file":"vcaFilter-01a6db85.js","sources":["../../../src/js/vca-web-components/vca-filter/vca-filter.js"],"sourcesContent":["/**\n * Enhances any group of elements by adding a text-search filter to them.\n * - You're able to define what wrapped content constitutes \"one element\" being searched against as a potential result.\n * - You're able to define which parts of that context element are \"searchable\" (by default, all of it).\n */\ncustomElements.define(\n\t'vca-filter',\n\tclass extends HTMLElement {\n\t\t// Setup variables used throughout this Class\n\t\t\t#setupComplete = false;\n\t\t\t#validConfiguration = false;\n\t\t\t#searchContexts = null;\n\t\t\t#filterLabel = \"Filter by:\"\n\n\t\t// Watch these component attributes for changes\n\t\t\tstatic observedAttributes = [\n\t\t\t\t'search-context',\n\t\t\t\t'search-targets'\n\t\t\t];\n\n\t\t/**\n\t\t * The class constructor method.\n\t\t * This is only ever called once per instance.\n\t\t * At this point you can't add Nodes inside the normal DOM, and you can't add or set an attribute either; because it's not connected to the DOM yet.\n\t\t */\n\t\tconstructor() {\n\t\t\t// Inherit everything from the parent HTMLElement class\n\t\t\t\tsuper();\n\n\t\t\t// Now we can do setup stuff that only needs running once\n\t\t}\n\n\t\t/**\n\t\t * Run methods when an instance of this custom element attaches to the DOM\n\t\t * i.e., if some JS adds an instance of this Custom Element into the page, connectedCallback will fire.\n\t\t */\n\t\tconnectedCallback () {\n\t\t\t// Set up the rest of the Custom Element instance now it has access to the DOM\n\t\t\t\tthis.setup();\n\t\t}\n\n\t\t/**\n\t\t * When an instance is removed from the DOM this event allows us to clean up things previously done in connectedCallback.\n\t\t */\n\t\tdisconnectedCallback() {\n\t\t\t// e.g., emptying localStorage or something that might otherwise persist needlessly\n\t\t}\n\n\t\t/**\n\t\t * React when the value of any of the observed attributes is changed on the component\n\t\t * @param {String} name The attribute name\n\t\t * @param {String} oldValue The old attribute value\n\t\t * @param {String} newValue The new attribute value\n\t\t */\n\t\tattributeChangedCallback (name, oldValue, newValue) {\n\t\t\t// re-build the searching based on what's changed\n\t\t\t\tthis.getSearchContexts();\n\t\t}\n\n\t\t/**\n\t\t* Setup is in its own function so that it can be called from the constructor or connectedCallback, because depending on how the component is loaded you may need either of those.\n\t\t*/\n\t\tsetup() {\n\t\t\t// Abort if the function has been run before\n\t\t\t\tif (this.#setupComplete) return;\n\n\t\t\t// Make sure we have search contexts (and targets if defined)\n\t\t\t\tthis.getSearchContexts();\n\t\t\t\tthis.getFilterLabel();\n\n\t\t\t// Insert the controls\n\t\t\t\tthis.insertAdjacentHTML(\n\t\t\t\t\t\"afterbegin\",\n\t\t\t\t\t`\n\t\t\t\t\t\t`\n\t\t\t\t);\n\n\t\t\t// Watch for interactions on the search input and filter accordingly\n\t\t\t\tthis.querySelector('.vca-filter-input')\n\t\t\t\t.addEventListener(\n\t\t\t\t\t'input',\n\t\t\t\t\tevent => this.filterContexts( event )\n\t\t\t\t);\n\n\t\t\t// Flag that the setup function has been run\n\t\t\t\tthis.#setupComplete = true;\n\t\t}\n\n\t\tgetFilterLabel() {\n\t\t\tthis.#filterLabel = this.getAttribute('filter-label') || \"Filter by:\";\n\t\t}\n\n\t\t/**\n\t\t * Reads the properties on the custom element\n\t\t */\n\t\tgetSearchContexts() {\n\t\t\tthis.findSearchContext = this.getAttribute('search-context') || null;\n\t\t\tthis.findSearchTargets = this.getAttribute('search-targets') || null;\n\n\t\t\tif(!this.findSearchContext) {\n\t\t\t\tconsole.error('This component requires a search-context property value');\n\t\t\t\tthis.#validConfiguration = false;\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tthis.#validConfiguration = true;\n\t\t\tthis.#searchContexts = this.querySelectorAll( `${this.findSearchContext}` );\n\t\t\tif( this.#searchContexts.length == 0 ) {\n\t\t\t\tconsole.warn(`The component does not have any child nodes that match the selector defined in the 'search-context' property - there is nothing to filter.`)\n\t\t\t}\n\t\t}\n\n\t\t/**\n\t\t * Loops through the Search Contexts, and inspects all Search Targets' text content to see if there's a case-insensitive match for what's been typed in the text input.\n\t\t * @param {*} event\n\t\t */\n\t\tfilterContexts( event ) {\n\t\t\tif( ! this.#validConfiguration ) {\n\t\t\t\tconsole.error('Impossible to filter as the configuration is invalid.');\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tthis.lookingFor = event.target.value;\n\n\t\t\tthis.#searchContexts.forEach( context => {\n\t\t\t\tthis.contextHasMatch = false; // by default assume the context does not contain a match\n\n\t\t\t\t// Do we have specific search targets, or are we just checking the entire context?\n\t\t\t\t\tif( this.findSearchTargets ) {\n\t\t\t\t\t\tcontext.querySelectorAll( this.findSearchTargets ).forEach( searchTarget => {\n\t\t\t\t\t\t\tif( searchTarget.textContent.toLowerCase().includes( this.lookingFor.toLowerCase() ) ) {\n\t\t\t\t\t\t\t\tcontext.dataset.vcaFilterMatched = 'true';\n\t\t\t\t\t\t\t\tthis.contextHasMatch = true; // If there's one match in the context that's enough to show the context; don't let future tests hide the context\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tif(!this.contextHasMatch) {\n\t\t\t\t\t\t\t\t\tcontext.dataset.vcaFilterMatched = 'false';\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\tif( context.textContent.toLowerCase().includes( this.lookingFor.toLowerCase() ) ) {\n\t\t\t\t\t\t\tcontext.dataset.vcaFilterMatched = 'true';\n\t\t\t\t\t\t\tthis.contextHasMatch = true; // If there's one match in the context that's enough to show the context; don't let future tests hide the context\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tif(!this.contextHasMatch) {\n\t\t\t\t\t\t\t\tcontext.dataset.vcaFilterMatched = 'false';\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t});\n\t\t}\n});\n"],"names":["_setupComplete","_validConfiguration","_searchContexts","_filterLabel","_a","__privateAdd","name","oldValue","newValue","__privateGet","event","__privateSet","context","searchTarget","__publicField"],"mappings":"ufAAA,IAAAA,EAAAC,EAAAC,EAAAC,EAAAC,EAKA,eAAe,OACd,cACAA,EAAA,cAAc,WAAY,CAkBzB,aAAc,CAEZ,QAlBDC,EAAA,KAAAL,EAAiB,IACjBK,EAAA,KAAAJ,EAAsB,IACtBI,EAAA,KAAAH,EAAkB,MAClBG,EAAA,KAAAF,EAAe,aAkBf,CAMD,mBAAqB,CAEnB,KAAK,MAAK,CACX,CAKD,sBAAuB,CAEtB,CAQD,yBAA0BG,EAAMC,EAAUC,EAAU,CAElD,KAAK,kBAAiB,CACvB,CAKD,OAAQ,CAEFC,EAAA,KAAKT,KAGT,KAAK,kBAAiB,EACtB,KAAK,eAAc,EAGnB,KAAK,mBACJ,aACA;AAAA;AAAA,eAEUS,EAAA,KAAKN,EAAY;AAAA;AAAA,eAGhC,EAGI,KAAK,cAAc,mBAAmB,EACrC,iBACA,QACAO,GAAS,KAAK,eAAgBA,CAAO,CAC1C,EAGIC,EAAA,KAAKX,EAAiB,IACvB,CAED,gBAAiB,CAChBW,EAAA,KAAKR,EAAe,KAAK,aAAa,cAAc,GAAK,aACzD,CAKD,mBAAoB,CAInB,GAHA,KAAK,kBAAoB,KAAK,aAAa,gBAAgB,GAAK,KAChE,KAAK,kBAAoB,KAAK,aAAa,gBAAgB,GAAK,KAE7D,CAAC,KAAK,kBAAmB,CAC3B,QAAQ,MAAM,yDAAyD,EACvEQ,EAAA,KAAKV,EAAsB,IAC3B,MACA,CAEDU,EAAA,KAAKV,EAAsB,IAC3BU,EAAA,KAAKT,EAAkB,KAAK,iBAAkB,GAAG,KAAK,iBAAiB,KACnEO,EAAA,KAAKP,GAAgB,QAAU,GAClC,QAAQ,KAAK,4IAA4I,CAE1J,CAMD,eAAgBQ,EAAQ,CACvB,GAAI,CAAED,EAAA,KAAKR,GAAsB,CAChC,QAAQ,MAAM,uDAAuD,EACrE,MACA,CAED,KAAK,WAAaS,EAAM,OAAO,MAE/BD,EAAA,KAAKP,GAAgB,QAASU,GAAW,CACxC,KAAK,gBAAkB,GAGlB,KAAK,kBACRA,EAAQ,iBAAkB,KAAK,iBAAiB,EAAG,QAASC,GAAgB,CACvEA,EAAa,YAAY,YAAa,EAAC,SAAU,KAAK,WAAW,YAAW,IAC/ED,EAAQ,QAAQ,iBAAmB,OACnC,KAAK,gBAAkB,IAEnB,KAAK,kBACRA,EAAQ,QAAQ,iBAAmB,QAG5C,CAAO,EAGGA,EAAQ,YAAY,YAAa,EAAC,SAAU,KAAK,WAAW,YAAW,IAC1EA,EAAQ,QAAQ,iBAAmB,OACnC,KAAK,gBAAkB,IAEnB,KAAK,kBACRA,EAAQ,QAAQ,iBAAmB,QAI3C,CAAI,CACD,CACH,EAlJGZ,EAAA,YACAC,EAAA,YACAC,EAAA,YACAC,EAAA,YAGAW,EARFV,EAQS,qBAAqB,CAC3B,iBACA,gBACJ,GAXCA,EAoJA"}