Browse Source

crazy gonzales optimization of htmlFormatMsg() to avoid AMAP DOM interacting (but with too many RegExps), some minor optimization for postToElem(), introducing of proxyURL()

master
Simon Grim 10 years ago
parent
commit
257aedf61a
  1. 12
      js/interface_common.js
  2. 331
      js/twister_formatpost.js

12
js/interface_common.js

@ -636,17 +636,7 @@ var postExpandFunction = function( e, postLi )
/*is there any link in the post?*/ /*is there any link in the post?*/
for (var i=0; i<link.length; i++){ for (var i=0; i<link.length; i++){
if (/((\.jpe{0,1}g)|(\.gif)|(\.png))$/i.test(link[i].href)){ if (/((\.jpe{0,1}g)|(\.gif)|(\.png))$/i.test(link[i].href)){
var url = link[i].href; var url = proxyURL(link[i].href);
if ($.Options.getUseProxyOpt() !== 'disable' && $.Options.getUseProxyForImgOnlyOpt()){
//proxy alternatives may be added to options page...
if ($.Options.getUseProxyOpt() === '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 ($.Options.getUseProxyOpt() ==='anonymouse') {
url = 'http://anonymouse.org/cgi-bin/anon-www.cgi/' + url;
}
}
$(previewContainer).append($("<img src='" + url + "' class='image-preview' />")); $(previewContainer).append($("<img src='" + url + "' class='image-preview' />"));
} }
} }

331
js/twister_formatpost.js

