Skip to content

Instantly share code, notes, and snippets.

@RoXuS
Created October 7, 2020 21:03
Show Gist options
  • Save RoXuS/390950549dbc29aac593f8b96095308b to your computer and use it in GitHub Desktop.
Save RoXuS/390950549dbc29aac593f8b96095308b to your computer and use it in GitHub Desktop.
/* eslint-disable no-multi-assign */
interface InputWrapper {
input?: HTMLInputElement;
inputListener?: () => void;
proxy?: HTMLInputElement;
proxyListener?: () => void;
}
const SUBMIT = 'submit';
const INPUT = 'input';
const username: InputWrapper = {};
const password: InputWrapper = {};
const proxyForm = document.createElement('form');
const createInput = () => document.createElement('input');
const hide = (element: HTMLElement) => {
element.tabIndex = -1;
element.setAttribute('aria-hidden', 'true');
};
const submitButton = createInput();
const shadowDOM = true;
let realForm: HTMLFormElement;
submitButton.type = SUBMIT;
username.proxy = username.input = createInput();
password.proxy = password.input = createInput();
proxyForm.appendChild(username.proxy);
proxyForm.appendChild(password.proxy);
proxyForm.appendChild(submitButton);
proxyForm.method = 'post';
proxyForm.style.cssText = 'visibility: hidden; height: 0; width: 0';
proxyForm.addEventListener(SUBMIT, (e) => {
e.preventDefault();
});
hide(username.proxy);
hide(password.proxy);
hide(submitButton);
hide(proxyForm);
export const attachProxyForm = (hostElement: HTMLElement): void => {
if (shadowDOM) {
hostElement.appendChild(proxyForm);
}
};
export const storePassword = (): void => {
submitButton.click();
};
const sync = (from: HTMLInputElement, to: HTMLInputElement) => {
const listener = () => {
const fromValue = from.value;
if (to.value !== fromValue) {
to.value = fromValue;
}
};
const fromValue = from.value;
if (!to.value && fromValue) {
to.value = fromValue;
}
from.addEventListener(INPUT, listener);
return listener;
};
const synchronise = (field: InputWrapper) => {
const { input, proxy } = field;
if (input && proxy) {
field.proxyListener = sync(proxy, input);
field.inputListener = sync(input, proxy);
}
};
const connect = (field: InputWrapper, newInput: HTMLInputElement) => {
if (shadowDOM) {
const {
input, inputListener, proxy, proxyListener,
} = field;
if (input && inputListener && proxy && proxyListener) {
input.removeEventListener(INPUT, inputListener);
proxy.removeEventListener(INPUT, proxyListener);
}
const { id, type } = (field.input = newInput);
Object.assign(proxy, { id, type });
synchronise(field);
}
};
export const connectUsername = (input: HTMLInputElement): void => {
connect(
username,
input
);
};
export const connectPassword = (input: HTMLInputElement): void => {
connect(
password,
input
);
if (realForm) {
realForm.removeEventListener(SUBMIT, storePassword);
}
if (input.form) {
realForm = input.form;
if (realForm) {
realForm.addEventListener(SUBMIT, storePassword);
}
}
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment