main

mattermost/focalboard

Last updated at: 29/12/2023 09:43

italicStyleStrategy.ts

TLDR

This file defines a function createItalicStyleStrategy that returns an InlineStrategy object for handling the italic style of text in a markdown plugin.

Methods

createItalicStyleStrategy

This method creates an InlineStrategy object that is responsible for finding and styling italic text in a markdown block. It defines regular expressions for different types of italic styles (e.g., *italic*, _italic_, ***bolditalic***, ___bolditalic___, ***italic* and bold**, **bold and *italic***, ___italic_ and bold__, __bold and _italic___). It also handles scenarios where the browser does not support certain regular expression features. The method returns the InlineStrategy object.

END

// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import {InlineStrategy} from '../pluginStrategy'
import findRangesWithRegex from '../utils/findRangesWithRegex'

const createItalicStyleStrategy = (): InlineStrategy => {
    const asteriskDelimitedRegex = '(?<!\\*)(\\*)(?!\\*)(.+?)(?<!\\*)\\*(?!\\*)' // *italic*
    const underscoreDelimitedRegex = '(?<!_)(_)(?!_)(.+?)(?<!_)_(?!_)' // _italic_
    const strongEmphasisRegex = '(\\*\\*\\*|___)(.+?)(\\*\\*\\*|___)' // ***bolditalic*** ___bolditalic___
    const boldWrappedAsteriskRegex =
		'(?<=\\*\\*)(\\*)(?!\\*)(.*?[^\\*]+)(?<!\\*)\\*(?![^\\*]\\*)|(?<!\\*)(\\*)(?!\\*)(.*?[^\\*]+)(?<!\\*)\\*(?=\\*\\*)' // ***italic* and bold** **bold and *italic***
    const boldWrappedUnderscoreRegex =
		'(?<=__)(_)(?!_)(.*?[^_]+)(?<!_)_(?![^_]_)|(?<!_)(_)(?!_)(.*?[^_]+)(?<!_)_(?=__)' // ___italic_ and bold__ __bold and _italic___
    let italicRegex: RegExp
    try {
        italicRegex = new RegExp(
            `${asteriskDelimitedRegex}|${underscoreDelimitedRegex}|${strongEmphasisRegex}|${boldWrappedAsteriskRegex}|${boldWrappedUnderscoreRegex}`,
            'g',
        )
    } catch {
        // Safari (as of 15.2) doesn't support RegEx lookbacks (https://caniuse.com/js-regexp-lookbehind)
        const altAsteriskDelimitedRegex = '([^\\*]|^)(\\*)([^\\*]+)(\\*)(?!\\*)' // *italic*
        const altUnderscoreDelimitedRegex = '([^_]|^)(_)([^_]+)(_)(?!_)' // _italic_
        // TODO: Add support for boldWrappedAsteriskRegex and boldWrappedUnderscoreRegex
        italicRegex = new RegExp(
            `${altAsteriskDelimitedRegex}|${altUnderscoreDelimitedRegex}|${strongEmphasisRegex}`,
            'g',
        )
    }

    const italicDelimiterRegex = /^(\*\*\*|\*|___|_)|(\*\*\*|\*|___|_)$/g

    return {
        style: 'ITALIC',
        delimiterStyle: 'ITALIC-DELIMITER',
        findStyleRanges: (block) => {
            // Return an array of arrays containing start and end indices for ranges of
            // text that should be italicized
            // e.g. [[0,6], [10,20]]
            const text = block.getText()
            const italicRanges = findRangesWithRegex(text, italicRegex)
            return italicRanges
        },
        findDelimiterRanges: (block, styleRanges) => {
            // Find ranges for delimiters at the beginning/end of styled text ranges
            // Returns an array of arrays containing start and end indices for delimiters
            const text = block.getText()
            let italicDelimiterRanges: number[][] = []
            styleRanges.forEach((styleRange) => {
                const delimiterRange = findRangesWithRegex(
                    text.substring(styleRange[0], styleRange[1] + 1),
                    italicDelimiterRegex,
                ).map((indices) => indices.map((x) => x + styleRange[0]))
                italicDelimiterRanges = italicDelimiterRanges.concat(delimiterRange)
            })
            return italicDelimiterRanges
        },
        delimiterStyles: {
            opacity: 0.4,
        },
    }
}

export default createItalicStyleStrategy