DEV: Support for import Handlebars from 'handlebars'; (#9600)

* Remove Handlebars.SafeString usage

* DEV: Support for `import Handlebars from 'handlebars'`;

* FIX: Sprockets was broken when `node_modules` was present

By default the old version of sprockets looks for application.js
anywhere, including in a node_modules folder if this exists
(which it will when we move to Ember CLI.)
This commit is contained in:
Robin Ward 2020-04-30 16:41:02 -04:00 committed by GitHub
parent 2cb9e85d14
commit d615de9139
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
27 changed files with 57 additions and 24 deletions

View File

@ -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));
});

View File

@ -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(
"<div class='preview'>" +
preview.replace(/\{\{value\}\}/g, value) +
"</div>"

View File

@ -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));
});

View File

@ -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));
});

View File

@ -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) || "");
});
}

View File

@ -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) {

View File

@ -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,

View File

@ -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);

View File

@ -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]);
}
}

View File

@ -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));
});

View File

@ -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));
});

View File

@ -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,

View File

@ -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(""));
}
});

View File

@ -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) {

View File

@ -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));
});

View File

@ -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 = `<a href='${url}'
class='${classes.join(" ")}'
data-topic-id='${topic.id}'>${title}</a>`;
return new Handlebars.SafeString(result);
return htmlSafe(result);
});

View File

@ -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 };

View File

@ -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

View File

@ -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]";

View File

@ -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")

View File

@ -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;
}
});
}

View File

@ -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) {

View File

@ -1 +1,2 @@
//= require handlebars.runtime
//= require handlebars-shim

View File

@ -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|

View File

@ -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;

View File

@ -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")