Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

demo worker #1418

Merged
merged 14 commits into from Feb 17, 2019
2 changes: 1 addition & 1 deletion docs/demo/demo.css
Expand Up @@ -62,7 +62,7 @@ header h1 {
flex-grow: 1;
}

#options.badParse {
.error {
border-color: red;
background-color: #FEE
}
259 changes: 204 additions & 55 deletions docs/demo/demo.js
Expand Up @@ -7,31 +7,40 @@ if (!window.fetch) {
window.fetch = unfetch;
}

onunhandledrejection = function (e) {
throw e.reason;
};

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');
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');
var $clearElem = document.querySelector('#clear');
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();

var markedVersions = {
commit: 'commit',
master: 'https://cdn.jsdelivr.net/gh/markedjs/marked/lib/marked.js'
};
var markedVersionCache = {};

var iframeLoaded = false;
$previewIframe.addEventListener('load', function () {
iframeLoaded = true;
lastInput = '';
inputDirty = true;
});

Expand Down Expand Up @@ -65,6 +74,9 @@ fetch('https://data.jsdelivr.com/v1/package/npm/marked')
})
.then(function () {
if ('version' in search && search.version) {
if (!(search.version in markedVersions)) {
addCommitVersion(search.version);
}
$markedVerElem.value = search.version;
} else {
$markedVerElem.value = 'master';
Expand All @@ -74,14 +86,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();
}
});
});
Expand All @@ -96,6 +101,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);
}
Expand All @@ -122,7 +138,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;
Expand All @@ -138,21 +161,51 @@ $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';
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;
}, ' ');
});
$commitVerElem.style.display = 'none';
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('&');
Expand Down Expand Up @@ -213,6 +266,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]);
Expand All @@ -234,57 +291,149 @@ function updateVersion() {
}

var delayTime = 1;
var options = {};
var checkChangeTimeout = null;
function checkForChanges() {
if (inputDirty && typeof marked !== 'undefined') {
if (inputDirty && $markedVerElem.value !== 'commit' && (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;
setResponseTime(delayTime);
if (delayTime < 50) {
delayTime = 50;
} else if (delayTime > 500) {
delayTime = 1000;
}
}
lexedList.push('{' + lexedLine.join(', ') + '}');
}
}
checkChangeTimeout = window.setTimeout(checkForChanges, delayTime);
};

var parsed = marked.parser(lexed, options);

if (iframeLoaded) {
$previewIframe.contentDocument.body.innerHTML = (parsed);
}
$htmlElem.value = (parsed);
$lexerElem.value = (lexedList.join('\n'));
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;
}

setScrollPercent(scrollPercent);
function setParsed(parsed, lexed) {
try {
$previewIframe.contentDocument.body.innerHTML = parsed;
} catch (ex) {}
$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);
setResponseTime(e.data.time);
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;
}
}
error = error.replace(/^Uncaught Error: /, '');
$previewElem.classList.add('error');
$htmlElem.classList.add('error');
$lexerElem.classList.add('error');
setParsed(error, error);
setScrollPercent(0);
};
}
window.setTimeout(checkForChanges, delayTime);
};
if (message.task !== 'defaults') {
markedWorker.working = true;
workerTimeout(0);
}
markedWorker.postMessage(message);
}

function workerTimeout(seconds) {
markedWorker.timeout = setTimeout(function () {
seconds++;
markedWorker.onerror('Marked has taken longer than ' + seconds + ' second' + (seconds > 1 ? 's' : '') + ' to respond...');
workerTimeout(seconds);
}, 1000);
}
checkForChanges();
setScrollPercent(0);
10 changes: 7 additions & 3 deletions docs/demo/index.html
Expand Up @@ -25,8 +25,10 @@ <h1>Marked Demo</h1>
<a id="permalink">Permalink</a> ·
<span>Version: </span>
<select id="markedVersion">
<option value="master">master</option>
</select> ·
<option value="commit">Add Commit:</option>
<option value="master" selected>master</option>
</select>
<input type="text" id="commitVersion" title="Press ENTER to add commit" />·
<button id="clear">Clear</button>
<select id="inputType">
<option value="markdown">Markdown</option>
Expand All @@ -44,7 +46,9 @@ <h1>Marked Demo</h1>
<option value="html">HTML Source</option>
<option value="lexer">Lexer Data</option>
<option value="quickref">Quick Reference</option>
</select>
</select> ·
Response Time:
<span id="responseTime"></span>
</div>

<div id="preview" class="pane">
Expand Down