mirror of
https://github.com/home-assistant/frontend.git
synced 2025-07-25 18:26:35 +00:00
Adjust password manager polyfill for form injections (#17830)
This commit is contained in:
parent
713ebfcc22
commit
e46f2cd9bf
@ -35,20 +35,47 @@ export class HaPasswordManagerPolyfill extends LitElement {
|
|||||||
super.connectedCallback();
|
super.connectedCallback();
|
||||||
this._styleElement = document.createElement("style");
|
this._styleElement = document.createElement("style");
|
||||||
this._styleElement.textContent = css`
|
this._styleElement.textContent = css`
|
||||||
|
/* Polyfill form is sized and vertically aligned with true form, then positioned offscreen
|
||||||
|
rather than hiding so it does not create a new stacking context */
|
||||||
.password-manager-polyfill {
|
.password-manager-polyfill {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
opacity: 0;
|
box-sizing: border-box;
|
||||||
z-index: -1;
|
|
||||||
}
|
}
|
||||||
.password-manager-polyfill input {
|
/* Excluding our wrapper, move any children back on screen, including anything injected that might not already be positioned */
|
||||||
|
.password-manager-polyfill > *:not(.wrapper),
|
||||||
|
.password-manager-polyfill > .wrapper > * {
|
||||||
|
position: relative;
|
||||||
|
left: 10000px;
|
||||||
|
}
|
||||||
|
/* Size and hide our polyfill fields */
|
||||||
|
.password-manager-polyfill .underneath {
|
||||||
|
display: block;
|
||||||
|
box-sizing: border-box;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 62px;
|
padding: 0 16px;
|
||||||
padding: 0;
|
|
||||||
border: 0;
|
border: 0;
|
||||||
|
z-index: -1;
|
||||||
|
height: 21px;
|
||||||
|
/* Transparency is only needed to hide during paint or in case of misalignment,
|
||||||
|
but LastPass will fail if it's 0, so we use 1% */
|
||||||
|
opacity: 0.01;
|
||||||
}
|
}
|
||||||
.password-manager-polyfill input[type="submit"] {
|
.password-manager-polyfill input.underneath {
|
||||||
width: 0;
|
height: 28px;
|
||||||
height: 0;
|
margin-bottom: 30.5px;
|
||||||
|
}
|
||||||
|
/* Button position is not important, but size should not be zero */
|
||||||
|
.password-manager-polyfill > input.underneath[type="submit"] {
|
||||||
|
width: 1px;
|
||||||
|
height: 1px;
|
||||||
|
margin: 0 auto;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
/* Ensure injected elements will be on top */
|
||||||
|
.password-manager-polyfill > *:not(.underneath, .wrapper),
|
||||||
|
.password-manager-polyfill > .wrapper > *:not(.underneath) {
|
||||||
|
isolation: isolate;
|
||||||
|
z-index: auto;
|
||||||
}
|
}
|
||||||
`.toString();
|
`.toString();
|
||||||
document.head.append(this._styleElement);
|
document.head.append(this._styleElement);
|
||||||
@ -77,16 +104,25 @@ export class HaPasswordManagerPolyfill extends LitElement {
|
|||||||
class="password-manager-polyfill"
|
class="password-manager-polyfill"
|
||||||
style=${styleMap({
|
style=${styleMap({
|
||||||
top: `${this.boundingRect?.y || 148}px`,
|
top: `${this.boundingRect?.y || 148}px`,
|
||||||
left: `calc(50% - ${(this.boundingRect?.width || 360) / 2}px)`,
|
left: `calc(50% - ${
|
||||||
|
(this.boundingRect?.width || 360) / 2
|
||||||
|
}px - 10000px)`,
|
||||||
width: `${this.boundingRect?.width || 360}px`,
|
width: `${this.boundingRect?.width || 360}px`,
|
||||||
})}
|
})}
|
||||||
aria-hidden="true"
|
action="/auth"
|
||||||
|
method="post"
|
||||||
@submit=${this._handleSubmit}
|
@submit=${this._handleSubmit}
|
||||||
>
|
>
|
||||||
${autocompleteLoginFields(this.step.data_schema).map((input) =>
|
${autocompleteLoginFields(this.step.data_schema).map((input) =>
|
||||||
this.render_input(input)
|
this.render_input(input)
|
||||||
)}
|
)}
|
||||||
<input type="submit" />
|
<input
|
||||||
|
type="submit"
|
||||||
|
value="Login"
|
||||||
|
class="underneath"
|
||||||
|
tabindex="-2"
|
||||||
|
aria-hidden="true"
|
||||||
|
/>
|
||||||
</form>
|
</form>
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
@ -99,26 +135,35 @@ export class HaPasswordManagerPolyfill extends LitElement {
|
|||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
return html`
|
return html`
|
||||||
<input
|
<!-- Label is a sibling so it can be stacked underneath without affecting injections adjacent to input (e.g. LastPass) -->
|
||||||
tabindex="-1"
|
<label for=${schema.name} class="underneath" aria-hidden="true">
|
||||||
.id=${schema.name}
|
${schema.name}
|
||||||
.name=${schema.name}
|
</label>
|
||||||
.type=${inputType}
|
<!-- LastPass fails if the input is hidden directly, so we trick it and hide a wrapper instead -->
|
||||||
.value=${this.stepData[schema.name] || ""}
|
<div class="wrapper" aria-hidden="true">
|
||||||
.autocomplete=${schema.autocomplete}
|
<!-- LastPass fails with tabindex of -1, so we trick with -2 -->
|
||||||
@input=${this._valueChanged}
|
<input
|
||||||
@change=${this._valueChanged}
|
class="underneath"
|
||||||
/>
|
tabindex="-2"
|
||||||
|
.id=${schema.name}
|
||||||
|
.name=${schema.name}
|
||||||
|
.type=${inputType}
|
||||||
|
.value=${this.stepData[schema.name] || ""}
|
||||||
|
.autocomplete=${schema.autocomplete}
|
||||||
|
@input=${this._valueChanged}
|
||||||
|
@change=${this._valueChanged}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
private _handleSubmit(ev: Event) {
|
private _handleSubmit(ev: SubmitEvent) {
|
||||||
ev.preventDefault();
|
ev.preventDefault();
|
||||||
fireEvent(this, "form-submitted");
|
fireEvent(this, "form-submitted");
|
||||||
}
|
}
|
||||||
|
|
||||||
private _valueChanged(ev: Event) {
|
private _valueChanged(ev: Event) {
|
||||||
const target = ev.target! as HTMLInputElement;
|
const target = ev.target as HTMLInputElement;
|
||||||
this.stepData = { ...this.stepData, [target.id]: target.value };
|
this.stepData = { ...this.stepData, [target.id]: target.value };
|
||||||
fireEvent(this, "value-changed", {
|
fireEvent(this, "value-changed", {
|
||||||
value: this.stepData,
|
value: this.stepData,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user