mirror of
https://github.com/pierre42100/ComunicWeb
synced 2024-11-22 20:19:21 +00:00
153 lines
5.2 KiB
JavaScript
153 lines
5.2 KiB
JavaScript
/*
|
|
* Javascript BBCode Parser
|
|
* @author Philip Nicolcev
|
|
* @license MIT License
|
|
*/
|
|
|
|
var BBCodeParser = (function(parserTags, parserColors) {
|
|
'use strict';
|
|
|
|
var me = {},
|
|
urlPattern = /^(?:https?|file|c):(?:\/{1,3}|\\{1})[-a-zA-Z0-9:;@#%&()~_?\+=\/\\\.]*$/,
|
|
emailPattern = /[^\s@]+@[^\s@]+\.[^\s@]+/,
|
|
fontFacePattern = /^([a-z][a-z0-9_]+|"[a-z][a-z0-9_\s]+")$/i,
|
|
tagNames = [],
|
|
tagNamesNoParse = [],
|
|
regExpAllowedColors,
|
|
regExpValidHexColors = /^#?[a-fA-F0-9]{6}$/,
|
|
ii, tagName, len;
|
|
|
|
// create tag list and lookup fields
|
|
for (tagName in parserTags) {
|
|
if (!parserTags.hasOwnProperty(tagName))
|
|
continue;
|
|
|
|
if (tagName === '*') {
|
|
tagNames.push('\\' + tagName);
|
|
} else {
|
|
tagNames.push(tagName);
|
|
if ( parserTags[tagName].noParse ) {
|
|
tagNamesNoParse.push(tagName);
|
|
}
|
|
}
|
|
|
|
parserTags[tagName].validChildLookup = {};
|
|
parserTags[tagName].validParentLookup = {};
|
|
parserTags[tagName].restrictParentsTo = parserTags[tagName].restrictParentsTo || [];
|
|
parserTags[tagName].restrictChildrenTo = parserTags[tagName].restrictChildrenTo || [];
|
|
|
|
len = parserTags[tagName].restrictChildrenTo.length;
|
|
for (ii = 0; ii < len; ii++) {
|
|
parserTags[tagName].validChildLookup[ parserTags[tagName].restrictChildrenTo[ii] ] = true;
|
|
}
|
|
len = parserTags[tagName].restrictParentsTo.length;
|
|
for (ii = 0; ii < len; ii++) {
|
|
parserTags[tagName].validParentLookup[ parserTags[tagName].restrictParentsTo[ii] ] = true;
|
|
}
|
|
}
|
|
|
|
regExpAllowedColors = new RegExp('^(?:' + parserColors.join('|') + ')$');
|
|
|
|
/*
|
|
* Create a regular expression that captures the innermost instance of a tag in an array of tags
|
|
* The returned RegExp captures the following in order:
|
|
* 1) the tag from the array that was matched
|
|
* 2) all (optional) parameters included in the opening tag
|
|
* 3) the contents surrounded by the tag
|
|
*
|
|
* @param {type} tagsArray - the array of tags to capture
|
|
* @returns {RegExp}
|
|
*/
|
|
function createInnermostTagRegExp(tagsArray) {
|
|
var openingTag = '\\[(' + tagsArray.join('|') + ')\\b(?:[ =]([\\w"#\\-\\:\\/= ]*?))?\\]',
|
|
notContainingOpeningTag = '((?:(?=([^\\[]+))\\4|\\[(?!\\1\\b(?:[ =](?:[\\w"#\\-\\:\\/= ]*?))?\\]))*?)',
|
|
closingTag = '\\[\\/\\1\\]';
|
|
|
|
return new RegExp( openingTag + notContainingOpeningTag + closingTag, 'i');
|
|
}
|
|
|
|
/*
|
|
* Escape the contents of a tag and mark the tag with a null unicode character.
|
|
* To be used in a loop with a regular expression that captures tags.
|
|
* Marking the tag prevents it from being matched again.
|
|
*
|
|
* @param {type} matchStr - the full match, including the opening and closing tags
|
|
* @param {type} tagName - the tag that was matched
|
|
* @param {type} tagParams - parameters passed to the tag
|
|
* @param {type} tagContents - everything between the opening and closing tags
|
|
* @returns {String} - the full match with the tag contents escaped and the tag marked with \u0000
|
|
*/
|
|
function escapeInnerTags(matchStr, tagName, tagParams, tagContents) {
|
|
tagParams = tagParams || "";
|
|
tagContents = tagContents || "";
|
|
tagContents = tagContents.replace(/\[/g, "[").replace(/\]/g, "]");
|
|
return "[\u0000" + tagName + tagParams + "]" + tagContents + "[/\u0000" + tagName + "]";
|
|
}
|
|
|
|
/*
|
|
* Escape all BBCodes that are inside the given tags.
|
|
*
|
|
* @param {string} text - the text to search through
|
|
* @param {string[]} tags - the tags to search for
|
|
* @returns {string} - the full text with the required code escaped
|
|
*/
|
|
function escapeBBCodesInsideTags(text, tags) {
|
|
var innerMostRegExp;
|
|
if (tags.length === 0 || text.length < 7)
|
|
return text;
|
|
innerMostRegExp = createInnermostTagRegExp(tags);
|
|
while (
|
|
text !== (text = text.replace(innerMostRegExp, escapeInnerTags))
|
|
);
|
|
return text.replace(/\u0000/g,'');
|
|
}
|
|
|
|
/*
|
|
* Process a tag and its contents according to the rules provided in parserTags.
|
|
*
|
|
* @param {type} matchStr - the full match, including the opening and closing tags
|
|
* @param {type} tagName - the tag that was matched
|
|
* @param {type} tagParams - parameters passed to the tag
|
|
* @param {type} tagContents - everything between the opening and closing tags
|
|
* @returns {string} - the fully processed tag and its contents
|
|
*/
|
|
function replaceTagsAndContent(matchStr, tagName, tagParams, tagContents) {
|
|
tagName = tagName.toLowerCase();
|
|
tagParams = tagParams || "";
|
|
tagContents = tagContents || "";
|
|
return parserTags[tagName].openTag(tagParams, tagContents) + (parserTags[tagName].content ? parserTags[tagName].content(tagParams, tagContents) : tagContents) + parserTags[tagName].closeTag(tagParams, tagContents);
|
|
}
|
|
|
|
function processTags(text, tagNames) {
|
|
var innerMostRegExp;
|
|
|
|
if (tagNames.length === 0 || text.length < 7)
|
|
return text;
|
|
|
|
innerMostRegExp = createInnermostTagRegExp(tagNames);
|
|
|
|
while (
|
|
text !== (text = text.replace(innerMostRegExp, replaceTagsAndContent))
|
|
);
|
|
|
|
return text;
|
|
}
|
|
|
|
/*
|
|
* Public Methods and Properties
|
|
*/
|
|
me.process = function(text, config) {
|
|
text = escapeBBCodesInsideTags(text, tagNamesNoParse);
|
|
|
|
return processTags(text, tagNames);
|
|
};
|
|
|
|
me.allowedTags = tagNames;
|
|
me.urlPattern = urlPattern;
|
|
me.emailPattern = emailPattern;
|
|
me.regExpAllowedColors = regExpAllowedColors;
|
|
me.regExpValidHexColors = regExpValidHexColors;
|
|
|
|
return me;
|
|
})(parserTags, parserColors);
|