Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to render linebreaks as <br> tags with Aurelia

I am retrieving some textual data using JSON, this data includes text formatted with linebreaks. I would very much like to render those linebreaks to the user.

Question: What is the "correct" / "recommended" approach to achieve this?

Options I've tried:

  • Binding normally: <p>${myText}</p> : Renders no linebreaks
  • Using <pre>: <p><pre>${myText}></pre></p> : Renders linebreaks, but have all the known and loved issues with long <pre> text, like horizontal scrolling in some browsers and suboptimal word breaking.
  • Binding normally using a valueConverter that replaces linebreaks with <br> tags: <p>${myText | textFormat}</p>
export class TextFormatValueConverter {
  toView(value) {
    return value.replace(new RegExp('\r?\n','g'), '<br>');
  }
}

This does render <br> tags, but the Aurelia binder escapes the tags and shows them as literal text to the user. * Binding using the above converter and innerHTML: <p innerHTML.bind="myText | textFormat"></p>: Renders ok but I'm worried that it might be vulnerable to exploits, as the texts comes from a legacy system that does not do any input sanitazion with regards to usage for the web.

like image 645
Vidar Avatar asked Jan 15 '16 10:01

Vidar


3 Answers

What you're doing is correct. Binding to innerHTML is sometimes necessary. The docs at aurelia.io include instructions for using a sanitization converter and a note about using a more complete implementation using the sanitize-html project.

That said, you can create a really light-weight custom attribute that does only what you need:

http://plnkr.co/edit/qykvo9PKAD0TawTlQ5sp?p=preview

preserve-breaks.js

import {inject} from 'aurelia-framework';

function htmlEncode(html) {
  return document.createElement('a').appendChild( 
    document.createTextNode(html)).parentNode.innerHTML;
}

@inject(Element)
export class PreserveBreaksCustomAttribute {
  constructor(element) {
    this.element = element;
  }

  valueChanged() {
    let html = htmlEncode(this.value);
    html = html.replace(/\r/g, '').replace(/\n/g, '<br/>');
    this.element.innerHTML = html;
  }
}

app.js

export class App {
  message = `this is my text
it has some line breaks
and some <script>evil javascript</script>
the line breaks were replaced with <br/> tags`;
}

app.html

<template>
  <require from="./preserve-breaks"></require>

  <div preserve-breaks.bind="message"></div>
</template>
like image 118
Jeremy Danyow Avatar answered Oct 22 '22 14:10

Jeremy Danyow


The problem is that Aurelia renders your converted HTML as escaped tags. To get around this just use your RegExp function to convert to <br>, then use innerHTML binding like so:

<p innerHTML.bind=“htmlText”>${myText}</p>

This will stop Aurelia from escaping the HTML. I see you're worried about using this approach, as you're afraid there could be bad HTML somewhere, but there's no other way to get around this as you can't tell Aurelia to only render specific tags.

If you're that concerned about the potential for bad HTML, why don't you write a piece of custom JS to unescape all the <br> tags after page load? (Ugly as hell, but I can't see another way.)

like image 36
Chuck Le Butt Avatar answered Oct 22 '22 15:10

Chuck Le Butt


I have found solution on Github : usage of style="white-space: pre-wrap;" on parent element fixes issue.

like image 32
szogun1987 Avatar answered Oct 22 '22 15:10

szogun1987