Skip to content

Commit 8b1ef99

Browse files
committed
Add live URL viewer on GitHub pages
Meant to be an always-updating version of https://quuz.org/url/liveview2.html. Much code, especially styling, copied from https://github.com/annevk/live-url-viewer. Closes #106.
1 parent fa96371 commit 8b1ef99

File tree

9 files changed

+304
-2
lines changed

9 files changed

+304
-2
lines changed

.eslintignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,4 @@ lib/URLSearchParams.js
55
lib/url-state-machine.js
66
lib/urlencoded.js
77
lib/utils.js
8+
live-viewer/whatwg-url.js

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,5 @@ lib/URLSearchParams.js
1111
lib/url-state-machine.js
1212
lib/urlencoded.js
1313
lib/utils.js
14+
live-viewer/whatwg-url.js
15+
out/

.travis.yml

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,22 @@
1-
language: node_js
1+
sudo: false
22

3+
language: node_js
34
node_js: stable
4-
sudo: false
55

66
install:
77
- yarn
88

99
script:
1010
- yarn lint
1111
- yarn test
12+
13+
before_deploy:
14+
- bash scripts/deploy-live-viewer.sh
15+
16+
deploy:
17+
provider: pages
18+
local-dir: out
19+
committer-from-gh: true
20+
skip-cleanup: true
21+
keep-history: true
22+
github-token: $GH_TOKEN

live-viewer/.eslintrc.json

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{
2+
"env": {
3+
"browser": true
4+
},
5+
"globals": {
6+
"whatwgURL": false
7+
}
8+
}

live-viewer/index.html

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
<!doctype html>
2+
<meta charset="utf-8">
3+
<title>Live URL Viewer</title>
4+
<link rel="stylesheet" href="style.css">
5+
<script src="whatwg-url.js"></script>
6+
7+
<h1>Live URL Viewer</h1>
8+
9+
<p>The output below will display a URL's parsed components from the browser versus those given by
10+
<a href="https://github.com/jsdom/whatwg-url">jsdom/whatwg-url</a>.
11+
12+
<p>jsdom/whatwg-url closely follows the <a href="http://url.spec.whatwg.org/">URL Standard</a> and
13+
the associated
14+
<a href="https://github.com/w3c/web-platform-tests/tree/master/url">web-platform-tests</a>, so this
15+
serves as a good comparison versus the standard itself.
16+
17+
<p>The output will be colored <span class="pass">dark green</span> unless a difference occurs
18+
between the two parsers in which case the affected URL component will be colored
19+
<span class="fail">red</span>.
20+
21+
<form>
22+
<label for="url">URL:</label>
23+
<input id="url" value="https://example.com/" autofocus>
24+
25+
<label for="base">Base URL:</label>
26+
<input id="base" value="about:blank">
27+
</form>
28+
29+
<h2>Browser's URL components</h2>
30+
31+
<table class="output" id="browser-output">
32+
<tr id="href"><th>href</th><td></td></tr>
33+
<tr id="protocol"><th>protocol</th><td></td></tr>
34+
<tr id="username"><th>username</th><td></td></tr>
35+
<tr id="password"><th>password</th><td></td></tr>
36+
<tr id="port"><th>port</th><td></td></tr>
37+
<tr id="hostname"><th>hostname</th><td></td></tr>
38+
<tr id="pathname"><th>pathname</th><td></td></tr>
39+
<tr id="search"><th>search</th><td></td></tr>
40+
<tr id="hash"><th>hash</th><td></td></tr>
41+
</table>
42+
43+
<p class="output error" id="browser-error"></p>
44+
45+
<h2>jsdom/whatwg-url's components</h2>
46+
47+
<table class="output" id="jsdom-output">
48+
<tr id="href"><th>href</th><td></td></tr>
49+
<tr id="protocol"><th>protocol</th><td></td></tr>
50+
<tr id="username"><th>username</th><td></td></tr>
51+
<tr id="password"><th>password</th><td></td></tr>
52+
<tr id="port"><th>port</th><td></td></tr>
53+
<tr id="hostname"><th>hostname</th><td></td></tr>
54+
<tr id="pathname"><th>pathname</th><td></td></tr>
55+
<tr id="search"><th>search</th><td></td></tr>
56+
<tr id="hash"><th>hash</th><td></td></tr>
57+
</table>
58+
59+
<p class="output error" id="jsdom-error"></p>
60+
61+
<footer>
62+
<a href="https://github.com/jsdom/whatwg-url/tree/master/live-viewer">Fork me on GitHub!</a>
63+
</footer>
64+
65+
<iframe hidden id="browser-iframe"></iframe>
66+
67+
<script src="live-viewer.js"></script>

