Skip to content

Commit

Permalink
Add live URL viewer on GitHub pages
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
domenic committed May 9, 2018
1 parent fa96371 commit 6a31107
Show file tree
Hide file tree
Showing 10 changed files with 8,913 additions and 2 deletions.
1 change: 1 addition & 0 deletions .eslintignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@ lib/URLSearchParams.js
lib/url-state-machine.js
lib/urlencoded.js
lib/utils.js
live-viewer/whatwg-url.js
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,4 @@ lib/URLSearchParams.js
lib/url-state-machine.js
lib/urlencoded.js
lib/utils.js
out/
15 changes: 13 additions & 2 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -1,11 +1,22 @@
language: node_js
sudo: false

language: node_js
node_js: stable
sudo: false

install:
- yarn

script:
- yarn lint
- yarn test

before_deploy:
- bash scripts/deploy-live-viewer.sh

deploy:
provider: pages
local-dir: out
committer-from-gh: true
skip-cleanup: true
keep-history: true
github-token: $GH_TOKEN
8 changes: 8 additions & 0 deletions live-viewer/.eslintrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"env": {
"browser": true
},
"globals": {
"whatwgURL": false
}
}
67 changes: 67 additions & 0 deletions live-viewer/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
<!doctype html>
<meta charset="utf-8">
<title>Live URL Viewer</title>
<link rel="stylesheet" href="style.css">
<script src="whatwg-url.js"></script>

<h1>Live URL Viewer</h1>

<p>The output below will display a URL's parsed components from the browser versus those given by
<a href="https://github.com/jsdom/whatwg-url">jsdom/whatwg-url</a>.

<p>jsdom/whatwg-url closely follows the <a href="http://url.spec.whatwg.org/">URL Standard</a> and
the associated
<a href="https://github.com/w3c/web-platform-tests/tree/master/url">web-platform-tests</a>, so this
serves as a good comparison versus the standard itself.

<p>The output will be colored <span class="pass">dark green</span> unless a difference occurs
between the two parsers in which case the affected URL component will be colored
<span class="fail">red</span>.

<form>
<label for="url">URL:</label>
<input id="url" value="https://example.com/" autofocus>

<label for="base">Base URL:</label>
<input id="base" value="about:blank">
</form>

<h2>Browser's URL components</h2>

<table class="output" id="browser-output">
<tr id="href"><th>href</th><td></td></tr>
<tr id="protocol"><th>protocol</th><td></td></tr>
<tr id="username"><th>username</th><td></td></tr>
<tr id="password"><th>password</th><td></td></tr>
<tr id="port"><th>port</th><td></td></tr>
<tr id="hostname"><th>hostname</th><td></td></tr>
<tr id="pathname"><th>pathname</th><td></td></tr>
<tr id="search"><th>search</th><td></td></tr>
<tr id="hash"><th>hash</th><td></td></tr>
</table>

<p class="output error" id="browser-error"></p>

<h2>jsdom/whatwg-url's components</h2>

<table class="output" id="jsdom-output">
<tr id="href"><th>href</th><td></td></tr>
<tr id="protocol"><th>protocol</th><td></td></tr>
<tr id="username"><th>username</th><td></td></tr>
<tr id="password"><th>password</th><td></td></tr>
<tr id="port"><th>port</th><td></td></tr>
<tr id="hostname"><th>hostname</th><td></td></tr>
<tr id="pathname"><th>pathname</th><td></td></tr>
<tr id="search"><th>search</th><td></td></tr>
<tr id="hash"><th>hash</th><td></td></tr>
</table>

<p class="output error" id="jsdom-error"></p>

<footer>
<a href="https://github.com/jsdom/whatwg-url/tree/master/live-viewer">Fork me on GitHub!</a>
</footer>

<iframe hidden id="browser-iframe"></iframe>

