diff --git a/app/assets/javascripts/admin/components/ace-editor.js.es6 b/app/assets/javascripts/admin/components/ace-editor.js.es6 index 192bc4b410c..f0f5750469c 100644 --- a/app/assets/javascripts/admin/components/ace-editor.js.es6 +++ b/app/assets/javascripts/admin/components/ace-editor.js.es6 @@ -1,8 +1,6 @@ import loadScript from "discourse/lib/load-script"; import { observes } from "ember-addons/ember-computed-decorators"; -const LOAD_ASYNC = !Ember.testing; - export default Ember.Component.extend({ mode: "css", classNames: ["ace-wrapper"], @@ -26,7 +24,7 @@ export default Ember.Component.extend({ @observes("mode") modeChanged() { - if (LOAD_ASYNC && this._editor && !this._skipContentChangeEvent) { + if (this._editor && !this._skipContentChangeEvent) { this._editor.getSession().setMode("ace/mode/" + this.get("mode")); } }, @@ -71,21 +69,17 @@ export default Ember.Component.extend({ didInsertElement() { this._super(); - loadScript("/javascripts/ace/ace.js", { scriptTag: true }).then(() => { + loadScript("/javascripts/ace/ace.js").then(() => { window.ace.require(["ace/ace"], loadedAce => { if (!this.element || this.isDestroying || this.isDestroyed) { return; } const editor = loadedAce.edit(this.$(".ace")[0]); - if (LOAD_ASYNC) { - editor.setTheme("ace/theme/chrome"); - } + editor.setTheme("ace/theme/chrome"); editor.setShowPrintMargin(false); editor.setOptions({ fontSize: "14px" }); - if (LOAD_ASYNC) { - editor.getSession().setMode("ace/mode/" + this.get("mode")); - } + editor.getSession().setMode("ace/mode/" + this.get("mode")); editor.on("change", () => { this._skipContentChangeEvent = true; this.set("content", editor.getSession().getValue()); diff --git a/app/assets/javascripts/discourse/lib/load-script.js.es6 b/app/assets/javascripts/discourse/lib/load-script.js.es6 index bd64c64ec15..087ec344bc2 100644 --- a/app/assets/javascripts/discourse/lib/load-script.js.es6 +++ b/app/assets/javascripts/discourse/lib/load-script.js.es6 @@ -44,7 +44,7 @@ export default function loadScript(url, opts) { $("script").each((i, tag) => { const src = tag.getAttribute("src"); - if (src && (opts.scriptTag || src !== url)) { + if (src && src !== url) { _loaded[tag.getAttribute("src")] = true; } }); @@ -86,22 +86,15 @@ export default function loadScript(url, opts) { cdnUrl = Discourse.CDN.replace(/\/$/, "") + url; } - // Some javascript depends on the path of where it is loaded (ace editor) - // to dynamically load more JS. In that case, add the `scriptTag: true` - // option. - if (opts.scriptTag) { - if (Ember.testing) { - throw new Error( - `In test mode scripts cannot be loaded async ${cdnUrl}` - ); - } - loadWithTag(cdnUrl, cb); - } else { + if (opts.css) { ajax({ url: cdnUrl, - dataType: opts.css ? "text" : "script", + dataType: "text", cache: true }).then(cb); + } else { + // Always load JavaScript with script tag to avoid Content Security Policy inline violations + loadWithTag(cdnUrl, cb); } }); } diff --git a/test/javascripts/lib/load-script-test.js.es6 b/test/javascripts/lib/load-script-test.js.es6 new file mode 100644 index 00000000000..d5b293daace --- /dev/null +++ b/test/javascripts/lib/load-script-test.js.es6 @@ -0,0 +1,24 @@ +import loadScript from "discourse/lib/load-script"; + +QUnit.module("lib:load-script"); + +QUnit.test( + "load with a script tag, and callbacks are only executed after script is loaded", + async assert => { + const src = "/javascripts/ace/ace.js"; + + await loadScript(src).then(() => { + assert.ok( + typeof ace !== "undefined", + "callbacks should only be executed after the script has fully loaded" + ); + + // cannot use the `find` test helper here because the script tag is injected outside of the test sandbox frame + const scriptTags = Array.from(document.getElementsByTagName("script")); + assert.ok( + scriptTags.some(scriptTag => scriptTag.src.includes(src)), + "the script should be loaded with a script tag" + ); + }); + } +); diff --git a/test/javascripts/test_helper.js b/test/javascripts/test_helper.js index 42e119cd063..15464f47a7f 100644 --- a/test/javascripts/test_helper.js +++ b/test/javascripts/test_helper.js @@ -52,7 +52,6 @@ window.MessageBus.stop(); // Trick JSHint into allow document.write var d = document; -d.write(''); d.write( '