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"); var postInfoName = elem.find('.post-info-name');
postInfoName.attr('href',$.MAL.userUrl(n)); postInfoName.text(n).attr('href', $.MAL.userUrl(n));
postInfoName.text(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(''));
}
}
if(!defaultScreenName)
{
elem.find(".post-area-new textarea").attr("placeholder", polyglot.t("You have to log in to post replies."));
} }
replyTo = replyTo.join('');
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 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; mentions.push(str); // FIXME feel the scope
var strUrlRegexp = "http[s]?://";
var strEmailRegexp = "\\S+@\\S+\\.\\S+"; // FIXME we're trying to not interact with DOM, coz' we want to run really fast [to hell of RegExps]
var strSplitCounterR = "\\(\\d{1,2}\\/\\d{1,2}\\)$"; // FIXME actually we should avoid it by dropping a template idea and construct html right here
var reAll = new RegExp("(?:^|[ \\n\\t.,:\\/?!])(#|@|" + strUrlRegexp + "|" + strEmailRegexp + "|" + strSplitCounterR + ")"); return $('#msg-user-link-template')[0].outerHTML
var reHttp = new RegExp(strUrlRegexp); .replace(/\bid\s*=\s*"[^]*?"+/ig, '') // $().removeAttr('id')
var reEmail = new RegExp(strEmailRegexp); //.replace(/\bhref\s*=\s*"[^]*?"+/ig, '') // $().removeAttr('href')
var reSplitCounter = new RegExp(strSplitCounterR); .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)
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]) ) { 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 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); return $('#hashtag-link-template')[0].outerHTML
extLinkTemplate.attr("title",url); .replace(/\bid\s*=\s*"[^]*?"+/ig, '') // $().removeAttr('id')
output.append(extLinkTemplate); //.replace(/\bhref\s*=\s*"[^]*?"+/ig, '') // $().removeAttr('href')
continue; .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))
} .replace(/(<a\s+(?=[^>]*?\bclass\s*=\s*"(?=[^"]*?\bopen-hashtag-modal\b))[^]*?>)[^]*?(<\/a>)/ig, [pre, '$1#', str, '$2'].join('')) // $().closest('a.open-profile-modal').text('#'+hashtag)
;
} }
if( reEmail.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')
var space = tmp.search(/[ \n\t]/); //.replace(/\bhref\s*=\s*"[^]*?"+/ig, '') // $().removeAttr('href')
var email; .replace(/<a\s+/ig, ['<a href="', proxyURL(str), '" '].join('')) // $().closest('a').attr('href', proxyURL(url))
if( space != -1 ) email = tmp.substring(0,space); else email = tmp; .replace(/(<a\s+[^]*?>)[^]*?(<\/a>)/ig, ['$1', str, '$2'].join('')) // $().closest('a').text(url)
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] == "#" ) { function htmlEmail(str) {
output.append(_formatText(msg.substr(0, index))); return $('#external-page-link-template')[0].outerHTML
tmp = msg.substr(index+1); .replace(/\bid\s*=\s*"[^]*?"+/ig, '') // $().removeAttr('id')
var hashtag = _extractHashtag(tmp); //.replace(/\bhref\s*=\s*"[^]*?"+/ig, '') // $().removeAttr('href')
if( hashtag.length ) { .replace(/<a\s+/ig, ['<a href="mailto:', str.toLowerCase(), '" '].join('')) // $().closest('a').attr('href', 'mailto:'+url)
var hashtag_lc=''; .replace(/(<a\s+[^]*?>)[^]*?(<\/a>)/ig, ['$1', str, '$2'].join('')) // $().closest('a').text(url)
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 htmlSplitCounter(str) {
output.append(_formatText(msg.substr(0, index))); return ['<span class="splited-post-counter">', str, '</span>'].join('');
tmp = msg.substring(index);
if( tmp.length ) {
var splitCounter = $('<span class="splited-post-counter"></span>');
splitCounter.text(tmp);
output.append(splitCounter);
msg = "";
continue;
}
}
} }
output.append(_formatText(msg)); msg = escapeHtmlEntities(msg)
msg = ""; .replace(/(^|\s|\w)@\S\w*/g, htmlMention)
} .replace(/(^|\s|\w)#\S\w*/g, htmlHashtag)
} .replace(/\bhttps?:\/\/\S+/ig, htmlHttp)
.replace(/\S+@\S+\.\S+/g, htmlEmail)
.replace(/\(\d{1,2}\/\d{1,2}\)$/, htmlSplitCounter)
;
// internal function for htmlFormatMsg return _formatText(msg);
function _formatText(msg)
{
// 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) { function proxyURL(url) {
var username = ""; var proxyOpt = $.Options.getUseProxyOpt();
for( var i = 0; i < s.length; i++ ) { if (proxyOpt !== 'disable' && !$.Options.getUseProxyForImgOnlyOpt()) {
var c = s.charCodeAt(i); // proxy alternatives may be added to options page
if( (c >= 'a'.charCodeAt(0) && c <= 'z'.charCodeAt(0)) || if (proxyOpt === 'ssl-proxy-my-addr') {
(c >= 'A'.charCodeAt(0) && c <= 'Z'.charCodeAt(0)) || url = ['https://ssl-proxy.my-addr.org/myaddrproxy.php/',
(c >= '0'.charCodeAt(0) && c <= '9'.charCodeAt(0)) || url.substring(0, url.indexOf(':')), url.substr(url.indexOf('/') + 1)].join('');
c == '_'.charCodeAt(0) ) { } else if (proxyOpt === 'anonymouse')
username += s[i]; url = ['http://anonymouse.org/cgi-bin/anon-www.cgi/', url].join('');
} else {
break;
} }
}
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