DEV: Convert highlighted-code to glimmer/gjs (#28914)
the radical change in the implementation doesn't stem from the glimmer migration, but rather the fact that previously the component was single-use – changing any of its args didn't (and couldn't) be reflected because hljs was replacing the nodes so all the ember bookkeeping was gone. Co-authored-by: David Taylor <david@taylorhq.com>
This commit is contained in:
parent
7b8343d482
commit
62d00722e1
|
@ -0,0 +1,25 @@
|
|||
import Component from "@glimmer/component";
|
||||
import { service } from "@ember/service";
|
||||
import { modifier } from "ember-modifier";
|
||||
import highlightSyntax from "discourse/lib/highlight-syntax";
|
||||
|
||||
export default class HighlightedCode extends Component {
|
||||
@service session;
|
||||
@service siteSettings;
|
||||
|
||||
highlight = modifier(async (element) => {
|
||||
const code = document.createElement("code");
|
||||
code.classList.add(`lang-${this.args.lang}`);
|
||||
code.textContent = this.args.code;
|
||||
|
||||
const pre = document.createElement("pre");
|
||||
pre.appendChild(code);
|
||||
|
||||
element.replaceChildren(pre);
|
||||
await highlightSyntax(pre, this.siteSettings, this.session);
|
||||
});
|
||||
|
||||
<template>
|
||||
<div {{this.highlight}}></div>
|
||||
</template>
|
||||
}
|
|
@ -1 +0,0 @@
|
|||
<pre><code class="lang-{{this.lang}}">{{this.code}}</code></pre>
|
|
@ -1,11 +0,0 @@
|
|||
import Component from "@ember/component";
|
||||
import { observes, on } from "@ember-decorators/object";
|
||||
import highlightSyntax from "discourse/lib/highlight-syntax";
|
||||
|
||||
export default class HighlightedCode extends Component {
|
||||
@on("didInsertElement")
|
||||
@observes("code")
|
||||
_refresh() {
|
||||
highlightSyntax(this.element, this.siteSettings, this.session);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,63 @@
|
|||
import { tracked } from "@glimmer/tracking";
|
||||
import { render, settled } from "@ember/test-helpers";
|
||||
import { module, test } from "qunit";
|
||||
import { setupRenderingTest } from "discourse/tests/helpers/component-test";
|
||||
import HighlightedCode from "admin/components/highlighted-code";
|
||||
|
||||
module("Integration | Component | highlighted-code", function (hooks) {
|
||||
setupRenderingTest(hooks);
|
||||
|
||||
test("highlighting code", async function (assert) {
|
||||
await render(<template>
|
||||
<HighlightedCode @lang="ruby" @code="def test; end" />
|
||||
</template>);
|
||||
|
||||
assert.dom("code.lang-ruby.hljs .hljs-keyword").hasText("def");
|
||||
});
|
||||
|
||||
test("large code blocks are not highlighted", async function (assert) {
|
||||
const longCodeBlock = "puts a\n".repeat(15000);
|
||||
|
||||
await render(<template>
|
||||
<HighlightedCode @lang="ruby" @code={{longCodeBlock}} />
|
||||
</template>);
|
||||
|
||||
assert.dom("pre code").hasText(longCodeBlock);
|
||||
});
|
||||
|
||||
test("highlighting code with lang=auto", async function (assert) {
|
||||
await render(<template>
|
||||
<HighlightedCode @lang="auto" @code="def test; end" />
|
||||
</template>);
|
||||
|
||||
assert.dom("code.hljs").hasNoClass("lang-auto", "lang-auto is removed");
|
||||
assert.dom("code.hljs").hasClass(/language-/, "language is detected");
|
||||
|
||||
assert
|
||||
.dom("code.hljs")
|
||||
.hasNoAttribute(
|
||||
"data-unknown-hljs-lang",
|
||||
"language is found from language- class"
|
||||
);
|
||||
});
|
||||
|
||||
test("re-highlights the code when it changes", async function (assert) {
|
||||
class State {
|
||||
@tracked code = "def foo; end";
|
||||
}
|
||||
|
||||
const testState = new State();
|
||||
|
||||
await render(<template>
|
||||
<HighlightedCode @lang="ruby" @code={{testState.code}} />
|
||||
{{testState.code}}
|
||||
</template>);
|
||||
|
||||
assert.dom("code.lang-ruby.hljs .hljs-title").hasText("foo");
|
||||
|
||||
testState.code = "def bar; end";
|
||||
await settled();
|
||||
|
||||
assert.dom("code.lang-ruby.hljs .hljs-title").hasText("bar");
|
||||
});
|
||||
});
|
|
@ -1,61 +0,0 @@
|
|||
import { render } from "@ember/test-helpers";
|
||||
import { hbs } from "ember-cli-htmlbars";
|
||||
import { module, test } from "qunit";
|
||||
import highlightSyntax from "discourse/lib/highlight-syntax";
|
||||
import { setupRenderingTest } from "discourse/tests/helpers/component-test";
|
||||
import { query } from "discourse/tests/helpers/qunit-helpers";
|
||||
|
||||
const LONG_CODE_BLOCK = "puts a\n".repeat(15000);
|
||||
|
||||
module("Integration | Component | highlighted-code", function (hooks) {
|
||||
setupRenderingTest(hooks);
|
||||
|
||||
test("highlighting code", async function (assert) {
|
||||
this.set("code", "def test; end");
|
||||
|
||||
await render(hbs`<HighlightedCode @lang="ruby" @code={{this.code}} />`);
|
||||
|
||||
assert.strictEqual(
|
||||
query("code.lang-ruby.hljs .hljs-keyword").innerText.trim(),
|
||||
"def"
|
||||
);
|
||||
});
|
||||
|
||||
test("large code blocks are not highlighted", async function (assert) {
|
||||
this.set("code", LONG_CODE_BLOCK);
|
||||
|
||||
await render(hbs`<HighlightedCode @lang="ruby" @code={{this.code}} />`);
|
||||
|
||||
assert.strictEqual(query("code").innerText.trim(), LONG_CODE_BLOCK.trim());
|
||||
});
|
||||
|
||||
test("highlighting code with lang=auto", async function (assert) {
|
||||
this.set("code", "def test; end");
|
||||
|
||||
await render(hbs`<HighlightedCode @lang="auto" @code={{this.code}} />`);
|
||||
|
||||
const codeElement = query("code.hljs");
|
||||
|
||||
assert.notOk(
|
||||
codeElement.classList.contains("lang-auto"),
|
||||
"lang-auto is removed"
|
||||
);
|
||||
assert.ok(
|
||||
Array.from(codeElement.classList).some((className) => {
|
||||
return className.startsWith("language-");
|
||||
}),
|
||||
"language is detected"
|
||||
);
|
||||
|
||||
await highlightSyntax(
|
||||
codeElement.parentElement, // <pre>
|
||||
this.siteSettings,
|
||||
this.session
|
||||
);
|
||||
|
||||
assert.notOk(
|
||||
codeElement.dataset.unknownHljsLang,
|
||||
"language is found from language- class"
|
||||
);
|
||||
});
|
||||
});
|
Loading…
Reference in New Issue