@ -52,71 +52,71 @@ function postToElem( post, kind, promoted ) {
// Now create the html elements // Now create the html elements
var elem = $.MAL.getPostTemplate().clone(true); var elem = $.MAL.getPostTemplate().clone(true);
elem.removeAttr('id'); elem.removeAttr('id')
elem.addClass(kind); .addClass(kind)
elem.attr('data-time', t); .attr('data-time', t)
;
if( post["isNew"] ) if( post['isNew'] )
elem.addClass('new'); elem.addClass('new');
var postData = elem.find(".post-data"); var postData = elem.find('.post-data');
postData.addClass(kind); postData.addClass(kind)
postData.attr('data-userpost', postJson); .attr('data-userpost', postJson)
postData.attr('data-content_to_rt', content_to_rt); .attr('data-content_to_rt', content_to_rt)
postData.attr('data-content_to_sigrt', content_to_sigrt); .attr('data-content_to_sigrt', content_to_sigrt)
postData.attr('data-screen-name', n); .attr('data-screen-name', n)
postData.attr('data-id', k); .attr('data-id', k)
postData.attr('data-lastk', userpost["lastk"]); .attr('data-lastk', userpost["lastk"])
postData.attr('data-text', msg); .attr('data-text', msg)
if( "reply" in userpost ) { ;
postData.attr('data-replied-to-screen-name', userpost["reply"]["n"]); if( 'reply' in userpost ) {
postData.attr('data-replied-to-id', userpost["reply"]["k"]); postData.attr('data-replied-to-screen-name', userpost.reply.n)
.attr('data-replied-to-id', userpost.reply.k)
postData.find('.post-expand').text(polyglot.t("Show conversation")); .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"]); } else if ( 'rt' in userpost && 'reply' in userpost.rt ) {
postData.attr('data-replied-to-id', userpost["rt"]["reply"]["k"]); postData.attr('data-replied-to-screen-name', userpost.rt.reply.n)
.attr('data-replied-to-id', userpost.rt.reply.k)
postData.find('.post-expand').text(polyglot.t("Show conversation")); .find('.post-expand').text(polyglot.t('Show conversation'))
} ;
}
var postInfoName = elem.find(".post-info-name");
postInfoName.attr('href',$.MAL.userUrl(n)); var postInfoName = elem.find('.post-info-name');
postInfoName.text(n); postInfoName.text(n).attr('href', $.MAL.userUrl(n));
getFullname( n, postInfoName ); getFullname( n, postInfoName );
elem.find(".post-info-tag").text = "@" + n; //elem.find('.post-info-tag').text("@" + n);
getAvatar( n, elem.find(".avatar") ); getAvatar( n, elem.find('.avatar') );
elem.find(".post-info-time").text(timeGmtToText(t)); elem.find('.post-info-time').text(timeGmtToText(t)).attr('title', timeSincePost(t));
elem.find(".post-info-time").attr("title",timeSincePost(t));
var mentions = []; var mentions = [];
htmlFormatMsg( msg, elem.find(".post-text"), mentions); elem.find('.post-text').html(htmlFormatMsg(msg, mentions));
postData.attr('data-text-mentions', mentions); postData.attr('data-text-mentions', mentions);
var replyTo = ""; var replyTo = [];
if( n != defaultScreenName ) if( n !== defaultScreenName )
replyTo += "@" + n + " "; replyTo.push(['@', n, ' '].join(''));
for (var i = 0; i < mentions.length; i++) { for (var i = 0; i < mentions.length; i++) {
if( mentions[i] != n && mentions[i] != defaultScreenName ) { if (mentions[i] !== n && mentions[i] !== defaultScreenName)
replyTo += "@" + mentions[i] + " "; replyTo.push(['@', mentions[i], ' '].join(''));
}
} }
replyTo = replyTo.join('');
var postTextArea = elem.find('.post-area-new textarea');
postTextArea.attr('data-reply-to', replyTo);
if (!defaultScreenName) if (!defaultScreenName)
{ postTextArea.attr('placeholder', polyglot.t('You have to log in to post replies.'));
elem.find(".post-area-new textarea").attr("placeholder", polyglot.t("You have to log in to post replies."));
}
else else
{ postTextArea.attr('placeholder', polyglot.t('reply_to', { fullname: replyTo })+ '...');
elem.find(".post-area-new textarea").attr("placeholder", polyglot.t("reply_to", { fullname: replyTo })+ "...");
} postData.attr('data-reply-to', replyTo);
elem.find(".post-area-new textarea").attr("data-reply-to",replyTo);
postData.attr("data-reply-to",replyTo);
if( retweeted_by != undefined ) { if( retweeted_by != undefined ) {
elem.find(".post-context").show(); elem.find('.post-context').show();
var retweetedByElem = elem.find(".post-retransmited-by"); elem.find('.post-retransmited-by')
retweetedByElem.attr("href", $.MAL.userUrl(retweeted_by)); .attr('href', $.MAL.userUrl(retweeted_by))
retweetedByElem.text('@'+retweeted_by); .text('@' + retweeted_by)
;
} }
if (typeof(promoted) !== 'undefined' && promoted) { if (typeof(promoted) !== 'undefined' && promoted) {
@ -130,8 +130,9 @@ function postToElem( post, kind, promoted ) {
else else
var mlm = ''; 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>'); 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>')
elem.append('<div class="langFilterSimData">'+polyglot.t('Reason: this', {'this': '<em>'+post['langFilter']['reason']+'</em>'})+mlm+'</div>'); .append('<div class="langFilterSimData">'+polyglot.t('Reason: this', {'this': '<em>'+post['langFilter']['reason']+'</em>'})+mlm+'</div>')
;
} else { } else {
elem.append('<div class="langFilterSimData">'+polyglot.t('This post is treated by language filter', {'treated': '<em>'+polyglot.t('not analyzed')+'</em>'})+'</div>'); elem.append('<div class="langFilterSimData">'+polyglot.t('This post is treated by language filter', {'treated': '<em>'+polyglot.t('not analyzed')+'</em>'})+'</div>');
} }
@ -158,8 +159,7 @@ function dmDataToSnippetItem(dmData, remoteUser) {
else else
getFullname( remoteUser, dmItem.find("a.post-info-name") ); getFullname( remoteUser, dmItem.find("a.post-info-name") );
dmItem.find(".post-text").html(escapeHtmlEntities(dmData.text)); dmItem.find(".post-text").html(escapeHtmlEntities(dmData.text));
dmItem.find(".post-info-time").text(timeGmtToText(dmData.time)); dmItem.find(".post-info-time").text(timeGmtToText(dmData.time)).attr("title",timeSincePost(dmData.time));
dmItem.find(".post-info-time").attr("title",timeSincePost(dmData.time));
return dmItem; return dmItem;
} }
@ -171,183 +171,96 @@ function dmDataToConversationItem(dmData, localUser, remoteUser) {
dmItem.removeAttr('id'); dmItem.removeAttr('id');
dmItem.addClass(classDm); dmItem.addClass(classDm);
getAvatar(dmData.fromMe ? localUser : remoteUser, dmItem.find(".post-photo").find("img") ); getAvatar(dmData.fromMe ? localUser : remoteUser, dmItem.find(".post-photo").find("img") );
dmItem.find(".post-info-time").text(timeGmtToText(dmData.time)); dmItem.find(".post-info-time").text(timeGmtToText(dmData.time)).attr("title",timeSincePost(dmData.time));
dmItem.find(".post-info-time").attr("title",timeSincePost(dmData.time));
var mentions = []; var mentions = [];
htmlFormatMsg( dmData.text, dmItem.find(".post-text"), mentions); dmItem.find('.post-text').html(htmlFormatMsg(dmData.text, mentions));
return dmItem; return dmItem;
} }
// convert message text to html, featuring @users and links formating. // convert message text to html, featuring @users and links formating.
// todo: hashtags function htmlFormatMsg(msg, mentions) {
function htmlFormatMsg( msg, output, mentions ) { function htmlMention(str, pre) {
var tmp; str = str.replace(new RegExp(['^', pre, '@'].join('')), '').toLowerCase();
var match = null;
var index;
var strUrlRegexp = "http[s]?://";
var strEmailRegexp = "\\S+@\\S+\\.\\S+";
var strSplitCounterR = "\\(\\d{1,2}\\/\\d{1,2}\\)$";
var reAll = new RegExp("(?:^|[ \\n\\t.,:\\/?!])(#|@|" + strUrlRegexp + "|" + strEmailRegexp + "|" + strSplitCounterR + ")");
var reHttp = new RegExp(strUrlRegexp);
var reEmail = new RegExp(strEmailRegexp);
var reSplitCounter = new RegExp(strSplitCounterR);
msg = escapeHtmlEntities(msg);
while( msg != undefined && msg.length ) {
match = reAll.exec(msg);
if( match ) {
index = (match[0] === match[1]) ? match.index : match.index + 1;
if( match[1] == "@" ) {
output.append(_formatText(msg.substr(0, index)));
tmp = msg.substr(index+1);
var username = _extractUsername(tmp);
if( username.length ) {
if( mentions.indexOf(username) < 0 )
mentions.push(username);
var userLinkTemplate = $("#msg-user-link-template").clone(true);
userLinkTemplate.removeAttr("id");
userLinkTemplate.attr("href",$.MAL.userUrl(username));
userLinkTemplate.text("@"+username);
output.append(userLinkTemplate);
msg = tmp.substr(String(username).length);
continue;
}
output.append('@');
msg = tmp;
continue;
}
if( reHttp.exec(match[1]) ) { mentions.push(str); // FIXME feel the scope
output.append(_formatText(msg.substr(0, index)));
tmp = msg.substring(index);
var space = tmp.search(/[ \n\t]/);
var url;
if( space != -1 ) url = tmp.substring(0,space); else url = tmp;
if( url.length ) {
msg = tmp.substr(String(url).length);
url = reverseHtmlEntities(url);
var extLinkTemplate = $("#external-page-link-template").clone(true);
extLinkTemplate.removeAttr("id");
if ($.Options.getUseProxyOpt() !== 'disable' && !$.Options.getUseProxyForImgOnlyOpt()){
//proxy alternatives may be added to options page...
if ($.Options.getUseProxyOpt() === 'ssl-proxy-my-addr') {
extLinkTemplate.attr('href', 'https://ssl-proxy.my-addr.org/myaddrproxy.php/' +
url.substring(0, url.indexOf(':')) +
url.substr(url.indexOf('/') + 1));
} else if ($.Options.getUseProxyOpt() ==='anonymouse') {
extLinkTemplate.attr('href', 'http://anonymouse.org/cgi-bin/anon-www.cgi/' + url);
}
} else {
extLinkTemplate.attr("href",url);
}
extLinkTemplate.text(url); // FIXME we're trying to not interact with DOM, coz' we want to run really fast [to hell of RegExps]
extLinkTemplate.attr("title",url); // FIXME actually we should avoid it by dropping a template idea and construct html right here
output.append(extLinkTemplate); return $('#msg-user-link-template')[0].outerHTML
continue; .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, [pre, '<a href="', $.MAL.userUrl(str), '" '].join('')) // $().closest('a.open-profile-modal').attr('href', $.MAL.userUrl(username))
.replace(/(<a\s+(?=[^>]*?\bclass\s*=\s*"(?=[^"]*?\bopen-profile-modal\b))[^]*?>)[^]*?(<\/a>)/ig, [pre, '$1@', str, '$2'].join('')) // $().closest('a.open-profile-modal').text('@'+username)
;
} }
if( reEmail.exec(match[1]) ) { function htmlHashtag(str, pre) {
output.append(_formatText(msg.substr(0, index))); str = str.replace(new RegExp(['^', pre, '#'].join('')), '');
tmp = msg.substring(index);
var space = tmp.search(/[ \n\t]/);
var email;
if( space != -1 ) email = tmp.substring(0,space); else email = tmp;
if( email.length ) {
var extLinkTemplate = $("#external-page-link-template").clone(true);
extLinkTemplate.removeAttr("id");
extLinkTemplate.attr("href","mailto:" + email);
extLinkTemplate.text(email);
extLinkTemplate.attr("title",email);
output.append(extLinkTemplate);
msg = tmp.substr(String(email).length);
continue;
}
}
if( match[1] == "#" ) { return $('#hashtag-link-template')[0].outerHTML
output.append(_formatText(msg.substr(0, index))); .replace(/\bid\s*=\s*"[^]*?"+/ig, '') // $().removeAttr('id')
tmp = msg.substr(index+1); //.replace(/\bhref\s*=\s*"[^]*?"+/ig, '') // $().removeAttr('href')
var hashtag = _extractHashtag(tmp); .replace(/<a\s+(?=[^>]*?\bclass\s*=\s*"(?=[^"]*?\bopen-hashtag-modal\b))/ig, ['<a href="', $.MAL.hashtagUrl(str.toLowerCase()), '" '].join('')) // $().closest('a.open-profile-modal').attr('href', $.MAL.hashtagUrl(hashtag))
if( hashtag.length ) { .replace(/(<a\s+(?=[^>]*?\bclass\s*=\s*"(?=[^"]*?\bopen-hashtag-modal\b))[^]*?>)[^]*?(<\/a>)/ig, [pre, '$1#', str, '$2'].join('')) // $().closest('a.open-profile-modal').text('#'+hashtag)
var hashtag_lc=''; ;
for( var i = 0; i < hashtag.length; i++ ) {
var c = hashtag[i];
hashtag_lc += (c >= 'A' && c <= 'Z') ? c.toLowerCase() : c;
}
var hashtagLinkTemplate = $("#hashtag-link-template").clone(true);
hashtagLinkTemplate.removeAttr("id");
hashtagLinkTemplate.attr("href",$.MAL.hashtagUrl(hashtag_lc));
hashtagLinkTemplate.text("#"+hashtag);
output.append(hashtagLinkTemplate);
msg = tmp.substr(String(hashtag).length);
continue;
}
output.append('#');
msg = tmp;
continue;
} }
if (reSplitCounter.exec(match[1])) { function htmlHttp(str) {
output.append(_formatText(msg.substr(0, index))); return $('#external-page-link-template')[0].outerHTML
tmp = msg.substring(index); .replace(/\bid\s*=\s*"[^]*?"+/ig, '') // $().removeAttr('id')
if( tmp.length ) { //.replace(/\bhref\s*=\s*"[^]*?"+/ig, '') // $().removeAttr('href')
var splitCounter = $('<span class="splited-post-counter"></span>'); .replace(/<a\s+/ig, ['<a href="', proxyURL(str), '" '].join('')) // $().closest('a').attr('href', proxyURL(url))
splitCounter.text(tmp); .replace(/(<a\s+[^]*?>)[^]*?(<\/a>)/ig, ['$1', str, '$2'].join('')) // $().closest('a').text(url)
output.append(splitCounter); ;
msg = "";
continue;
}
}
} }
output.append(_formatText(msg)); function htmlEmail(str) {
msg = ""; return $('#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(), '" '].join('')) // $().closest('a').attr('href', 'mailto:'+url)
.replace(/(<a\s+[^]*?>)[^]*?(<\/a>)/ig, ['$1', str, '$2'].join('')) // $().closest('a').text(url)
;
} }
// internal function for htmlFormatMsg function htmlSplitCounter(str) {
function _formatText(msg) return ['<span class="splited-post-counter">', str, '</span>'].join('');
{
// TODO: add options for emotions and linefeeds
//msg = $.emotions(msg);
if( $.Options.getLineFeedsOpt() == "enable" )
msg = msg.replace(/\n/g, '<br />');
return msg;
} }
function _extractUsername(s) { msg = escapeHtmlEntities(msg)
var username = ""; .replace(/(^|\s|\w)@\S\w*/g, htmlMention)
for( var i = 0; i < s.length; i++ ) { .replace(/(^|\s|\w)#\S\w*/g, htmlHashtag)
var c = s.charCodeAt(i); .replace(/\bhttps?:\/\/\S+/ig, htmlHttp)
if( (c >= 'a'.charCodeAt(0) && c <= 'z'.charCodeAt(0)) || .replace(/\S+@\S+\.\S+/g, htmlEmail)
(c >= 'A'.charCodeAt(0) && c <= 'Z'.charCodeAt(0)) || .replace(/\(\d{1,2}\/\d{1,2}\)$/, htmlSplitCounter)
(c >= '0'.charCodeAt(0) && c <= '9'.charCodeAt(0)) || ;
c == '_'.charCodeAt(0) ) {
username += s[i]; return _formatText(msg);
} else {
break;
} }
function proxyURL(url) {
var proxyOpt = $.Options.getUseProxyOpt();
if (proxyOpt !== 'disable' && !$.Options.getUseProxyForImgOnlyOpt()) {
// proxy alternatives may be added to options page
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)].join('');
} else if (proxyOpt === 'anonymouse')
url = ['http://anonymouse.org/cgi-bin/anon-www.cgi/', url].join('');
} }
return username.toLowerCase();
return url;
} }
// internal function for htmlFormatMsg // internal function for htmlFormatMsg
function _extractHashtag(s) { // TODO: add options for emotions; msg = $.emotions(msg);
var hashtag = ""; // TODO: add at least basic markdown (optional) like *text* -> bold text and _text_ -> italic text
s = reverseHtmlEntities(s); function _formatText(msg) {
for( var i = 0; i < s.length; i++ ) { if ($.Options.getLineFeedsOpt() === 'enable')
if( " \n\t.,:/?!;'\"()[]{}*#".indexOf(s[i]) < 0 ) { msg = msg.replace(/\n/g, '<br />');
hashtag += s[i];
} else { return msg;
break;
}
}
return hashtag;
} }
function escapeHtmlEntities(str) { function escapeHtmlEntities(str) {

Loading…
Cancel
Save