diff --git a/app/assets/javascripts/admin/helpers/check-icon.js b/app/assets/javascripts/admin/helpers/check-icon.js index 88cddc3d4dc..4641a15fa2a 100644 --- a/app/assets/javascripts/admin/helpers/check-icon.js +++ b/app/assets/javascripts/admin/helpers/check-icon.js @@ -1,7 +1,8 @@ import { registerUnbound } from "discourse-common/lib/helpers"; import { renderIcon } from "discourse-common/lib/icon-library"; +import { htmlSafe } from "@ember/template"; registerUnbound("check-icon", function(value) { let icon = value ? "check" : "times"; - return new Handlebars.SafeString(renderIcon("string", icon)); + return htmlSafe(renderIcon("string", icon)); }); diff --git a/app/assets/javascripts/admin/mixins/setting-component.js b/app/assets/javascripts/admin/mixins/setting-component.js index 200ec00c1f8..e7afc119f27 100644 --- a/app/assets/javascripts/admin/mixins/setting-component.js +++ b/app/assets/javascripts/admin/mixins/setting-component.js @@ -7,6 +7,7 @@ import Mixin from "@ember/object/mixin"; import showModal from "discourse/lib/show-modal"; import { Promise } from "rsvp"; import { ajax } from "discourse/lib/ajax"; +import { htmlSafe } from "@ember/template"; const CUSTOM_TYPES = [ "bool", @@ -63,7 +64,7 @@ export default Mixin.create({ } let preview = setting.get("preview"); if (preview) { - return new Handlebars.SafeString( + return htmlSafe( "
" + preview.replace(/\{\{value\}\}/g, value) + "
" diff --git a/app/assets/javascripts/discourse-common/addon/helpers/d-icon.js b/app/assets/javascripts/discourse-common/addon/helpers/d-icon.js index 454bb224b06..97f93273d95 100644 --- a/app/assets/javascripts/discourse-common/addon/helpers/d-icon.js +++ b/app/assets/javascripts/discourse-common/addon/helpers/d-icon.js @@ -1,6 +1,7 @@ import { registerUnbound } from "discourse-common/lib/helpers"; import { renderIcon } from "discourse-common/lib/icon-library"; +import { htmlSafe } from "@ember/template"; registerUnbound("d-icon", function(id, params) { - return new Handlebars.SafeString(renderIcon("string", id, params)); + return htmlSafe(renderIcon("string", id, params)); }); diff --git a/app/assets/javascripts/discourse-common/addon/helpers/fa-icon.js b/app/assets/javascripts/discourse-common/addon/helpers/fa-icon.js index 1d657d086f1..12b1823cede 100644 --- a/app/assets/javascripts/discourse-common/addon/helpers/fa-icon.js +++ b/app/assets/javascripts/discourse-common/addon/helpers/fa-icon.js @@ -1,6 +1,7 @@ import { registerUnbound } from "discourse-common/lib/helpers"; import { renderIcon } from "discourse-common/lib/icon-library"; import deprecated from "discourse-common/lib/deprecated"; +import { htmlSafe } from "@ember/template"; export function iconHTML(id, params) { return renderIcon("string", id, params); @@ -8,5 +9,5 @@ export function iconHTML(id, params) { registerUnbound("fa-icon", function(icon, params) { deprecated("Use `{{d-icon}}` instead of `{{fa-icon}}"); - return new Handlebars.SafeString(iconHTML(icon, params)); + return htmlSafe(iconHTML(icon, params)); }); diff --git a/app/assets/javascripts/discourse-common/addon/lib/helpers.js b/app/assets/javascripts/discourse-common/addon/lib/helpers.js index 0f87040d953..759cc8995ad 100644 --- a/app/assets/javascripts/discourse-common/addon/lib/helpers.js +++ b/app/assets/javascripts/discourse-common/addon/lib/helpers.js @@ -1,6 +1,7 @@ import { get } from "@ember/object"; import Helper from "@ember/component/helper"; import RawHandlebars from "discourse-common/lib/raw-handlebars"; +import { htmlSafe } from "@ember/template"; export function makeArray(obj) { if (obj === null || obj === undefined) { @@ -13,7 +14,7 @@ export function htmlHelper(fn) { return Helper.helper(function(...args) { args = args.length > 1 ? args[0].concat({ hash: args[args.length - 1] }) : args; - return new Handlebars.SafeString(fn.apply(this, args) || ""); + return htmlSafe(fn.apply(this, args) || ""); }); } diff --git a/app/assets/javascripts/discourse-common/addon/lib/raw-handlebars.js b/app/assets/javascripts/discourse-common/addon/lib/raw-handlebars.js index ca08cfd476e..6fe75917464 100644 --- a/app/assets/javascripts/discourse-common/addon/lib/raw-handlebars.js +++ b/app/assets/javascripts/discourse-common/addon/lib/raw-handlebars.js @@ -1,7 +1,8 @@ +import Handlebars from "handlebars"; + // This is a mechanism for quickly rendering templates which is Ember aware // templates are highly compatible with Ember so you don't need to worry about calling "get" // and discourseComputed properties function, additionally it uses stringParams like Ember does - const RawHandlebars = Handlebars.create(); function buildPath(blk, args) { diff --git a/app/assets/javascripts/discourse/app/components/create-topics-notice.js b/app/assets/javascripts/discourse/app/components/create-topics-notice.js index 7789ccd2bc4..7db4e65df95 100644 --- a/app/assets/javascripts/discourse/app/components/create-topics-notice.js +++ b/app/assets/javascripts/discourse/app/components/create-topics-notice.js @@ -3,6 +3,7 @@ import { alias } from "@ember/object/computed"; import Component from "@ember/component"; import { observes } from "discourse-common/utils/decorators"; import LivePostCounts from "discourse/models/live-post-counts"; +import { htmlSafe } from "@ember/template"; export default Component.extend({ classNameBindings: ["hidden:hidden", ":create-topics-notice"], @@ -81,7 +82,7 @@ export default Component.extend({ msg = "too_few_posts_notice_MF"; } - return new Handlebars.SafeString( + return htmlSafe( I18n.messageFormat(msg, { requiredTopics: this.requiredTopics, requiredPosts: this.requiredPosts, diff --git a/app/assets/javascripts/discourse/app/helpers/category-link.js b/app/assets/javascripts/discourse/app/helpers/category-link.js index d2141122e5e..7f566b576fa 100644 --- a/app/assets/javascripts/discourse/app/helpers/category-link.js +++ b/app/assets/javascripts/discourse/app/helpers/category-link.js @@ -5,6 +5,7 @@ import { iconHTML } from "discourse-common/lib/icon-library"; import Category from "discourse/models/category"; import Site from "discourse/models/site"; import { escapeExpression } from "discourse/lib/utilities"; +import { htmlSafe } from "@ember/template"; let _renderer = defaultCategoryLinkRenderer; @@ -79,9 +80,7 @@ export function categoryLinkHTML(category, options) { categoryOptions.recursive = true; } } - return new Handlebars.SafeString( - categoryBadgeHTML(category, categoryOptions) - ); + return htmlSafe(categoryBadgeHTML(category, categoryOptions)); } registerUnbound("category-link", categoryLinkHTML); diff --git a/app/assets/javascripts/discourse/app/helpers/custom-html.js b/app/assets/javascripts/discourse/app/helpers/custom-html.js index fc055ee9b99..b9d424a2c9f 100644 --- a/app/assets/javascripts/discourse/app/helpers/custom-html.js +++ b/app/assets/javascripts/discourse/app/helpers/custom-html.js @@ -1,16 +1,17 @@ import PreloadStore from "preload-store"; +import { htmlSafe } from "@ember/template"; let _customizations = {}; export function getCustomHTML(key) { const c = _customizations[key]; if (c) { - return new Handlebars.SafeString(c); + return htmlSafe(c); } const html = PreloadStore.get("customHTML"); if (html && html[key] && html[key].length) { - return new Handlebars.SafeString(html[key]); + return htmlSafe(html[key]); } } diff --git a/app/assets/javascripts/discourse/app/helpers/discourse-tag.js b/app/assets/javascripts/discourse/app/helpers/discourse-tag.js index 1477cf93367..9a560075315 100644 --- a/app/assets/javascripts/discourse/app/helpers/discourse-tag.js +++ b/app/assets/javascripts/discourse/app/helpers/discourse-tag.js @@ -1,6 +1,7 @@ import { registerUnbound } from "discourse-common/lib/helpers"; import renderTag from "discourse/lib/render-tag"; +import { htmlSafe } from "@ember/template"; export default registerUnbound("discourse-tag", function(name, params) { - return new Handlebars.SafeString(renderTag(name, params)); + return htmlSafe(renderTag(name, params)); }); diff --git a/app/assets/javascripts/discourse/app/helpers/discourse-tags.js b/app/assets/javascripts/discourse/app/helpers/discourse-tags.js index 6a7eb5e5c02..ba367e72811 100644 --- a/app/assets/javascripts/discourse/app/helpers/discourse-tags.js +++ b/app/assets/javascripts/discourse/app/helpers/discourse-tags.js @@ -1,6 +1,7 @@ import { registerUnbound } from "discourse-common/lib/helpers"; import renderTags from "discourse/lib/render-tags"; +import { htmlSafe } from "@ember/template"; export default registerUnbound("discourse-tags", function(topic, params) { - return new Handlebars.SafeString(renderTags(topic, params)); + return htmlSafe(renderTags(topic, params)); }); diff --git a/app/assets/javascripts/discourse/app/helpers/format-date.js b/app/assets/javascripts/discourse/app/helpers/format-date.js index fea8f452a70..1cb8c8fbd15 100644 --- a/app/assets/javascripts/discourse/app/helpers/format-date.js +++ b/app/assets/javascripts/discourse/app/helpers/format-date.js @@ -1,5 +1,6 @@ import { registerUnbound } from "discourse-common/lib/helpers"; import { autoUpdatingRelativeAge } from "discourse/lib/formatter"; +import { htmlSafe } from "@ember/template"; /** Display logic for dates. It is unbound in Ember but will use jQuery to @@ -22,7 +23,7 @@ registerUnbound("format-date", function(val, params) { if (val) { var date = new Date(val); - return new Handlebars.SafeString( + return htmlSafe( autoUpdatingRelativeAge(date, { format: format, title: title, diff --git a/app/assets/javascripts/discourse/app/helpers/raw-plugin-outlet.js b/app/assets/javascripts/discourse/app/helpers/raw-plugin-outlet.js index 4aa8484a553..c03b8f66dc7 100644 --- a/app/assets/javascripts/discourse/app/helpers/raw-plugin-outlet.js +++ b/app/assets/javascripts/discourse/app/helpers/raw-plugin-outlet.js @@ -1,10 +1,11 @@ import { rawConnectorsFor } from "discourse/lib/plugin-connectors"; import RawHandlebars from "discourse-common/lib/raw-handlebars"; +import { htmlSafe } from "@ember/template"; RawHandlebars.registerHelper("raw-plugin-outlet", function(args) { const connectors = rawConnectorsFor(args.hash.name); if (connectors.length) { const output = connectors.map(c => c.template({ context: this })); - return new Handlebars.SafeString(output.join("")); + return htmlSafe(output.join("")); } }); diff --git a/app/assets/javascripts/discourse/app/helpers/raw.js b/app/assets/javascripts/discourse/app/helpers/raw.js index db6b48d3849..f1fb8739273 100644 --- a/app/assets/javascripts/discourse/app/helpers/raw.js +++ b/app/assets/javascripts/discourse/app/helpers/raw.js @@ -1,5 +1,6 @@ import { registerUnbound } from "discourse-common/lib/helpers"; import { findRawTemplate } from "discourse/lib/raw-templates"; +import { htmlSafe } from "@ember/template"; let _injections; @@ -31,7 +32,7 @@ function renderRaw(ctx, container, template, templateName, params) { } } - return new Handlebars.SafeString(template(params)); + return htmlSafe(template(params)); } registerUnbound("raw", function(templateName, params) { diff --git a/app/assets/javascripts/discourse/app/helpers/topic-featured-link.js b/app/assets/javascripts/discourse/app/helpers/topic-featured-link.js index 8316af884d5..ab31cc5ec4e 100644 --- a/app/assets/javascripts/discourse/app/helpers/topic-featured-link.js +++ b/app/assets/javascripts/discourse/app/helpers/topic-featured-link.js @@ -1,6 +1,7 @@ import { registerUnbound } from "discourse-common/lib/helpers"; import renderTopicFeaturedLink from "discourse/lib/render-topic-featured-link"; +import { htmlSafe } from "@ember/template"; export default registerUnbound("topic-featured-link", function(topic, params) { - return new Handlebars.SafeString(renderTopicFeaturedLink(topic, params)); + return htmlSafe(renderTopicFeaturedLink(topic, params)); }); diff --git a/app/assets/javascripts/discourse/app/helpers/topic-link.js b/app/assets/javascripts/discourse/app/helpers/topic-link.js index 44f9d10d54f..bf8004a8885 100644 --- a/app/assets/javascripts/discourse/app/helpers/topic-link.js +++ b/app/assets/javascripts/discourse/app/helpers/topic-link.js @@ -1,4 +1,5 @@ import { registerUnbound } from "discourse-common/lib/helpers"; +import { htmlSafe } from "@ember/template"; registerUnbound("topic-link", (topic, args) => { const title = topic.get("fancyTitle"); @@ -14,5 +15,5 @@ registerUnbound("topic-link", (topic, args) => { const result = `${title}`; - return new Handlebars.SafeString(result); + return htmlSafe(result); }); diff --git a/app/assets/javascripts/discourse/app/helpers/user-avatar.js b/app/assets/javascripts/discourse/app/helpers/user-avatar.js index 9d5f0cdc05b..0421799eceb 100644 --- a/app/assets/javascripts/discourse/app/helpers/user-avatar.js +++ b/app/assets/javascripts/discourse/app/helpers/user-avatar.js @@ -2,6 +2,7 @@ import { get } from "@ember/object"; import { registerUnbound } from "discourse-common/lib/helpers"; import { avatarImg, formatUsername } from "discourse/lib/utilities"; import { prioritizeNameInUx } from "discourse/lib/settings"; +import { htmlSafe } from "@ember/template"; let _customAvatarHelpers; @@ -75,7 +76,7 @@ function renderAvatar(user, options) { } registerUnbound("avatar", function(user, params) { - return new Handlebars.SafeString(renderAvatar.call(this, user, params)); + return htmlSafe(renderAvatar.call(this, user, params)); }); export { renderAvatar }; diff --git a/app/assets/javascripts/discourse/app/lib/text.js b/app/assets/javascripts/discourse/app/lib/text.js index 7f75cb497dc..867ecf9d328 100644 --- a/app/assets/javascripts/discourse/app/lib/text.js +++ b/app/assets/javascripts/discourse/app/lib/text.js @@ -5,6 +5,7 @@ import { sanitize as textSanitize } from "pretty-text/sanitizer"; import loadScript from "discourse/lib/load-script"; import { formatUsername } from "discourse/lib/utilities"; import { Promise } from "rsvp"; +import { htmlSafe } from "@ember/template"; function getOpts(opts) { const siteSettings = Discourse.__container__.lookup("site-settings:main"), @@ -26,7 +27,7 @@ function getOpts(opts) { // Use this to easily create a pretty text instance with proper options export function cook(text, options) { - return new Handlebars.SafeString(createPrettyText(options).cook(text)); + return htmlSafe(createPrettyText(options).cook(text)); } // everything should eventually move to async API and this should be renamed diff --git a/app/assets/javascripts/discourse/app/lib/utilities.js b/app/assets/javascripts/discourse/app/lib/utilities.js index 03ef200016b..b848ca7f862 100644 --- a/app/assets/javascripts/discourse/app/lib/utilities.js +++ b/app/assets/javascripts/discourse/app/lib/utilities.js @@ -1,5 +1,6 @@ import { escape } from "pretty-text/sanitizer"; import toMarkdown from "discourse/lib/to-markdown"; +import Handlebars from "handlebars"; const homepageSelector = "meta[name=discourse_current_homepage]"; diff --git a/app/assets/javascripts/discourse/app/services/logs-notice.js b/app/assets/javascripts/discourse/app/services/logs-notice.js index 7292e4465fc..217e1bad7ff 100644 --- a/app/assets/javascripts/discourse/app/services/logs-notice.js +++ b/app/assets/javascripts/discourse/app/services/logs-notice.js @@ -5,6 +5,7 @@ import discourseComputed, { observes } from "discourse-common/utils/decorators"; import { autoUpdatingRelativeAge } from "discourse/lib/formatter"; +import { htmlSafe } from "@ember/template"; const LOGS_NOTICE_KEY = "logs-notice-text"; @@ -53,7 +54,7 @@ const LogsNotice = EmberObject.extend({ @discourseComputed("text") message(text) { - return new Handlebars.SafeString(text); + return htmlSafe(text); }, @discourseComputed("currentUser") diff --git a/app/assets/javascripts/handlebars-shim.js b/app/assets/javascripts/handlebars-shim.js new file mode 100644 index 00000000000..e01e17c49ee --- /dev/null +++ b/app/assets/javascripts/handlebars-shim.js @@ -0,0 +1,9 @@ +// allow us to import this as a module +if (typeof define !== "undefined") { + define("handlebars", ["exports"], function(__exports__) { + // It might not be defined server side, which is OK for pretty-text + if (typeof Handlebars !== "undefined") { + __exports__.default = Handlebars; + } + }); +} diff --git a/app/assets/javascripts/pretty-text/sanitizer.js b/app/assets/javascripts/pretty-text/sanitizer.js index d17ff4c178f..ceeeeaba9e9 100644 --- a/app/assets/javascripts/pretty-text/sanitizer.js +++ b/app/assets/javascripts/pretty-text/sanitizer.js @@ -24,7 +24,6 @@ function escapeChar(chr) { } export function escape(string) { - // don't escape SafeStrings, since they're already safe if (string === null) { return ""; } else if (!string) { diff --git a/app/assets/javascripts/template_include.js b/app/assets/javascripts/template_include.js index 461d711ea31..e61120646eb 100644 --- a/app/assets/javascripts/template_include.js +++ b/app/assets/javascripts/template_include.js @@ -1 +1,2 @@ //= require handlebars.runtime +//= require handlebars-shim diff --git a/app/assets/javascripts/template_include.js.erb b/app/assets/javascripts/template_include.js.erb deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/config/application.rb b/config/application.rb index 6bd11004ae6..0145ddbe7a0 100644 --- a/config/application.rb +++ b/config/application.rb @@ -171,6 +171,11 @@ module Discourse # the exclusion list does not include hbs so you double compile all this stuff initializer :fix_sprockets_loose_file_searcher, after: :set_default_precompile do |app| app.config.assets.precompile.delete(Sprockets::Railtie::LOOSE_APP_ASSETS) + + # We don't want application from node_modules, only from the root + app.config.assets.precompile.delete(/(?:\/|\\|\A)application\.(css|js)$/) + app.config.assets.precompile += ['application.js'] + start_path = ::Rails.root.join("app/assets").to_s exclude = ['.es6', '.hbs', '.hbr', '.js', '.css', ''] app.config.assets.precompile << lambda do |logical_path, filename| diff --git a/lib/freedom_patches/raw_handlebars.rb b/lib/freedom_patches/raw_handlebars.rb index 1242481f0e7..feaee4d0697 100644 --- a/lib/freedom_patches/raw_handlebars.rb +++ b/lib/freedom_patches/raw_handlebars.rb @@ -16,7 +16,7 @@ class Barber::Precompiler transpiled = transpiler.perform(source) # very hacky but lets us use ES6. I'm ashamed of this code -RW - transpiled = transpiled[0...transpiled.index('export ')] + transpiled = transpiled[transpiled.index('var RawHandlebars = ')...transpiled.index('export ')] @precompiler = StringIO.new <<~END var __RawHandlebars; diff --git a/lib/pretty_text.rb b/lib/pretty_text.rb index 8f260089efe..73c18d0099c 100644 --- a/lib/pretty_text.rb +++ b/lib/pretty_text.rb @@ -76,6 +76,7 @@ module PrettyText ctx.eval("__PRETTY_TEXT = true") ctx_load(ctx, "#{Rails.root}/app/assets/javascripts/discourse-loader.js") + ctx_load(ctx, "#{Rails.root}/app/assets/javascripts/handlebars-shim.js") ctx_load(ctx, "vendor/assets/javascripts/lodash.js") ctx_load_manifest(ctx, "pretty-text-bundle.js") ctx_load_manifest(ctx, "markdown-it-bundle.js")