twister-html/js/twister_formatpost.js

644 lines
28 KiB
JavaScript
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// twister_formatpost.js
// 2013 Miguel Freitas
//
// Format JSON posts and DMs to HTML.
// format "userpost" to html element
// kind = "original"/"ancestor"/"descendant"
function postToElem( post, kind, promoted ) {
/*
"userpost" :
{
"n" : username,
"k" : seq number,
"t" : "post" / "dm" / "rt"
"msg" : message (post/rt)
"time" : unix utc
"height" : best height at user
"dm" : encrypted message (dm) -opt
"rt" : original userpost - opt
"sig_rt" : sig of rt - opt
"reply" : - opt
{
"n" : reference username
"k" : reference k
}
}
"sig_userpost" : signature by userpost.n
*/
// Obtain data from userpost
var postJson = $.toJSON(post);
var userpost = post["userpost"];
if( "rt" in userpost ) {
var rt = userpost["rt"];
var n = rt["n"];
var k = rt["k"];
var t = rt["time"];
var msg = rt["msg"];
var content_to_rt = $.toJSON(rt);
var content_to_sigrt = userpost["sig_rt"];
var retweeted_by = userpost["n"];
} else {
var n = userpost["n"];
var k = userpost["k"];
var t = userpost["time"];
var msg = userpost["msg"]
var content_to_rt = $.toJSON(userpost);
var content_to_sigrt = post["sig_userpost"];
var retweeted_by = undefined;
}
// Now create the html elements
var elem = $.MAL.getPostTemplate().clone(true);
elem.removeAttr('id')
.addClass(kind)
.attr('data-time', t)
;
if( post['isNew'] )
elem.addClass('new');
var postData = elem.find('.post-data');
postData.addClass(kind)
.attr('data-userpost', postJson)
.attr('data-content_to_rt', content_to_rt)
.attr('data-content_to_sigrt', content_to_sigrt)
.attr('data-screen-name', n)
.attr('data-id', k)
.attr('data-lastk', userpost["lastk"])
.attr('data-text', msg)
;
if( 'reply' in userpost ) {
postData.attr('data-replied-to-screen-name', userpost.reply.n)
.attr('data-replied-to-id', userpost.reply.k)
.find('.post-expand').text(polyglot.t('Show conversation'))
;
} else if ( 'rt' in userpost && 'reply' in userpost.rt ) {
postData.attr('data-replied-to-screen-name', userpost.rt.reply.n)
.attr('data-replied-to-id', userpost.rt.reply.k)
.find('.post-expand').text(polyglot.t('Show conversation'))
;
}
var postInfoName = elem.find('.post-info-name');
postInfoName.text(n).attr('href', $.MAL.userUrl(n));
getFullname( n, postInfoName );
//elem.find('.post-info-tag').text("@" + n);
setPostInfoSent(n,k,elem.find('.post-info-sent'));
getAvatar( n, elem.find('.avatar') );
elem.find('.post-info-time').text(timeGmtToText(t)).attr('title', timeSincePost(t));
var mentions = [];
elem.find('.post-text').html(htmlFormatMsg(msg, mentions));
postData.attr('data-text-mentions', mentions);
var replyTo = '';
if( n !== defaultScreenName )
replyTo += '@' + n + ' ';
for (var i = 0; i < mentions.length; i++) {
if (mentions[i] !== n && mentions[i] !== defaultScreenName)
replyTo += '@' + mentions[i] + ' ';
}
var postTextArea = elem.find('.post-area-new textarea');
postTextArea.attr('data-reply-to', replyTo);
if (!defaultScreenName)
postTextArea.attr('placeholder', polyglot.t('You have to log in to post replies.'));
else
postTextArea.attr('placeholder', polyglot.t('reply_to', { fullname: replyTo })+ '...');
postData.attr('data-reply-to', replyTo);
if( retweeted_by != undefined ) {
elem.find('.post-context').show();
elem.find('.post-retransmited-by')
.attr('href', $.MAL.userUrl(retweeted_by))
.text('@' + retweeted_by)
;
}
if (typeof(promoted) !== 'undefined' && promoted) {
elem.find('.post-propagate').remove();
} else {
if ($.Options.filterLang.val !== 'disable' && $.Options.filterLangSimulate.val) {
// FIXME it's must be stuff from template actually
if (typeof(post['langFilter']) !== 'undefined') {
if (typeof(post['langFilter']['prob'][0]) !== 'undefined')
var mlm = ' // '+polyglot.t('Most possible language: this', {'this': '<em>'+post['langFilter']['prob'][0].toString()+'</em>'});
else
var mlm = '';
elem.append('<div class="langFilterSimData">'+polyglot.t('This post is treated by language filter', {'treated': '<em>'+((post['langFilter']['pass']) ? polyglot.t('passed') : polyglot.t('blocked'))+'</em>'})+'</div>')
.append('<div class="langFilterSimData">'+polyglot.t('Reason: this', {'this': '<em>'+post['langFilter']['reason']+'</em>'})+mlm+'</div>')
;
} else {
elem.append('<div class="langFilterSimData">'+polyglot.t('This post is treated by language filter', {'treated': '<em>'+polyglot.t('not analyzed')+'</em>'})+'</div>');
}
}
}
return elem;
}
function setPostInfoSent(n, k, item) {
if( n === defaultScreenName && k >= 0 ) {
getPostMaxAvailability(n,k,
function(args,count) {
if( count >= 3 ) { // assume 3 peers (me + 2) is enough for "sent"
args.item.text("\u2713"); // check mark
} else {
args.item.text("\u231B"); // hour glass
setTimeout(setPostInfoSent,2000,n,k,item);
}
}, {n:n,k:k,item:item});
}
}
// format dmdata (returned by getdirectmsgs) to display in "snippet" per user list
function dmDataToSnippetItem(dmData, remoteUser) {
var dmItem = $("#dm-snippet-template").clone(true);
dmItem.removeAttr('id');
dmItem.attr("data-dm-screen-name",remoteUser);
dmItem.attr("data-last_id", dmData.id);
dmItem.attr("data-time", dmData.time);
dmItem.find(".post-info-tag").text("@" + remoteUser);
dmItem.find("a.post-info-name").attr("href", $.MAL.userUrl(remoteUser));
dmItem.find("a.dm-chat-link").attr("href", $.MAL.dmchatUrl(remoteUser));
getAvatar( remoteUser, dmItem.find(".post-photo").find("img") );
if( remoteUser.length && remoteUser[0] === '*' )
getGroupChatName( remoteUser, dmItem.find("a.post-info-name") );
else
getFullname( remoteUser, dmItem.find("a.post-info-name") );
dmItem.find(".post-text").html(escapeHtmlEntities(dmData.text));
dmItem.find(".post-info-time").text(timeGmtToText(dmData.time)).attr("title",timeSincePost(dmData.time));
return dmItem;
}
// format dmdata (returned by getdirectmsgs) to display in conversation thread
function dmDataToConversationItem(dmData, localUser, remoteUser) {
var from = (dmData.from && dmData.from.length && dmData.from.charCodeAt(0))
? dmData.from
: (dmData.fromMe ? localUser : remoteUser);
var classDm = dmData.fromMe ? "sent" : "received";
var dmItem = $("#dm-chat-template").clone(true);
dmItem.removeAttr('id');
dmItem.addClass(classDm);
getAvatar(from, dmItem.find(".post-photo").find("img") );
dmItem.find(".post-info-time").text(timeGmtToText(dmData.time)).attr("title",timeSincePost(dmData.time));
setPostInfoSent(from,dmData.k,dmItem.find('.post-info-sent'));
var mentions = [];
dmItem.find('.post-text').html(htmlFormatMsg(dmData.text, mentions));
return dmItem;
}
// convert message text to html, featuring @users and links formating.
function htmlFormatMsg(msg, mentions) {
function getStrStart(str, startPoint, stopChars, isStopCharMustExist, stopCharsTrailing) {
for (var i = startPoint; i > -1; i--) {
if (stopChars.indexOf(str[i]) > -1)
break;
}
if (i !== -1 || !isStopCharMustExist) {
for (i += 1; i < startPoint + 1; i++) {
if (stopCharsTrailing.indexOf(str[i]) === -1)
break;
}
} else
i = startPoint + 1;
return i;
}
function getStrEnd(str, startPoint, stopChars, isStopCharMustExist, stopCharsTrailing) {
for (var i = startPoint; i < str.length; i++) {
if (stopChars.indexOf(str[i]) > -1)
break;
}
if (i !== str.length || !isStopCharMustExist) {
for (i -= 1; i > startPoint - 1; i--) {
if (stopCharsTrailing.indexOf(str[i]) === -1)
break;
}
} else
i = startPoint - 1;
return i;
}
function markdown(str, chr, tag) {
function whiteSpace(i, j) {
j++;
for (i += 1; i < j; i++) {
if (p[i].w)
return true;
}
return false;
}
var i, j, t, l, r, strEncoded;
var w = false;
var p = [];
// collecting chars position data
for (i = 0; i < str.length; i++) {
if (str[i] === chr) {
for (j = i + 1; j < str.length; j++) {
if (str[j] !== chr)
break;
}
if (i === 0) {
p.push({i: i, k: j - i, t: -1, w: w, a: -1, p: -1});
w = false;
} else if (j === str.length) {
p.push({i: i, k: j - i, t: 1, w: w, a: -1, p: -1});
w = false;
} else {
if (stopCharsMarkDown.indexOf(str[i - 1]) > -1) {
l = 1;
for (t = i - 2; t > -1; t--) {
if (str[t] === chr) {
l = -1;
break;
} else if (stopCharsMarkDown.indexOf(str[t]) === -1) {
l = whiteSpaces.indexOf(str[t]);
break;
}
}
} else
l = whiteSpaces.indexOf(str[i - 1]);
if (stopCharsMarkDown.indexOf(str[j]) > -1) {
r = 1;
for (t = j + 1; t < str.length; t++) {
if (str[t] === chr) {
r = -1;
break;
} else if (stopCharsMarkDown.indexOf(str[t]) === -1) {
r = whiteSpaces.indexOf(str[t]);
break;
}
}
} else
r = whiteSpaces.indexOf(str[j]);
if (l > -1) {
if (r > -1) {
if (j - i > 2) {
l = p.push({i: i, k: j - i - 1, t: -1, w: w, a: -1, p: -1}) - 1;
p[l].a = p.push({i: j - 1, k: 1, t: 1, w: false, a: l, p: -1}) - 1;
}
t = 10;
} else
t = -1;
} else {
if (r > -1)
t = 1;
else
t = 0;
}
if (t !== 10)
p.push({i: i, k: j - i, t: t, w: w, a: -1, p: -1});
w = false;
}
i = j - 1;
} else if (!w && whiteSpaces.indexOf(str[i]) > -1) {
w = true;
}
}
// calculating dependencies
for (i = 0; i < p.length; i++) {
if (p[i].t < 1 && p[i].a === -1) {
t = i;
for (j = i + 1; j < p.length; j++) {
if (p[i].t === 0 && whiteSpace(i, j)) {
i = j - 1;
break;
} else if (p[j].t < 1 && p[j].a === -1) {
p[t].p = j;
t = j;
} else if (p[j].t === 1 && p[j].a === -1) {
p[i].a = j;
p[j].a = i;
i = j;
break;
}
}
}
}
for (i = 0; i < p.length; i++) {
if (p[i].t === -1 && p[i].a === -1) {
for (j = p[i].p; j > -1; j = p[j].p) {
if (whiteSpace(i, j)) {
i = j - 1;
break;
} else if (p[j].t === 0
&& !(p[j].p > -1 && p[p[j].p].t === 0 && !whiteSpace(j, p[j].p))) {
p[j].a = i;
p[i].a = j;
i = j;
break;
}
}
}
}
// changing the string
if (chr === '`') {
for (i = 0; i < p.length; i++) {
if (p[i].a > -1) {
if (p[i].t === -1 || (p[i].t === 0 && p[i].a > i)) {
if (p[i].k > 1)
t = '<' + tag + '>' + Array(p[i].k).join(chr);
else
t = '<' + tag + '>';
j = p[i].a;
t = t + str.slice(p[i].i + p[i].k, p[j].i);
if (p[j].k > 1)
t = t + Array(p[i].k).join(chr) + '</' + tag + '>';
else
t = t + '</' + tag + '>';
html.push(t.replace(/&(?!lt;|gt;)/g, '&amp;'));
strEncoded = '>' + (html.length - 1).toString() + '<';
str = str.slice(0, p[i].i) + strEncoded + str.slice(p[j].i + p[j].k);
l = strEncoded.length - p[j].i - p[j].k + p[i].i;
i = j;
for (j += 1; j < p.length; j++)
p[j].i += l;
}
}
}
} else {
for (i = 0; i < p.length; i++) {
if (p[i].a > -1) {
if (p[i].t === -1 || (p[i].t === 0 && p[i].a > i)) {
if (p[i].k > 1)
html.push('<' + tag + '>' + Array(p[i].k).join(chr));
else
html.push('<' + tag + '>');
} else if (p[i].t === 1 || (p[i].t === 0 && p[i].a < i)) {
if (p[i].k > 1)
html.push(Array(p[i].k).join(chr) + '</' + tag + '>');
else
html.push('</' + tag + '>');
}
strEncoded = '>' + (html.length - 1).toString() + '<';
str = str.slice(0, p[i].i) + strEncoded + str.slice(p[i].i + p[i].k);
l = strEncoded.length - p[i].k;
for (j = i + 1; j < p.length; j++)
p[j].i += l;
}
}
}
return str;
}
function htmlSplitCounter(str) {
html.push('<span class="splited-post-counter">' + str + '</span>');
return '>' + (html.length - 1).toString() + '<';
}
function unpackHtml(str) {
var t;
for (var i = 0; i < str.length - 2; i++) {
if (str[i] === '>') {
for (var j = i + 2; j < str.length; j++) {
if (str[j] === '<')
break;
}
t = html[parseInt(str.slice(i + 1, j))];
str = str.slice(0, i) + t + str.slice(j + 1);
i = i + t.length - 1;
}
}
return str;
}
var mentionsChars = 'abcdefghijklmnopqrstuvwxyz_0123456789';
var stopCharsTrailing = '/\\*~_-`.,:;?!%\'"[](){}^|«»…\u201C\u201D\u2026\u2014\u4E00\u3002\uFF0C\uFF1A\uFF1F\uFF01\u3010\u3011\u2047\u2048\u2049';
var stopCharsTrailingUrl = stopCharsTrailing.slice(1);
var whiteSpaces = ' \f\n\r\t\v\u00A0\u1680\u180E\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200A\u2028\u2029\u202F\u205F\u3000';
var whiteSpacesUrl = '\'\"' + whiteSpaces;
var stopCharsLeft = '<' + whiteSpaces;
var stopCharsRight = '>' + whiteSpaces;
var stopCharsRightHashtags = '>/\\.,:;?!%\'"[](){}^|«»…\u201C\u201D\u2026\u2014\u4E00\u3002\uFF0C\uFF1A\uFF1F\uFF01\u3010\u3011\u2047\u2048\u2049' // same as stopCharsTrailing but without '*~_-`' plus '>'
+ whiteSpaces;
var stopCharsMarkDown = '/\\*~_-`.,:;?!%+=&\'"[](){}^|«»…\u201C\u201D\u2026\u2014\u4E00\u3002\uFF0C\uFF1A\uFF1F\uFF01\u3010\u3011\u2047\u2048\u2049';
var i, j, k, str, strEncoded;
var html = [];
msg = markdown(escapeHtmlEntities(msg),
'`', 'samp'); // kind of monospace, sequence of chars inside will be escaped from markup
for (i = 0; i < msg.length - 7; i++) {
if (msg.slice(i, i + 2) === '](') {
// FIXME there can be text with [] inside [] or links with () wee need to handle it too
j = getStrStart(msg, i - 2, '[', true, '');
if (j < i - 1) {
k = getStrEnd(msg, i + 3, ')', true, whiteSpaces);
if (k > i + 2) {
strEncoded = msg.slice(j, i); // just temporary storage for name of possiible link
for (i += 2; i < k; i++) {
if (whiteSpacesUrl.indexOf(msg[i]) === -1) // drop whitespaces and ' and " // apostrophes and quotes to prevent injection of js events
break;
}
if (i < k) {
// check for injections like [href=(' or ")]('#' or 'javascript' or 'data')[:] // () and [] here just to explain somehow an idea, it's not about markup syntax
if (msg[i] === '#' || msg.slice(i, i + 10).toLowerCase() === 'javascript'
|| msg.slice(i, i + 4).toLowerCase() === 'data') {
html.push('…<br><b><i>' + polyglot.t('busted_oh') + '</i> '
+ polyglot.t('busted_avowal') + ':</b><br><samp>'
+ msg.slice(i, k + 1)
.replace(/&(?!lt;|gt;)/g, '&amp;')
.replace(/"/g, '&quot;')
.replace(/'/g, '&apos;')
+ '</samp><br>'
);
} else {
if (getStrEnd(msg, i + 1, whiteSpacesUrl, false, '') < k) // use only first word as href target, others drop silently
k = getStrEnd(msg, i + 1, whiteSpacesUrl, false, '');
html.push($('#external-page-link-template')[0].outerHTML
.replace(/\bid\s*=\s*"[^]*?"+/ig, '') // $().removeAttr('id')
//.replace(/\bhref\s*=\s*"[^]*?"+/ig, '') // $().removeAttr('href')
.replace(/<a\s+/ig, '<a href="' + proxyURL(msg.slice(i, k + 1)) + '" ') // $().closest('a').attr('href', proxyURL(url))
.replace(/(<a\s+[^]*?>)[^]*?(<\/a>)/ig, '$1'
+ unpackHtml(
markdown(markdown(markdown(markdown(strEncoded, // name of link, see above
'*', 'b'), // bold
'~', 'i'), // italic
'_', 'u'), // underlined
'-', 's') // striketrough
.replace(/&(?!lt;|gt;)/g, '&amp;')
.replace(/"/g, '&quot;')
.replace(/'/g, '&apos;')
)
+ '$2') // $().closest('a').text(url)
);
}
strEncoded = '>' + (html.length - 1).toString() + '<';
msg = msg.slice(0, j - 1) + strEncoded + msg.slice(getStrEnd(msg, k + 1, ')', true, '') + 2);
i = j + strEncoded.length - 1;
} // else
// i = just no
}
}
} else if (msg.slice(i, i + 4).toLowerCase() === 'http') {
if (msg.slice(i + 4, i + 7) === '://' && stopCharsRight.indexOf(msg[i + 7]) === -1) {
j = getStrEnd(msg, i + 7, stopCharsRight, false, stopCharsTrailingUrl);
if (j > i + 6) {
str = msg.slice(i, j + 1);
// FIXME we're trying to not interact with DOM, coz' we want to run really fast [to hell of RegExps]
// FIXME actually we should avoid it by dropping a template idea and construct html right here
html.push($('#external-page-link-template')[0].outerHTML
.replace(/\bid\s*=\s*"[^]*?"+/ig, '') // $().removeAttr('id')
//.replace(/\bhref\s*=\s*"[^]*?"+/ig, '') // $().removeAttr('href')
.replace(/<a\s+/ig, '<a href="' + proxyURL(str) + '" ') // $().closest('a').attr('href', proxyURL(url))
.replace(/(<a\s+[^]*?>)[^]*?(<\/a>)/ig, '$1' + str + '$2') // $().closest('a').text(url)
);
strEncoded = '>' + (html.length - 1).toString() + '<';
msg = msg.slice(0, i) + strEncoded + msg.slice(i + str.length);
i = i + strEncoded.length - 1;
}
} else if (msg.slice(i + 4, i + 8).toLowerCase() === 's://' && stopCharsRight.indexOf(msg[i + 8]) === -1) {
j = getStrEnd(msg, i + 8, stopCharsRight, false, stopCharsTrailingUrl);
if (j > i + 7) {
str = msg.slice(i, j + 1);
html.push($('#external-page-link-template')[0].outerHTML
.replace(/\bid\s*=\s*"[^]*?"+/ig, '') // $().removeAttr('id')
//.replace(/\bhref\s*=\s*"[^]*?"+/ig, '') // $().removeAttr('href')
.replace(/<a\s+/ig, '<a href="' + proxyURL(str) + '" ') // $().closest('a').attr('href', proxyURL(url))
.replace(/(<a\s+[^]*?>)[^]*?(<\/a>)/ig, '$1' + str + '$2') // $().closest('a').text(url)
);
strEncoded = '>' + (html.length - 1).toString() + '<';
msg = msg.slice(0, i) + strEncoded + msg.slice(i + str.length);
i = i + strEncoded.length - 1;
}
}
}
}
for (i = 1; i < msg.length - 1; i++) {
if (msg[i] === '@' && stopCharsLeft.indexOf(msg[i - 1]) === -1
&& stopCharsTrailing.indexOf(msg[i - 1]) === -1 && stopCharsRight.indexOf(msg[i + 1]) === -1) {
j = getStrStart(msg, i - 1, stopCharsLeft, false, stopCharsTrailing);
if (j < i) {
k = getStrEnd(msg, i + 1, stopCharsRight, false, stopCharsTrailing);
if (k > i) {
str = msg.slice(j, k + 1);
html.push($('#external-page-link-template')[0].outerHTML
.replace(/\bid\s*=\s*"[^]*?"+/ig, '') // $().removeAttr('id')
//.replace(/\bhref\s*=\s*"[^]*?"+/ig, '') // $().removeAttr('href')
.replace(/<a\s+/ig, '<a href="mailto:' + str.toLowerCase() + '" ') // $().closest('a').attr('href', 'mailto:'+url)
.replace(/(<a\s+[^]*?>)[^]*?(<\/a>)/ig, '$1' + str + '$2') // $().closest('a').text(url)
);
strEncoded = '>' + (html.length - 1).toString() + '<';
msg = msg.slice(0, j) + strEncoded + msg.slice(j + str.length);
i = j + strEncoded.length - 1;
}
}
}
}
for (i = 0; i < msg.length - 1; i++) {
if (msg[i] === '@' && mentionsChars.indexOf(msg[i + 1].toLowerCase()) > -1) {
for (j = i + 2; j < msg.length; j++) {
if (mentionsChars.indexOf(msg[j].toLowerCase()) === -1)
break;
}
str = msg.slice(i + 1, j).toLowerCase();
mentions.push(str); // FIXME
html.push($('#msg-user-link-template')[0].outerHTML
.replace(/\bid\s*=\s*"[^]*?"+/ig, '') // $().removeAttr('id')
//.replace(/\bhref\s*=\s*"[^]*?"+/ig, '') // $().removeAttr('href')
.replace(/<a\s+(?=[^>]*?\bclass\s*=\s*"(?=[^"]*?\bopen-profile-modal\b))/ig, '<a href="' + $.MAL.userUrl(str) + '" ') // $().closest('a.open-profile-modal').attr('href', $.MAL.userUrl(username))
.replace(/(<a\s+(?=[^>]*?\bclass\s*=\s*"(?=[^"]*?\bopen-profile-modal\b))[^]*?>)[^]*?(<\/a>)/ig, '$1@' + str + '$2') // $().closest('a.open-profile-modal').text('@'+username)
);
strEncoded = '>' + (html.length - 1).toString() + '<';
msg = msg.slice(0, i) + strEncoded + msg.slice(i + str.length + 1);
i = i + strEncoded.length - 1;
}
}
for (i = 0; i < msg.length - 1; i++) {
if (msg[i] === '#' && msg[i + 1] !== '#' && stopCharsRight.indexOf(msg[i + 1]) === -1) {
j = getStrEnd(msg, i + 1, stopCharsRightHashtags, false, stopCharsTrailing);
if (j > i) {
str = msg.slice(i + 1, j + 1);
html.push($('#hashtag-link-template')[0].outerHTML
.replace(/\bid\s*=\s*"[^]*?"+/ig, '') // $().removeAttr('id')
//.replace(/\bhref\s*=\s*"[^]*?"+/ig, '') // $().removeAttr('href')
.replace(/<a\s+(?=[^>]*?\bclass\s*=\s*"(?=[^"]*?\bopen-hashtag-modal\b))/ig, '<a href="' + $.MAL.hashtagUrl(encodeURIComponent(str.toLowerCase())) + '" ') // $().closest('a.open-profile-modal').attr('href', $.MAL.hashtagUrl(hashtag))
.replace(/(<a\s+(?=[^>]*?\bclass\s*=\s*"(?=[^"]*?\bopen-hashtag-modal\b))[^]*?>)[^]*?(<\/a>)/ig, '$1#' + str.replace(/&amp;/g, '&') + '$2') // $().closest('a.open-profile-modal').text('#'+hashtag)
);
strEncoded = '>' + (html.length - 1).toString() + '<';
msg = msg.slice(0, i) + strEncoded + msg.slice(i + str.length + 1);
i = i + strEncoded.length - 1;
}
}
}
msg = unpackHtml(
markdown(markdown(markdown(markdown(msg,
'*', 'b'), // bold
'~', 'i'), // italic
'_', 'u'), // underlined
'-', 's') // striketrough
.replace(/\(\d{1,2}\/\d{1,2}\)$/, htmlSplitCounter)
.replace(/&(?!lt;|gt;)/g, '&amp;') // FIXME in many cases there is no need to escape ampersand in HTML 5
.replace(/"/g, '&quot;')
.replace(/'/g, '&apos;')
);
if ($.Options.displayLineFeeds.val === 'enable')
msg = msg.replace(/\n/g, '<br />');
// TODO: add options for emotions; msg = $.emotions(msg);
// TODO make markdown optionally mutable ?
return msg;
}
function proxyURL(url) {
var proxyOpt = $.Options.useProxy.val;
if (proxyOpt !== 'disable' && !$.Options.useProxyForImgOnly.val) {
// proxy alternatives may be added to options page FIXME currently not; and we need more fresh proxies
if (proxyOpt === 'ssl-proxy-my-addr') {
url = 'https://ssl-proxy.my-addr.org/myaddrproxy.php/' +
url.substring(0, url.indexOf(':')) + url.substr(url.indexOf('/') + 1);
} else if (proxyOpt === 'anonymouse')
url = 'http://anonymouse.org/cgi-bin/anon-www.cgi/' + url;
}
return url;
}
function escapeHtmlEntities(str) {
return str
//.replace(/&/g, '&amp;') we do it not here
.replace(/</g, '&lt;')
.replace(/>/g, '&gt;')
//.replace(/"/g, '&quot;')
//.replace(/'/g, '&apos;')
;
}
function reverseHtmlEntities(str) {
return str
.replace(/&lt;/g, '<')
.replace(/&gt;/g, '>')
.replace(/&quot;/g, '"')
.replace(/&apos;/g, "'")
.replace(/&amp;/g, '&');
}