summaryrefslogtreecommitdiffstats
path: root/web/react/utils/text_formatting.jsx
blob: 90ff7f41f870dc42fde190b92ab8e80a6ed870a2 (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
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
// Copyright (c) 2015 Spinpunch, Inc. All Rights Reserved.
// See License.txt for license information.

const Constants = require('./constants.jsx');
const UserStore = require('../stores/user_store.jsx');

export function formatText(text, options = {}) {
    let output = sanitize(text);
    let tokens = new Map();

    // TODO strip urls first

    output = stripAtMentions(output, tokens);
    output = stripSelfMentions(output, tokens);

    output = replaceTokens(output, tokens);

    output = replaceNewlines(output, options.singleline);

    return output;

    // TODO autolink urls
    // TODO highlight search terms
    // TODO autolink hashtags

    // TODO leave space for markdown
}

export function sanitize(text) {
    let output = text;

    // normal string.replace only does a single occurrance so use a regex instead
    output = output.replace(/&/g, '&');
    output = output.replace(/</g, '&lt;');
    output = output.replace(/>/g, '&gt;');

    return output;
}

function stripAtMentions(text, tokens) {
    let output = text;

    function stripAtMention(fullMatch, prefix, mention, username) {
        if (Constants.SPECIAL_MENTIONS.indexOf(username) !== -1 || UserStore.getProfileByUsername(username)) {
            const index = tokens.size;
            const alias = `ATMENTION${index}`;

            tokens.set(alias, {
                value: `<a class='mention-link' href='#' data-mention='${username}'>${mention}</a>`,
                originalText: mention
            });

            return prefix + alias;
        } else {
            return fullMatch;
        }
    }

    output = output.replace(/(^|\s)(@([a-z0-9.\-_]+))/gi, stripAtMention);

    return output;
}
window.stripAtMentions = stripAtMentions;

function stripSelfMentions(text, tokens) {
    let output = text;

    let mentionKeys = UserStore.getCurrentMentionKeys();

    // look for any existing tokens which are self mentions and should be highlighted
    var newTokens = new Map();
    for (let [alias, token] of tokens) {
        if (mentionKeys.indexOf(token.originalText) !== -1) {
            const index = newTokens.size;
            const newAlias = `SELFMENTION${index}`;

            newTokens.set(newAlias, {
                value: `<span class='mention-highlight'>${alias}</span>`,
                originalText: token.originalText
            });

            output = output.replace(alias, newAlias);
        }
    }

    // the new tokens are stashed in a separate map since we can't add objects to a map during iteration
    for (let newToken of newTokens) {
        tokens.set(newToken[0], newToken[1]);
    }

    // look for self mentions in the text
    function stripSelfMention(fullMatch, prefix, mention) {
        const index = tokens.size;
        const alias = `SELFMENTION${index}`;

        tokens.set(alias, {
            value: `<span class='mention-highlight'>${mention}</span>`,
            originalText: mention
        });

        return prefix + alias;
    }

    for (let mention of UserStore.getCurrentMentionKeys()) {
        output = output.replace(new RegExp(`(^|\\W)(${mention})\\b`, 'gi'), stripSelfMention);
    }

    return output;
}

function replaceTokens(text, tokens) {
    let output = text;

    // iterate backwards through the map so that we do replacement in the opposite order that we added tokens
    const aliases = [...tokens.keys()];
    for (let i = aliases.length - 1; i >= 0; i--) {
        const alias = aliases[i];
        const token = tokens.get(alias);
        console.log('replacing ' + alias + ' with ' + token.value);
        output = output.replace(alias, token.value);
    }

    return output;
}
window.replaceTokens = replaceTokens;

function replaceNewlines(text, singleline) {
    if (!singleline) {
        return text.replace(/\n/g, '<br />');
    } else {
        return text.replace(/\n/g, ' ');
    }
}