UNPKG

structured-field-values

Version:

Implementation of Structured Field Values from IETF httpbis RFC8941

257 lines (224 loc) 6.6 kB
<!DOCTYPE html> <meta charset=utf-8> <meta name=viewport content="width=device-width,initial-scale=1"> <title>Structured Field Values DEMO</title> <style> :root { --width: 56vw; --font-family: "Google Sans", Segoe UI, system-ui, -apple-system, sans-serif; --font-color: #333; --font-family-mono: Menlo, Consolas, Liberation, Mono, Courier, monospace; } @media screen and (max-device-width: 960px) { :root { --width: 96vw; } } body { font-family: var(--font-family); width: var(--width); color: var(--font-color); margin: 0 auto; padding-top: 10px; } h1, h2 { margin: 0 0 10px 0; font-weight: 400; } h1 { font-size: 1.2em; } h2 { font-size: 1em; } main { display: flex; flex-direction: column; justify-content: space-between; align-items: center; align-content: center; height: 80vh; } footer { width: 100%; display: flex; justify-content: flex-end; font-style: italic; } textarea { font-family: var(--font-family-mono); width: 100%; box-sizing: border-box; } button { height: 100%; padding: auto; background-color: #eee; border: solid 1px #ccc; border-radius: 2px; margin: 0 4px; } .encoded { height: 15vh; } .decoded { height: 30vh; } .active { background-color: #a2c7fd; } .center { display: flex; justify-content: center; box-sizing: border-box; } .samples { font-family: var(--font-family-mono); font-size: 0.5em; margin: 0; padding: 0 0 0 1em; } .samples li { margin: 4px; } .samples a { padding: 1px; display: inline-block; border-bottom: solid 2px #2981c1; background-color: #eef4ff; text-decoration: none; } .worn { width: 100%; padding: 0; margin: 0; font-size: 0.6em; font-style: italic; } .error { margin: 0; padding: 0; width: 100%; height: 2em; font-family: var(--font-family-mono); font-size: 0.5em; color: red; } </style> <h1>Structured Field Values DEMO</h1> <h2><a href=https://www.rfc-editor.org/rfc/rfc8941.html>RFC 8941: Structured Field Values for HTTP</a></h2> <main> <label for=encoded>encoded</label> <textarea id=encoded class=encoded></textarea> <p class="decode error"></p> <div class=center> <button class="decode Item">decode item ⬇️ </button> <button class="decode List">decode list ⬇️ </button> <button class="decode Dict">decode dict ⬇️ </button> </div> <div class=center> <button class="encode Item">encode item ⬆️ </button> <button class="encode List">encode list ⬆️ </button> <button class="encode Dict">encode dict ⬆️ </button> </div> <p class="encode error"></p> <label for=decoded>decoded</label> <textarea id=decoded class=decoded></textarea> <p class="worn">decode a token(Symbol) is not supported</p> </main> <hr> <h2>sample</h2> <ul class=samples> <li>item: <a class="sample Item" href="">?1</a></li> <li>item: <a class="sample Item" href="">a</a></li> <li>item: <a class="sample Item" href="">"a"</a></li> <li>item: <a class="sample Item" href="">100</a></li> <li>item: <a class="sample Item" href="">@1659578233</a></li> <li>list: <a class="sample List" href="">1,2,3,4</a></li> <li>list: <a class="sample List" href="">"a";x, "b";y=?0, 10, (1 2)</a></li> <li>dict: <a class="sample Dict" href="">a=10, b=20, c=30</a> <li>dict: <a class="sample Dict" href="">a="x", b=10, c=?0, d=(1 2)</a></li> <li>Accept-CH(<a href=https://www.rfc-editor.org/rfc/rfc8942.html>RFC 8942: HTTP Client Hints</a>): <a class="sample List" href="">Sec-CH-Example, Sec-CH-Example-2</a></li> <li>Cache-Status(<a href=https://tools.ietf.org/html/draft-ietf-httpbis-cache-header-07>id</a>): <a class="sample List" href="">OriginCache; hit; ttl=1100; collapsed, "CDN Company Here"; hit; ttl=545</a></li> <li>Proxy-Status(<a href=https://tools.ietf.org/html/draft-ietf-httpbis-proxy-status-02>id</a>): <a class="sample List" href="">ExampleProxy; error="http_protocol_error"; details="Malformed response header - space before colon"</a></li> </ul> <hr> <footer><small>Author <a href=https://jxck.io>Jxck</a><small></footer> <script type=module> const $ = document.querySelector.bind(document) const $$ = document.querySelectorAll.bind(document) EventTarget.prototype.on = EventTarget.prototype.addEventListener import * as sfv from "./index.js" const $encoded = $("textarea.encoded") const $decoded = $("textarea.decoded") const $encodeError = $(".encode.error") const $decodeError = $(".decode.error") function clear() { $decodeError.textContent = "" $encodeError.textContent = "" $$("button").forEach(($button) => { $button.classList.remove("active") }) } document.on("DOMContentLoaded", async (e) => { $$(".decode").forEach(($decode) => $decode.on("click", (e) => { try { clear() const encoded = $encoded.value console.log(encoded) location.hash = btoa(encoded) const method = e.target.classList.item(1) const decoded = sfv[`decode${method}`](encoded) console.log(decoded) $decoded.value = JSON.stringify(decoded, function(key, value) { if (typeof value === "symbol") { return value.toString() } return value }, " ") e.target.classList.add("active") } catch(error) { console.error(error) $decodeError.textContent = error } })) $$(".encode").forEach(($encode) => $encode.on("click", (e) => { try { clear() const decoded = JSON.parse($decoded.value, function(k, v) { if (k === "value" && typeof v === "string") { const token = v.match(/^Symbol\((.*)\)$/) if (token) { v = Symbol.for(token[1]) } } return v }) console.log(decoded) const method = e.target.classList.item(1) const encoded = sfv[`encode${method}`](decoded) console.log(encoded) $encoded.value = encoded e.target.classList.add("active") } catch(error) { console.error(error) $encodeError.textContent = error } })) $$(".sample").forEach(($sample) => { $sample.on("click", (e) => { clear() e.preventDefault() const sample = e.target.textContent $encoded.value = sample $decoded.value = "" }) }) if (location.hash === "") { $encoded.value = $$(".sample.List")[1].textContent $(".decode.List").click() } else { $encoded.value = atob(location.hash.substr(1)) } }) </script>