diff --git a/client/commonFramework/code-uri.js b/client/commonFramework/code-uri.js index a0694b892b..3051c12bd2 100644 --- a/client/commonFramework/code-uri.js +++ b/client/commonFramework/code-uri.js @@ -42,6 +42,8 @@ window.common = (function(global) { return decoded .split('?') .splice(1) + .pop() + .split('&') .reduce(function(found, param) { var key = param.split('=')[0]; if (key === 'solution') { @@ -55,6 +57,23 @@ window.common = (function(global) { codeUri.isInQuery(location.search) || codeUri.isInQuery(location.hash); }, + getKeyInQuery(query, keyToFind = '') { + return query + .split('&') + .reduce(function(oldValue, param) { + var key = param.split('=')[0]; + var value = param.split('=')[1]; + if (key === keyToFind) { + return value; + } + return oldValue; + }, null); + }, + getSolutionFromQuery(query = '') { + return decodeFcc( + codeUri.decode(codeUri.getKeyInQuery(query, 'solution')) + ); + }, parse: function() { if (!codeUri.enabled) { return null; @@ -62,6 +81,7 @@ window.common = (function(global) { var query; if (location.search && codeUri.isInQuery(location.search)) { query = location.search.replace(/^\?/, ''); + if (history && typeof history.replaceState === 'function') { history.replaceState( history.state, @@ -73,30 +93,29 @@ window.common = (function(global) { } else { query = location.hash.replace(/^\#\?/, ''); } + if (!query) { return null; } - return query - .split('&') - .reduce(function(solution, param) { - var key = param.split('=')[0]; - var value = param.split('=')[1]; - if (key === 'solution') { - return decodeFcc(codeUri.decode(value || '')); - } - return solution; - }, null); + return this.getSolutionFromQuery(query); }, querify: function(solution) { if (!codeUri.enabled) { return null; } if (history && typeof history.replaceState === 'function') { + // grab the url up to the query + // destroy any hash symbols still clinging to life + const url = (location.href.split('?')[0]).replace(/(#*)$/, ''); history.replaceState( history.state, null, - '?solution=' + codeUri.encode(encodeFcc(solution)) + url + + '#?' + + (codeUri.shouldRun() ? '' : 'run=disabled&') + + 'solution=' + + codeUri.encode(encodeFcc(solution)) ); } else { location.hash = '?solution=' + @@ -105,7 +124,13 @@ window.common = (function(global) { return solution; }, - enabled: true + enabled: true, + shouldRun() { + return !this.getKeyInQuery( + (location.search || location.hash).replace(/^(\?|#\?)/, ''), + 'run' + ); + } }; common.init.push(function() { @@ -113,6 +138,7 @@ window.common = (function(global) { }); common.codeUri = codeUri; + common.shouldRun = () => codeUri.shouldRun(); return common; }(window)); diff --git a/client/commonFramework/update-preview.js b/client/commonFramework/update-preview.js index 0f483a6a9c..ab99e46a6f 100644 --- a/client/commonFramework/update-preview.js +++ b/client/commonFramework/update-preview.js @@ -34,6 +34,11 @@ window.common = (function(global) { body { padding: 0px 3px 0px 3px; } `; + const codeDisabledError = ` + + `; const iFrameScript$ = common.getScriptContent$('/js/iFrameScripts.js').shareReplay(); @@ -74,7 +79,7 @@ window.common = (function(global) { preview.write( libraryIncludes + jQuery + - code + + (common.shouldRun() ? code : codeDisabledError) + '' + iframeScript ); diff --git a/client/iFrameScripts.js b/client/iFrameScripts.js index 2fc6ac8b69..e9d1456f88 100644 --- a/client/iFrameScripts.js +++ b/client/iFrameScripts.js @@ -11,6 +11,9 @@ window.$(document).ready(function() { var common = parent.common; common.getJsOutput = function evalJs(code = '') { + if (window.__err || !common.shouldRun()) { + return window.__err || 'code disabled'; + } let output; try { /* eslint-disable no-eval */ diff --git a/public/js/lib/loop-protect/loop-protect.js b/public/js/lib/loop-protect/loop-protect.js index 5050605b9e..1452d9525d 100644 --- a/public/js/lib/loop-protect/loop-protect.js +++ b/public/js/lib/loop-protect/loop-protect.js @@ -20,6 +20,7 @@ if (typeof DEBUG === 'undefined') { DEBUG = true; } var reSingle = /\b(for|while|do)\b/; var labelRe = /\b([a-z_]{1}\w+:)/i; var comments = /(?:\/\*(?:[\s\S]*?)\*\/)|(?:([\s;])+\/\/(?:.*)$)/gm; + var loopTimeout = 500; var loopProtect = rewriteLoops; @@ -404,8 +405,7 @@ if (typeof DEBUG === 'undefined') { DEBUG = true; } } line.hit++; - if ((now - line.time) > 100) {//} && line.hit !== line.last+1) { - // We've spent over 100ms on this loop... smells infinite. + if ((now - line.time) > loopTimeout) {//} && line.hit !== line.last+1) { loopProtect.hit(state.line); // Returning true prevents the loop running again return true;