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

[PM-8873] Add pattern for deep iframe nesting for login items #161

Merged
merged 4 commits into from
Jun 24, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
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
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
---
slug: iframe-multi-step-formless-login
title: iframe-multi-step formless login
sidebar_label: iframe, multi-step (formless)
sidebar_label: multi-step (iframe, formless)
sidebar_position: 10
description: iframed multi-step login inputs without an enclosing form which will store user inputs of each step and will POST on final submit
as_seen_on: icloud.com
Expand Down
24 changes: 24 additions & 0 deletions client/docs/forms/login/nested-iframe-login.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
---
slug: nested-iframe-login
title: nested iframe login form
sidebar_label: iframe (nested)
sidebar_position: 3
description: two sibling iframed login forms nested within a series of inline frames (iframe) that will POST on submit. Intermediate depth can be specified with a query string param of `depth` and integer value (e.g. `depth=6`). Intermediate depth defaults to a value of "3".
unlisted: true
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will make the page available on a deployed instance, but it won't have a user path via nav or web search.

This will allow us to refine the case before publishing a user path to the page

---

import { NestedIframeControl } from "@site/src/components/NestedIframeControl";
import { NestedIframeLogin } from "@site/src/components/NestedIframeLogin";

<div className="col col--12 margin-vert--lg hide-on-bare-page">
<div className="row">
<label htmlFor="nested-iframe-control" className="margin-right--sm">
<span>Select nested iframe depth:</span>
</label>
<NestedIframeControl />
</div>
</div>

<NestedIframeLogin slug="nested-iframe-login" />

<hr />
3 changes: 2 additions & 1 deletion client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@
"docusaurus": "docusaurus",
"lint:a11y": "NODE_EXTRA_CA_CERTS=../api/ssl.crt node ./scripts/lint-a11y.js",
"serve": "docusaurus serve --no-open",
"start": "docusaurus start --no-open",
"start": "./scripts/docusaurus-start.sh",
"start:insecure": "docusaurus start --no-open",
"swizzle": "docusaurus swizzle",
"typecheck": "tsc",
"write-heading-ids": "docusaurus write-heading-ids",
Expand Down
16 changes: 16 additions & 0 deletions client/scripts/docusaurus-start.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
#!/usr/bin/env bash

ROOT_DIR=$(git rev-parse --show-toplevel)

# shellcheck source=.env
set -o allexport
HTTPS=true

# Generate via ./scripts/generate-certs, or mkcert
# (see: https://docusaurus.io/docs/cli#enabling-https)
source $ROOT_DIR/api/.env
SSL_CRT_FILE=$ROOT_DIR/api/$SSL_CERT
SSL_KEY_FILE=$ROOT_DIR/api/$SSL_KEY
set +o allexport

npm run docusaurus start
33 changes: 33 additions & 0 deletions client/src/components/NestedIframeControl.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { useLocation, useHistory } from "@docusaurus/router";

export function NestedIframeControl({
name = "nested-iframe-control",
}: {
name?: string;
}) {
let { pathname, search } = useLocation();
const history = useHistory();
const queryParams = new URLSearchParams(search);
const depthParam = queryParams.get("depth");
const defaultValue = parseInt(depthParam || "3", 10);

function handleInputChange({ target }: React.ChangeEvent<HTMLInputElement>) {
const newValue = target?.value ? parseInt(target.value, 10) : 0;

history.push(pathname + `?depth=${newValue}`);
}

return (
<input
type="number"
name={name}
defaultValue={defaultValue}
min={0}
max={100}
step={1}
inputMode="numeric"
pattern="\d*"
onChange={handleInputChange}
/>
);
}
122 changes: 122 additions & 0 deletions client/src/components/NestedIframeLogin.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
import { useLocation } from "@docusaurus/router";
import Admonition from "@theme/Admonition";
import styled from "@emotion/styled";
import {
EmailInput,
PasswordInput,
SubmitButton,
UsernameInput,
} from "./Inputs";

