Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update linting in remote-input-element #35

Merged
merged 5 commits into from
Apr 8, 2024
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
fix prettier
TylerJDev committed Mar 29, 2024
commit bb7988a812a236bee2064496599471ea03e8808f
6 changes: 6 additions & 0 deletions .prettierrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"trailingComma": "none",
"tabWidth": 2,
"semi": false,
"singleQuote": true
}
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -13,7 +13,7 @@
"scripts": {
"clean": "rm -rf dist",
"lint": "eslint './src/**' './test/**.js'",
"prebuild": "npm run clean",
"prebuild": "npm run clean & npm run lint",
"build": "tsc --outDir dist/umd --module umd && tsc",
"pretest": "npm run build",
"test": "karma start test/karma.config.js",
Empty file removed prettier.config.js
Empty file.
184 changes: 92 additions & 92 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,192 +1,192 @@
const states = new WeakMap();
const states = new WeakMap()

class RemoteInputElement extends HTMLElement {
constructor() {
super();
const fetch = fetchResults.bind(null, this, true);
super()
const fetch = fetchResults.bind(null, this, true)
const state = {
currentQuery: null,
oninput: debounce<Event>((e) => fetch(e)),
fetch,
controller: null,
};
states.set(this, state);
controller: null
}
states.set(this, state)
}

static get observedAttributes() {
return ["src"];
return ['src']
}

attributeChangedCallback(name: string, oldValue: string) {
if (oldValue && name === "src") {
fetchResults(this, false);
if (oldValue && name === 'src') {
fetchResults(this, false)
}
}

connectedCallback() {
const input = this.input;
if (!input) return;
const input = this.input
if (!input) return

input.setAttribute("autocomplete", "off");
input.setAttribute("spellcheck", "false");
input.setAttribute('autocomplete', 'off')
input.setAttribute('spellcheck', 'false')

const state = states.get(this);
if (!state) return;
const state = states.get(this)
if (!state) return

input.addEventListener("focus", state.fetch);
input.addEventListener("change", state.fetch);
input.addEventListener("input", state.oninput);
input.addEventListener('focus', state.fetch)
input.addEventListener('change', state.fetch)
input.addEventListener('input', state.oninput)
}

disconnectedCallback() {
const input = this.input;
if (!input) return;
const input = this.input
if (!input) return

const state = states.get(this);
if (!state) return;
const state = states.get(this)
if (!state) return

input.removeEventListener("focus", state.fetch);
input.removeEventListener("change", state.fetch);
input.removeEventListener("input", state.oninput);
input.removeEventListener('focus', state.fetch)
input.removeEventListener('change', state.fetch)
input.removeEventListener('input', state.oninput)
}

get input(): HTMLInputElement | HTMLTextAreaElement | null {
const input = this.querySelector("input, textarea");
const input = this.querySelector('input, textarea')
return input instanceof HTMLInputElement ||
input instanceof HTMLTextAreaElement
? input
: null;
: null
}

get src(): string {
return this.getAttribute("src") || "";
return this.getAttribute('src') || ''
}

set src(url: string) {
this.setAttribute("src", url);
this.setAttribute('src', url)
}
}

function makeAbortController() {
if ("AbortController" in window) {
return new AbortController();
if ('AbortController' in window) {
return new AbortController()
}

return { signal: null, abort() {} };
return { signal: null, abort() {} }
}

async function fetchResults(
remoteInput: RemoteInputElement,
checkCurrentQuery: boolean,
event?: Event,
event?: Event
) {
const input = remoteInput.input;
if (!input) return;
const input = remoteInput.input
if (!input) return

const state = states.get(remoteInput);
if (!state) return;
const state = states.get(remoteInput)
if (!state) return

const query = input.value;
if (checkCurrentQuery && state.currentQuery === query) return;
const query = input.value
if (checkCurrentQuery && state.currentQuery === query) return

state.currentQuery = query;
state.currentQuery = query

const src = remoteInput.src;
if (!src) return;
const src = remoteInput.src
if (!src) return

const resultsContainer = document.getElementById(
remoteInput.getAttribute("aria-owns") || "",
);
if (!resultsContainer) return;
remoteInput.getAttribute('aria-owns') || ''
)
if (!resultsContainer) return

const url = new URL(src, window.location.href);
const params = new URLSearchParams(url.search);
params.append(remoteInput.getAttribute("param") || "q", query);
url.search = params.toString();
const url = new URL(src, window.location.href)
const params = new URLSearchParams(url.search)
params.append(remoteInput.getAttribute('param') || 'q', query)
url.search = params.toString()

if (state.controller) {
state.controller.abort();
state.controller.abort()
} else {
remoteInput.dispatchEvent(new CustomEvent("loadstart"));
remoteInput.setAttribute("loading", "");
remoteInput.dispatchEvent(new CustomEvent('loadstart'))
remoteInput.setAttribute('loading', '')
}

state.controller = makeAbortController();
state.controller = makeAbortController()

let response;
let html = "";
let response
let html = ''
try {
response = await fetchWithNetworkEvents(remoteInput, url.toString(), {
signal: state.controller.signal,
credentials: "same-origin",
headers: { accept: "text/fragment+html" },
});
html = await response.text();
remoteInput.removeAttribute("loading");
state.controller = null;
credentials: 'same-origin',
headers: { accept: 'text/fragment+html' }
})
html = await response.text()
remoteInput.removeAttribute('loading')
state.controller = null
} catch (error) {
if (error instanceof Error && error.name !== "AbortError") {
remoteInput.removeAttribute("loading");
state.controller = null;
if (error instanceof Error && error.name !== 'AbortError') {
remoteInput.removeAttribute('loading')
state.controller = null
}
return;
return
}

if (response && response.ok) {
resultsContainer.innerHTML = html;
resultsContainer.innerHTML = html
remoteInput.dispatchEvent(
new CustomEvent("remote-input-success", {
new CustomEvent('remote-input-success', {
bubbles: true,
detail: { eventType: event ? event.type : undefined },
}),
);
detail: { eventType: event ? event.type : undefined }
})
)
} else {
remoteInput.dispatchEvent(
new CustomEvent("remote-input-error", { bubbles: true }),
);
new CustomEvent('remote-input-error', { bubbles: true })
)
}
}

