import { Dict } from "src/util";
var VERSION = '0.4.0';
export interface BBCodeConfig {
showQuotePrefix?: boolean;
classPrefix?: string;
mentionPrefix?: string;
}
// default options
const defaults: BBCodeConfig = {
showQuotePrefix: true,
classPrefix: 'bbcode_',
mentionPrefix: '@'
};
export var version = VERSION;
// copied from here:
// http://blog.mattheworiordan.com/post/13174566389/url-regular-expression-for-links-with-or-without-the had to make an
// update to allow / in the query string, since some sites will have a / there made another update to support colons in
// the query string made another update to disallow an ending dot(.)
var URL_PATTERN = new RegExp("(" // overall match
+ "(" // brackets covering match for protocol (optional) and domain
+ "([A-Za-z]{3,9}:(?:\\/\\/)?)" // allow something@ for email addresses
+ "(?:[\\-;:&=\\+\\$,\\w]+@)?[A-Za-z0-9\\.\\-]+[A-Za-z0-9\\-]"
// anything looking at all like a domain, non-unicode domains
+ "|" // or instead of above
+ "(?:www\\.|[\\-;:&=\\+\\$,\\w]+@)" // starting with something@ or www.
+ "[A-Za-z0-9\\.\\-]+[A-Za-z0-9\\-]" // anything looking at all like a domain
+ ")" // end protocol/domain
+ "(" // brackets covering match for path, query string and anchor
+ "(?:\\/[\\+~%\\/\\.\\w\\-_]*)?" // allow optional /path
+ "\\??(?:[\\-\\+=&;%@\\.\\w_\\/:]*)" // allow optional query string starting with ?
+ "#?(?:[\\.\\!\\/\\\\\\w]*)" // allow optional anchor #anchor
+ ")?" // make URL suffix optional
+ ")");
function doReplace(content: string, matches: Replacement[], options: BBCodeConfig) {
var i, obj, regex, hasMatch, tmp;
// match/replace until we don't change the input anymore
do {
hasMatch = false;
for (i = 0; i < matches.length; ++i) {
obj = matches[i];
regex = new RegExp(obj.e, 'gi');
tmp = content.replace(regex, obj.func.bind(undefined, options));
if (tmp !== content) {
content = tmp;
hasMatch = true;
}
}
} while (hasMatch);
return content;
}
function listItemReplace(options: BBCodeConfig, fullMatch: string, tag: string, value: string) {
console.log(fullMatch);
return '
';
}
export var extractQuotedText = function (value: string, parts?: string[]) {
var quotes = ["\"", "'"], i, quote, nextPart;
for (i = 0; i < quotes.length; ++i) {
quote = quotes[i];
if (value && value[0] === quote) {
value = value.slice(1);
if (value[value.length - 1] !== quote) {
while (parts && parts.length) {
nextPart = parts.shift();
value += " " + nextPart;
if (nextPart[nextPart.length - 1] === quote) {
break;
}
}
}
value = value.replace(new RegExp("[" + quote + "]+$"), '');
break;
}
}
return [value, parts];
};
export var parseParams = function (tagName: string, params: string) {
let paramMap: Dict = {};
if (!params) {
return paramMap;
}
// first, collapse spaces next to equals
params = params.replace(/\s*[=]\s*/g, "=");
let parts = params.split(/\s+/);
while (parts.length) {
let part = parts.shift();
// check if the param itself is a valid url
if (!URL_PATTERN.exec(part)) {
let index = part.indexOf('=');
if (index > 0) {
let rv = extractQuotedText(part.slice(index + 1), parts);
paramMap[part.slice(0, index).toLowerCase()] = rv[0] as string;
parts = rv[1] as string[];
}
else {
let rv = extractQuotedText(part, parts);
paramMap[tagName] = rv[0] as string;
parts = rv[1] as string[];
}
} else {
let rv = extractQuotedText(part, parts);
paramMap[tagName] = rv[0] as string;
parts = rv[1] as string[];
}
}
return paramMap;
};
function tagReplace(options: BBCodeConfig, fullMatch: string, tag: string, params: string, value: string) {
let val: string;
tag = tag.toLowerCase();
let paramsObj = parseParams(tag, params || undefined);
let inlineValue = paramsObj[tag];
switch (tag) {
case 'quote':
val = '
';
case 'url':
return '' + value + '';
case 'email':
return '' + value + '';
case 'anchor':
return '' + value + '';
case 'b':
return '' + value + '';
case 'i':
return '' + value + '';
case 'u':
return '' + value + '';
case 's':
return '' + value + '';
case 'indent':
return '
' + value + '
';
case 'list':
tag = 'ul';
let className = options.classPrefix + 'list';
if (inlineValue && /[1Aa]/.test(inlineValue)) {
tag = 'ol';
if (/1/.test(inlineValue)) {
className += '_numeric';
}
else if (/A/.test(inlineValue)) {
className += '_alpha';
}
else if (/a/.test(inlineValue)) {
className += '_alpha_lower';
}
}
val = '<' + tag + ' class="' + className + '">';
// parse the value
val += doReplace(value, [{ e: '\\[([*])\\]([^\r\n]+)', func: listItemReplace }], options);
return val + '' + tag + '>';
case 'code':
case 'php':
case 'java':
case 'javascript':
case 'cpp':
case 'ruby':
case 'python':
return '
' + value + '
';
case 'highlight':
return '' + value + '';
case 'html':
return value;
case 'mention':
val = '' + (options.mentionPrefix || '') + value + '';
case 'span':
case 'h1':
case 'h2':
case 'h3':
case 'h4':
case 'h5':
case 'h6':
return '<' + tag + '>' + value + '' + tag + '>';
case 'youtube':
return '';
case 'gvideo':
return '