export function NestedIframeLogin({
slug = "nested-iframe-login",
}: {
slug?: string;
}): JSX.Element {
const location = useLocation();
const queryParams = new URLSearchParams(location.search);
const depthParam = queryParams.get("depth") || "3";
const userInputType =
queryParams.get("userInputType") !== "email" ? "username" : "email";
const depth = parseInt(depthParam, 10);
const newDepth = depth - 1;

const iframeStyle = {
width: "100%",
minHeight: `calc(370px + ${depth}rem)`,
};

if (depth > 100) {
return (
<Admonition type="warning">
Depth value is too high; try a lower value.
</Admonition>
);
}

if (depth < 0) {
return (
<Admonition type="warning">
Depth value is too low; try a higher value.
</Admonition>
);
}

if (depth > 0) {
const src = `/forms/login/${slug}?depth=${newDepth}&docusaurus-data-bare-page=true`;

if (depth === 1) {
return (
<>
<FrameLabel>iframe depth: {depth}</FrameLabel>
<iframe
id="form-iframe-1"
title={`frame ${newDepth}`}
src={src + `&userInputType=username`}
style={{ ...iframeStyle, width: "40%", marginRight: "5%" }}
scrolling="no"
loading="lazy"
></iframe>
<iframe
id="form-iframe-2"
title={`frame ${newDepth}`}
src={src + `&userInputType=email`}
style={{ ...iframeStyle, width: "40%" }}
scrolling="no"
loading="lazy"
></iframe>
</>
);
}

return (
<>
<FrameLabel>iframe depth: {depth}</FrameLabel>
<iframe
id="test-iframe"
title={`frame ${newDepth}`}
src={src}
style={iframeStyle}
loading="lazy"
></iframe>
</>
);
}

return (
<>
<FrameLabel>iframe depth: {depth}</FrameLabel>
<br />
<NestedForm userInputType={userInputType} />
</>
);
}

function NestedForm({
userInputType,
}: {
userInputType: "username" | "email";
}) {
return (
<>
<strong>Login with {userInputType}</strong>
<form className="card__body" method="POST" action="/login">
{userInputType === "username" ? <UsernameInput /> : <EmailInput />}
<PasswordInput />
<SubmitButton label="Submit" />
</form>
</>
);
}

const FrameLabel = styled.div`
border-bottom: 1px solid #3d3d3d;
line-height: 2rem;
font-weight: bold;

:before {
display: block;
margin-top: 10px;
content: "";
}
`;
17 changes: 17 additions & 0 deletions client/src/css/custom.css
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ input[type="email"],
input[type="tel"],
input[type="search"],
input[type="password"],
input[type="number"],
input[type="text"] {
border: 1px solid var(--ifm-color-emphasis-300);
border-radius: var(--ifm-pagination-nav-border-radius);
Expand All @@ -95,6 +96,7 @@ input[type="email"]:hover,
input[type="tel"]:hover,
input[type="search"]:hover,
input[type="password"]:hover,
input[type="number"]:hover,
input[type="text"]:hover {
border-color: var(--ifm-pagination-nav-color-hover);
}
Expand All @@ -106,6 +108,7 @@ input[type="email"]:focus,
input[type="tel"]:focus,
input[type="search"]:focus,
input[type="password"]:focus,
input[type="number"]:focus,
input[type="text"]:focus,
select:active,
input:not([type]):active, /* text type is stripped from built html */
Expand All @@ -114,6 +117,7 @@ input[type="email"]:active,
input[type="tel"]:active,
input[type="search"]:active,
input[type="password"]:active,
input[type="number"]:active,
input[type="text"]:active {
outline: var(--ifm-pagination-nav-color-hover) 2px solid;
background: var(--docsearch-searchbox-focus-background);
Expand All @@ -132,6 +136,19 @@ html[data-hide-sidebar="true"] .theme-doc-sidebar-container {
display: none;
}

html[data-bare-page="true"] .container,
html[data-bare-page="true"] .col,
html[data-bare-page="true"] .row {
margin: 0;
padding: 0;
}

html[data-bare-page="true"] article hr,
html[data-bare-page="true"] main .theme-unlisted-banner,
html[data-bare-page="true"] .hide-on-bare-page {
display: none;
}

.navbar__brand {
margin-right: 5px;
}
Expand Down