Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Javascript porting from libtext-creolize-perl
/*!
* WikiCreole JavaScript Library v0.0.3 experimental
*
* Copyright 2011, MIZUTANI Tociyuki
* licensed under the GPL Version 2 licenses.
*
* 2011-12-21
*/
function WikiCreole() {}
(function(){
var escape_htmlall = function(s) {
return s.replace(/[\x3c\x3e\x26\x22\x27\x5c]/g, function(c){
return c == '\x3c' ? '\x26lt;'
: c == '\x3e' ? '\x26gt;'
: c == '\x22' ? '\x26quot;'
: c == '\x26' ? '\x26amp;'
: '\x26\x23' + c.charCodeAt(0) + ';';
});
};
var escape_html = function(s) {
return s.replace(/(?:[\x3c\x3e\x22\x27\x5c]|\x26(?:(?:[a-zA-z]\w*|\x23(?:\d{1,10}|x[0-9a-fA-F]{2,8}));)?)/g, function(c){
return c == '\x3c' ? '\x26lt;'
: c == '\x3e' ? '\x26gt;'
: c == '\x22' ? '\x26quot;'
: c == '\x26' ? '\x26amp;'
: c.charAt(0) == '\x26' ? c
: '\x26\x23' + c.charCodeAt(0) + ';';
});
};
var HTMARKUP = {
'<hr>': '<hr />', '</hr>': '\n',
'<table>': '<table>\n<tr>', '</table>': '</tr>\n</table>\n',
'</table><table>': '</tr>\n<tr>',
'<|>': '<td>', '</|>': '</td>', '<|=>': '<th>', '</|=>': '</th>',
'<blockquote>': '<blockquote>\n', '</blockquote>': '</blockquote>\n',
'<ul>': '<ul>\n<li>', '</ul>': '</li>\n</ul>\n',
'</ul><ul>': '</li>\n<li>',
'<ol>': '<ol>\n<li>', '</ol>': '</li>\n</ol>\n',
'</ol><ol>': '</li>\n<li>',
'<dl>': '<dl>\n<dt>', '</dl>': '</dd>\n</dl>\n',
'</dl><dl>': '</dd>\n<dt>',
'<**>': '<strong>', '</**>': '</strong>',
'<//>': '<em>', '<///>': '</em>',
'<##>': '<tt>', '</##>': '</tt>',
'<^^>': '<sup>', '</^^>': '</sup>',
'<,,>': '<sub>', '</,,>': '</sub>',
'<__>': '<span class="underline">', '</__>': '</span>',
};
var markup = function(prev, sign) {
var e = '</' + prev + '>';
var s = '<' + sign + '>';
var joint = e + s;
if (HTMARKUP.hasOwnProperty(joint))
return HTMARKUP[joint];
var result = '';
if (prev)
result += HTMARKUP.hasOwnProperty(e) ? HTMARKUP[e] : (e + '\n');
if (sign)
result += HTMARKUP.hasOwnProperty(s) ? HTMARKUP[s] : s;
return result;
};
var emit_block = function(c, sign, mark) {
var level = mark.length;
var result = '';
var code = c.code;
if (level > 0 && code.length > 0 && code[0][0] == 0)
emit_block(c, '', '');
while (code.length >= 2 && level < code[0][0]) {
if (code[1][0] < level) {
code[0][0] = level;
break;
}
var prev = code.shift()[1];
if (prev)
result += markup(prev, '');
}
if (code.length == 0) {
result += markup('', sign);
code.unshift([level, sign]);
}
else if (code[0][1] && code[0][0] < level) {
result += '\n' + markup('', sign);
code.unshift([level, sign]);
}
else {
result += markup(code[0][1], sign);
code[0] = [level, sign];
}
c.result += result;
return c;
};
var yyinline = function(s, blk) {
var inline = /(?:\[\[[^\]]*(?:\][^\]]+)*\]\]|\{\{\{[^\}]*(?:\}\}?[^\}]+)*\}\}\}+|\{\{[^\}]*(?:\}[^\}]+)*\}\}|<<<[^>]*(?:>>?[^>]+)*>>>|<<[^>]*(?:>[^>]+)*>>|\b(?:f|ht)tps?:\x2f\x2f(?:[A-Za-z0-9\-_~&*+=\x2f.!$\x27\(\),;:@?#]|%[0-9A-Fa-f]{2})+(?:[A-Za-z0-9\-_~&*+=\x2f$@#]|%[0-9A-Fa-f]{2})+|\\\\[\n ]*|[*][*]|\x2f\x2f|##|\^\^|,,|__|~(?:\[\[[^\]]*(?:\][^\]]+)*\]\]|\[+|\{\{\{[^\}]*(?:\}\}?[^\}]+)*\}\}\}+|\{\{[^\}]*(?:\}[^\}]+)*\}\}|\{+|<<<[^>]*(?:>>?[^>]+)*>>>|<<[^>]*(?:>[^>]+)*>>|<+|\b(?:f|ht)tps?:\x2f\x2f(?:[A-Za-z0-9\-_~&*+=\x2f.!$\x27\(\),;:@?#]|%[0-9A-Fa-f]{2})+(?:[A-Za-z0-9\-_~&*+=\x2f$@#]|%[0-9A-Fa-f]{2})+|\\\\|[*][*]|\x2f\x2f|##|\^\^|,,|__|[^\n ]?)|:|\|=?)/gm;
var pos = 0;
var c = {'result': ''};
var phrase_member = {};
var phrase = [];
for (;;) {
var a = inline.exec(s);
if (! a) {
c.result += escape_html(s.slice(pos));
break;
}
c.result += escape_html(s.slice(pos, a.index));
pos = inline.lastIndex;
var sign = a[0];
if (sign.substr(0, 3) == '{{{') {
var m = /^...[ ]*([^ ]*(?:[ ]+[^ ]+)*)[ ]*...$/.exec(sign);
if (m) {
c.result += escape_htmlall(m[1]);
continue;
}
}
else if (sign.substr(0, 2) == '{{') {
var m = /^..[ ]*([^ \|]*(?:[ ]+[^ \|]+)*)[ ]*(?:\|[ ]*([^ ]*(?:[ ]+[^ ]+)*)[ ]*)?..$/.exec(sign);
if (m) {
var src = encodeURI(decodeURI(m[1]));
var alt = m[2] === undefined ? '' : m[2];
c.result += '<img src="' + escape_html(src) + '" alt="'
+ escape_html(alt) + '" />';
continue;
}
}
else if (sign.substr(0, 2) == '[[') {
var m = /^..[ ]*([^ \|]*(?:[ ]+[^ \|]+)*)[ ]*(?:\|[ ]*([^ ]*(?:[ ]+[^ ]+)*)[ ]*)?..$/.exec(sign);
if (m) {
var href = encodeURI(decodeURI(m[1]));
var text = m[2] === undefined ? m[1] : m[2];
if (! (/^(?:ht|f)tps?:\x2f\x2f/.test(href)))
href = 'http://example.net/wiki/' + href;
c.result += '<a href="' + escape_html(href) + '">'
+ escape_html(text) + '</a>';
continue;
}
}
else if (sign.substr(0, 3) == '<<<') {
sign = sign.slice(3, sign.length - 3);
}
else if (sign.substr(0, 2) == '<<') {
sign = sign.slice(2, sign.length - 2);
}
else if (/^(?:ht|f)tp:\x2f\x2f/.test(sign)) {
c.result += '<a href="' + escape_html(sign) + '">'
+ escape_html(sign) + '</a>';
continue;
}
else if (sign.substr(0, 2) == '\\\\') {
c.result += '<br />\n';
continue;
}
else if (sign.substr(0, 1) == '~') {
if (sign != '~')
sign = sign.slice(1);
}
else if (sign == ':') {
if (blk == 'dl') {
c.result += phrase.map(function(x){return HTMARKUP['</' + x + '>']}).join('');
phrase = [];
phrase_member = {};
c.result += '</dt><dd>';
blk = '';
continue;
}
}
else if (sign == '|' || sign == '|=') {
if (blk == 'table' || blk == '|' || blk == '|=') {
if (blk == '|' || blk == '|=') {
c.result += phrase.map(function(x){return HTMARKUP['</' + x + '>']}).join('');
c.result += HTMARKUP['</' + blk + '>'];
}
c.result += HTMARKUP['<' + sign + '>'];
blk = sign;
phrase = [];
phrase_member = {};
continue;
}
}
else if (! phrase_member[sign]) {
phrase_member[sign] = 1;
phrase.unshift(sign);
c.result += HTMARKUP['<' + sign + '>'];
continue
}
else if (phrase[0] == sign) {
phrase_member[sign] = 0;
phrase.shift();
c.result += HTMARKUP['</' + sign + '>'];
continue
}
c.result += escape_html(sign);
}
c.result += phrase.map(function(x){return HTMARKUP['</' + x + '>']}).join('');
if (blk == '|' || blk == '|=')
c.result += HTMARKUP['</' + blk + '>'];
if (blk == 'dl')
c.result += '</dt><dd>';
return c.result;
};
var yyblock = function(s) {
if (s.length > 0 && s.substr(s.length - 1, 1) == '\n')
s += '\n';
else
s += '\n\n';
var pos = 0, eol, epos = s.length;
var capture1 = {'sign': 'p', 'mark': '', 'start': pos, 'end': pos};
var capture2 = {'sign': '', 'mark': '', 'start': pos, 'end': pos};
var c = {'code': [], 'result': ''};
while (pos < epos) {
capture1.start = capture1.end = pos;
while (pos < epos) {
if (pos > 0 && s.charAt(pos - 1) != '\n')
pos = s.indexOf('\n', pos) + 1;
capture1.end = pos;
if (s.substr(pos, 4) == '{{{\n') {
capture2.start = pos + 4;
capture2.end = s.indexOf('\n}}}\n', pos + 2);
if (capture2.end == -1) {
pos = capture1.end + 4;
continue;
}
capture2.sign = 'pre';
capture2.mark = '';
pos = capture2.end + 5;
break;
}
while (s.charAt(pos) == ' ')
++pos;
var mark = s.charAt(pos);
if (mark == '\n') {
capture2.start = capture2.end = pos;
capture2.sign = '';
capture2.mark = '';
++pos;
break;
}
if (s.substr(pos, 4) == '----') {
capture2.start = capture2.end = pos;
pos += 4;
while (s.charAt(pos) == '-')
++pos;
while (s.charAt(pos) == ' ')
++pos;
if (s.charAt(pos) != '\n')
continue;
capture2.sign = 'hr';
capture2.mark = '';
++pos;
break;
}
if (mark == '=') {
capture2.sign = 'heading';
capture2.start = pos;
while (s.charAt(pos) == '=')
++pos;
capture2.mark = s.slice(capture2.start, pos);
while (s.charAt(pos) == ' ')
++pos;
capture2.start = pos;
eol = s.indexOf('\n', pos);
pos = eol - 1;
while (pos >= capture2.start && s.charAt(pos) == ' ')
--pos;
capture2.end = pos + 1;
while (pos >= capture2.start && s.charAt(pos) == '=')
--pos;
if (pos < capture2.start || s.charAt(pos) != '~') {
while (pos >= capture2.start && s.charAt(pos) == ' ')
--pos;
capture2.end = pos + 1;
}
pos = eol + 1;
break;
}
if (mark == '|') {
capture2.sign = 'table';
capture2.mark = '';
capture2.start = pos;
eol = s.indexOf('\n', pos);
pos = eol - 1;
while (pos >= capture2.start && s.charAt(pos) == ' ')
--pos;
capture2.end = pos + 1;
if (pos > capture2.start && s.charAt(pos) == '|') {
--pos;
if (pos < capture2.start || s.charAt(pos) != '~') {
while (pos >= capture2.start && s.charAt(pos) == ' ')
--pos;
capture2.end = pos + 1;
}
}
pos = eol + 1;
break;
}
if (mark == '>' || (capture1.sign != 'dl' && mark == ':')) {
capture2.sign = 'blockquote';
capture2.mark = '';
capture2.start = pos;
if (capture1.sign != 'blockquote')
break;
}
if (mark == '*' || mark == '#' || mark == ';') {
capture2.start = pos;
while (s.charAt(pos) == mark)
++pos;
if (mark != ';') {
var n = pos - capture2.start;
if (n == 2 && capture1.sign != 'ul' && capture1.sign != 'ol')
continue;
}
capture2.sign = mark == '*' ? 'ul' : mark == '#' ? 'ol' : 'dl';
capture2.mark = s.slice(capture2.start, pos);
while (s.charAt(pos) == ' ')
++pos;
capture2.start = pos;
break;
}
pos = s.indexOf('\n', pos) + 1;
}
if (capture1.start < capture1.end) {
if (s.charAt(capture1.end - 1) == '\n')
--capture1.end;
if (capture1.sign == 'p')
emit_block(c, 'p', '');
var data = s.slice(capture1.start, capture1.end);
if (capture1.sign == 'blockquote') {
data = data.replace(/^[ ]*[:>][ ]?/gm, '');
c.result += this.yyblock(data + '\n\n');
}
else {
c.result += yyinline(data, capture1.sign);
}
}
capture1.sign = 'p';
var sign2 = capture2.sign;
if (sign2 == 'heading') {
var n = capture2.mark.length;
n = n > 6 ? 6 : n;
emit_block(c, '', '');
var inline = yyinline(s.slice(capture2.start, capture2.end), sign2);
c.result += '<h' + n + '>' + inline + '</h' + n + '>\n';
continue;
}
emit_block(c, sign2, capture2.mark);
if (sign2 == 'pre') {
var data = s.slice(capture2.start, capture2.end);
data = data.replace(/^[ ]\}\}\}$/gm, '}}}');
c.result += escape_htmlall(data);
}
else if (sign2 == 'table')
c.result += yyinline(s.slice(capture2.start, capture2.end), sign2);
else if (sign2 == 'ul' || sign2 == 'ol')
capture1.sign = sign2;
else if (sign2 == 'dl' || sign2 == 'blockquote')
capture1.sign = sign2;
}
return c.result;
};
WikiCreole.prototype.yyblock = yyblock;
WikiCreole.prototype.to_html = function(text_creole){
return this.pretty_tag(this.yyblock(text_creole));
};
WikiCreole.prototype.pretty_tag = function(s) {
return s.replace(/(<(?!pre|img)\w[^>]*>)[ ]+/g, '$1')
.replace(/[ ]+(<\x2f(?!pre)[^>]*>)/g, '$1');
};
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.