diff --git a/kitsune/sumo/static/sumo/js/upload.js b/kitsune/sumo/static/sumo/js/upload.js index 98410880e..5fc0f4c11 100644 --- a/kitsune/sumo/static/sumo/js/upload.js +++ b/kitsune/sumo/static/sumo/js/upload.js @@ -1,3 +1,15 @@ +function dialogSet(inner, title) { + var kbox = new KBox($('

').text(inner), { + title: title, + destroy: true, + closeOnOutClick: true, + modal: true, + id: 'upload-dialog', + container: $('body') + }); + kbox.open(); +} + $(document).ready(function () { var UPLOAD = { max_filename_length: 80, // max filename length in characters @@ -6,18 +18,6 @@ $(document).ready(function () { error_login: gettext('Please check you are logged in, and try again.') }; - function dialogSet(inner, title) { - var kbox = new KBox($('

').text(inner), { - title: title, - destroy: true, - closeOnOutClick: true, - modal: true, - id: 'upload-dialog', - container: $('body') - }); - kbox.open(); - } - $('input.delete', 'div.attachments-list').each(function () { var $form = $(this).closest('form'); $(this).wrapDeleteInput({ diff --git a/package-lock.json b/package-lock.json index 20329c238..18ca23630 100644 --- a/package-lock.json +++ b/package-lock.json @@ -6776,6 +6776,29 @@ "fill-range": "^2.1.0" } }, + "exports-loader": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/exports-loader/-/exports-loader-3.0.0.tgz", + "integrity": "sha512-b23Yg5SKR63ZvikGrQgfGgwd40MDehaYb7vOXgD7C0fMV04wS8U1I4f7n1j1wEhtQNKUqgdFox/ol2rOruOpOA==", + "dev": true, + "requires": { + "source-map": "^0.6.1" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } + } + }, + "expose-loader": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/expose-loader/-/expose-loader-3.0.0.tgz", + "integrity": "sha512-X7ncrzmiQbJHOyLwuymECHk4NYvoPFwnsINMYFaRrm4fxuxR59hV1v65bho3TpIoWieP8WZmhz6micKny8orWg==", + "dev": true + }, "ext": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/ext/-/ext-1.4.0.tgz", @@ -8304,6 +8327,24 @@ } } }, + "imports-loader": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/imports-loader/-/imports-loader-3.0.0.tgz", + "integrity": "sha512-PhDB+rxpc95/1cM8ehxWAcuDIDi3eXhqHhax09iyUeAYBJ2bT6QbBp7aDj8IfU9Ns+2l1K226GhoWVAU823CTA==", + "dev": true, + "requires": { + "source-map": "^0.6.1", + "strip-comments": "^2.0.1" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } + } + }, "imurmurhash": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", @@ -15552,6 +15593,12 @@ "is-utf8": "^0.2.0" } }, + "strip-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-comments/-/strip-comments-2.0.1.tgz", + "integrity": "sha512-ZprKx+bBLXv067WTCALv8SSz5l2+XhpYCsVtSqlMnkAXMWDq+/ekVbl1ghqP9rUHTzv6sm/DwCOiYutU/yp1fw==", + "dev": true + }, "strip-eof": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", diff --git a/package.json b/package.json index 8c8742675..a1fc036ad 100644 --- a/package.json +++ b/package.json @@ -74,6 +74,9 @@ "cssnano": "^4.1.10", "eslint": "1.10.3", "html-webpack-plugin": "^5.3.2", + "exports-loader": "^3.0.0", + "expose-loader": "^3.0.0", + "imports-loader": "^3.0.0", "kss": "^3.0.0-beta.25", "mocha": "2.3.2", "mocha-jsdom": "^2.0.0", diff --git a/webpack.config.js b/webpack.config.js index 868845be0..b6a508350 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -2,6 +2,7 @@ const path = require("path"); const entrypoints = require("./webpack/entrypoints"); const entrypointsHtml = require("./webpack/entrypoints-html"); +const globalExposeRules = require("./webpack/global-expose-rules"); module.exports = (env, argv) => { const config = { @@ -25,6 +26,7 @@ module.exports = (env, argv) => { loader: "babel-loader", }, }, + ...globalExposeRules, ], }, entry: entrypoints, diff --git a/webpack/entrypoints.js b/webpack/entrypoints.js index 1dd26b967..b7c955f63 100644 --- a/webpack/entrypoints.js +++ b/webpack/entrypoints.js @@ -25,6 +25,7 @@ module.exports = { "sumo/js/instant_search.es6", "sumo/js/responsive-nav-toggle.js", "sumo/js/profile-avatars.js", + "./webpack/protocol-compat.js", "protocol/js/protocol-base.js", "protocol/js/protocol-utils.js", "protocol/js/protocol-supports.js", diff --git a/webpack/eslintrc.js b/webpack/eslintrc.js index c71ca988d..3c41287ac 100644 --- a/webpack/eslintrc.js +++ b/webpack/eslintrc.js @@ -10,7 +10,7 @@ module.exports = { "no-undef": 2 }, "globals": { - // globals we need to expose in webpack + // globals exposed in webpack/global-expose-rules.js "_": "readonly", "moment": "readonly", "nunjucks": "readonly", diff --git a/webpack/global-expose-rules.js b/webpack/global-expose-rules.js new file mode 100644 index 000000000..d76a75012 --- /dev/null +++ b/webpack/global-expose-rules.js @@ -0,0 +1,92 @@ +// because most of our JS stack was written well before modules were a thing, +// many files place variables in the global scope for other files to use. +// in webpack, unless a file explicitly places a variable under `window.`, +// we have to expose each of these variables manually: +module.exports = [ + // expose these library exports globally: + expose("underscore/underscore.js", "_"), + expose("moment/moment.js", "moment"), + expose("nunjucks/browser/nunjucks-slim.js", "nunjucks"), + expose("codemirror/lib/codemirror.js", "CodeMirror"), + expose("../kitsune/sumo/static/sumo/js/libs/rickshaw.js", "Rickshaw"), + expose( + "../kitsune/sumo/static/sumo/js/protocol-details-init.js", + "detailsInit detailsInit" + ), + expose("../kitsune/sumo/static/sumo/js/sumo-tabs.es6", "tabsInit tabsInit"), + // wrap these files to make them behave like an es6 module, exporting the named variable, and expose that globally: + exportAndExpose( + "../kitsune/sumo/static/sumo/js/libs/uitour.js", + "Mozilla.UITour" + ), + exportAndExpose("../kitsune/sumo/static/sumo/js/analytics.js", "trackEvent"), + exportAndExpose( + "../kitsune/sumo/static/sumo/js/dnt-helper.js", + "_dntEnabled" + ), + exportAndExpose( + "../kitsune/sumo/static/sumo/js/libs/django/urlify.js", + "URLify" + ), + exportAndExpose("../kitsune/sumo/static/sumo/js/upload.js", "dialogSet"), + // making jquery and jquery-ui play nice, and exposed globally is a bit difficult, but this works: + { + test: require.resolve("jquery"), + loader: "exports-loader", + options: { + type: "module", + exports: "default $", + }, + }, + { + test: require.resolve("../kitsune/sumo/static/sumo/js/jquery-ui-custom.js"), + loader: "exports-loader", + options: { + type: "module", + exports: "default $", + }, + }, + // this library attempts to expose a bunch of stuff globally by adding them to `this`, imports-loader makes that work: + { + test: require.resolve( + "../kitsune/sumo/static/sumo/js/libs/diff_match_patch_uncompressed.js" + ), + loader: "imports-loader", + options: { + wrapper: "window", + }, + }, +]; + +function expose(path, exposes) { + // expose a module's export globally + return { + test: require.resolve(path), + loader: "expose-loader", + options: { + exposes, + }, + }; +} + +function exportAndExpose(path, funcName) { + // export a function or variable from a module, and expose it globally + return { + test: require.resolve(path), + use: [ + { + loader: "expose-loader", + options: { + exposes: `${funcName} default`, + }, + }, + { + loader: "exports-loader", + options: { + type: "module", + exports: `default ${funcName}`, + }, + }, + ], + }; +} diff --git a/webpack/protocol-compat.js b/webpack/protocol-compat.js new file mode 100644 index 000000000..331369223 --- /dev/null +++ b/webpack/protocol-compat.js @@ -0,0 +1,2 @@ +// Necessary until we upgrade protocol to include this fix: https://github.com/mozilla/protocol/issues/687 +window.Mzp = {};