live-viewer/live-viewer.js

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
"use strict";
2+
(() => {
3+
const urlInput = document.querySelector("#url");
4+
const baseInput = document.querySelector("#base");
5+
6+
// Use an iframe to avoid <base> affecting the main page. This is especially bad in Edge where it
7+
// appears to break Edge's DevTools.
8+
const browserIframeDocument = document.querySelector("#browser-iframe").contentDocument;
9+
const browserAnchor = browserIframeDocument.createElement("a");
10+
const browserBase = browserIframeDocument.createElement("base");
11+
browserIframeDocument.head.appendChild(browserBase);
12+
browserIframeDocument.body.appendChild(browserAnchor);
13+
14+
const components = [
15+
"href", "protocol", "username",
16+
"password", "port", "hostname",
17+
"pathname", "search", "hash"
18+
];
19+
20+
urlInput.addEventListener("input", update);
21+
baseInput.addEventListener("input", update);
22+
setFromFragment();
23+
update();
24+
25+
function update() {
26+
const browserResult = getBrowserResult();
27+
const jsdomResult = getJsdomResult();
28+
const mismatchedComponents = getMismatchedComponents(browserResult, jsdomResult);
29+
30+
setResult("browser", browserResult, mismatchedComponents);
31+
setResult("jsdom", jsdomResult, mismatchedComponents);
32+
updateFragmentForSharing();
33+
}
34+
35+
function setResult(kind, result, mismatchedComponents) {
36+
const output = document.querySelector(`#${kind}-output`);
37+
const error = document.querySelector(`#${kind}-error`);
38+
39+
if (result instanceof Error) {
40+
output.hidden = true;
41+
error.hidden = false;
42+
error.textContent = result.toString();
43+
} else {
44+
output.hidden = false;
45+
error.hidden = true;
46+
for (const component of components) {
47+
const componentEl = output.querySelector(`#${component}`).querySelector("td");
48+
setComponentElValue(componentEl, result[component]);
49+
setComponentElMismatch(componentEl, mismatchedComponents.has(component));
50+
}
51+
}
52+
}
53+
54+
function setComponentElValue(componentEl, value) {
55+
const isEmptyString = value === "";
56+
componentEl.textContent = isEmptyString ? "(empty string)" : value;
57+
componentEl.classList.toggle("empty-string", isEmptyString);
58+
}
59+
60+
function setComponentElMismatch(componentEl, isMismatched) {
61+
componentEl.classList.toggle("pass", !isMismatched);
62+
componentEl.classList.toggle("fail", isMismatched);
63+
}
64+
65+
function getMismatchedComponents(result1, result2) {
66+
const mismatched = new Set();
67+
for (const component of components) {
68+
if (result1[component] !== result2[component]) {
69+
mismatched.add(component);
70+
}
71+
}
72+
return mismatched;
73+
}
74+
75+
function getBrowserResult() {
76+
// First make sure the base is not invalid by testing it against an about:blank base.
77+
browserBase.href = "about:blank";
78+
browserAnchor.href = baseInput.value;
79+
if (browserAnchor.protocol === ":") {
80+
return new Error("Browser could not parse the base URL");
81+
}
82+
83+
// Now actually parse the URL against the base.
84+
browserAnchor.href = urlInput.value;
85+
browserBase.href = baseInput.value;
86+
if (browserAnchor.protocol === ":") {
87+
return new Error("Browser could not parse the input");
88+
}
89+
90+
return browserAnchor;
91+
}
92+
93+
function getJsdomResult() {
94+
try {
95+
return new whatwgURL.URL(urlInput.value, baseInput.value);
96+
} catch (e) {
97+
return e;
98+
}
99+
}
100+
101+
function updateFragmentForSharing() {
102+
location.hash = `url=${btoa(urlInput.value)}&base=${btoa(baseInput.value)}`;
103+
}
104+
105+
function setFromFragment() {
106+
const pieces = /#url=([^&]+)&base=(.*)/.exec(location.hash);
107+
if (!pieces) {
108+
return;
109+
}
110+
const [, urlEncoded, baseEncoded] = pieces;
111+
urlInput.value = atob(urlEncoded);
112+
baseInput.value = atob(baseEncoded);
113+
}
114+
})();

