HEX
Server: Microsoft-IIS/8.5
System: Windows NT YDAWBH120 6.3 build 9600 (Windows Server 2012 R2 Standard Edition) AMD64
User: tentjecom_web (0)
PHP: 7.4.14
Disabled: NONE
Upload Files
File: D:/HostingSpaces/RMourik/bassol.nl/wwwroot/CMSModules/Chat/CMSPages/Scripts/BBCodeParser.js
ChatBBCodeParserObj = function () {

    var that = this,
        urlRegExp = /(^|\s+|\(|\]|=)(((ht|f)tps?:\/\/)|(www\.))[A-Za-z0-9-]+(\.[A-Za-z0-9-]+)*\.[A-Za-z]{2,4}(:[0-9]+)?(\/?|(\/[^\s\[\]]+))?($|\s+|\)|\[|\])/gi;
    urlRegExpValidation = /^(((ht|f)tps?:\/\/)|(www\.))[A-Za-z0-9-]+(\.[A-Za-z0-9-]+)*\.[A-Za-z]{2,4}(:[0-9]+)?(\/?|(\/\S+))?$/i;

    // Returns resolved bbcode (HTML). 
    // If textOnly == true, returns only resolved text without HTML tags 
    // (for test, if message will be empty after it will be resolved or when bbcode is disabled).
    this.ParseBBCode = function (bbcode, textOnly) {
        var parsedCode = that.GetTags(bbcode);
        if (parsedCode.Tags == null) {
            return GetText(bbcode);
        }

        var tags = parsedCode.Tags,
            text = parsedCode.Text,

            html = (text[0] == null) ? "" : GetText(text[0]),
            indText = 1,
            parsedTag,
            stack = new Array();

        for (var indTag = 0; indTag < tags.length; indTag++, indText++) {

            parsedTag = ParseTag(tags[indTag]);

            // Start tag
            if (parsedTag[1] != null) {

                // Special case - image is not pair tag in html
                if ((parsedTag[0] == "[img]") && (tags.length > indTag + 1) && (tags[indTag + 1] == "[/img]")) {
                    parsedTag[2] = text[indText++];
                    indTag++;
                }
                else {
                    if (IsValidStartTag(parsedTag)) {
                        stack.push(parsedTag[1]);
                    }
                }
            }

            // End tag
            else {
                // If end tag is related to the last start tag
                if ((parsedTag[3] != null) && (stack.length > 0) && (parsedTag[3] == stack[stack.length - 1])) {
                    stack.pop();
                }

                // Parsed tag is not related to the last start tag
                else {
                    var stackInd = stack.indexOf(parsedTag[3]);
                    if (stackInd >= 0) {
                        while ((stack.length > 0) && (stack[stack.length - 1] != parsedTag[3])) {
                            html += ResolveTag(CreateEndTag(stack.pop()), textOnly);
                        }
                    }
                    // stack is emty or there is no start tag related to actual end tag, render end tag as text
                    if (stack.length == 0 || stackInd < 0) {
                        html += parsedTag[0];
                        html += (text[indText] == null) ? "" : GetText(text[indText]);
                        continue;
                    }
                }
            }

            html += ResolveTag(parsedTag, textOnly);

            // If URL tag is resolving, then don't try to resolve URL by GetText again
            if (parsedTag[1] == "url") {
                html += (text[indText] == null) ? "" : text[indText];
            }
            else {
                html += (text[indText] == null) ? "" : GetText(text[indText]);
            }
        }

        // End tags missing - create end tags
        if (stack.length > 0) {
            for (var i = stack.length - 1; i >= 0; i--) {
                html += ResolveTag(CreateEndTag(stack[i]), textOnly);
            }
        }
        return html;
    };


    this.ResolveURLs = function (msg) {
        var urls = msg.match(urlRegExp);
        if (urls == null) {
            return msg;
        }
        var output = "",
            start = 0,
            end = 0,
            url = null;

        while ((urls != null) && (urls[0] != null)) {
            url = $cmsj.trim(urls[0]);
            var resolve = true,
                trim = false,
                trimLeft = false,
                trimRigth = false,
                urlLastChar = url[url.length - 1];

            switch (url[0]) {
                case '(':
                    if (urlLastChar == ')') {
                        trim = true;
                    }
                    else {
                        trimLeft = true;
                    }
                    break;
                case ']':
                    if (urlLastChar == '[') {
                        trim = true;
                    }
                    else {
                        trimLeft = true;
                    }
                    break;
                case '=':
                    if (urlLastChar == ']') {
                        trim = true;
                    }
                    else {
                        resolve = false;
                    }
                    break;
            }

            if (!trim && !trimLeft && resolve) {
                switch (urlLastChar) {
                    case ')':
                    case '[':
                        trimRigth = true;
                        break;
                }
            }

            if (trim) {
                url = url.substring(1, url.length - 1);
            }
            else if (trimLeft) {
                url = url.substring(1, url.length);
            }
            else if (trimRigth) {
                url = url.substring(0, url.length - 1);
            }

            var protocol = url.match(/^www.\S+/) ? "http://" : "";
            end = msg.indexOf(url, start);

            if (resolve) {
                output += msg.substring(start, end) + '<a class="ChatBBCodeUrl" href="' + protocol + url + '" onclick="return !window.open(\'' + protocol + url + '\',\'_blank\',\'\');">' + url + "</a>";
            }
            else {
                output += msg.substring(start, end) + url;
            }

            start = end + url.length;
            urls = msg.substr(start).match(urlRegExp);
        }
        output += msg.substring(start);
        return output;
    };


    function CreateEndTag(tag) {
        var endTag = ParseTag("[" + tag + "]");
        endTag[0] = "[/" + endTag[1] + "]";
        return endTag;
    };


    function GetText(text) {
        if (ChatManager.Settings.ResolveURLEnabled) {
            return that.ResolveURLs(text);
        }
        return text;
    }


    function IsValidStartTag(parsedTag) {
        switch (parsedTag[1]) {
            case "b":
            case "i":
            case "u":
            case "s":
            case "quote":
            case "code":
                if (parsedTag[2] != null) {
                    return false;
                }
                return true;
                break;
            case "url":
            case "color":
                if (parsedTag[2] != null) {
                    return true;
                }
        }
        return false;
    };


    function IsValidURL(url) {
        return url.match(urlRegExpValidation) ? true : false;
    };


    function IsValidColor(color) {
        var valid = color.match(/^\w+$/) ? true : false;
        if (!valid) {
            valid = color.match(/^#([0-9A-Fa-f]{3}){1,2}$/) ? true : false;
        }
        return valid;
    };


    function ResolveTag(tagobj, textOnly) {
        if (tagobj == null) {
            return "";
        }
        var resolved = "";
        var isImage = false;
        switch (tagobj[0]) {
            case "[b]":
                resolved = "<strong>";
                break;
            case "[/b]":
                resolved = "</strong>";
                break;
            case "[i]":
                resolved = "<i>";
                break;
            case "[/i]":
                resolved = "</i>";
                break;
            case "[u]":
                resolved = '<span style="text-decoration:underline">';
                break;
            case "[/u]":
                resolved = "</span>";
                break;
            case "[s]":
                resolved = '<s>';
                break;
            case "[/s]":
                resolved = "</s>";
                break;
            case "[quote]":
                resolved = '<span class="ChatBBQuote" style="font-size:0.9em"><i>';
                break;
            case "[/quote]":
                resolved = "</i></span>";
                break;
            case "[code]":
                resolved = '<span class="ChatBBCode" style="font-family:Courier">';
                break;
            case "[/code]":
                resolved = "</span>";
                break;
            case "[/url]":
                resolved = "</a>";
                break;
            case "[/color]":
                resolved = "</span>";
                break;
            case "[img]":
                if (tagobj[2] != null) {
                    var encodedAttr = tagobj[2].replace(/"/g, "%22");
                    resolved = '<img class="ChatBBCodeImg" src="' + encodedAttr + '" alt="' + encodedAttr + '" />';
                    isImage = true;
                }
                break;
            default:
                switch (tagobj[1]) {
                    case "url":
                        if (tagobj[2] != null) {
                            if (IsValidURL(tagobj[2])) {
                                var encodedHref = tagobj[2].replace(/"/g, "%22").replace(/'/g, "%27");
                                resolved = '<a class="ChatBBCodeUrl" href="' + encodedHref + '" onclick="return !window.open(\'' + encodedHref + '\',\'_blank\',\'\');">';
                            }
                            else {
                                resolved = tagobj[2] + " ";
                            }
                        }
                        break;
                    case "color":
                        if ((tagobj[2] != null) && IsValidColor(tagobj[2])) {
                            resolved = '<span class="ChatBBCodeColor" style="color:' + tagobj[2] + '">';
                        }
                        break;
                }
        }
        if (resolved.length > 0) {
            if (textOnly && !isImage) {
                return "";
            }
            return resolved;
        }
        return GetText(tagobj[0]);
    };



    this.GetTags = function (bbcode) {
        var reTags = /\[\s*(?:(?:\w+\s*(?:=[^\]]*)?)|(?:\/\s*\w+))\s*\]/gi;
        return { "Tags": bbcode.match(reTags),
            "Text": cbSplit(bbcode, reTags)
        };
    };


    function ParseTag(tag) {
        var reTag = /\[\s*(?:(?:(\w+)\s*(?:=([^\]]*))?)|(?:\/\s*(\w+)))\s*\]([^\[]*)/gi;
        return reTag.exec(tag);
    };


    /* Cross-Browser Split 1.0.1
    (c) Steven Levithan <stevenlevithan.com>; MIT License
    An ECMA-compliant, uniform cross-browser split method */
    function cbSplit(str, separator, limit) {

        // if `separator` is not a regex, use the native `split`
        if (Object.prototype.toString.call(separator) !== "[object RegExp]") {
            return String.prototype.split(str, separator, limit);
        }

        var output = [],
        lastLastIndex = 0,
        flags = (separator.ignoreCase ? "i" : "") +
                (separator.multiline ? "m" : "") +
                (separator.sticky ? "y" : ""),
        separator = RegExp(separator.source, flags + "g"), // make `global` and avoid `lastIndex` issues by working with a copy
        separator2, match, lastIndex, lastLength,
        _compliantExecNpcg = /()??/.exec("")[1] === undefined, // NPCG: nonparticipating capturing group
        str = str + ""; // type conversion

        if (!_compliantExecNpcg) {
            separator2 = RegExp("^" + separator.source + "$(?!\\s)", flags); // doesn't need /g or /y, but they don't hurt
        }

        /* behavior for `limit`: if it's...
        - `undefined`: no limit.
        - `NaN` or zero: return an empty array.
        - a positive number: use `Math.floor(limit)`.
        - a negative number: no limit.
        - other: type-convert, then use the above rules. */
        if (limit === undefined || +limit < 0) {
            limit = Infinity;
        } else {
            limit = Math.floor(+limit);
            if (!limit) {
                return [];
            }
        }

        while (match = separator.exec(str)) {
            lastIndex = match.index + match[0].length; // `separator.lastIndex` is not reliable cross-browser

            if (lastIndex > lastLastIndex) {
                output.push(str.slice(lastLastIndex, match.index));

                // fix browsers whose `exec` methods don't consistently return `undefined` for nonparticipating capturing groups
                if (!_compliantExecNpcg && match.length > 1) {
                    match[0].replace(separator2, function () {
                        for (var i = 1; i < arguments.length - 2; i++) {
                            if (arguments[i] === undefined) {
                                match[i] = undefined;
                            }
                        }
                    });
                }

                if (match.length > 1 && match.index < str.length) {
                    Array.prototype.push.apply(output, match.slice(1));
                }

                lastLength = match[0].length;
                lastLastIndex = lastIndex;

                if (output.length >= limit) {
                    break;
                }
            }

            if (separator.lastIndex === match.index) {
                separator.lastIndex++; // avoid an infinite loop
            }
        }

        if (lastLastIndex === str.length) {
            if (lastLength || !separator.test("")) {
                output.push("");
            }
        } else {
            output.push(str.slice(lastLastIndex));
        }

        return output.length > limit ? output.slice(0, limit) : output;
    };
    // END Cross-Browser Split 1.0.1

}