<script src="live-viewer.js"></script>
114 changes: 114 additions & 0 deletions live-viewer/live-viewer.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
"use strict";
(() => {
const urlInput = document.querySelector("#url");
const baseInput = document.querySelector("#base");

// Use an iframe to avoid <base> affecting the main page. This is especially bad in Edge where it
// appears to break Edge's DevTools.
const browserIframeDocument = document.querySelector("#browser-iframe").contentDocument;
const browserAnchor = browserIframeDocument.createElement("a");
const browserBase = browserIframeDocument.createElement("base");
browserIframeDocument.head.appendChild(browserBase);
browserIframeDocument.body.appendChild(browserAnchor);

const components = [
"href", "protocol", "username",
"password", "port", "hostname",
"pathname", "search", "hash"
];

urlInput.addEventListener("input", update);
baseInput.addEventListener("input", update);
setFromFragment();
update();

function update() {
const browserResult = getBrowserResult();
const jsdomResult = getJsdomResult();
const mismatchedComponents = getMismatchedComponents(browserResult, jsdomResult);

setResult("browser", browserResult, mismatchedComponents);
setResult("jsdom", jsdomResult, mismatchedComponents);
updateFragmentForSharing();
}

function setResult(kind, result, mismatchedComponents) {
const output = document.querySelector(`#${kind}-output`);
const error = document.querySelector(`#${kind}-error`);

if (result instanceof Error) {
output.hidden = true;
error.hidden = false;
error.textContent = result.toString();
} else {
output.hidden = false;
error.hidden = true;
for (const component of components) {
const componentEl = output.querySelector(`#${component}`).querySelector("td");
setComponentElValue(componentEl, result[component]);
setComponentElMismatch(componentEl, mismatchedComponents.has(component));
}
}
}

function setComponentElValue(componentEl, value) {
const isEmptyString = value === "";
componentEl.textContent = isEmptyString ? "(empty string)" : value;
componentEl.classList.toggle("empty-string", isEmptyString);
}

function setComponentElMismatch(componentEl, isMismatched) {
componentEl.classList.toggle("pass", !isMismatched);
componentEl.classList.toggle("fail", isMismatched);
}

function getMismatchedComponents(result1, result2) {
const mismatched = new Set();
for (const component of components) {
if (result1[component] !== result2[component]) {
mismatched.add(component);
}
}
return mismatched;
}

function getBrowserResult() {
// First make sure the base is not invalid by testing it against an about:blank base.
browserBase.href = "about:blank";
browserAnchor.href = baseInput.value;
if (browserAnchor.protocol === ":") {
return new Error("Browser could not parse the base URL");
}

// Now actually parse the URL against the base.
browserAnchor.href = urlInput.value;
browserBase.href = baseInput.value;
if (browserAnchor.protocol === ":") {
return new Error("Browser could not parse the input");
}

return browserAnchor;
}

function getJsdomResult() {
try {
return new whatwgURL.URL(urlInput.value, baseInput.value);
} catch (e) {
return e;
}
}

function updateFragmentForSharing() {
location.hash = `url=${btoa(urlInput.value)}&base=${btoa(baseInput.value)}`;
}

function setFromFragment() {
const pieces = /#url=([^&]+)&base=(.*)/.exec(location.hash);
if (!pieces) {
return;
}
const [, urlEncoded, baseEncoded] = pieces;
urlInput.value = atob(urlEncoded);
baseInput.value = atob(baseEncoded);
}
})();
87 changes: 87 additions & 0 deletions live-viewer/style.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
* {
font-family: Georgia;
box-sizing: border-box;
}

body {
max-width: 70em;
margin: 12px;
}

h1, h2, h3, h4, h5, h6 {
font-style: italic;
color: DarkBlue;
margin-bottom: 0.2em;
}

h1 {
margin-top: 0;
}

h2, h3, h4, h5, h6 {
margin-top: 1em;
}

h2 {
font-size: 1.5em;
font-weight: bold;
}

p {
margin-top: 0.5em;
word-spacing: 0.3ex;
}

footer {
position: absolute;
top: 1em;
right: 1em;
}

form label {
display: block;
margin-bottom: 6px;
}

form input {
width: 90%;
margin-bottom: 20px;
padding: 3px;
}

.output {
background-color: whitesmoke;
border: 1px dashed crimson;
width: 95%;
padding: 1em;
margin: 0;
}

.output.error {
color: Crimson;
}

.output th {
width: 100px;
text-align: right;
padding-right: 20px;
}

.output td {
font-family: 'Bitstream Vera Sans Mono', 'Andale Mono', 'Lucida Console', monospace, fixed;
}

.pass {
color: green;
}

.fail {
color: red;
}

.output td.empty-string {
font-family: inherit;
font-size: smaller;
font-style: italic;
color: #CCC;
}
Loading

0 comments on commit 6a31107

Please sign in to comment.