From ee5c8d58900f1b1050c9685b1d928e830dedf5a5 Mon Sep 17 00:00:00 2001 From: David Graham Date: Fri, 18 Oct 2019 11:44:35 -0600 Subject: [PATCH 1/2] Hide private instance state Move private instance variables into a WeakMap so they aren't exposed as public API on the element. --- src/index.ts | 39 +++++++++++++++++++++++---------------- 1 file changed, 23 insertions(+), 16 deletions(-) diff --git a/src/index.ts b/src/index.ts index e7d2877..005da0b 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,13 +1,11 @@ -class RemoteInputElement extends HTMLElement { - currentQuery: string | null - debounceInputChange: (event: Event) => void - boundFetchResults: (event: Event) => void +const states = new WeakMap() +class RemoteInputElement extends HTMLElement { constructor() { super() - this.currentQuery = null - this.debounceInputChange = debounce(() => fetchResults(this)) - this.boundFetchResults = () => fetchResults(this) + const fetch = fetchResults.bind(this, this, true) + const state = {currentQuery: null, oninput: debounce(fetch), fetch} + states.set(this, state) } static get observedAttributes() { @@ -27,18 +25,24 @@ class RemoteInputElement extends HTMLElement { input.setAttribute('autocomplete', 'off') input.setAttribute('spellcheck', 'false') - input.addEventListener('focus', this.boundFetchResults) - input.addEventListener('change', this.boundFetchResults) - input.addEventListener('input', this.debounceInputChange) + const state = states.get(this) + if (!state) return + + input.addEventListener('focus', state.fetch) + input.addEventListener('change', state.fetch) + input.addEventListener('input', state.oninput) } disconnectedCallback() { const input = this.input if (!input) return - input.removeEventListener('focus', this.boundFetchResults) - input.removeEventListener('change', this.boundFetchResults) - input.removeEventListener('input', this.debounceInputChange) + const state = states.get(this) + if (!state) return + + input.removeEventListener('focus', state.fetch) + input.removeEventListener('change', state.fetch) + input.removeEventListener('input', state.oninput) } get input(): HTMLInputElement | HTMLTextAreaElement | null { @@ -55,14 +59,17 @@ class RemoteInputElement extends HTMLElement { } } -async function fetchResults(remoteInput: RemoteInputElement, checkCurrentQuery: boolean = true) { +async function fetchResults(remoteInput: RemoteInputElement, checkCurrentQuery: boolean) { const input = remoteInput.input if (!input) return + const state = states.get(remoteInput) + if (!state) return + const query = input.value - if (checkCurrentQuery && remoteInput.currentQuery === query) return + if (checkCurrentQuery && state.currentQuery === query) return - remoteInput.currentQuery = query + state.currentQuery = query const src = remoteInput.src if (!src) return From 83a1eab9bbe3d27a4c4eebcd4e6cf9526c284782 Mon Sep 17 00:00:00 2001 From: David Graham Date: Fri, 18 Oct 2019 13:14:35 -0600 Subject: [PATCH 2/2] Remove unused `this` value --- src/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/index.ts b/src/index.ts index 005da0b..15d7132 100644 --- a/src/index.ts +++ b/src/index.ts @@ -3,7 +3,7 @@ const states = new WeakMap() class RemoteInputElement extends HTMLElement { constructor() { super() - const fetch = fetchResults.bind(this, this, true) + const fetch = fetchResults.bind(null, this, true) const state = {currentQuery: null, oninput: debounce(fetch), fetch} states.set(this, state) }