Welcome to mirror list, hosted at ThFree Co, Russian Federation.

build_html_to_markdown_renderer.js « services « rich_content_editor « components « vue_shared « javascripts « assets « app - gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: 9744e25a8e1e644e366cf2fb14400f4fc3aaaa6e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
/* eslint-disable @gitlab/require-i18n-strings */
import { defaults, repeat } from 'lodash';

const DEFAULTS = {
  subListIndentSpaces: 4,
  unorderedListBulletChar: '-',
  incrementListMarker: false,
  strong: '*',
  emphasis: '_',
};

const countIndentSpaces = text => {
  const matches = text.match(/^\s+/m);

  return matches ? matches[0].length : 0;
};

const buildHTMLToMarkdownRender = (baseRenderer, formattingPreferences = {}) => {
  const {
    subListIndentSpaces,
    unorderedListBulletChar,
    incrementListMarker,
    strong,
    emphasis,
  } = defaults(formattingPreferences, DEFAULTS);
  const sublistNode = 'LI OL, LI UL';
  const unorderedListItemNode = 'UL LI';
  const orderedListItemNode = 'OL LI';
  const emphasisNode = 'EM, I';
  const strongNode = 'STRONG, B';
  const headingNode = 'H1, H2, H3, H4, H5, H6';
  const preCodeNode = 'PRE CODE';

  return {
    TEXT_NODE(node) {
      return baseRenderer.getSpaceControlled(
        baseRenderer.trim(baseRenderer.getSpaceCollapsedText(node.nodeValue)),
        node,
      );
    },
    /*
     * This converter overwrites the default indented list converter
     * to allow us to parameterize the number of indent spaces for
     * sublists.
     *
     * See the original implementation in
     * https://github.com/nhn/tui.editor/blob/master/libs/to-mark/src/renderer.basic.js#L161
     */
    [sublistNode](node, subContent) {
      const baseResult = baseRenderer.convert(node, subContent);
      // Default to 1 to prevent possible divide by 0
      const firstLevelIndentSpacesCount = countIndentSpaces(baseResult) || 1;
      const reindentedList = baseResult
        .split('\n')
        .map(line => {
          const itemIndentSpacesCount = countIndentSpaces(line);
          const nestingLevel = Math.ceil(itemIndentSpacesCount / firstLevelIndentSpacesCount);
          const indentSpaces = repeat(' ', subListIndentSpaces * nestingLevel);

          return line.replace(/^ +/, indentSpaces);
        })
        .join('\n');

      return reindentedList;
    },
    [unorderedListItemNode](node, subContent) {
      const baseResult = baseRenderer.convert(node, subContent);
      const formatted = baseResult.replace(/^(\s*)([*|-])/, `$1${unorderedListBulletChar}`);
      const { attributeDefinition } = node.dataset;

      return attributeDefinition ? `${formatted.trimRight()}\n${attributeDefinition}\n` : formatted;
    },
    [orderedListItemNode](node, subContent) {
      const baseResult = baseRenderer.convert(node, subContent);

      return incrementListMarker ? baseResult : baseResult.replace(/^(\s*)\d+?\./, '$11.');
    },
    [emphasisNode](node, subContent) {
      const result = baseRenderer.convert(node, subContent);

      return result.replace(/(^[*_]{1}|[*_]{1}$)/g, emphasis);
    },
    [strongNode](node, subContent) {
      const result = baseRenderer.convert(node, subContent);
      const strongSyntax = repeat(strong, 2);

      return result.replace(/^[*_]{2}/, strongSyntax).replace(/[*_]{2}$/, strongSyntax);
    },
    [headingNode](node, subContent) {
      const result = baseRenderer.convert(node, subContent);
      const { attributeDefinition } = node.dataset;

      return attributeDefinition ? `${result.trimRight()}\n${attributeDefinition}\n\n` : result;
    },
    [preCodeNode](node, subContent) {
      const isReferenceDefinition = Boolean(node.dataset.sseReferenceDefinition);

      return isReferenceDefinition
        ? `\n\n${node.innerText}\n\n`
        : baseRenderer.convert(node, subContent);
    },
    IMG(node) {
      const { originalSrc } = node.dataset;
      return `![${node.alt}](${originalSrc || node.src})`;
    },
  };
};

export default buildHTMLToMarkdownRender;