From 4cee59a9cff51b048fb97023a97cb2eedc9bd2bc Mon Sep 17 00:00:00 2001 From: Lucas Duailibe Date: Wed, 11 Apr 2018 14:29:07 -0300 Subject: [PATCH] update --- website/playground/index.js | 876 ++++++++++++++++++---------------- website/playground/old.js | 655 +++++++++++++++++++++++++ website/static/playground2.js | 693 --------------------------- 3 files changed, 1112 insertions(+), 1112 deletions(-) create mode 100644 website/playground/old.js delete mode 100644 website/static/playground2.js diff --git a/website/playground/index.js b/website/playground/index.js index 3906e6f3..72fb64dc 100644 --- a/website/playground/index.js +++ b/website/playground/index.js @@ -1,357 +1,425 @@ /* eslint-env browser */ /* eslint no-var: off, strict: off, prefer-arrow-callback: off */ -/* global Clipboard CodeMirror formatMarkdown LZString */ +/* global Clipboard CodeMirror formatMarkdown LZString preact */ -var prettierVersion = "?"; -var inputEditor; -var docEditor; -var astEditor; -var outputEditor; -var output2Editor; +var h = preact.h; +var CATEGORIES = ["Global", "JavaScript", "Markdown", "Special"]; var OPTIONS = [ + "parser", "printWidth", "tabWidth", - "singleQuote", - "trailingComma", - "bracketSpacing", - "jsxBracketSameLine", - "parser", - "semi", "useTabs", - "insertPragma", - "requirePragma", - "proseWrap", + { name: "semi", inverted: true }, + "singleQuote", + { name: "bracketSpacing", inverted: true }, + "jsxBracketSameLine", "arrowParens", - "rangeStart", - "rangeEnd", - "doc", - "ast", - "output2" + "trailingComma", + "proseWrap", + "insertPragma", + "requirePragma" ]; -var IDEMPOTENT_MESSAGE = "✓ Second format is unchanged."; +// ---------- Options components ----------- -var worker = new Worker("/worker.js"); - -const DEFAULT_OPTIONS = { - options: undefined, - content: "" -}; - -function createRangeOverlay(rangeStartLocation, rangeEndLocation) { - var rangeStartLine = rangeStartLocation.line; - var rangeEndLine = rangeEndLocation.line; - var rangeStartPos = rangeStartLocation.pos; - var rangeEndPos = rangeEndLocation.pos; - var isEndOnSameLineAsStart = rangeStartLine === rangeEndLine; - var highlightedToken = "searching"; - - return { - token: function(stream) { - var currentLine = stream.lineOracle.line; - - // we are on the line containing rangeStart - if (currentLine === rangeStartLine) { - // on the same line as, but not reached rangeStart yet, - // jump straight to it - if (rangeStartPos > stream.pos) { - stream.pos = rangeStartPos; - return; - } - // the rangeEnd is on the same line as the rangeStart - if (isEndOnSameLineAsStart) { - // we are still within the range, - // keep iterating along the string stream, - // marking it as highlighted - if (stream.pos < rangeEndPos) { - stream.pos += 1; - return highlightedToken; - } - // we've moved outside of the range - // just skip to the end - return stream.skipToEnd(); - } - // keep iterating along the string stream, - // marking it as highlighted - stream.pos += 1; - return highlightedToken; - } - - // we are on the line containing rangeEnd - if (currentLine === rangeEndLine) { - // keep iterating along the string stream, - // marking it as highlighted - if (rangeEndPos > stream.pos) { - stream.pos += 1; - return highlightedToken; - } - // we've moved outside of the range - // just skip to the end - return stream.skipToEnd(); - } - - // we are on a line which is completely included - // within the range, mark it all as highlighted - if (currentLine > rangeStartLine && currentLine < rangeEndLine) { - stream.skipToEnd(); - return highlightedToken; - } - - // no action can be required on the current line - // as it must fall outside of the range, - // so just skip to the end - return stream.skipToEnd(); - } - }; -} - -function indexToEditorLocation(editorContent, index) { - var line = 0; - var count = 0; - var startIndex = 0; - for (var c, i = 0; count < index && i < editorContent.length; i++) { - count++; - c = editorContent[i]; - if (c === "\n") { - line++; - startIndex = count; - } +function BooleanOption(props) { + function maybeInvert(value) { + return props.option.inverted ? !value : value; } - return { - line: line, - pos: count - startIndex - }; + return h( + "label", + null, + h("input", { + type: "checkbox", + checked: maybeInvert(props.value), + onChange: function(ev) { + props.onOptionChange(props.option, maybeInvert(ev.target.checked)); + } + }), + " ", + props.option.cliName + ); } +function ChoiceOption(props) { + return h( + "label", + null, + props.option.cliName, + " ", + h( + "select", + { + onChange: function(ev) { + props.onOptionChange(props.option, ev.target.value); + } + }, + props.option.choices.map(function(choice) { + return h( + "option", + { value: choice.value, selected: choice.value === props.value }, + choice.value + ); + }) + ) + ); +} + +function NumberOption(props) { + return h( + "label", + null, + props.option.cliName, + " ", + h("input", { + type: "number", + min: props.option.range.start, + max: props.option.range.end, + step: props.option.range.step, + value: props.value, + onChange: function(ev) { + props.onOptionChange(props.option, parseInt(ev.target.value, 10)); + } + }) + ); +} + +function Options(props) { + var optionsByCategory = props.availableOptions.reduce(function(acc, opt) { + acc[opt.category] = opts = acc[opt.category] || []; + opts.push(opt); + return acc; + }, {}); + + return h( + "div", + { className: "options-container" + (props.open ? " open" : "") }, + h( + "div", + { className: "options" }, + CATEGORIES.map(function(category) { + return h( + "details", + { className: "sub-options", open: "true" }, + h("summary", null, category), + (optionsByCategory[category] || []).map(function(opt) { + return h(getComponentByOptionType(opt), { + option: opt, + value: props.options[opt.name], + onOptionChange: props.onOptionChange + }); + }) + ); + }) + ) + ); +} + +// ---------- Editor components ----------- + +var Editor = createClass({ + componentDidMount: function() { + this._codeMirror = CodeMirror.fromTextArea(this._ref, this.props.options); + this._codeMirror.on("change", this.handleChange.bind(this)); + this._codeMirror.setValue(this.props.value || ""); + }, + handleChange: function(doc, change) { + if (change.origin !== "setValue") { + this.props.onChange(doc.getValue()); + } + }, + componentWillReceiveProps(nextProps) { + if ( + nextProps.value && + nextProps.value !== this.props.value && + this._codeMirror.getValue() !== nextProps.value + ) { + this._codeMirror.setValue(nextProps.value); + } else if (!nextProps.value) { + this._codeMirror.setValue(""); + } + }, + render: function(props) { + return h( + "div", + { className: "editor input" }, + h("textarea", { + ref: function(ref) { + this._ref = ref; + }.bind(this) + }) + ); + } +}); + +function InputEditor(props) { + return h(Editor, { + options: { + lineNumbers: true, + keyMap: "sublime", + autoCloseBrackets: true, + matchBrackets: true, + showCursorWhenSelecting: true, + tabWidth: 2, + mode: props.mode + }, + value: props.value, + onChange: props.onChange + }); +} + +function OutputEditor(props) { + return h(Editor, { + options: { + readOnly: true, + lineNumbers: true, + mode: props.mode + }, + value: props.value + }); +} + +function Button(props) { + return h("button", Object.assign({ type: "button", class: "btn" }, props)); +} + +function BottomBar(props) { + return h( + "div", + { class: "bottom-bar" }, + h( + "div", + { class: "bottom-bar-buttons" }, + h( + Button, + { onClick: props.onShowOptionsClick }, + props.optionsOpen ? "Hide options" : "Show options" + ), + h(Button, { onClick: props.onClearClick }, "Clear") + ), + h( + "div", + { class: "bottom-bar-buttons bottom-bar-buttons-right" }, + h(Button, null, "Copy Link"), + h(Button, null, "Copy markdown"), + h( + "a", + { + href: + "https://github.com/prettier/prettier/issues/new?body=" + + encodeURIComponent(props.reportBody), + target: "_blank", + rel: "noopener", + class: "btn" + }, + "Report issue" + ) + ) + ); +} + +var App = createClass({ + state: Object.assign({ loaded: false, formatted: "" }, loadPersistedState()), + + _format: function() { + this._worker.postMessage( + { type: "format", code: this.state.content, options: this.state.options }, + function(message) { + this.setState({ formatted: message.formatted }); + }.bind(this) + ); + persistState(this.state); + }, + + handleOptionChange: function(option, value) { + this.setState(function(state) { + return { + options: Object.assign({}, state.options, { [option.name]: value }) + }; + }, this._format.bind(this)); + }, + handleOptionsOpen: function() { + this.setState( + function(state) { + return { + editorState: Object.assign({}, state.editorState, { + optionsOpen: !state.editorState.optionsOpen + }) + }; + }, + function() { + persistState(this.state); + } + ); + }, + handleContentChange: function(value) { + this.setState({ content: value }, this._format.bind(this)); + }, + + componentDidMount: function() { + this._worker = new WorkerApi("/worker2.js"); + + this._worker.postMessage( + { type: "meta" }, + function(message) { + var availableOptions = getOptions(message.supportInfo.options); + var options = + this.state.options || + availableOptions.reduce(function(options, opt) { + options[opt.name] = opt.default; + return options; + }, {}); + + this.setState({ + loaded: true, + version: message.version, + availableOptions: availableOptions, + options: options + }); + }.bind(this) + ); + + this._format(); + }, + + render: function(props, state) { + if (!state.loaded) { + return "Loading..."; + } + var editorState = state.editorState; + return h( + "div", + { className: "playground-container" }, + h( + "div", + { className: "editors-container" }, + h(Options, { + availableOptions: state.availableOptions, + options: state.options, + open: editorState.optionsOpen, + onOptionChange: this.handleOptionChange.bind(this) + }), + h( + "div", + { className: "editors" }, + h(InputEditor, { + mode: getCodemirrorMode(state.options), + value: state.content, + onChange: this.handleContentChange.bind(this) + }), + h(OutputEditor, { + mode: getCodemirrorMode(state.options), + value: state.formatted + }) + ) + ), + h(BottomBar, { + optionsOpen: editorState.optionsOpen, + onShowOptionsClick: this.handleOptionsOpen.bind(this), + onClearClick: function() { + this.handleContentChange(""); + }.bind(this), + reportBody: formatMarkdown( + state.content, + state.formatted, + "", + state.version, + window.location.href, + state.options, + state.availableOptions.reduce(function(cliOptions, option) { + var value = state.options[option.name]; + if (option.type === "boolean") { + if ((value && !option.inverted) || (!value && option.inverted)) { + cliOptions.push([option.cliName, true]); + } + } else if (value !== option.default) { + cliOptions.push([option.cliName, value]); + } + return cliOptions; + }, []) + ) + }) + ); + } +}); + window.onload = function() { - var state = (function loadState(hash) { - var parsed; - try { - // providing backwards support for old json encoded URIComponent - if (hash.indexOf("%7B%22") !== -1) { - parsed = JSON.parse(decodeURIComponent(hash)); - } else { - parsed = JSON.parse(LZString.decompressFromEncodedURIComponent(hash)); - } - } catch (error) { - return DEFAULT_OPTIONS; - } - // Support old links with the deprecated "postcss" value for the parser option. - if (parsed && parsed.options && parsed.options.parser === "postcss") { - parsed.options.parser = "css"; - } - - return parsed || DEFAULT_OPTIONS; - })(location.hash.slice(1)); - - worker.onmessage = function(message) { - if (prettierVersion === "?") { - prettierVersion = message.data.version; - - var link = document.createElement("a"); - var match = prettierVersion.match(/^\d+\.\d+\.\d+-pr.(\d+)$/); - if (match) { - link.href = "https://github.com/prettier/prettier/pull/" + match[1]; - link.textContent = "PR #" + match[1]; - prettierVersion = "pr-" + match[1]; - } else { - if (prettierVersion.match(/\.0$/)) { - link.href = - "https://github.com/prettier/prettier/releases/tag/" + - prettierVersion; - } else { - link.href = - "https://github.com/prettier/prettier/blob/master/CHANGELOG.md#" + - prettierVersion.replace(/\./g, ""); - } - link.textContent = "v" + prettierVersion; - } - document.getElementById("version").appendChild(link); - } - if (outputEditor && docEditor && astEditor) { - outputEditor.setValue(message.data.formatted); - docEditor.setValue(message.data.doc || ""); - astEditor.setValue(message.data.ast || ""); - output2Editor.setValue( - message.data.formatted === "" - ? "" - : message.data.formatted2 === message.data.formatted - ? IDEMPOTENT_MESSAGE - : message.data.formatted2 || "" - ); - document.getElementById("button-report-issue").search = - "body=" + encodeURIComponent(createMarkdown(true)); - } - }; - - // Warm up the worker (load the current parser while CodeMirror loads) - worker.postMessage({ text: "", options: state.options }); - - state.options && setOptions(state.options); - - var editorOptions = { - lineNumbers: true, - keyMap: "sublime", - autoCloseBrackets: true, - matchBrackets: true, - showCursorWhenSelecting: true, - tabWidth: 2, - mode: "jsx" - }; - inputEditor = CodeMirror.fromTextArea( - document.getElementById("input-editor"), - editorOptions - ); - docEditor = CodeMirror.fromTextArea(document.getElementById("doc-editor"), { - readOnly: true, - lineNumbers: false, - mode: "jsx" - }); - astEditor = CodeMirror.fromTextArea(document.getElementById("ast-editor"), { - readOnly: true, - lineNumbers: false, - mode: "jsx" - }); - outputEditor = CodeMirror.fromTextArea( - document.getElementById("output-editor"), - { - readOnly: true, - lineNumbers: true, - mode: "jsx" - } - ); - output2Editor = CodeMirror.fromTextArea( - document.getElementById("output2-editor"), - { - readOnly: true, - lineNumbers: true, - mode: "jsx" - } - ); - - var editors = document.querySelectorAll(".editor"); - for (var i = 0; i < editors.length; i++) { - editors[i].classList.remove("loading"); - } - - setEditorStyles(); - - inputEditor.setValue(state.content); - inputEditor.on("change", formatAsync); - formatAsync(); - - document.querySelector(".options-container").onchange = formatAsync; - - document.getElementById("button-clear").onclick = function() { - inputEditor.setValue(""); - }; - - var optionsElement = document.getElementById("options-details"); - document.getElementById("button-options").onclick = function() { - var classes = optionsElement.classList; - if (classes.contains("open")) { - classes.remove("open"); - this.innerHTML = "Show options"; - } else { - classes.add("open"); - this.innerHTML = "Hide options"; - } - }; - - var clipboard = new Clipboard("#button-copy-link, #button-copy-markdown", { - text: function(trigger) { - switch (trigger.id) { - case "button-copy-link": - return window.location.href; - case "button-copy-markdown": - return createMarkdown(); - default: - return ""; - } - } - }); - clipboard.on("success", function(e) { - showTooltip(e.trigger, "Copied!"); - }); - clipboard.on("error", function(e) { - showTooltip(e.trigger, "Press ctrl+c to copy"); - }); + preact.render(h(App), document.getElementById("root")); }; -function setOptions(options) { - OPTIONS.forEach(function(option) { - var elem = document.getElementById(option); - if (elem.tagName === "SELECT") { - elem.value = options[option]; - } else if (elem.type === "number") { - elem.value = options[option]; - } else { - var isInverted = elem.hasAttribute("data-inverted"); - elem.checked = isInverted ? !options[option] : options[option]; +// -------- Worker API ------------- + +function WorkerApi(source) { + var worker = new Worker(source); + var counter = 0; + var handlers = {}; + + worker.onmessage = function(event) { + var uid = event.data.uid; + var message = event.data.message; + if (handlers[uid]) { + var handler = handlers[uid]; + delete handlers[uid]; + + handler(message); } - }); + }; + + function postMessage(message, handler) { + var uid = ++counter; + handlers[uid] = handler; + worker.postMessage({ + uid: uid, + message: message + }); + } + + return { postMessage: postMessage }; } -function getOptions() { - var options = {}; - OPTIONS.forEach(function(option) { - var elem = document.getElementById(option); - if (elem.tagName === "SELECT") { - options[option] = elem.value; - } else if (elem.type === "number") { - if (elem.value !== "") { - options[option] = Number(elem.value); - } - } else { - var isInverted = elem.hasAttribute("data-inverted"); - options[option] = isInverted ? !elem.checked : elem.checked; - } - }); - return options; +// -------- UTILITY FUNCTIONS -------- + +function loadPersistedState() { + var editorState = { optionsOpen: false }; + try { + Object.assign( + editorState, + JSON.parse(window.localStorage.getItem("editorState")) + ); + } catch (error) { + // noop + } + var queryState = parseQuery() || {}; + return { + editorState: editorState, + content: typeof queryState.content === "string" ? queryState.content : "", + options: queryState.options + }; } -function getCLIOptions() { - return OPTIONS.sort() - .map(function(option) { - var elem = document.getElementById(option); - var match = elem.parentNode.textContent.match(/--\S+/); - if (!match) { - return null; - } - var name = match[0]; - if (elem.tagName === "SELECT") { - if (elem.value === elem.options[0].value) { - return null; - } - return [name, elem.value]; - } else if (elem.type === "number") { - if (elem.value === elem.getAttribute("value")) { - return null; - } - return [name, elem.value]; - } else if (elem.type === "checkbox") { - if (!elem.checked) { - return null; - } - return [name, true]; - } - return null; - }) - .filter(Boolean); +function persistState(state) { + try { + window.localStorage.setItem( + "editorState", + JSON.stringify(state.editorState) + ); + } catch (_) { + // noop + } + saveQuery({ content: state.content, options: state.options }); } -function replaceHash(hash) { - if ( - typeof URL === "function" && - typeof history === "object" && - typeof history.replaceState === "function" - ) { - var url = new URL(location); - url.hash = hash; - history.replaceState(null, null, url); - } else { - location.hash = hash; +function getComponentByOptionType(option) { + switch (option.type) { + case "boolean": + return BooleanOption; + case "int": + return NumberOption; + case "choice": + return ChoiceOption; + default: + throw new Error("unsupported type"); } } @@ -368,104 +436,62 @@ function getCodemirrorMode(options) { } } -var inputEditorOverlay; +function getOptions(supportedOptions) { + supportedOptions = supportedOptions.reduce(function(acc, opt) { + acc[opt.name] = opt; + return acc; + }, {}); -function formatAsync() { - var options = getOptions(); - setEditorStyles(); + return OPTIONS.reduce(function(options, opt) { + opt = typeof opt === "string" ? { name: opt } : opt; + if (!supportedOptions[opt.name]) { + return options; + } - var value = LZString.compressToEncodedURIComponent( - JSON.stringify( - Object.assign({ content: inputEditor.getValue(), options: options }) - ) - ); - replaceHash(value); + var modified = Object.assign({}, opt, supportedOptions[opt.name]); + modified.cliName = + "--" + + (opt.inverted ? "no-" : "") + + opt.name.replace(/([a-z])([A-Z])/g, "$1-$2").toLowerCase(); + if (modified.type === "boolean" && opt.inverted) { + modified.default = !modified.default; + } - if ( - typeof options.rangeStart === "number" && - typeof options.rangeEnd === "number" - ) { - var rangeStartLocation = indexToEditorLocation( - inputEditor.getValue(), - options.rangeStart - ); - var rangeEndLocation = indexToEditorLocation( - inputEditor.getValue(), - options.rangeEnd - ); - inputEditor.removeOverlay(inputEditorOverlay); - inputEditorOverlay = createRangeOverlay( - rangeStartLocation, - rangeEndLocation - ); - inputEditor.addOverlay(inputEditorOverlay); + options.push(modified); + return options; + }, []); +} + +// Parse the URL hash as a config object +function parseQuery() { + var hash = document.location.hash.slice(1); + try { + // providing backwards support for old json encoded URIComponent + if (hash.indexOf("%7B%22") !== -1) { + return JSON.parse(decodeURIComponent(hash)); + } + return JSON.parse(LZString.decompressFromEncodedURIComponent(hash)); + } catch (error) { + return {}; } - - worker.postMessage({ - text: inputEditor.getValue() || getExample(options.parser), - options: options, - ast: options.ast, - doc: options.doc, - formatted2: options.output2 - }); } -function setEditorStyles() { - var options = getOptions(); - - inputEditor.setOption("placeholder", getExample(options.parser)); - - var mode = getCodemirrorMode(options); - inputEditor.setOption("mode", mode); - outputEditor.setOption("mode", mode); - output2Editor.setOption("mode", mode); - - inputEditor.setOption("rulers", [ - { column: options.printWidth, color: "#eeeeee" } - ]); - - [outputEditor, output2Editor].forEach(function(editor) { - editor.setOption("rulers", [ - { column: options.printWidth, color: "#444444" } - ]); - }); - document.querySelector(".ast").style.display = options.ast ? "" : "none"; - document.querySelector(".doc").style.display = options.doc ? "" : "none"; - document.querySelector(".output2").style.display = options.output2 - ? "" - : "none"; +function saveQuery(state) { + var hash = LZString.compressToEncodedURIComponent(JSON.stringify(state)); + if ( + typeof URL === "function" && + typeof history === "object" && + typeof history.replaceState === "function" + ) { + var url = new URL(location); + url.hash = hash; + history.replaceState(null, null, url); + } else { + location.hash = hash; + } } -function createMarkdown(full) { - var output = outputEditor.getValue(); - var output2 = output2Editor.getValue(); - var options = getOptions(); - var input = inputEditor.getValue() || getExample(options.parser); - var cliOptions = getCLIOptions(); - var markdown = formatMarkdown( - input, - output, - output2 === IDEMPOTENT_MESSAGE ? "" : output2, - prettierVersion, - window.location.href, - options, - cliOptions, - full - ); - return markdown; -} - -function showTooltip(elem, text) { - var tooltip = document.createElement("span"); - tooltip.className = "tooltip"; - tooltip.textContent = text; - elem.appendChild(tooltip); - window.setTimeout(function() { - elem.removeChild(tooltip); - }, 2000); -} - -function getExample(parser) { +function getCodeExample(parser) { switch (parser) { case "babylon": return [ @@ -653,3 +679,15 @@ function getExample(parser) { return ""; } } + +// Preact without ES6 classes +function createClass(obj) { + function F() { + preact.Component.call(this); + } + var p = (F.prototype = new preact.Component()); + for (var i in obj) { + p[i] = obj[i]; + } + return (p.constructor = F); +} diff --git a/website/playground/old.js b/website/playground/old.js new file mode 100644 index 00000000..3906e6f3 --- /dev/null +++ b/website/playground/old.js @@ -0,0 +1,655 @@ +/* eslint-env browser */ +/* eslint no-var: off, strict: off, prefer-arrow-callback: off */ +/* global Clipboard CodeMirror formatMarkdown LZString */ + +var prettierVersion = "?"; +var inputEditor; +var docEditor; +var astEditor; +var outputEditor; +var output2Editor; + +var OPTIONS = [ + "printWidth", + "tabWidth", + "singleQuote", + "trailingComma", + "bracketSpacing", + "jsxBracketSameLine", + "parser", + "semi", + "useTabs", + "insertPragma", + "requirePragma", + "proseWrap", + "arrowParens", + "rangeStart", + "rangeEnd", + "doc", + "ast", + "output2" +]; + +var IDEMPOTENT_MESSAGE = "✓ Second format is unchanged."; + +var worker = new Worker("/worker.js"); + +const DEFAULT_OPTIONS = { + options: undefined, + content: "" +}; + +function createRangeOverlay(rangeStartLocation, rangeEndLocation) { + var rangeStartLine = rangeStartLocation.line; + var rangeEndLine = rangeEndLocation.line; + var rangeStartPos = rangeStartLocation.pos; + var rangeEndPos = rangeEndLocation.pos; + var isEndOnSameLineAsStart = rangeStartLine === rangeEndLine; + var highlightedToken = "searching"; + + return { + token: function(stream) { + var currentLine = stream.lineOracle.line; + + // we are on the line containing rangeStart + if (currentLine === rangeStartLine) { + // on the same line as, but not reached rangeStart yet, + // jump straight to it + if (rangeStartPos > stream.pos) { + stream.pos = rangeStartPos; + return; + } + // the rangeEnd is on the same line as the rangeStart + if (isEndOnSameLineAsStart) { + // we are still within the range, + // keep iterating along the string stream, + // marking it as highlighted + if (stream.pos < rangeEndPos) { + stream.pos += 1; + return highlightedToken; + } + // we've moved outside of the range + // just skip to the end + return stream.skipToEnd(); + } + // keep iterating along the string stream, + // marking it as highlighted + stream.pos += 1; + return highlightedToken; + } + + // we are on the line containing rangeEnd + if (currentLine === rangeEndLine) { + // keep iterating along the string stream, + // marking it as highlighted + if (rangeEndPos > stream.pos) { + stream.pos += 1; + return highlightedToken; + } + // we've moved outside of the range + // just skip to the end + return stream.skipToEnd(); + } + + // we are on a line which is completely included + // within the range, mark it all as highlighted + if (currentLine > rangeStartLine && currentLine < rangeEndLine) { + stream.skipToEnd(); + return highlightedToken; + } + + // no action can be required on the current line + // as it must fall outside of the range, + // so just skip to the end + return stream.skipToEnd(); + } + }; +} + +function indexToEditorLocation(editorContent, index) { + var line = 0; + var count = 0; + var startIndex = 0; + for (var c, i = 0; count < index && i < editorContent.length; i++) { + count++; + c = editorContent[i]; + if (c === "\n") { + line++; + startIndex = count; + } + } + return { + line: line, + pos: count - startIndex + }; +} + +window.onload = function() { + var state = (function loadState(hash) { + var parsed; + try { + // providing backwards support for old json encoded URIComponent + if (hash.indexOf("%7B%22") !== -1) { + parsed = JSON.parse(decodeURIComponent(hash)); + } else { + parsed = JSON.parse(LZString.decompressFromEncodedURIComponent(hash)); + } + } catch (error) { + return DEFAULT_OPTIONS; + } + // Support old links with the deprecated "postcss" value for the parser option. + if (parsed && parsed.options && parsed.options.parser === "postcss") { + parsed.options.parser = "css"; + } + + return parsed || DEFAULT_OPTIONS; + })(location.hash.slice(1)); + + worker.onmessage = function(message) { + if (prettierVersion === "?") { + prettierVersion = message.data.version; + + var link = document.createElement("a"); + var match = prettierVersion.match(/^\d+\.\d+\.\d+-pr.(\d+)$/); + if (match) { + link.href = "https://github.com/prettier/prettier/pull/" + match[1]; + link.textContent = "PR #" + match[1]; + prettierVersion = "pr-" + match[1]; + } else { + if (prettierVersion.match(/\.0$/)) { + link.href = + "https://github.com/prettier/prettier/releases/tag/" + + prettierVersion; + } else { + link.href = + "https://github.com/prettier/prettier/blob/master/CHANGELOG.md#" + + prettierVersion.replace(/\./g, ""); + } + link.textContent = "v" + prettierVersion; + } + document.getElementById("version").appendChild(link); + } + if (outputEditor && docEditor && astEditor) { + outputEditor.setValue(message.data.formatted); + docEditor.setValue(message.data.doc || ""); + astEditor.setValue(message.data.ast || ""); + output2Editor.setValue( + message.data.formatted === "" + ? "" + : message.data.formatted2 === message.data.formatted + ? IDEMPOTENT_MESSAGE + : message.data.formatted2 || "" + ); + document.getElementById("button-report-issue").search = + "body=" + encodeURIComponent(createMarkdown(true)); + } + }; + + // Warm up the worker (load the current parser while CodeMirror loads) + worker.postMessage({ text: "", options: state.options }); + + state.options && setOptions(state.options); + + var editorOptions = { + lineNumbers: true, + keyMap: "sublime", + autoCloseBrackets: true, + matchBrackets: true, + showCursorWhenSelecting: true, + tabWidth: 2, + mode: "jsx" + }; + inputEditor = CodeMirror.fromTextArea( + document.getElementById("input-editor"), + editorOptions + ); + docEditor = CodeMirror.fromTextArea(document.getElementById("doc-editor"), { + readOnly: true, + lineNumbers: false, + mode: "jsx" + }); + astEditor = CodeMirror.fromTextArea(document.getElementById("ast-editor"), { + readOnly: true, + lineNumbers: false, + mode: "jsx" + }); + outputEditor = CodeMirror.fromTextArea( + document.getElementById("output-editor"), + { + readOnly: true, + lineNumbers: true, + mode: "jsx" + } + ); + output2Editor = CodeMirror.fromTextArea( + document.getElementById("output2-editor"), + { + readOnly: true, + lineNumbers: true, + mode: "jsx" + } + ); + + var editors = document.querySelectorAll(".editor"); + for (var i = 0; i < editors.length; i++) { + editors[i].classList.remove("loading"); + } + + setEditorStyles(); + + inputEditor.setValue(state.content); + inputEditor.on("change", formatAsync); + formatAsync(); + + document.querySelector(".options-container").onchange = formatAsync; + + document.getElementById("button-clear").onclick = function() { + inputEditor.setValue(""); + }; + + var optionsElement = document.getElementById("options-details"); + document.getElementById("button-options").onclick = function() { + var classes = optionsElement.classList; + if (classes.contains("open")) { + classes.remove("open"); + this.innerHTML = "Show options"; + } else { + classes.add("open"); + this.innerHTML = "Hide options"; + } + }; + + var clipboard = new Clipboard("#button-copy-link, #button-copy-markdown", { + text: function(trigger) { + switch (trigger.id) { + case "button-copy-link": + return window.location.href; + case "button-copy-markdown": + return createMarkdown(); + default: + return ""; + } + } + }); + clipboard.on("success", function(e) { + showTooltip(e.trigger, "Copied!"); + }); + clipboard.on("error", function(e) { + showTooltip(e.trigger, "Press ctrl+c to copy"); + }); +}; + +function setOptions(options) { + OPTIONS.forEach(function(option) { + var elem = document.getElementById(option); + if (elem.tagName === "SELECT") { + elem.value = options[option]; + } else if (elem.type === "number") { + elem.value = options[option]; + } else { + var isInverted = elem.hasAttribute("data-inverted"); + elem.checked = isInverted ? !options[option] : options[option]; + } + }); +} + +function getOptions() { + var options = {}; + OPTIONS.forEach(function(option) { + var elem = document.getElementById(option); + if (elem.tagName === "SELECT") { + options[option] = elem.value; + } else if (elem.type === "number") { + if (elem.value !== "") { + options[option] = Number(elem.value); + } + } else { + var isInverted = elem.hasAttribute("data-inverted"); + options[option] = isInverted ? !elem.checked : elem.checked; + } + }); + return options; +} + +function getCLIOptions() { + return OPTIONS.sort() + .map(function(option) { + var elem = document.getElementById(option); + var match = elem.parentNode.textContent.match(/--\S+/); + if (!match) { + return null; + } + var name = match[0]; + if (elem.tagName === "SELECT") { + if (elem.value === elem.options[0].value) { + return null; + } + return [name, elem.value]; + } else if (elem.type === "number") { + if (elem.value === elem.getAttribute("value")) { + return null; + } + return [name, elem.value]; + } else if (elem.type === "checkbox") { + if (!elem.checked) { + return null; + } + return [name, true]; + } + return null; + }) + .filter(Boolean); +} + +function replaceHash(hash) { + if ( + typeof URL === "function" && + typeof history === "object" && + typeof history.replaceState === "function" + ) { + var url = new URL(location); + url.hash = hash; + history.replaceState(null, null, url); + } else { + location.hash = hash; + } +} + +function getCodemirrorMode(options) { + switch (options.parser) { + case "css": + case "less": + case "scss": + return "css"; + case "markdown": + return "markdown"; + default: + return "jsx"; + } +} + +var inputEditorOverlay; + +function formatAsync() { + var options = getOptions(); + setEditorStyles(); + + var value = LZString.compressToEncodedURIComponent( + JSON.stringify( + Object.assign({ content: inputEditor.getValue(), options: options }) + ) + ); + replaceHash(value); + + if ( + typeof options.rangeStart === "number" && + typeof options.rangeEnd === "number" + ) { + var rangeStartLocation = indexToEditorLocation( + inputEditor.getValue(), + options.rangeStart + ); + var rangeEndLocation = indexToEditorLocation( + inputEditor.getValue(), + options.rangeEnd + ); + inputEditor.removeOverlay(inputEditorOverlay); + inputEditorOverlay = createRangeOverlay( + rangeStartLocation, + rangeEndLocation + ); + inputEditor.addOverlay(inputEditorOverlay); + } + + worker.postMessage({ + text: inputEditor.getValue() || getExample(options.parser), + options: options, + ast: options.ast, + doc: options.doc, + formatted2: options.output2 + }); +} + +function setEditorStyles() { + var options = getOptions(); + + inputEditor.setOption("placeholder", getExample(options.parser)); + + var mode = getCodemirrorMode(options); + inputEditor.setOption("mode", mode); + outputEditor.setOption("mode", mode); + output2Editor.setOption("mode", mode); + + inputEditor.setOption("rulers", [ + { column: options.printWidth, color: "#eeeeee" } + ]); + + [outputEditor, output2Editor].forEach(function(editor) { + editor.setOption("rulers", [ + { column: options.printWidth, color: "#444444" } + ]); + }); + document.querySelector(".ast").style.display = options.ast ? "" : "none"; + document.querySelector(".doc").style.display = options.doc ? "" : "none"; + document.querySelector(".output2").style.display = options.output2 + ? "" + : "none"; +} + +function createMarkdown(full) { + var output = outputEditor.getValue(); + var output2 = output2Editor.getValue(); + var options = getOptions(); + var input = inputEditor.getValue() || getExample(options.parser); + var cliOptions = getCLIOptions(); + var markdown = formatMarkdown( + input, + output, + output2 === IDEMPOTENT_MESSAGE ? "" : output2, + prettierVersion, + window.location.href, + options, + cliOptions, + full + ); + return markdown; +} + +function showTooltip(elem, text) { + var tooltip = document.createElement("span"); + tooltip.className = "tooltip"; + tooltip.textContent = text; + elem.appendChild(tooltip); + window.setTimeout(function() { + elem.removeChild(tooltip); + }, 2000); +} + +function getExample(parser) { + switch (parser) { + case "babylon": + return [ + 'function HelloWorld({greeting = "hello", greeted = \'"World"\', silent = false, onMouseOver,}) {', + "", + " if(!greeting){return null};", + "", + " // TODO: Don't use random in render", + ' let num = Math.floor (Math.random() * 1E+7).toString().replace(/\\.\\d+/ig, "")', + "", + " return
", + "", + " { greeting.slice( 0, 1 ).toUpperCase() + greeting.slice(1).toLowerCase() }", + ' {greeting.endsWith(",") ? " " : ", " }', + " ", + "\t{ greeted }", + "\t", + " { (silent)", + ' ? "."', + ' : "!"}', + "", + "
;", + "", + "}" + ].join("\n"); + case "flow": + return [ + "declare export function graphql>", + " (query: GQLDocument, config?: Config>):", + " (Component: Component) => React$ComponentType<$Diff, {", + " data: Object|void,", + " mutate: Function|void", + " }>>", + "", + 'declare type FetchPolicy = "cache-first" | "cache-and-network" | "network-only" | "cache-only"' + ].join("\n"); + case "typescript": + return [ + "interface MyInterface {", + " foo(): string,", + " bar: Array,", + "}", + "", + "export abstract class Foo implements MyInterface {", + " foo() {", + " // TODO: return an actual value here", + " return 'hello'", + " }", + " get bar() {", + " return [ 1,", + "", + " 2, 3,", + " ]", + " }", + "}", + "", + "type RequestType = 'GET' | 'HEAD' | 'POST' | 'PUT' | 'OPTIONS' | 'CONNECT' | 'DELETE' | 'TRACE'" + ].join("\n"); + case "css": + // Excerpted from the Bootstrap source, which is licensed under the MIT license: + // https://github.com/twbs/bootstrap/blob/v4.0.0-beta.3/LICENSE + return [ + "@media (max-width: 480px) {", + " .bd-examples {margin-right: -.75rem;margin-left: -.75rem", + " }", + " ", + ' .bd-examples>[class^="col-"] {', + " padding-right: .75rem;", + " padding-left: .75rem;", + " ", + " }", + "}" + ].join("\n"); + case "scss": + // Excerpted from the Bootstrap source, which is licensed under the MIT license: + // https://github.com/twbs/bootstrap/blob/v4.0.0-beta.3/LICENSE + return [ + "@function color-yiq($color) {", + " $r: red($color);$g: green($color);$b: blue($color);", + "", + " $yiq: (($r * 299) + ($g * 587) + ($b * 114)) / 1000;", + "", + " @if ($yiq >= $yiq-contrasted-threshold) {", + " @return $yiq-text-dark;", + "} @else {", + " @return $yiq-text-light;", + " }", + "}", + "", + "@each $color, $value in $colors {", + " .swatch-#{$color} {", + " color: color-yiq($value);", + " background-color: #{$value};", + " }", + "}" + ].join("\n"); + case "less": + // Copied from http://lesscss.org/features/#detached-rulesets-feature + return [ + "@my-ruleset: {", + " .my-selector {", + " @media tv {", + " background-color: black;", + " }", + " }", + " };", + "@media (orientation:portrait) {", + " @my-ruleset();", + "}" + ].join("\n"); + case "json": + // Excerpted & adapted from Wikipedia, under the Creative Commons Attribution-ShareAlike License + // https://en.wikipedia.org/wiki/JSON#Example + return [ + '{"allOn": "Single", "Line": "example",', + '"noSpace":true,', + ' "quote": {', + " 'singleQuote': 'example',", + ' "indented": true,', + " },", + ' "phoneNumbers": [', + ' {"type": "home",', + ' "number": "212 555-1234"},', + ' {"type": "office",', + ' "trailing": "commas by accident"},', + " ],", + "}" + ].join("\n"); + case "graphql": + return [ + "query Browse($offset: Int, $limit: Int, $categories: [String!], $search: String) {", + " browse(limit: $limit, offset: $offset, categories: $categories, search: $search) {", + " total,", + " results {", + " title", + " price", + " }", + " }", + "}" + ].join("\n"); + case "markdown": + return [ + "Header", + "======", + "", + "_Look,_ code blocks are formatted *too!*", + "", + "``` js", + "function identity(x) { return x }", + "```", + "", + "Pilot|Airport|Hours", + "--|:--:|--:", + "John Doe|SKG|1338", + "Jane Roe|JFK|314", + "", + "- - - - - - - - - - - - - - -", + "", + "+ List", + " + with a [link] (/to/somewhere)", + "+ and [another one]", + "", + "", + " [another one]: http://example.com 'Example title'", + "", + "Lorem ipsum dolor sit amet, consectetur adipiscing elit.", + "Curabitur consectetur maximus risus, sed maximus tellus tincidunt et." + ].join("\n"); + case "vue": + return [ + "", + "", + "", + "", + "" + ].join("\n"); + default: + return ""; + } +} diff --git a/website/static/playground2.js b/website/static/playground2.js deleted file mode 100644 index 72fb64dc..00000000 --- a/website/static/playground2.js +++ /dev/null @@ -1,693 +0,0 @@ -/* eslint-env browser */ -/* eslint no-var: off, strict: off, prefer-arrow-callback: off */ -/* global Clipboard CodeMirror formatMarkdown LZString preact */ - -var h = preact.h; - -var CATEGORIES = ["Global", "JavaScript", "Markdown", "Special"]; -var OPTIONS = [ - "parser", - "printWidth", - "tabWidth", - "useTabs", - { name: "semi", inverted: true }, - "singleQuote", - { name: "bracketSpacing", inverted: true }, - "jsxBracketSameLine", - "arrowParens", - "trailingComma", - "proseWrap", - "insertPragma", - "requirePragma" -]; - -// ---------- Options components ----------- - -function BooleanOption(props) { - function maybeInvert(value) { - return props.option.inverted ? !value : value; - } - return h( - "label", - null, - h("input", { - type: "checkbox", - checked: maybeInvert(props.value), - onChange: function(ev) { - props.onOptionChange(props.option, maybeInvert(ev.target.checked)); - } - }), - " ", - props.option.cliName - ); -} - -function ChoiceOption(props) { - return h( - "label", - null, - props.option.cliName, - " ", - h( - "select", - { - onChange: function(ev) { - props.onOptionChange(props.option, ev.target.value); - } - }, - props.option.choices.map(function(choice) { - return h( - "option", - { value: choice.value, selected: choice.value === props.value }, - choice.value - ); - }) - ) - ); -} - -function NumberOption(props) { - return h( - "label", - null, - props.option.cliName, - " ", - h("input", { - type: "number", - min: props.option.range.start, - max: props.option.range.end, - step: props.option.range.step, - value: props.value, - onChange: function(ev) { - props.onOptionChange(props.option, parseInt(ev.target.value, 10)); - } - }) - ); -} - -function Options(props) { - var optionsByCategory = props.availableOptions.reduce(function(acc, opt) { - acc[opt.category] = opts = acc[opt.category] || []; - opts.push(opt); - return acc; - }, {}); - - return h( - "div", - { className: "options-container" + (props.open ? " open" : "") }, - h( - "div", - { className: "options" }, - CATEGORIES.map(function(category) { - return h( - "details", - { className: "sub-options", open: "true" }, - h("summary", null, category), - (optionsByCategory[category] || []).map(function(opt) { - return h(getComponentByOptionType(opt), { - option: opt, - value: props.options[opt.name], - onOptionChange: props.onOptionChange - }); - }) - ); - }) - ) - ); -} - -// ---------- Editor components ----------- - -var Editor = createClass({ - componentDidMount: function() { - this._codeMirror = CodeMirror.fromTextArea(this._ref, this.props.options); - this._codeMirror.on("change", this.handleChange.bind(this)); - this._codeMirror.setValue(this.props.value || ""); - }, - handleChange: function(doc, change) { - if (change.origin !== "setValue") { - this.props.onChange(doc.getValue()); - } - }, - componentWillReceiveProps(nextProps) { - if ( - nextProps.value && - nextProps.value !== this.props.value && - this._codeMirror.getValue() !== nextProps.value - ) { - this._codeMirror.setValue(nextProps.value); - } else if (!nextProps.value) { - this._codeMirror.setValue(""); - } - }, - render: function(props) { - return h( - "div", - { className: "editor input" }, - h("textarea", { - ref: function(ref) { - this._ref = ref; - }.bind(this) - }) - ); - } -}); - -function InputEditor(props) { - return h(Editor, { - options: { - lineNumbers: true, - keyMap: "sublime", - autoCloseBrackets: true, - matchBrackets: true, - showCursorWhenSelecting: true, - tabWidth: 2, - mode: props.mode - }, - value: props.value, - onChange: props.onChange - }); -} - -function OutputEditor(props) { - return h(Editor, { - options: { - readOnly: true, - lineNumbers: true, - mode: props.mode - }, - value: props.value - }); -} - -function Button(props) { - return h("button", Object.assign({ type: "button", class: "btn" }, props)); -} - -function BottomBar(props) { - return h( - "div", - { class: "bottom-bar" }, - h( - "div", - { class: "bottom-bar-buttons" }, - h( - Button, - { onClick: props.onShowOptionsClick }, - props.optionsOpen ? "Hide options" : "Show options" - ), - h(Button, { onClick: props.onClearClick }, "Clear") - ), - h( - "div", - { class: "bottom-bar-buttons bottom-bar-buttons-right" }, - h(Button, null, "Copy Link"), - h(Button, null, "Copy markdown"), - h( - "a", - { - href: - "https://github.com/prettier/prettier/issues/new?body=" + - encodeURIComponent(props.reportBody), - target: "_blank", - rel: "noopener", - class: "btn" - }, - "Report issue" - ) - ) - ); -} - -var App = createClass({ - state: Object.assign({ loaded: false, formatted: "" }, loadPersistedState()), - - _format: function() { - this._worker.postMessage( - { type: "format", code: this.state.content, options: this.state.options }, - function(message) { - this.setState({ formatted: message.formatted }); - }.bind(this) - ); - persistState(this.state); - }, - - handleOptionChange: function(option, value) { - this.setState(function(state) { - return { - options: Object.assign({}, state.options, { [option.name]: value }) - }; - }, this._format.bind(this)); - }, - handleOptionsOpen: function() { - this.setState( - function(state) { - return { - editorState: Object.assign({}, state.editorState, { - optionsOpen: !state.editorState.optionsOpen - }) - }; - }, - function() { - persistState(this.state); - } - ); - }, - handleContentChange: function(value) { - this.setState({ content: value }, this._format.bind(this)); - }, - - componentDidMount: function() { - this._worker = new WorkerApi("/worker2.js"); - - this._worker.postMessage( - { type: "meta" }, - function(message) { - var availableOptions = getOptions(message.supportInfo.options); - var options = - this.state.options || - availableOptions.reduce(function(options, opt) { - options[opt.name] = opt.default; - return options; - }, {}); - - this.setState({ - loaded: true, - version: message.version, - availableOptions: availableOptions, - options: options - }); - }.bind(this) - ); - - this._format(); - }, - - render: function(props, state) { - if (!state.loaded) { - return "Loading..."; - } - var editorState = state.editorState; - return h( - "div", - { className: "playground-container" }, - h( - "div", - { className: "editors-container" }, - h(Options, { - availableOptions: state.availableOptions, - options: state.options, - open: editorState.optionsOpen, - onOptionChange: this.handleOptionChange.bind(this) - }), - h( - "div", - { className: "editors" }, - h(InputEditor, { - mode: getCodemirrorMode(state.options), - value: state.content, - onChange: this.handleContentChange.bind(this) - }), - h(OutputEditor, { - mode: getCodemirrorMode(state.options), - value: state.formatted - }) - ) - ), - h(BottomBar, { - optionsOpen: editorState.optionsOpen, - onShowOptionsClick: this.handleOptionsOpen.bind(this), - onClearClick: function() { - this.handleContentChange(""); - }.bind(this), - reportBody: formatMarkdown( - state.content, - state.formatted, - "", - state.version, - window.location.href, - state.options, - state.availableOptions.reduce(function(cliOptions, option) { - var value = state.options[option.name]; - if (option.type === "boolean") { - if ((value && !option.inverted) || (!value && option.inverted)) { - cliOptions.push([option.cliName, true]); - } - } else if (value !== option.default) { - cliOptions.push([option.cliName, value]); - } - return cliOptions; - }, []) - ) - }) - ); - } -}); - -window.onload = function() { - preact.render(h(App), document.getElementById("root")); -}; - -// -------- Worker API ------------- - -function WorkerApi(source) { - var worker = new Worker(source); - var counter = 0; - var handlers = {}; - - worker.onmessage = function(event) { - var uid = event.data.uid; - var message = event.data.message; - if (handlers[uid]) { - var handler = handlers[uid]; - delete handlers[uid]; - - handler(message); - } - }; - - function postMessage(message, handler) { - var uid = ++counter; - handlers[uid] = handler; - worker.postMessage({ - uid: uid, - message: message - }); - } - - return { postMessage: postMessage }; -} - -// -------- UTILITY FUNCTIONS -------- - -function loadPersistedState() { - var editorState = { optionsOpen: false }; - try { - Object.assign( - editorState, - JSON.parse(window.localStorage.getItem("editorState")) - ); - } catch (error) { - // noop - } - var queryState = parseQuery() || {}; - return { - editorState: editorState, - content: typeof queryState.content === "string" ? queryState.content : "", - options: queryState.options - }; -} - -function persistState(state) { - try { - window.localStorage.setItem( - "editorState", - JSON.stringify(state.editorState) - ); - } catch (_) { - // noop - } - saveQuery({ content: state.content, options: state.options }); -} - -function getComponentByOptionType(option) { - switch (option.type) { - case "boolean": - return BooleanOption; - case "int": - return NumberOption; - case "choice": - return ChoiceOption; - default: - throw new Error("unsupported type"); - } -} - -function getCodemirrorMode(options) { - switch (options.parser) { - case "css": - case "less": - case "scss": - return "css"; - case "markdown": - return "markdown"; - default: - return "jsx"; - } -} - -function getOptions(supportedOptions) { - supportedOptions = supportedOptions.reduce(function(acc, opt) { - acc[opt.name] = opt; - return acc; - }, {}); - - return OPTIONS.reduce(function(options, opt) { - opt = typeof opt === "string" ? { name: opt } : opt; - if (!supportedOptions[opt.name]) { - return options; - } - - var modified = Object.assign({}, opt, supportedOptions[opt.name]); - modified.cliName = - "--" + - (opt.inverted ? "no-" : "") + - opt.name.replace(/([a-z])([A-Z])/g, "$1-$2").toLowerCase(); - if (modified.type === "boolean" && opt.inverted) { - modified.default = !modified.default; - } - - options.push(modified); - return options; - }, []); -} - -// Parse the URL hash as a config object -function parseQuery() { - var hash = document.location.hash.slice(1); - try { - // providing backwards support for old json encoded URIComponent - if (hash.indexOf("%7B%22") !== -1) { - return JSON.parse(decodeURIComponent(hash)); - } - return JSON.parse(LZString.decompressFromEncodedURIComponent(hash)); - } catch (error) { - return {}; - } -} - -function saveQuery(state) { - var hash = LZString.compressToEncodedURIComponent(JSON.stringify(state)); - if ( - typeof URL === "function" && - typeof history === "object" && - typeof history.replaceState === "function" - ) { - var url = new URL(location); - url.hash = hash; - history.replaceState(null, null, url); - } else { - location.hash = hash; - } -} - -function getCodeExample(parser) { - switch (parser) { - case "babylon": - return [ - 'function HelloWorld({greeting = "hello", greeted = \'"World"\', silent = false, onMouseOver,}) {', - "", - " if(!greeting){return null};", - "", - " // TODO: Don't use random in render", - ' let num = Math.floor (Math.random() * 1E+7).toString().replace(/\\.\\d+/ig, "")', - "", - " return
", - "", - " { greeting.slice( 0, 1 ).toUpperCase() + greeting.slice(1).toLowerCase() }", - ' {greeting.endsWith(",") ? " " : ", " }', - " ", - "\t{ greeted }", - "\t", - " { (silent)", - ' ? "."', - ' : "!"}', - "", - "
;", - "", - "}" - ].join("\n"); - case "flow": - return [ - "declare export function graphql>", - " (query: GQLDocument, config?: Config>):", - " (Component: Component) => React$ComponentType<$Diff, {", - " data: Object|void,", - " mutate: Function|void", - " }>>", - "", - 'declare type FetchPolicy = "cache-first" | "cache-and-network" | "network-only" | "cache-only"' - ].join("\n"); - case "typescript": - return [ - "interface MyInterface {", - " foo(): string,", - " bar: Array,", - "}", - "", - "export abstract class Foo implements MyInterface {", - " foo() {", - " // TODO: return an actual value here", - " return 'hello'", - " }", - " get bar() {", - " return [ 1,", - "", - " 2, 3,", - " ]", - " }", - "}", - "", - "type RequestType = 'GET' | 'HEAD' | 'POST' | 'PUT' | 'OPTIONS' | 'CONNECT' | 'DELETE' | 'TRACE'" - ].join("\n"); - case "css": - // Excerpted from the Bootstrap source, which is licensed under the MIT license: - // https://github.com/twbs/bootstrap/blob/v4.0.0-beta.3/LICENSE - return [ - "@media (max-width: 480px) {", - " .bd-examples {margin-right: -.75rem;margin-left: -.75rem", - " }", - " ", - ' .bd-examples>[class^="col-"] {', - " padding-right: .75rem;", - " padding-left: .75rem;", - " ", - " }", - "}" - ].join("\n"); - case "scss": - // Excerpted from the Bootstrap source, which is licensed under the MIT license: - // https://github.com/twbs/bootstrap/blob/v4.0.0-beta.3/LICENSE - return [ - "@function color-yiq($color) {", - " $r: red($color);$g: green($color);$b: blue($color);", - "", - " $yiq: (($r * 299) + ($g * 587) + ($b * 114)) / 1000;", - "", - " @if ($yiq >= $yiq-contrasted-threshold) {", - " @return $yiq-text-dark;", - "} @else {", - " @return $yiq-text-light;", - " }", - "}", - "", - "@each $color, $value in $colors {", - " .swatch-#{$color} {", - " color: color-yiq($value);", - " background-color: #{$value};", - " }", - "}" - ].join("\n"); - case "less": - // Copied from http://lesscss.org/features/#detached-rulesets-feature - return [ - "@my-ruleset: {", - " .my-selector {", - " @media tv {", - " background-color: black;", - " }", - " }", - " };", - "@media (orientation:portrait) {", - " @my-ruleset();", - "}" - ].join("\n"); - case "json": - // Excerpted & adapted from Wikipedia, under the Creative Commons Attribution-ShareAlike License - // https://en.wikipedia.org/wiki/JSON#Example - return [ - '{"allOn": "Single", "Line": "example",', - '"noSpace":true,', - ' "quote": {', - " 'singleQuote': 'example',", - ' "indented": true,', - " },", - ' "phoneNumbers": [', - ' {"type": "home",', - ' "number": "212 555-1234"},', - ' {"type": "office",', - ' "trailing": "commas by accident"},', - " ],", - "}" - ].join("\n"); - case "graphql": - return [ - "query Browse($offset: Int, $limit: Int, $categories: [String!], $search: String) {", - " browse(limit: $limit, offset: $offset, categories: $categories, search: $search) {", - " total,", - " results {", - " title", - " price", - " }", - " }", - "}" - ].join("\n"); - case "markdown": - return [ - "Header", - "======", - "", - "_Look,_ code blocks are formatted *too!*", - "", - "``` js", - "function identity(x) { return x }", - "```", - "", - "Pilot|Airport|Hours", - "--|:--:|--:", - "John Doe|SKG|1338", - "Jane Roe|JFK|314", - "", - "- - - - - - - - - - - - - - -", - "", - "+ List", - " + with a [link] (/to/somewhere)", - "+ and [another one]", - "", - "", - " [another one]: http://example.com 'Example title'", - "", - "Lorem ipsum dolor sit amet, consectetur adipiscing elit.", - "Curabitur consectetur maximus risus, sed maximus tellus tincidunt et." - ].join("\n"); - case "vue": - return [ - "", - "", - "", - "", - "" - ].join("\n"); - default: - return ""; - } -} - -// Preact without ES6 classes -function createClass(obj) { - function F() { - preact.Component.call(this); - } - var p = (F.prototype = new preact.Component()); - for (var i in obj) { - p[i] = obj[i]; - } - return (p.constructor = F); -}