Skip to content

Commit bbd31ba

Browse files
committed
Results mostly working (JS only)
1 parent 44065ed commit bbd31ba

File tree

13 files changed

+300
-39
lines changed

13 files changed

+300
-39
lines changed

src/app/advanced/[engine]/index.html/page.tsx

Lines changed: 42 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,15 @@
1-
import React from 'react';
2-
import { getEngine } from '@/engines';
1+
'use client'
2+
import React, { useState } from 'react';
3+
import { getEngine, runTest } from '@/engines';
34
import { ShareLinks } from '@/components/ShareLinks';
45
import { notFound } from 'next/navigation';
6+
import { TestInput } from '@/types/TestInput';
7+
import { TestOutput } from '@/types/TestOutput';
8+
import { TestResults } from '@/components/TestResults';
59

610
export default function Page({ params }: { params: { engine: string } }) {
11+
const [testOutput, setTestOutput] = useState<TestOutput | null>();
12+
const [testInput, setTestInput] = useState<TestInput | null>();
713
const engine = getEngine(params.engine);
814
if (!engine) {
915
return notFound();
@@ -12,47 +18,69 @@ export default function Page({ params }: { params: { engine: string } }) {
1218
let flash = <></>;
1319
if (engine.level === 'alpha') {
1420
flash = <div className="alert alert-warning" role="alert">
15-
Online testing with {engine.short_name} is not complete - alpha testing only!
16-
</div>;
21+
Online testing with {engine.short_name} is not complete - alpha testing only!
22+
</div>;
1723
} else if (engine.level === 'beta') {
1824
flash = <div className="alert alert-warning" role="alert">
19-
Online testing with {engine.short_name} is still in beta.
20-
</div>;
25+
Online testing with {engine.short_name} is still in beta.
26+
</div>;
2127
}
2228

23-
const inputs = [ "", "", "", "", "" ];
29+
const inputs = ["", "", "", "", ""];
2430

2531
const inputRows = inputs.map((input, index) => (
2632
<div className="mb-3 col-6 row" key={`key${index}`}>
27-
<label htmlFor={`row${index}`} className="col-sm-2 col-form-label">Input {index+1}</label>
33+
<label htmlFor={`row${index}`} className="col-sm-2 col-form-label">Input {index + 1}</label>
2834
<div className="col-sm-10">
2935
<input type="text" className="form-control" id={`input${index}`} name="input" />
3036
</div>
3137
</div>
3238
));
3339

40+
const onSubmit = async (event: React.FormEvent<HTMLFormElement>) => {
41+
event.preventDefault();
42+
const form = event.currentTarget;
43+
const formData = new FormData(form);
44+
const localInput: TestInput = {
45+
regex: formData.get('regex') as string,
46+
replacement: formData.get('replacement') as string,
47+
options: formData.get('options') as string,
48+
inputs: formData.getAll('input') as string[]
49+
};
50+
console.log(localInput);
51+
setTestInput(localInput);
52+
setTestOutput(null);
53+
setTestOutput(await runTest(engine, formData));
54+
55+
//window.history.pushState(null, "", `/advanced/${engine.handle}/results.html`);
56+
};
57+
3458
return (
3559
<>
3660
<div className="d-flex justify-content-between align-items-center">
3761
<h1>{engine.short_name} Regular Expression Test Page</h1>
3862
<a className="btn btn-success" href={engine.help_url} target="_blank">{engine.help_label}</a>
3963
</div>
4064
<ShareLinks url={`https://regexplanet.com/advanced/${engine.handle}/index.html`} text={`Test your ${engine.short_name} regular expression`} />
41-
<hr/>
65+
<hr />
4266
{flash}
67+
{(testInput ?
68+
(testOutput ? <TestResults testOutput={testOutput} /> : <><h2>Results</h2><p>Loading...</p></>)
69+
: <></>)
70+
}
4371
<h2>Expression to test</h2>
44-
<form method="post">
72+
<form method="post" action="results.html" onSubmit={onSubmit}>
4573
<div className="mb-3">
4674
<label htmlFor="regex" className="form-label">Regular Expression</label>
4775
<input type="text" className="form-control" id="regex" name="regex" />
4876
</div>
4977
<div className="mb-3">
5078
<label htmlFor="replacement" className="form-label">Replacement</label>
51-
<input type="password" className="form-control" id="replacement" name="replacement" />
79+
<input type="text" className="form-control" id="replacement" name="replacement" />
5280
</div>
53-
<div className="mb-3 form-check">
54-
<input type="checkbox" className="form-check-input" id="exampleCheck1" />
55-
<label className="form-check-label" htmlFor="exampleCheck1">Check me out</label>
81+
<div className="mb-3">
82+
<label htmlFor="options" className="form-label">Options</label>
83+
<input type="text" className="form-control" id="options" name="options" />
5684
</div>
5785
<button type="submit" className="btn btn-primary">Test</button>
5886
{inputRows}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
'use client';
2+
import { getEngine } from "@/engines";
3+
import { notFound } from "next/navigation";
4+
import { useFormStatus } from "react-dom";
5+
6+
export default function Page({ params }: { params: { engine: string } }) {
7+
const { pending, data, method } = useFormStatus();
8+
9+
const engine = getEngine(params.engine);
10+
if (!engine) {
11+
return notFound();
12+
}
13+
14+
15+
return (
16+
<>
17+
<div className="d-flex justify-content-between align-items-center">
18+
<h1>{engine.short_name} Test Results</h1>
19+
<a className="btn btn-success" href={engine.help_url} target="_blank">{engine.help_label}</a>
20+
</div>
21+
<p>Results will be displayed here.</p>
22+
<p>{pending} {method}</p>
23+
<pre>{JSON.stringify(params, null, 2)}</pre>
24+
<pre>{JSON.stringify(data, null, 2)}</pre>
25+
</>
26+
);
27+
}
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
"use server"
2+
import { TestResults } from "@/components/TestResults";
3+
import { TestOutput } from "@/types/TestOutput";
4+
import RootLayout from "@/app/layout";
5+
import { Navbar } from "@/components/Navbar";
6+
import { Footer } from "@/components/Footer";
7+
import { TestInput } from "@/types/TestInput";
8+
9+
10+
// doesn't have layout
11+
export async function postpage(testOutput: TestOutput) {
12+
return (
13+
<>
14+
<TestResults testOutput={testOutput} />
15+
</>
16+
);
17+
}
18+
19+
// ⨯ Error: Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: object.
20+
export async function bad500_2(testOutput: TestOutput) {
21+
return (
22+
<RootLayout>
23+
<TestResults testOutput={testOutput} />
24+
</RootLayout>
25+
);
26+
}
27+
28+
export async function bad500(testOutput: TestOutput) {
29+
return (
30+
<html lang="en">
31+
<body>
32+
<Navbar />
33+
<div className="container-lg mt-4">
34+
<TestResults testOutput={testOutput} />
35+
</div>
36+
<Footer />
37+
</body>
38+
</html>
39+
40+
);
41+
}
42+
43+
export async function renderPageSimple(
44+
engine: string,
45+
method: string,
46+
testInput: TestInput,
47+
testOutput: TestOutput
48+
) {
49+
return `${engine} ${method} input=${JSON.stringify(
50+
testInput
51+
)} output=${JSON.stringify(testOutput)}`;
52+
}
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
import { TestInput } from "@/types/TestInput";
2+
import { TestOutput } from "@/types/TestOutput";
3+
import { NextRequest } from "next/server";
4+
//import { renderToStaticMarkup, renderToString } from "react-dom/server";
5+
import { postpage } from "./postpage";
6+
import { getEngine, runTest } from "@/engines";
7+
import { notFound } from "next/navigation";
8+
9+
10+
11+
async function renderPage(
12+
engine: string,
13+
method: string,
14+
testInput: TestInput,
15+
testOutput: TestOutput
16+
) {
17+
//return (await postpage(testOutput)).toString(); // [object Object]
18+
//return renderToStaticMarkup;(await postpage(testOutput)); next fatal compile error
19+
const { renderToString } = await import("react-dom/server");
20+
return renderToString(await postpage(testOutput));
21+
}
22+
23+
export async function GET(
24+
request: Request,
25+
{ params }: { params: { engine: string } }
26+
) {
27+
const engine = getEngine(params.engine);
28+
if (!engine) {
29+
return notFound();
30+
}
31+
32+
const testInput = {
33+
regex: "test",
34+
replacement: "test",
35+
options: "get",
36+
inputs: ["test"],
37+
};
38+
39+
/*
40+
const rawItem = request.url;
41+
if (!rawItem) {
42+
return new Response("No test input", {
43+
status: 400,
44+
});
45+
}
46+
const testInput = JSON.parse(rawItem) as TestInput;
47+
*/
48+
const formData = new FormData();
49+
formData.set("regex", testInput.regex);
50+
51+
const testOutput = runTest(engine, formData);
52+
53+
const html = JSON.stringify(testOutput);
54+
55+
return new Response(html, {
56+
status: 200,
57+
});
58+
}
59+
60+
export async function POST(
61+
request: NextRequest,
62+
{ params }: { params: { engine: string } }
63+
) {
64+
const engine = getEngine(params.engine);
65+
if (!engine) {
66+
return notFound();
67+
}
68+
69+
const rawData = await request.formData();
70+
71+
const testInput = {
72+
regex: (rawData.get("regex") || "") as string,
73+
replacement: (rawData.get("replacement") || "") as string,
74+
options: (rawData.get("options") || "") as string,
75+
inputs: (rawData.getAll("input") || []) as string[],
76+
};
77+
78+
const testOutput = await runTest(engine, rawData);
79+
80+
const html = await renderPage(engine.handle, "post", testInput, testOutput);
81+
82+
return new Response(html, {
83+
status: 200,
84+
headers: {
85+
"Content-Type": "text/html"
86+
},
87+
});
88+
}

src/app/status.html/page.tsx

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import React, { useCallback } from 'react';
55
import { getEngines } from '@/engines';
66
import Link from 'next/link';
77
import fetchJsonp from 'fetch-jsonp';
8+
import { EngineStatus } from '@/types/EngineStatus';
89

910

1011
function getHost(test_url: string) {
@@ -23,13 +24,6 @@ function getHost(test_url: string) {
2324
</>
2425
}
2526

26-
type EngineStatus = {
27-
success: boolean;
28-
version?: string;
29-
time_millis?: number;
30-
err?: Error;
31-
}
32-
3327
const SLOW_TIME_MILLIS = 10 * 1000;
3428

3529
function EngineStatusColumns(status: EngineStatus | undefined ) {
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
'use client'
2+
3+
import { usePathname, useSearchParams } from 'next/navigation'
4+
5+
export default function Page() {
6+
7+
const pathname = usePathname()
8+
const searchParams = useSearchParams()
9+
10+
let fullpath = pathname;
11+
if (searchParams.toString().length > 0) {
12+
fullpath += '?' + searchParams.toString();
13+
}
14+
15+
return (
16+
<>
17+
<iframe height="737" title="Embedded Wufoo Form" style={{ "width": "100%", "border": "none" }} sandbox="allow-popups-to-escape-sandbox allow-top-navigation allow-scripts allow-popups allow-forms allow-same-origin" src={`https://fileformat.wufoo.com/embed/z5yinul1mj3me9/?field14=regexplanet-next&field16=${encodeURIComponent(fullpath)}`}></iframe>
18+
<p>{fullpath}</p>
19+
</>
20+
);
21+
}

src/app/support/contact.html/page.tsx

Lines changed: 4 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,14 @@
1-
'use client'
2-
3-
import { usePathname, useSearchParams } from 'next/navigation'
41
import { Suspense } from 'react'
2+
import ClientPage from './ClientPage';
53

64
export default function Page() {
7-
<Suspense>
8-
<SuspendablePage />
9-
</Suspense>
10-
}
11-
12-
function SuspendablePage() {
13-
const pathname = usePathname()
14-
const searchParams = useSearchParams()
155

16-
let fullpath = pathname;
17-
if (searchParams.toString().length > 0) {
18-
fullpath += '?' + searchParams.toString();
19-
}
206

217
return (
228
<>
23-
<iframe height="737" title="Embedded Wufoo Form" style={{"width":"100%","border":"none"}} sandbox="allow-popups-to-escape-sandbox allow-top-navigation allow-scripts allow-popups allow-forms allow-same-origin" src={`https://fileformat.wufoo.com/embed/z5yinul1mj3me9/?field14=regexplanet-next&field16=${encodeURIComponent(fullpath)}`}></iframe>
9+
<Suspense fallback={<div>Loading...</div>}>
10+
<ClientPage />
11+
</Suspense>
2412
</>
2513
);
2614
}

src/components/TestResults.tsx

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import { TestOutput } from "@/types/TestOutput";
2+
3+
type props = {
4+
testOutput: TestOutput;
5+
};
6+
7+
export function TestResults({ testOutput }: props) {
8+
9+
const messageClass = testOutput.success ? "alert alert-info" : "alert alert-danger";
10+
return (
11+
<>
12+
<h2>Results</h2>
13+
{ testOutput.message ? <div className={messageClass}>{testOutput.message}</div> : <></>}
14+
{ testOutput.html ? <div dangerouslySetInnerHTML={{ __html: testOutput.html }} /> : <></> }
15+
<hr/>
16+
</>
17+
);
18+
}

src/engines/RegexEngine.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11

2-
32
type RegexEngine = {
43
description: string;
54
enabled: boolean;

0 commit comments

Comments
 (0)