` element is selected,
+ // the HTML within the selection range does not include the `` element itself.
+ // To create a complete code block, wrap the selected content with the `` tags.
+ //
+ // selected contentes => selected contents
+ wrapPreCode(range) {
+ const rangeAncestor = range.commonAncestorContainer;
+
+ let codeElement = null;
+
+ if (rangeAncestor.nodeName == 'CODE') {
+ codeElement = rangeAncestor;
+ } else {
+ codeElement = rangeAncestor.parentElement.closest('code');
+ }
+
+ if (!codeElement) {
+ return range.cloneContents();
+ }
+
+ const pre = document.createElement('pre');
+ const code = codeElement.cloneNode(false);
+
+ code.appendChild(range.cloneContents());
+ pre.appendChild(code);
+
+ return pre;
+ }
+
+ convertHtmlToCommonMark(html) {
+ const turndownService = new TurndownService({
+ codeBlockStyle: 'fenced',
+ headingStyle: 'atx'
+ });
+
+ turndownService.addRule('del', {
+ filter: ['del'],
+ replacement: content => `~~${content}~~`
+ });
+
+ turndownService.addRule('checkList', {
+ filter: node => {
+ return node.type === 'checkbox' && node.parentNode.nodeName === 'LI';
+ },
+ replacement: (content, node) => {
+ return node.checked ? '[x]' : '[ ]';
+ }
+ });
+
+ // Table does not maintain its original format,
+ // and the text within the table is displayed as it is
+ //
+ // | A | B | C |
+ // |---|---|---|
+ // | 1 | 2 | 3 |
+ // =>
+ // A B C
+ // 1 2 3
+ turndownService.addRule('table', {
+ filter: ['td', 'th'],
+ replacement: (content, node) => {
+ const separator = node.parentElement.lastElementChild === node ? '' : ' ';
+ return content + separator;
+ }
+ });
+ turndownService.addRule('tableHeading', {
+ filter: ['thead', 'tbody', 'tfoot', 'tr'],
+ replacement: (content, _node) => content
+ });
+ turndownService.addRule('tableRow', {
+ filter: ['tr'],
+ replacement: (content, _node) => {
+ return content + '\n'
+ }
+ });
+
+ return turndownService.turndown(html);
+ }
+
+ prepareHtml(htmlFragment) {
+ // Remove all anchor elements.
+ // Title1ΒΆ
=> Title1
+ htmlFragment.querySelectorAll('a.wiki-anchor').forEach(e => e.remove());
+
+ // Convert code highlight blocks to CommonMark format code blocks.
+ // =>
+ htmlFragment.querySelectorAll('code[data-language]').forEach(e => {
+ e.classList.replace(e.dataset['language'], 'language-' + e.dataset['language'])
+ });
+
+ return htmlFragment.innerHTML;
+ }
+}
+
+export default class extends Controller {
+ static targets = [ 'content' ];
+
+ quote(event) {
+ const { url, textFormatting } = event.params;
+ const selectedRange = QuoteExtractor.extract(this.contentTarget);
+
+ let formatter;
+
+ if (textFormatting === 'common_mark') {
+ formatter = new QuoteCommonMarkFormatter();
+ } else {
+ formatter = new QuoteTextFormatter();
+ }
+
+ post(url, {
+ body: JSON.stringify({ quote: formatter.format(selectedRange) }),
+ contentType: 'application/json',
+ responseKind: 'script'
+ });
+ }
+}