Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

how to avoid escaping raw html? #57

Closed
docteurklein opened this issue Jul 4, 2019 · 2 comments
Closed

how to avoid escaping raw html? #57

docteurklein opened this issue Jul 4, 2019 · 2 comments
Labels
help template engine Applies to built-in template engine

Comments

@docteurklein
Copy link

docteurklein commented Jul 4, 2019

hi! amazing lib that is hybrids.

I'm struggling with the tag literals to insert a <mark> tag in some places:

//import { html, define } from "hybrids";
  import { html, define } from 'https://unpkg.com/hybrids@4.0.2/src';
//import lunr from "lunr";

function search(host, event) {
  host.query = event.target.value;
}

const FullTextSearch = {
  indexUrl: "",
  query: "",
  index: async ({ indexUrl }) =>
    lunr.Index.load(await (await fetch(indexUrl)).json()),
  results: async ({ index, query }) => query ? (await index).search(`${query}`) : [],
  render: ({ query, results }) => html`
    <input placeholder="search" type="search" oninput="${search}" />
    <ul>${html.resolve(
      results.then(
        r => html`${r.map(result => html`<li>
            <a href="${result.ref}">${result.ref}</a>
            <article>${html.resolve(fetch(result.ref).then(async content =>
                html`${extract(query, await content.text(), result.matchData.metadata)}`
            ))}</article>
        </li>`)}`
      ).catch(e => html`${e}`),
      html`…`
    )}</ul>
  `
};

function extract(query, content, metadata) {
    let positions = Object.values(metadata).flatMap((term) => Object.values(term).flatMap(t => t.position));
    return positions
        .map(([start, len]) => `[…] ${content.substring(start - 50, start + len + 50)} […]`)
        .map(fragment => fragment.replace(new RegExp(`(${query})`, 'i'), `<mark>$1</mark>`))
    ;
}

define("fulltext-search", FullTextSearch);

Not exactly sure why, but the <mark> markup is displayed as is.
Any idea how I could solve this problem?

Thanks!

@smalluban
Copy link
Contributor

In the documentation of the template engine, you can find a section about values. Because of different reasons expression inside of the element resolves to textContent. If it is the only one expression inside of the element, element.textContent = ... is used, or if it is a concatenation of expression, the engine creates text nodes. Although, you can pass HTML by using innerHTML property of the element, like this:

// Use it with caution, it might open XSS attack
html`<div innerHTML="${htmlCode}"></div>`;

In your example, instead of passing value inside of the <article> element, you should use it when your data resolve in extract function:

function extract(query, content, metadata) {
    let positions = Object.values(metadata).flatMap((term) => Object.values(term).flatMap(t => t.position));
    const html = positions
        .map(([start, len]) => `[…] ${content.substring(start - 50, start + len + 50)} […]`)
        .map(fragment => fragment.replace(new RegExp(`(${query})`, 'i'), `<mark>$1</mark>`));

    return html`<article innerHTML="${html.join('')}"></article`;
}

Because your data is async, you can't pass it directly in your main template. The difference is that <article> element will be rendered when the component receives data, but this is the only way to pass raw html to elements. Still, please be careful, it might open XSS attack.

@smalluban smalluban added help template engine Applies to built-in template engine labels Jul 5, 2019
@docteurklein
Copy link
Author

amazing! thanks. I thought I went all over the docs but seems like I missed that part about values! 🤦‍♂️

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
help template engine Applies to built-in template engine
Development

No branches or pull requests

2 participants