Similar to the last comment in #9874, how does one access Ember.Handlebars.Utils.escapeExpression
in a modern way, without importing all of ember
? I need to escape HTML in my app (because I am decorating some user-input with markup) before marking it as htmlSafe()
and can't find any way of doing so without writing my own escaping function or importing some kind of addon.
@peabnuts123 Have you found an answer yet? Did asking this on the ember community slack or forum help you get any answers to your question?
I found some dialog on this post, https://medium.com/@bradleyscollins/how-does-one-access-ember-handlebars-utils-escapeexpression-ebbe33093186
No, I never did find a satisfactory answer, though I did not post in the Slack or Forum.
I currently have the following in my component
import Ember from 'ember';
const htmlEscape = Ember.Handlebars.Utils.escapeExpression;
so that in the future I may import htmlEscape
properly and remove these lines
@peabnuts123 I found this.
https://github.com/ember-cli/ember-rfc176-data/issues/12#issuecomment-315103656
https://github.com/ember-cli/ember-rfc176-data/pull/18#issuecomment-315105054
Yea, nice links - I had found the same thread in my travels. I think the idea for the future is to import it from Handlebars
directly e.g.
import { htmlEscape } from "Handlebars";
or similar. This has the unfortunate downside of relying on Handlebars to export these functionalities themselves via the module API, which I think we're just kind of "waiting on" at this point
Trying to upgrade an addon to a more recent version of Ember I stumbled upon this issue.
Since we cannot rely on global Ember
variable and Handlebars
is not a valid module, how are we supposed to migrate this particular piece of code?
import Ember from 'ember';
const htmlEscape = Ember.Handlebars.Utils.escapeExpression;
We need this.
Right now you need to either/or:
@rwjblue said:
Closing this for now. If we need to add these API's to HTMLBars in the future, it will be simple.
What about now? Something possible that I should know about?
Is there a resolution on this? It feels like a quintessential util for people who need to process text.
@rwjblue Any thoughts? :)
Folks please see the comment that closed the related PR:
After discussing with the core team today- we've decided to not move forward with this PR because Ember doesn't use it internally, and hasn't for quite some time now- it was always an artifact from Handlebars itself.
The work for the module RFC removed non-Ember re-exports, and authors were advised to import what they need directly from any particular non-Ember module (e.g., rsvp or jQuery). This is still our position.
If you feel like you still have a use case, please submit an RFC.
I am happy with this position / this has been my understanding throughout this issue.
If people find this issue in the future still wanting to access this function - you will need access it from the Handlebars
package directly. However, I think they still have not structured their package as a module i.e. you may need to import all of Handlebars
and then use Handlebars.Utils.escapeExpression.
import Handlebars from 'handlebars';
import { htmlSafe } from '@ember/template';
let userInput = getUserInput(); // Something unsafe, e.g. user-controlled text
let escapedInput = Handlebars.Utils.escapeExpression(userInput); // Escape any HTML in this string so that it will render as <, & etc.
let alteredHtml = escapedInput.replace(/hello/g, '<span class="highlight">hello</span>'); // Add some HTML to the text
let safeHtml = htmlSafe(alteredHtml);
// safeHtml is now safe to render in the DOM
@MelSumner
Ember doesn't use it internally
So I understand this issue is 100% upstream. Out of curiosity, is there something similar'ish that can be done using only Ember utils?
@Redsandro
Something like this should work:
// your-app/utils/misc.js
import { isHTMLSafe } from '@ember/template';
const ESCAPE = {
'&': '&',
'<': '<',
'>': '>',
'"': '"',
"'": ''',
'`': '`',
'=': '=',
};
const BAD_CHARS = /[&<>"'`=]/g;
const POSSIBLE = /[&<>"'`=]/;
let escapeChar = function(chr) {
return ESCAPE[chr];
};
// borrowed from Handlebars.utils.escapeexpression
// https://github.com/emberjs/ember.js/pull/18791
let escapeExpression = function(string) {
if (typeof string !== 'string') {
// don't escape SafeStrings, since they're already safe
if (string && isHTMLSafe(string)) {
return string.toHTML(); // private API, since SafeString isn't public
} else if (string === null) {
return '';
} else if (!string) {
return String(string);
}
// Force a string conversion as this will be done by the append regardless and
// the regex test will do this transparently behind the scenes, causing issues if
// an object's to string has escaped characters in it.
string = String(string);
}
if (!POSSIBLE.test(string)) {
return string;
}
return string.replace(BAD_CHARS, escapeChar);
};
export { escapeExpression as escape };
What about using a dedicated package for this?
sanitize-html supports escaping disallowed tags
dompurify (very similar to sanitize-html) allows you to keep some tags or attributes, or strip out undesired html while leaving the content in place, among many other things. I use dompurify in emberobserver to only allow certain tags to be rendered in addon READMEs and to ensure all links have the correct rel
applied.
@kategengler Those are also good suggestions, but I don't think they interop with SafeString
in Ember. Not needed for all use-cases though.
SafeString is a string marked as safe by the user, it doesn’t do any escaping itself, and it doesn’t have any expectations of what has been escaped, if anything. You can use any escaping library you like. As @MelSumner said, Ember doesn’t use any escaping functions internally anymore.
@pzuraq Yeah, but wouldn't the escaping library need to know if a string is a safe-string or not? To know whether it should, or should not, escape them?
And it seems to me like the SafeString class itself, plus the method toHTML
are private.
This isn't a big problem + I don't mind using private APIs (or perhaps them not being private is my misunderstanding), but it seems to me like making them public would be helpful in the aforementioned regard.
@sandstrom I don't think that the htmlSafe
API is meant to be unwrapped ever, and definitely not mutated. My understanding was that it was meant to only be used at the _edge_ of your state, so once you're actually ready to put a string into the DOM somewhere.
I'll double check to see about that. FWIW, there have also been discussions of having a new htmlSafe
API, one that has some other benefits (for instance, you probably want to be able to do (eq '' someHtmlSafeString)
type checks), so maybe the ability to unwrap and rewrap strings could be added in the future if I'm correct about the current API.
@pzuraq Alright, I'm happy with that! 😄
This isn't by any means a big issue in our application, so it's all good.
Have a great weekend & thanks for all the awsome work you (and others) are doing on Ember! 🏅
(for reference, here is my PR about making escapeExpression
public https://github.com/emberjs/ember.js/pull/18791)
Most helpful comment
We need this.
Right now you need to either/or:
@rwjblue said:
What about now? Something possible that I should know about?