refactor HTML module; add functionality to Ox.parseMarkdown; add tests
This commit is contained in:
parent
d6b86b518b
commit
3683bf3d29
1 changed files with 103 additions and 85 deletions
|
@ -26,67 +26,50 @@
|
||||||
].join('|') + ')\\/?>', 'gi')
|
].join('|') + ')\\/?>', 'gi')
|
||||||
},
|
},
|
||||||
replace = {
|
replace = {
|
||||||
mail: [
|
a: [
|
||||||
/\b([0-9A-Z\.\+\-_]+@(?:[0-9A-Z\-]+\.)+[A-Z]{2,6})\b/gi, '$1'
|
[
|
||||||
/*
|
/<a [^<>]*?href="((\/|https?:\/\/|mailto:).+?)".*?>/gi,
|
||||||
function(match, mail) {
|
'<a href="{1}">',
|
||||||
return Ox.encodeEmailAddress(mail);
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
],
|
|
||||||
namedEntity: [
|
|
||||||
new RegExp('(' + Ox.values(htmlEntities).join('|') + ')', 'g'),
|
|
||||||
function(match) {
|
|
||||||
return Ox.keyOf(htmlEntities, match);
|
|
||||||
}
|
|
||||||
],
|
|
||||||
numericEntity: [
|
|
||||||
/&#([0-9A-FX]+);/gi,
|
|
||||||
function(match, code) {
|
|
||||||
return Ox.char(
|
|
||||||
/^X/i.test(code)
|
|
||||||
? parseInt(code.slice(1), 16)
|
|
||||||
: parseInt(code, 10)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
],
|
|
||||||
tag: {
|
|
||||||
a: [
|
|
||||||
[
|
|
||||||
/<a [^<>]*?href="((\/|https?:\/\/|mailto:).+?)".*?>/gi,
|
|
||||||
'<a href="{1}">',
|
|
||||||
],
|
|
||||||
[
|
|
||||||
/<\/a>/gi,
|
|
||||||
'</a>'
|
|
||||||
]
|
|
||||||
],
|
],
|
||||||
img: [
|
[
|
||||||
[
|
/<\/a>/gi,
|
||||||
/<img [^<>]*?src="((\/|https?:\/\/).+?)".*?>/gi,
|
'</a>'
|
||||||
'<img src="$1">'
|
]
|
||||||
]
|
],
|
||||||
|
img: [
|
||||||
|
[
|
||||||
|
/<img [^<>]*?src="((\/|https?:\/\/).+?)".*?>/gi,
|
||||||
|
'<img src="$1">'
|
||||||
|
]
|
||||||
|
],
|
||||||
|
rtl: [
|
||||||
|
[
|
||||||
|
/<rtl>/gi,
|
||||||
|
'<div style="direction: rtl">'
|
||||||
],
|
],
|
||||||
rtl: [
|
[
|
||||||
|
/<\/rtl>/gi,
|
||||||
|
'</div>'
|
||||||
|
]
|
||||||
|
],
|
||||||
|
'*': function(tag) {
|
||||||
|
return [
|
||||||
[
|
[
|
||||||
/<rtl>/gi,
|
new RegExp('</?' + tag + ' ?/?>', 'gi'),
|
||||||
'<div style="direction: rtl">'
|
'{0}'
|
||||||
],
|
|
||||||
[
|
|
||||||
/<\/rtl>/gi,
|
|
||||||
'</div>'
|
|
||||||
]
|
]
|
||||||
],
|
];
|
||||||
'*': function(tag) {
|
}
|
||||||
return [
|
},
|
||||||
[
|
salt = Ox.range(2).map(function(){
|
||||||
new RegExp('</?' + tag + ' ?/?>', 'gi'),
|
return Ox.range(16).map(function() {
|
||||||
'{0}'
|
return Ox.char(65 + Ox.random(26));
|
||||||
]
|
}).join('');
|
||||||
];
|
});
|
||||||
}
|
|
||||||
},
|
function addLinks(string, obfuscate) {
|
||||||
url: [
|
return string
|
||||||
|
.replace(
|
||||||
/\b((https?:\/\/|www\.).+?)([\.,:;!\?\)\]]*?(\s|$))/gi,
|
/\b((https?:\/\/|www\.).+?)([\.,:;!\?\)\]]*?(\s|$))/gi,
|
||||||
function(match, url, prefix, end) {
|
function(match, url, prefix, end) {
|
||||||
prefix = prefix.toLowerCase() == 'www.' ? 'http://' : '';
|
prefix = prefix.toLowerCase() == 'www.' ? 'http://' : '';
|
||||||
|
@ -95,13 +78,34 @@
|
||||||
{end: end, prefix: prefix, url: url}
|
{end: end, prefix: prefix, url: url}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
]
|
)
|
||||||
},
|
.replace(
|
||||||
salt = Ox.range(2).map(function(){
|
/\b([0-9A-Z\.\+\-_]+@(?:[0-9A-Z\-]+\.)+[A-Z]{2,6})\b/gi,
|
||||||
return Ox.range(16).map(function() {
|
obfuscate ? function(match, mail) {
|
||||||
return Ox.char(65 + Ox.random(26));
|
return Ox.encodeEmailAddress(mail);
|
||||||
}).join('');
|
} : '<a href="mailto:$1">$1</a>'
|
||||||
});
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function decodeHTMLEntities(string) {
|
||||||
|
return string
|
||||||
|
.replace(
|
||||||
|
new RegExp('(' + Ox.values(htmlEntities).join('|') + ')', 'g'),
|
||||||
|
function(match) {
|
||||||
|
return Ox.keyOf(htmlEntities, match);
|
||||||
|
}
|
||||||
|
)
|
||||||
|
.replace(
|
||||||
|
/&#([0-9A-FX]+);/gi,
|
||||||
|
function(match, code) {
|
||||||
|
return Ox.char(
|
||||||
|
/^X/i.test(code)
|
||||||
|
? parseInt(code.slice(1), 16)
|
||||||
|
: parseInt(code, 10)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
// Splits a string into text (even indices) and tags (odd indices), ignoring
|
// Splits a string into text (even indices) and tags (odd indices), ignoring
|
||||||
// tags with starting positions that are included in the ignore array
|
// tags with starting positions that are included in the ignore array
|
||||||
|
@ -136,11 +140,6 @@
|
||||||
@*/
|
@*/
|
||||||
Ox.addLinks = function(string, isHTML) {
|
Ox.addLinks = function(string, isHTML) {
|
||||||
var isLink = false;
|
var isLink = false;
|
||||||
function replaceString(string) {
|
|
||||||
return string
|
|
||||||
.replace(replace.mail[0], replace.mail[1])
|
|
||||||
.replace(replace.url[0], replace.url[1]);
|
|
||||||
}
|
|
||||||
return isHTML
|
return isHTML
|
||||||
? splitHTMLTags(string).map(function(string, i) {
|
? splitHTMLTags(string).map(function(string, i) {
|
||||||
var isTag = i % 2;
|
var isTag = i % 2;
|
||||||
|
@ -151,9 +150,9 @@
|
||||||
isLink = false;
|
isLink = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return isTag || isLink ? string : replaceString(string);
|
return isTag || isLink ? string : addLinks(string);
|
||||||
}).join('')
|
}).join('')
|
||||||
: Ox.normalizeHTML(replaceString(string));
|
: Ox.normalizeHTML(addLinks(string));
|
||||||
};
|
};
|
||||||
|
|
||||||
/*@
|
/*@
|
||||||
|
@ -224,9 +223,7 @@
|
||||||
Ox.decodeHTMLEntities = function(string, decodeAll) {
|
Ox.decodeHTMLEntities = function(string, decodeAll) {
|
||||||
return decodeAll
|
return decodeAll
|
||||||
? Ox.decodeHTMLEntities(Ox.normalizeHTML(string))
|
? Ox.decodeHTMLEntities(Ox.normalizeHTML(string))
|
||||||
: String(string)
|
: decodeHTMLEntities(string);
|
||||||
.replace(replace.namedEntity[0], replace.namedEntity[1])
|
|
||||||
.replace(replace.numericEntity[0], replace.numericEntity[1]);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/*@
|
/*@
|
||||||
|
@ -360,10 +357,20 @@
|
||||||
[example](http://example.com "example.com") -> <a href="http://example.com" title="example.com">example</a>
|
[example](http://example.com "example.com") -> <a href="http://example.com" title="example.com">example</a>
|
||||||
> Ox.parseMarkdown('*foo* **bar** `baz` ``back`tick``')
|
> Ox.parseMarkdown('*foo* **bar** `baz` ``back`tick``')
|
||||||
'<em>foo</em> <strong>bar</strong> <code>baz</code> <code>back`tick</code>'
|
'<em>foo</em> <strong>bar</strong> <code>baz</code> <code>back`tick</code>'
|
||||||
|
> Ox.parseMarkdown('<http://example.com>')
|
||||||
|
'<a href="http://example.com">http://example.com</a>'
|
||||||
> Ox.parseMarkdown('[example](http://example.com "example.com")')
|
> Ox.parseMarkdown('[example](http://example.com "example.com")')
|
||||||
'<a href="http://example.com" title="example.com">example</a>'
|
'<a href="http://example.com" title="example.com">example</a>'
|
||||||
> Ox.parseMarkdown('[example](http://example.com?foo=bar&bar=baz)')
|
> Ox.parseMarkdown('[example](http://example.com?foo=bar&bar=baz)')
|
||||||
'<a href="http://example.com?foo=bar&bar=baz">example</a>'
|
'<a href="http://example.com?foo=bar&bar=baz">example</a>'
|
||||||
|
> Ox(Ox.parseMarkdown('<mail@example.com>')).startsWith('<a href="')
|
||||||
|
true
|
||||||
|
> Ox(Ox.parseMarkdown('<mail@example.com>')).endsWith('</a>')
|
||||||
|
true
|
||||||
|
> Ox(Ox.parseMarkdown('<mail@example.com>')).count(':')
|
||||||
|
1
|
||||||
|
> Ox(Ox.parseMarkdown('<mail@example.com>')).decodeHTMLEntities()
|
||||||
|
'<a href="mailto:mail@example.com">mail@example.com</a>'
|
||||||
*/
|
*/
|
||||||
Ox.parseMarkdown = function(string) {
|
Ox.parseMarkdown = function(string) {
|
||||||
// see https://github.com/coreyti/showdown/blob/master/src/showdown.js
|
// see https://github.com/coreyti/showdown/blob/master/src/showdown.js
|
||||||
|
@ -379,24 +386,35 @@
|
||||||
)
|
)
|
||||||
.replace(
|
.replace(
|
||||||
/\n```(.*)\n([^`]+)\n```/g,
|
/\n```(.*)\n([^`]+)\n```/g,
|
||||||
function(match, a, b) {
|
function(match, classname, code) {
|
||||||
return '<pre><code' + (a ? ' class="' + a + '"' : '') + '>'
|
return '<pre><code'
|
||||||
+ b + '\n</code></pre>';
|
+ (classname ? ' class="' + classname + '"' : '')
|
||||||
|
+ '>' + code + '\n</code></pre>';
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
.replace(
|
.replace(
|
||||||
/(^|[^\\])(`+)([^\r]*?[^`])\2(?!`)/gm,
|
/(^|[^\\])(`+)([^\r]*?[^`])\2(?!`)/gm,
|
||||||
function(match, a, b, c, d) {
|
function(match, prev, backticks, code, next) {
|
||||||
return a + '<code>'
|
return prev + '<code>'
|
||||||
+ Ox.encodeHTMLEntities(c.trim()) + '</code>';
|
+ Ox.encodeHTMLEntities(code.trim()) + '</code>';
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
.replace(
|
.replace(
|
||||||
/(\[((?:\[[^\]]*\]|[^\[\]])*)\]\([ \t]*()<?(.*?)>?[ \t]*((['"])(.*?)\6[ \t]*)?\))/g,
|
/(\[((?:\[[^\]]*\]|[^\[\]])*)\]\([ \t]*()<?(.*?)>?[ \t]*((['"])(.*?)\6[ \t]*)?\))/g,
|
||||||
function(match, a, b, c, d, e, f, g) {
|
function(match, all, text, id, url, rest, quote, title) {
|
||||||
return '<a href="' + Ox.encodeHTMLEntities(d) + '"' + (
|
return '<a href="' + Ox.encodeHTMLEntities(url) + '"' + (
|
||||||
g ? ' title="' + Ox.encodeHTMLEntities(g) + '"' : ''
|
title ? ' title="' + Ox.encodeHTMLEntities(title) + '"' : ''
|
||||||
) + '>' + b + '</a>';
|
) + '>' + text + '</a>';
|
||||||
|
}
|
||||||
|
)
|
||||||
|
.replace(
|
||||||
|
/<((https?|ftp|dict):[^'">\s]+)>/gi,
|
||||||
|
'<a href=\"$1\">$1</a>'
|
||||||
|
)
|
||||||
|
.replace(
|
||||||
|
/<(?:mailto:)?([-.\w]+\@[-a-z0-9]+(\.[-a-z0-9]+)*\.[a-z]+)>/gi,
|
||||||
|
function(match, mail) {
|
||||||
|
return Ox.encodeEmailAddress(mail);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -447,7 +465,7 @@
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
tags.forEach(function(tag) {
|
tags.forEach(function(tag) {
|
||||||
var array = replace.tag[tag] || replace.tag['*'](tag);
|
var array = replace[tag] || replace['*'](tag);
|
||||||
Ox.forEach(array, function(value) {
|
Ox.forEach(array, function(value) {
|
||||||
html = html.replace(value[0], function() {
|
html = html.replace(value[0], function() {
|
||||||
matches.push(Ox.formatString(value[1], arguments));
|
matches.push(Ox.formatString(value[1], arguments));
|
||||||
|
|
Loading…
Reference in a new issue