async function fetchWithNetworkEvents(
el: Element,
url: string,
options: RequestInit,
options: RequestInit
): Promise<Response> {
try {
const response = await fetch(url, options);
el.dispatchEvent(new CustomEvent("load"));
el.dispatchEvent(new CustomEvent("loadend"));
return response;
const response = await fetch(url, options)
el.dispatchEvent(new CustomEvent('load'))
el.dispatchEvent(new CustomEvent('loadend'))
return response
} catch (error) {
if (error instanceof Error && error?.name !== "AbortError") {
el.dispatchEvent(new CustomEvent("error"));
el.dispatchEvent(new CustomEvent("loadend"));
if (error instanceof Error && error?.name !== 'AbortError') {
el.dispatchEvent(new CustomEvent('error'))
el.dispatchEvent(new CustomEvent('loadend'))
}
throw error;
throw error
}
}

function debounce<T>(callback: (_args: T) => void) {
let timeout: ReturnType<typeof setTimeout>;
let timeout: ReturnType<typeof setTimeout>
return function (args: T) {
clearTimeout(timeout);
clearTimeout(timeout)
timeout = setTimeout(() => {
clearTimeout(timeout);
callback(args);
}, 300);
};
clearTimeout(timeout)
callback(args)
}, 300)
}
}

export default RemoteInputElement;
export default RemoteInputElement

declare global {
// eslint-disable-next-line no-unused-vars
interface Window {
RemoteInputElement: typeof RemoteInputElement;
RemoteInputElement: typeof RemoteInputElement
}
}

if (!window.customElements.get("remote-input")) {
window.RemoteInputElement = RemoteInputElement;
window.customElements.define("remote-input", RemoteInputElement);
if (!window.customElements.get('remote-input')) {
window.RemoteInputElement = RemoteInputElement
window.customElements.define('remote-input', RemoteInputElement)
}
Loading