From acf9c82388733e42118e25f7a0739f45f02c95eb Mon Sep 17 00:00:00 2001 From: Tony Brix Date: Wed, 13 Feb 2019 12:16:39 -0600 Subject: [PATCH 01/13] use worker to prevent dos --- docs/demo/demo.css | 2 +- docs/demo/demo.js | 188 +++++++++++++++++++++++++++++++------------- docs/demo/worker.js | 75 ++++++++++++++++++ 3 files changed, 211 insertions(+), 54 deletions(-) create mode 100644 docs/demo/worker.js diff --git a/docs/demo/demo.css b/docs/demo/demo.css index 92d2f4a504..8502d49190 100644 --- a/docs/demo/demo.css +++ b/docs/demo/demo.css @@ -62,7 +62,7 @@ header h1 { flex-grow: 1; } -#options.badParse { +.error { border-color: red; background-color: #FEE } diff --git a/docs/demo/demo.js b/docs/demo/demo.js index 3762cb3819..1e57b420b4 100644 --- a/docs/demo/demo.js +++ b/docs/demo/demo.js @@ -7,12 +7,17 @@ if (!window.fetch) { window.fetch = unfetch; } +onunhandledrejection = function (e) { + throw e.reason; +}; + var $markdownElem = document.querySelector('#markdown'); var $markedVerElem = document.querySelector('#markedVersion'); var $markedVer = document.querySelector('#markedCdn'); var $optionsElem = document.querySelector('#options'); var $outputTypeElem = document.querySelector('#outputType'); var $inputTypeElem = document.querySelector('#inputType'); +var $previewElem = document.querySelector('#preview'); var $previewIframe = document.querySelector('#preview iframe'); var $permalinkElem = document.querySelector('#permalink'); var $clearElem = document.querySelector('#clear'); @@ -20,6 +25,7 @@ var $htmlElem = document.querySelector('#html'); var $lexerElem = document.querySelector('#lexer'); var $panes = document.querySelectorAll('.pane'); var $inputPanes = document.querySelectorAll('.inputPane'); +var lastInput = ''; var inputDirty = true; var $activeOutputElem = null; var search = searchToObject(); @@ -74,14 +80,7 @@ fetch('https://data.jsdelivr.com/v1/package/npm/marked') if ('options' in search && search.options) { $optionsElem.value = search.options; } else { - $optionsElem.value = JSON.stringify( - marked.getDefaults(), - function (key, value) { - if (value && typeof value === 'object' && Object.getPrototypeOf(value) !== Object.prototype) { - return undefined; - } - return value; - }, ' '); + setDefaultOptions(); } }); }); @@ -141,18 +140,32 @@ $optionsElem.addEventListener('keydown', handleInput, false); $clearElem.addEventListener('click', function () { $markdownElem.value = ''; $markedVerElem.value = 'master'; - updateVersion().then(function () { - $optionsElem.value = JSON.stringify( - marked.getDefaults(), - function (key, value) { - if (value && typeof value === 'object' && Object.getPrototypeOf(value) !== Object.prototype) { - return undefined; - } - return value; - }, ' '); - }); + updateVersion().then(setDefaultOptions); }, false); +function setDefaultOptions() { + if (window.Worker) { + messageWorker({ + task: 'defaults', + version: markedVersions[$markedVerElem.value]} + ); + } else { + var defaults = marked.getDefaults(); + setOptions(defaults); + } +} + +function setOptions(opts) { + $optionsElem.value = JSON.stringify( + opts, + function (key, value) { + if (value && typeof value === 'object' && Object.getPrototypeOf(value) !== Object.prototype) { + return undefined; + } + return value; + }, ' '); +} + function searchToObject() { // modified from https://stackoverflow.com/a/7090123/806777 var pairs = location.search.slice(1).split('&'); @@ -213,6 +226,10 @@ function updateLink() { } function updateVersion() { + if (window.Worker) { + handleInput(); + return Promise.resolve(); + } var promise; if ($markedVerElem.value in markedVersionCache) { promise = Promise.resolve(markedVersionCache[$markedVerElem.value]); @@ -234,57 +251,122 @@ function updateVersion() { } var delayTime = 1; -var options = {}; +var checkChangeTimeout = null; function checkForChanges() { - if (inputDirty && typeof marked !== 'undefined') { + if (inputDirty && (typeof marked !== 'undefined' || window.Worker)) { inputDirty = false; updateLink(); - var startTime = new Date(); - - var scrollPercent = getScrollPercent(); - + var options = {}; + var optionsString = $optionsElem.value || '{}'; try { - var optionsString = $optionsElem.value || '{}'; var newOptions = JSON.parse(optionsString); options = newOptions; - $optionsElem.classList.remove('badParse'); + $optionsElem.classList.remove('error'); } catch (err) { - $optionsElem.classList.add('badParse'); + $optionsElem.classList.add('error'); } - var lexed = marked.lexer($markdownElem.value, options); - - var lexedList = []; - - for (var i = 0; i < lexed.length; i++) { - var lexedLine = []; - for (var j in lexed[i]) { - lexedLine.push(j + ':' + jsonString(lexed[i][j])); + var version = markedVersions[$markedVerElem.value]; + var markdown = $markdownElem.value; + var hash = version + markdown + optionsString; + if (lastInput !== hash) { + lastInput = hash; + if (window.Worker) { + delayTime = 100; + messageWorker({ + task: 'parse', + version: version, + markdown: markdown, + options: options + }); + } else { + var startTime = new Date(); + var lexed = marked.lexer(markdown, options); + var lexedList = []; + for (var i = 0; i < lexed.length; i++) { + var lexedLine = []; + for (var j in lexed[i]) { + lexedLine.push(j + ':' + jsonString(lexed[i][j])); + } + lexedList.push('{' + lexedLine.join(', ') + '}'); + } + var parsed = marked.parser(lexed, options); + var scrollPercent = getScrollPercent(); + setParsed(parsed, lexedList.join('\n')); + setScrollPercent(scrollPercent); + var endTime = new Date(); + delayTime = endTime - startTime; + if (delayTime < 50) { + delayTime = 50; + } else if (delayTime > 500) { + delayTime = 1000; + } } - lexedList.push('{' + lexedLine.join(', ') + '}'); - } - - var parsed = marked.parser(lexed, options); - - if (iframeLoaded) { - $previewIframe.contentDocument.body.innerHTML = (parsed); } - $htmlElem.value = (parsed); - $lexerElem.value = (lexedList.join('\n')); + } + checkChangeTimeout = window.setTimeout(checkForChanges, delayTime); +}; - setScrollPercent(scrollPercent); +function setParsed(parsed, lexed) { + if (iframeLoaded) { + $previewIframe.contentDocument.body.innerHTML = parsed; + } + $htmlElem.value = parsed; + $lexerElem.value = lexed; +} - var endTime = new Date(); - delayTime = endTime - startTime; - if (delayTime < 50) { - delayTime = 50; - } else if (delayTime > 500) { - delayTime = 1000; +var markedWorker; +function messageWorker(message) { + if (!markedWorker || markedWorker.working) { + if (markedWorker) { + clearTimeout(markedWorker.timeout); + markedWorker.terminate(); } + markedWorker = new Worker('worker.js'); + markedWorker.onmessage = function (e) { + clearTimeout(markedWorker.timeout); + markedWorker.working = false; + switch (e.data.task) { + case 'defaults': + setOptions(e.data.defaults); + break; + case 'parse': + $previewElem.classList.remove('error'); + $htmlElem.classList.remove('error'); + $lexerElem.classList.remove('error'); + var scrollPercent = getScrollPercent(); + setParsed(e.data.parsed, e.data.lexed); + setScrollPercent(scrollPercent); + break; + } + clearTimeout(checkChangeTimeout); + delayTime = 10; + checkForChanges(); + }; + markedWorker.onerror = markedWorker.onmessageerror = function (err) { + clearTimeout(markedWorker.timeout); + var error = 'There was an error in the Worker'; + if (err) { + if (err.message) { + error = err.message; + } else { + error = err; + } + } + $previewElem.classList.add('error'); + $htmlElem.classList.add('error'); + $lexerElem.classList.add('error'); + setParsed(error, error); + setScrollPercent(0); + }; } - window.setTimeout(checkForChanges, delayTime); -}; + markedWorker.working = true; + markedWorker.timeout = setTimeout(function () { + markedWorker.onerror('Marked is taking a while...'); + }, 1000); + markedWorker.postMessage(message); +} checkForChanges(); setScrollPercent(0); diff --git a/docs/demo/worker.js b/docs/demo/worker.js new file mode 100644 index 0000000000..e9c21c141d --- /dev/null +++ b/docs/demo/worker.js @@ -0,0 +1,75 @@ +/* global marked */ +var versionCache = {}; +var currentVersion; +onmessage = function (e) { + if (e.data.version === currentVersion) { + parse(e); + } else { + getVersion(e.data.version).then(function (text) { + // eslint-disable-next-line no-new-func + Function(text)(); + currentVersion = e.data.version; + + parse(e); + }); + } +}; + +onunhandledrejection = function (e) { + throw e.reason; +}; + +function parse(e) { + switch (e.data.task) { + case 'defaults': + var defaults = marked.getDefaults(); + defaults.renderer = null; + postMessage({ + task: e.data.task, + defaults: defaults + }); + break; + case 'parse': + var lexed = marked.lexer(e.data.markdown, e.data.options); + var lexedList = []; + for (var i = 0; i < lexed.length; i++) { + var lexedLine = []; + for (var j in lexed[i]) { + lexedLine.push(j + ':' + jsonString(lexed[i][j])); + } + lexedList.push('{' + lexedLine.join(', ') + '}'); + } + var parsed = marked.parser(lexed, e.data.options); + + postMessage({ + task: e.data.task, + lexed: lexedList.join('\n'), + parsed: parsed + }); + break; + } +} + +function jsonString(input) { + var output = (input + '') + .replace(/\n/g, '\\n') + .replace(/\r/g, '\\r') + .replace(/\t/g, '\\t') + .replace(/\f/g, '\\f') + .replace(/[\\"']/g, '\\$&') + .replace(/\u0000/g, '\\0'); + return '"' + output + '"'; +}; + +function getVersion(ver) { + if (ver in versionCache) { + return Promise.resolve(versionCache[ver]); + } + + return fetch(ver) + .then(function (res) { return res.text(); }) + .then(function (text) { + versionCache[ver] = text; + return text; + }); +} From ab42f86430fbbc437f5d2cb13d7dd353ab16a009 Mon Sep 17 00:00:00 2001 From: Tony Brix Date: Wed, 13 Feb 2019 14:18:15 -0600 Subject: [PATCH 02/13] add response time --- docs/demo/demo.js | 29 +++++++++++++++++++++++++++-- docs/demo/index.html | 4 +++- docs/demo/worker.js | 8 ++++++-- 3 files changed, 36 insertions(+), 5 deletions(-) diff --git a/docs/demo/demo.js b/docs/demo/demo.js index 1e57b420b4..17aa6bcd2d 100644 --- a/docs/demo/demo.js +++ b/docs/demo/demo.js @@ -17,6 +17,7 @@ var $markedVer = document.querySelector('#markedCdn'); var $optionsElem = document.querySelector('#options'); var $outputTypeElem = document.querySelector('#outputType'); var $inputTypeElem = document.querySelector('#inputType'); +var $responseTimeElem = document.querySelector('#responseTime'); var $previewElem = document.querySelector('#preview'); var $previewIframe = document.querySelector('#preview iframe'); var $permalinkElem = document.querySelector('#permalink'); @@ -298,6 +299,7 @@ function checkForChanges() { setScrollPercent(scrollPercent); var endTime = new Date(); delayTime = endTime - startTime; + setResponseTime(delayTime); if (delayTime < 50) { delayTime = 50; } else if (delayTime > 500) { @@ -309,6 +311,22 @@ function checkForChanges() { checkChangeTimeout = window.setTimeout(checkForChanges, delayTime); }; +function setResponseTime(ms) { + var amount = ms; + var suffix = 'ms'; + if (ms > 1000 * 60 * 60) { + amount = 'Too Long'; + suffix = ''; + } else if (ms > 1000 * 60) { + amount = '>' + Math.floor(ms / (1000 * 60)); + suffix = 'm'; + } else if (ms > 1000) { + amount = '>' + Math.floor(ms / 1000); + suffix = 's'; + } + $responseTimeElem.textContent = amount + suffix; +} + function setParsed(parsed, lexed) { if (iframeLoaded) { $previewIframe.contentDocument.body.innerHTML = parsed; @@ -339,6 +357,7 @@ function messageWorker(message) { var scrollPercent = getScrollPercent(); setParsed(e.data.parsed, e.data.lexed); setScrollPercent(scrollPercent); + setResponseTime(e.data.time); break; } clearTimeout(checkChangeTimeout); @@ -363,10 +382,16 @@ function messageWorker(message) { }; } markedWorker.working = true; + workerTimeout(0); + markedWorker.postMessage(message); +} + +function workerTimeout(seconds) { markedWorker.timeout = setTimeout(function () { - markedWorker.onerror('Marked is taking a while...'); + seconds++; + markedWorker.onerror('Marked has taken longer than ' + seconds + ' second' + (seconds > 1 ? 's' : '') + ' to respond...'); + workerTimeout(seconds); }, 1000); - markedWorker.postMessage(message); } checkForChanges(); setScrollPercent(0); diff --git a/docs/demo/index.html b/docs/demo/index.html index ea99133473..335eea5fc8 100644 --- a/docs/demo/index.html +++ b/docs/demo/index.html @@ -44,7 +44,9 @@