live-viewer/style.css

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
* {
2+
font-family: Georgia;
3+
box-sizing: border-box;
4+
}
5+
6+
body {
7+
max-width: 70em;
8+
margin: 12px;
9+
}
10+
11+
h1, h2, h3, h4, h5, h6 {
12+
font-style: italic;
13+
color: DarkBlue;
14+
margin-bottom: 0.2em;
15+
}
16+
17+
h1 {
18+
margin-top: 0;
19+
}
20+
21+
h2, h3, h4, h5, h6 {
22+
margin-top: 1em;
23+
}
24+
25+
h2 {
26+
font-size: 1.5em;
27+
font-weight: bold;
28+
}
29+
30+
p {
31+
margin-top: 0.5em;
32+
word-spacing: 0.3ex;
33+
}
34+
35+
footer {
36+
position: absolute;
37+
top: 1em;
38+
right: 1em;
39+
}
40+
41+
form label {
42+
display: block;
43+
margin-bottom: 6px;
44+
}
45+
46+
form input {
47+
width: 90%;
48+
margin-bottom: 20px;
49+
padding: 3px;
50+
}
51+
52+
.output {
53+
background-color: whitesmoke;
54+
border: 1px dashed crimson;
55+
width: 95%;
56+
padding: 1em;
57+
margin: 0;
58+
}
59+
60+
.output.error {
61+
color: Crimson;
62+
}
63+
64+
.output th {
65+
width: 100px;
66+
text-align: right;
67+
padding-right: 20px;
68+
}
69+
70+
.output td {
71+
font-family: 'Bitstream Vera Sans Mono', 'Andale Mono', 'Lucida Console', monospace, fixed;
72+
}
73+
74+
.pass {
75+
color: green;
76+
}
77+
78+
.fail {
79+
color: red;
80+
}
81+
82+
.output td.empty-string {
83+
font-family: inherit;
84+
font-size: smaller;
85+
font-style: italic;
86+
color: #CCC;
87+
}

package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
"webidl-conversions": "^4.0.2"
1616
},
1717
"devDependencies": {
18+
"browserify": "^16.2.2",
1819
"domexception": "^1.0.1",
1920
"eslint": "^4.19.1",
2021
"istanbul": "~0.4.5",
@@ -30,6 +31,7 @@
3031
"lint": "eslint .",
3132
"prepublish": "node scripts/transform.js && node scripts/convert-idl.js",
3233
"pretest": "node scripts/get-latest-platform-tests.js && node scripts/transform.js && node scripts/convert-idl.js",
34+
"build-live-viewer": "browserify lib/public-api.js --standalone whatwgURL > live-viewer/whatwg-url.js",
3335
"test": "jest"
3436
},
3537
"jest": {

scripts/deploy-live-viewer.sh

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
#!/bin/bash
2+
set -o errexit
3+
set -o nounset
4+
set -o pipefail
5+
cd "$(dirname "$0")"
6+
7+
yarn build-live-viewer
8+
9+
mkdir -p ../out
10+
cp -r ../live-viewer/* ../out # exclude files starting with . by using /*

0 commit comments

Comments
 (0)