Marked Demo

- + · + Response Time: +
diff --git a/docs/demo/worker.js b/docs/demo/worker.js index e9c21c141d..b94a8c78bc 100644 --- a/docs/demo/worker.js +++ b/docs/demo/worker.js @@ -30,6 +30,7 @@ function parse(e) { }); break; case 'parse': + var startTime = new Date(); var lexed = marked.lexer(e.data.markdown, e.data.options); var lexedList = []; for (var i = 0; i < lexed.length; i++) { @@ -40,12 +41,15 @@ function parse(e) { lexedList.push('{' + lexedLine.join(', ') + '}'); } var parsed = marked.parser(lexed, e.data.options); - + var endTime = new Date(); + // setTimeout(function () { postMessage({ task: e.data.task, lexed: lexedList.join('\n'), - parsed: parsed + parsed: parsed, + time: endTime - startTime }); + // }, 10000); break; } } From 9e2c72f64af2ee5ae6c0121fa3ded927cbc9c6d9 Mon Sep 17 00:00:00 2001 From: Tony Brix Date: Wed, 13 Feb 2019 18:04:46 -0600 Subject: [PATCH 03/13] fix ie11 --- docs/demo/demo.js | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/docs/demo/demo.js b/docs/demo/demo.js index 17aa6bcd2d..279b73743e 100644 --- a/docs/demo/demo.js +++ b/docs/demo/demo.js @@ -1,10 +1,13 @@ /* globals marked, unfetch, ES6Promise */ +var useWorker = !!window.Worker; if (!window.Promise) { window.Promise = ES6Promise; + useWorker = false; } if (!window.fetch) { window.fetch = unfetch; + useWorker = false; } onunhandledrejection = function (e) { @@ -145,7 +148,7 @@ $clearElem.addEventListener('click', function () { }, false); function setDefaultOptions() { - if (window.Worker) { + if (useWorker) { messageWorker({ task: 'defaults', version: markedVersions[$markedVerElem.value]} @@ -227,7 +230,7 @@ function updateLink() { } function updateVersion() { - if (window.Worker) { + if (useWorker) { handleInput(); return Promise.resolve(); } @@ -254,7 +257,7 @@ function updateVersion() { var delayTime = 1; var checkChangeTimeout = null; function checkForChanges() { - if (inputDirty && (typeof marked !== 'undefined' || window.Worker)) { + if (inputDirty && (typeof marked !== 'undefined' || (useWorker))) { inputDirty = false; updateLink(); @@ -274,7 +277,7 @@ function checkForChanges() { var hash = version + markdown + optionsString; if (lastInput !== hash) { lastInput = hash; - if (window.Worker) { + if (useWorker) { delayTime = 100; messageWorker({ task: 'parse', From 3681bcff33d6e3237acd70aa14098be3889fa228 Mon Sep 17 00:00:00 2001 From: Tony Brix Date: Wed, 13 Feb 2019 18:24:44 -0600 Subject: [PATCH 04/13] allow version to be a github commit --- docs/demo/demo.js | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/docs/demo/demo.js b/docs/demo/demo.js index 279b73743e..f8ce4657a7 100644 --- a/docs/demo/demo.js +++ b/docs/demo/demo.js @@ -75,6 +75,13 @@ fetch('https://data.jsdelivr.com/v1/package/npm/marked') }) .then(function () { if ('version' in search && search.version) { + if (!(search.version in markedVersions)) { + markedVersions[search.version] = 'https://cdn.jsdelivr.net/gh/markedjs/marked@' + search.version + '/lib/marked.js'; + var opt = document.createElement('option'); + opt.textContent = search.version.substring(0, 7); + opt.value = search.version; + $markedVerElem.insertBefore(opt, $markedVerElem.firstChild); + } $markedVerElem.value = search.version; } else { $markedVerElem.value = 'master'; From 0f4ac747a29195b2261bdbbc9e532f502d8d2b13 Mon Sep 17 00:00:00 2001 From: Tony Brix Date: Thu, 14 Feb 2019 00:08:33 -0600 Subject: [PATCH 05/13] add commit input --- docs/demo/demo.js | 54 ++++++++++++++++++++++++++++++++++++-------- docs/demo/index.html | 4 +++- docs/demo/worker.js | 22 ++++++++++++++---- 3 files changed, 66 insertions(+), 14 deletions(-) diff --git a/docs/demo/demo.js b/docs/demo/demo.js index f8ce4657a7..83466bd4ef 100644 --- a/docs/demo/demo.js +++ b/docs/demo/demo.js @@ -16,6 +16,8 @@ onunhandledrejection = function (e) { var $markdownElem = document.querySelector('#markdown'); var $markedVerElem = document.querySelector('#markedVersion'); +var $commitVerElem = document.querySelector('#commitVersion'); +$commitVerElem.style.display = 'none'; var $markedVer = document.querySelector('#markedCdn'); var $optionsElem = document.querySelector('#options'); var $outputTypeElem = document.querySelector('#outputType'); @@ -35,6 +37,7 @@ var $activeOutputElem = null; var search = searchToObject(); var markedVersions = { + commit: 'commit', master: 'https://cdn.jsdelivr.net/gh/markedjs/marked/lib/marked.js' }; var markedVersionCache = {}; @@ -76,11 +79,7 @@ fetch('https://data.jsdelivr.com/v1/package/npm/marked') .then(function () { if ('version' in search && search.version) { if (!(search.version in markedVersions)) { - markedVersions[search.version] = 'https://cdn.jsdelivr.net/gh/markedjs/marked@' + search.version + '/lib/marked.js'; - var opt = document.createElement('option'); - opt.textContent = search.version.substring(0, 7); - opt.value = search.version; - $markedVerElem.insertBefore(opt, $markedVerElem.firstChild); + addCommitVersion(search.version); } $markedVerElem.value = search.version; } else { @@ -106,6 +105,17 @@ fetch('./quickref.md') document.querySelector('#quickref').value = text; }); +function addCommitVersion(version) { + if (version in markedVersions) { + return; + } + markedVersions[version] = 'https://cdn.jsdelivr.net/gh/markedjs/marked@' + version + '/lib/marked.js'; + var opt = document.createElement('option'); + opt.textContent = version.substring(0, 7); + opt.value = version; + $markedVerElem.insertBefore(opt, $markedVerElem.firstChild); +} + function handleInputChange() { handleChange($inputPanes, $inputTypeElem.value); } @@ -132,7 +142,14 @@ $outputTypeElem.addEventListener('change', handleOutputChange, false); handleOutputChange(); $inputTypeElem.addEventListener('change', handleInputChange, false); handleInputChange(); -$markedVerElem.addEventListener('change', updateVersion, false); +$markedVerElem.addEventListener('change', function () { + if ($markedVerElem.value === 'commit') { + $commitVerElem.style.display = ''; + } else { + $commitVerElem.style.display = 'none'; + updateVersion(); + } +}, false); function handleInput() { inputDirty = true; @@ -148,9 +165,25 @@ $optionsElem.addEventListener('keyup', handleInput, false); $optionsElem.addEventListener('keypress', handleInput, false); $optionsElem.addEventListener('keydown', handleInput, false); +$commitVerElem.addEventListener('keypress', function (e) { + if (e.which === 13) { + var commit = $commitVerElem.value.toLowerCase(); + if (!commit.match(/^[0-9a-f]{40}$/)) { + alert('That is not a valid commit'); + return; + } + addCommitVersion(commit); + $markedVerElem.value = commit; + $commitVerElem.style.display = 'none'; + $commitVerElem.value = ''; + updateVersion(); + } +}, false); + $clearElem.addEventListener('click', function () { $markdownElem.value = ''; $markedVerElem.value = 'master'; + $commitVerElem.style.display = 'none'; updateVersion().then(setDefaultOptions); }, false); @@ -264,7 +297,7 @@ function updateVersion() { var delayTime = 1; var checkChangeTimeout = null; function checkForChanges() { - if (inputDirty && (typeof marked !== 'undefined' || (useWorker))) { + if (inputDirty && (typeof marked !== 'undefined' || (useWorker)) && $markedVerElem.value !== 'commit') { inputDirty = false; updateLink(); @@ -384,6 +417,7 @@ function messageWorker(message) { error = err; } } + error = error.replace(/^Uncaught Error: /, ''); $previewElem.classList.add('error'); $htmlElem.classList.add('error'); $lexerElem.classList.add('error'); @@ -391,8 +425,10 @@ function messageWorker(message) { setScrollPercent(0); }; } - markedWorker.working = true; - workerTimeout(0); + if (message.task !== 'defaults') { + markedWorker.working = true; + workerTimeout(0); + } markedWorker.postMessage(message); } diff --git a/docs/demo/index.html b/docs/demo/index.html index 335eea5fc8..b33c4614e1 100644 --- a/docs/demo/index.html +++ b/docs/demo/index.html @@ -25,8 +25,10 @@

Marked Demo

· Version: · + + · - + · From 2cbda35f9d0357399dfa01880476e2053b99564a Mon Sep 17 00:00:00 2001 From: Tony Brix Date: Thu, 14 Feb 2019 00:15:09 -0600 Subject: [PATCH 07/13] set title to press enter --- docs/demo/index.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/demo/index.html b/docs/demo/index.html index 1fc2610bdb..efe4206647 100644 --- a/docs/demo/index.html +++ b/docs/demo/index.html @@ -28,7 +28,7 @@

Marked Demo

- · + · + From f8d2413a0887c66669aaddcb9d9913126bfd2196 Mon Sep 17 00:00:00 2001 From: Tony Brix Date: Thu, 14 Feb 2019 11:14:15 -0600 Subject: [PATCH 10/13] clean up code --- docs/demo/demo.js | 278 ++++++++++++++++++++++++-------------------- docs/demo/worker.js | 48 ++++---- 2 files changed, 177 insertions(+), 149 deletions(-) diff --git a/docs/demo/demo.js b/docs/demo/demo.js index 9cead6a65a..03db868b34 100644 --- a/docs/demo/demo.js +++ b/docs/demo/demo.js @@ -31,158 +31,157 @@ var lastInput = ''; var inputDirty = true; var $activeOutputElem = null; var search = searchToObject(); - var markedVersions = { master: 'https://cdn.jsdelivr.net/gh/markedjs/marked/lib/marked.js' }; var markedVersionCache = {}; +var delayTime = 1; +var checkChangeTimeout = null; +var markedWorker; + +$previewIframe.addEventListener('load', handleIframeLoad); + +$outputTypeElem.addEventListener('change', handleOutputChange, false); + +$inputTypeElem.addEventListener('change', handleInputChange, false); + +$markedVerElem.addEventListener('change', handleVersionChange, false); + +$markdownElem.addEventListener('change', handleInput, false); +$markdownElem.addEventListener('keyup', handleInput, false); +$markdownElem.addEventListener('keypress', handleInput, false); +$markdownElem.addEventListener('keydown', handleInput, false); + +$optionsElem.addEventListener('change', handleInput, false); +$optionsElem.addEventListener('keyup', handleInput, false); +$optionsElem.addEventListener('keypress', handleInput, false); +$optionsElem.addEventListener('keydown', handleInput, false); $commitVerElem.style.display = 'none'; -$previewIframe.addEventListener('load', function () { - lastInput = ''; - inputDirty = true; +$commitVerElem.addEventListener('keypress', handleAddVersion, false); + +$clearElem.addEventListener('click', handleClearClick, false); + +Promise.all([ + setInitialQuickref(), + setInitialOutputType() + .then(handleOutputChange), + setInitialText(), + setInitialVersion() + .then(setInitialOptions) +]).then(function () { + checkForChanges(); + setScrollPercent(0); }); -if ('text' in search && search.text) { - $markdownElem.value = search.text; -} else { - fetch('./initial.md') +function setInitialText() { + if (search.text) { + $markdownElem.value = search.text; + } else { + return fetch('./initial.md') + .then(function (res) { return res.text(); }) + .then(function (text) { + if ($markdownElem.value === '') { + $markdownElem.value = text; + } + }); + } +} + +function setInitialQuickref() { + return fetch('./quickref.md') .then(function (res) { return res.text(); }) .then(function (text) { - if ($markdownElem.value === '') { - $markdownElem.value = text; - inputDirty = true; - setScrollPercent(0); - } + document.querySelector('#quickref').value = text; }); } -fetch('https://data.jsdelivr.com/v1/package/npm/marked') - .then(function (res) { - return res.json(); - }) - .then(function (json) { - for (var i = 0; i < json.versions.length; i++) { - var ver = json.versions[i]; - markedVersions[ver] = 'https://cdn.jsdelivr.net/npm/marked@' + ver + '/lib/marked.js'; - var opt = document.createElement('option'); - opt.textContent = ver; - opt.value = ver; - $markedVerElem.appendChild(opt); - } - }) - .then(function () { - if ('version' in search && search.version) { - if (!(search.version in markedVersions)) { - var match = search.version.match(/^(\w+):(.+)$/); - if (match) { - switch (match[1]) { - case 'commit': - addCommitVersion(search.version, match[2].substring(0, 7), match[2]); - return search.version; - case 'pr': - return getPrCommit(match[2]) - .then(function (commit) { - if (!commit) { - return 'master'; - } - addCommitVersion(search.version, 'PR #' + match[2], commit); - return search.version; - }); +function setInitialVersion() { + return fetch('https://data.jsdelivr.com/v1/package/npm/marked') + .then(function (res) { + return res.json(); + }) + .then(function (json) { + for (var i = 0; i < json.versions.length; i++) { + var ver = json.versions[i]; + markedVersions[ver] = 'https://cdn.jsdelivr.net/npm/marked@' + ver + '/lib/marked.js'; + var opt = document.createElement('option'); + opt.textContent = ver; + opt.value = ver; + $markedVerElem.appendChild(opt); + } + }) + .then(function () { + if (search.version) { + if (!markedVersions[search.version]) { + var match = search.version.match(/^(\w+):(.+)$/); + if (match) { + switch (match[1]) { + case 'commit': + addCommitVersion(search.version, match[2].substring(0, 7), match[2]); + return search.version; + case 'pr': + return getPrCommit(match[2]) + .then(function (commit) { + if (!commit) { + return 'master'; + } + addCommitVersion(search.version, 'PR #' + match[2], commit); + return search.version; + }); + } } } } - } - return 'master'; - }) - .then(function (version) { - $markedVerElem.value = version; - }) - .then(updateVersion) - .then(function () { - if ('options' in search && search.options) { - $optionsElem.value = search.options; - } else { - setDefaultOptions(); - } - }) - .then(function () { - checkForChanges(); - setScrollPercent(0); - }); - -if (search.outputType) { - $outputTypeElem.value = search.outputType; + return 'master'; + }) + .then(function (version) { + $markedVerElem.value = version; + }) + .then(updateVersion); } -fetch('./quickref.md') - .then(function (res) { return res.text(); }) - .then(function (text) { - document.querySelector('#quickref').value = text; - }); - -function addCommitVersion(value, text, commit) { - if (value in markedVersions) { - return; +function setInitialOptions() { + if (search.options) { + $optionsElem.value = search.options; + } else { + setDefaultOptions(); } - markedVersions[value] = 'https://cdn.jsdelivr.net/gh/markedjs/marked@' + commit + '/lib/marked.js'; - var opt = document.createElement('option'); - opt.textContent = text; - opt.value = value; - $markedVerElem.insertBefore(opt, $markedVerElem.firstChild); } -function handleInputChange() { - handleChange($inputPanes, $inputTypeElem.value); +function setInitialOutputType() { + if (search.outputType) { + $outputTypeElem.value = search.outputType; + } } -function handleOutputChange() { - $activeOutputElem = handleChange($panes, $outputTypeElem.value); - updateLink(); +function handleIframeLoad() { + lastInput = ''; + inputDirty = true; } -function handleChange(panes, visiblePane) { - var active = null; - for (var i = 0; i < panes.length; i++) { - if (panes[i].id === visiblePane) { - panes[i].style.display = ''; - active = panes[i]; - } else { - panes[i].style.display = 'none'; - } - } - return active; +function handleInput() { + inputDirty = true; }; -$outputTypeElem.addEventListener('change', handleOutputChange, false); -handleOutputChange(); -$inputTypeElem.addEventListener('change', handleInputChange, false); -handleInputChange(); -$markedVerElem.addEventListener('change', function () { +function handleVersionChange() { if ($markedVerElem.value === 'commit' || $markedVerElem.value === 'pr') { $commitVerElem.style.display = ''; } else { $commitVerElem.style.display = 'none'; updateVersion(); } -}, false); - -function handleInput() { - inputDirty = true; -}; - -$markdownElem.addEventListener('change', handleInput, false); -$markdownElem.addEventListener('keyup', handleInput, false); -$markdownElem.addEventListener('keypress', handleInput, false); -$markdownElem.addEventListener('keydown', handleInput, false); +} -$optionsElem.addEventListener('change', handleInput, false); -$optionsElem.addEventListener('keyup', handleInput, false); -$optionsElem.addEventListener('keypress', handleInput, false); -$optionsElem.addEventListener('keydown', handleInput, false); +function handleClearClick() { + $markdownElem.value = ''; + $markedVerElem.value = 'master'; + $commitVerElem.style.display = 'none'; + updateVersion().then(setDefaultOptions); +} -$commitVerElem.addEventListener('keypress', function (e) { +function handleAddVersion(e) { if (e.which === 13) { switch ($markedVerElem.value) { case 'commit': @@ -215,14 +214,40 @@ $commitVerElem.addEventListener('keypress', function (e) { }); } } -}, false); +} -$clearElem.addEventListener('click', function () { - $markdownElem.value = ''; - $markedVerElem.value = 'master'; - $commitVerElem.style.display = 'none'; - updateVersion().then(setDefaultOptions); -}, false); +function handleInputChange() { + handleChange($inputPanes, $inputTypeElem.value); +} + +function handleOutputChange() { + $activeOutputElem = handleChange($panes, $outputTypeElem.value); + updateLink(); +} + +function handleChange(panes, visiblePane) { + var active = null; + for (var i = 0; i < panes.length; i++) { + if (panes[i].id === visiblePane) { + panes[i].style.display = ''; + active = panes[i]; + } else { + panes[i].style.display = 'none'; + } + } + return active; +}; + +function addCommitVersion(value, text, commit) { + if (markedVersions[value]) { + return; + } + markedVersions[value] = 'https://cdn.jsdelivr.net/gh/markedjs/marked@' + commit + '/lib/marked.js'; + var opt = document.createElement('option'); + opt.textContent = text; + opt.value = value; + $markedVerElem.insertBefore(opt, $markedVerElem.firstChild); +} function getPrCommit(pr) { return fetch('https://api.github.com/repos/markedjs/marked/pulls/' + pr + '/commits') @@ -293,6 +318,7 @@ function getScrollSize() { return e.scrollHeight - e.clientHeight; }; + function getScrollPercent() { var size = getScrollSize(); @@ -302,6 +328,7 @@ function getScrollPercent() { return $activeOutputElem.scrollTop / size; }; + function setScrollPercent(percent) { $activeOutputElem.scrollTop = percent * getScrollSize(); }; @@ -324,7 +351,7 @@ function updateVersion() { return Promise.resolve(); } var promise; - if ($markedVerElem.value in markedVersionCache) { + if (markedVersionCache[$markedVerElem.value]) { promise = Promise.resolve(markedVersionCache[$markedVerElem.value]); } else { promise = fetch(markedVersions[$markedVerElem.value]) @@ -343,8 +370,6 @@ function updateVersion() { }).then(handleInput); } -var delayTime = 1; -var checkChangeTimeout = null; function checkForChanges() { if (inputDirty && $markedVerElem.value !== 'commit' && $markedVerElem.value !== 'pr' && (typeof marked !== 'undefined' || window.Worker)) { inputDirty = false; @@ -427,7 +452,6 @@ function setParsed(parsed, lexed) { $lexerElem.value = lexed; } -var markedWorker; function messageWorker(message) { if (!markedWorker || markedWorker.working) { if (markedWorker) { diff --git a/docs/demo/worker.js b/docs/demo/worker.js index 13bd196a19..cb189390aa 100644 --- a/docs/demo/worker.js +++ b/docs/demo/worker.js @@ -7,30 +7,24 @@ if (!self.fetch) { self.importScripts('https://cdn.jsdelivr.net/npm/unfetch/dist/unfetch.umd.js'); self.fetch = unfetch; } + var versionCache = {}; var currentVersion; + +onunhandledrejection = function (e) { + throw e.reason; +}; + onmessage = function (e) { if (e.data.version === currentVersion) { parse(e); } else { - getVersion(e.data.version).then(function (text) { - try { - // eslint-disable-next-line no-new-func - Function(text)(); - } catch (err) { - throw new Error('Cannot load that version of marked'); - } - currentVersion = e.data.version; - + loadVersion(e.data.version).then(function () { parse(e); }); } }; -onunhandledrejection = function (e) { - throw e.reason; -}; - function parse(e) { switch (e.data.task) { case 'defaults': @@ -87,15 +81,25 @@ function jsonString(input) { return '"' + output + '"'; }; -function getVersion(ver) { +function loadVersion(ver) { + var promise; if (ver in versionCache) { - return Promise.resolve(versionCache[ver]); + promise = Promise.resolve(versionCache[ver]); + } else { + promise = fetch(ver) + .then(function (res) { return res.text(); }) + .then(function (text) { + versionCache[ver] = text; + return text; + }); } - - return fetch(ver) - .then(function (res) { return res.text(); }) - .then(function (text) { - versionCache[ver] = text; - return text; - }); + return promise.then(function (text) { + try { + // eslint-disable-next-line no-new-func + Function(text)(); + } catch (err) { + throw new Error('Cannot load that version of marked'); + } + currentVersion = ver; + }); } From 5e2d77378cb5592268a0aca78c120897d7516717 Mon Sep 17 00:00:00 2001 From: Tony Brix Date: Thu, 14 Feb 2019 11:18:47 -0600 Subject: [PATCH 11/13] fix startup --- docs/demo/demo.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/demo/demo.js b/docs/demo/demo.js index 03db868b34..a343440523 100644 --- a/docs/demo/demo.js +++ b/docs/demo/demo.js @@ -64,12 +64,13 @@ $clearElem.addEventListener('click', handleClearClick, false); Promise.all([ setInitialQuickref(), - setInitialOutputType() - .then(handleOutputChange), + setInitialOutputType(), setInitialText(), setInitialVersion() .then(setInitialOptions) ]).then(function () { + handleInputChange(); + handleOutputChange(); checkForChanges(); setScrollPercent(0); }); From 40d65e5582bfce979feb65152ef1bad87c0d5076 Mon Sep 17 00:00:00 2001 From: Tony Brix Date: Thu, 14 Feb 2019 11:25:01 -0600 Subject: [PATCH 12/13] add loading screen --- docs/demo/demo.css | 4 +++ docs/demo/demo.js | 4 +++ docs/demo/index.html | 83 +++++++++++++++++++++++--------------------- 3 files changed, 51 insertions(+), 40 deletions(-) diff --git a/docs/demo/demo.css b/docs/demo/demo.css index 8502d49190..398c663a51 100644 --- a/docs/demo/demo.css +++ b/docs/demo/demo.css @@ -62,6 +62,10 @@ header h1 { flex-grow: 1; } +#main { + display: none; +} + .error { border-color: red; background-color: #FEE diff --git a/docs/demo/demo.js b/docs/demo/demo.js index a343440523..2e5198adb3 100644 --- a/docs/demo/demo.js +++ b/docs/demo/demo.js @@ -11,6 +11,8 @@ onunhandledrejection = function (e) { throw e.reason; }; +var $loadingElem = document.querySelector('#loading'); +var $mainElem = document.querySelector('#main'); var $markdownElem = document.querySelector('#markdown'); var $markedVerElem = document.querySelector('#markedVersion'); var $commitVerElem = document.querySelector('#commitVersion'); @@ -73,6 +75,8 @@ Promise.all([ handleOutputChange(); checkForChanges(); setScrollPercent(0); + $loadingElem.style.display = 'none'; + $mainElem.style.display = 'block'; }); function setInitialText() { diff --git a/docs/demo/index.html b/docs/demo/index.html index faae46fa60..7d21663695 100644 --- a/docs/demo/index.html +++ b/docs/demo/index.html @@ -18,52 +18,55 @@

Marked Demo

-
-
-
- Input · - · - Version: - - · - - +
Loading...
+
+
+
+
+ Input · + · + Version: + + · + + +
+ +
- - -
-
-
- · - Response Time: - -
+
+
+ · + Response Time: + +
-
- - -
+
+ + +
- + - + - + +
From 14da71c5cb3a42e2154407c5f4d9760d9b2ae32a Mon Sep 17 00:00:00 2001 From: Tony Brix Date: Thu, 14 Feb 2019 11:52:14 -0600 Subject: [PATCH 13/13] clean up more code --- docs/demo/demo.js | 4 ++-- docs/demo/index.html | 2 +- docs/demo/initial.md | 2 +- docs/demo/worker.js | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/demo/demo.js b/docs/demo/demo.js index 2e5198adb3..de6882a5be 100644 --- a/docs/demo/demo.js +++ b/docs/demo/demo.js @@ -80,7 +80,7 @@ Promise.all([ }); function setInitialText() { - if (search.text) { + if ('text' in search) { $markdownElem.value = search.text; } else { return fetch('./initial.md') @@ -148,7 +148,7 @@ function setInitialVersion() { } function setInitialOptions() { - if (search.options) { + if ('options' in search) { $optionsElem.value = search.options; } else { setDefaultOptions(); diff --git a/docs/demo/index.html b/docs/demo/index.html index 7d21663695..96a8ec14b1 100644 --- a/docs/demo/index.html +++ b/docs/demo/index.html @@ -58,7 +58,7 @@

Marked Demo

- +
diff --git a/docs/demo/initial.md b/docs/demo/initial.md index 2465aef041..d2b7d77c10 100644 --- a/docs/demo/initial.md +++ b/docs/demo/initial.md @@ -30,7 +30,7 @@ It's easy. It's not overly bloated, unlike HTML. Also, as the creator of [mark > or formatting instructions. Ready to start writing? Either start changing stuff on the left or -[clear everything](?text=) with a simple click. +[clear everything](/demo/?text=) with a simple click. [Marked]: https://github.com/markedjs/marked/ [Markdown]: http://daringfireball.net/projects/markdown/ diff --git a/docs/demo/worker.js b/docs/demo/worker.js index cb189390aa..06b8befe78 100644 --- a/docs/demo/worker.js +++ b/docs/demo/worker.js @@ -83,7 +83,7 @@ function jsonString(input) { function loadVersion(ver) { var promise; - if (ver in versionCache) { + if (versionCache[ver]) { promise = Promise.resolve(versionCache[ver]); } else { promise = fetch(ver)