Há tempos mostrei aqui um tweet de um dos funcionários do Blogger prometendo que um novo sistema de comentários estava a caminho. Creio eu que a implementação da nova interface e a integração com o Google+(rede social da Google) durante 2010 e 2011, devem ter atrasado os planos.
Exemplo qualquer de comentários aninhados |
O novo sistema de comentários é do tipo Threaded, ou aninhado. Para se ter uma idéia é só dar uma olhada em blogs da plataforma Wordpress.org ou B2Evolution. É um sistema dinâmico onde possui funções de mostrar/esconder e responder comentários, entre outros recursos. Muitos blogueiros utilizam sistemas de comentários independentes, tipo Disqus ou Intense Debate. Este último é um dos piores na minha sincera opinião, às vezes é lento, influindo na velocidade de carregamento do blog, dá uns bugs do tipo não aceitar o login e congela o navegador (Acontece comigo, juro! Eu não consigo comentar em blogs que possui o Intense Debate.)
O Marcos Lemos(@hordones) do Ferramentas Blog, há poucos dias chamou-me a atenção de novos códigos incluídos nos templates, o threaded_comment_css e o threaded_comment_js. Eu já os tinha vistos mas estava sem tempo para analisá-los.
Começo aqui com o código dos comentários aninhados (Threaded Comments) incluídos no template:
<b:includable id='threaded_comments' var='post'>
<b:include name='threaded_comment_css'/>
<div class='comments' id='comments'>
<a name='comments'/>
<h4>
<b:if cond='data:post.numComments == 1'>
1 <data:commentLabel/>:
<b:else/>
<data:post.numComments/> <data:commentLabelPlural/>:
</b:if>
</h4>
<div class='comments-content'>
<b:if cond='data:post.embedCommentForm'>
<b:include data='post' name='threaded_comment_js'/>
</b:if>
<div id='comment-holder'>
<data:post.commentHtml/>
</div>
</div>
<p class='comment-footer'>
<b:if cond='data:post.allowNewComments'>
<b:include data='post' name='threaded-comment-form'/>
<b:else/>
<data:post.noNewCommentsText/>
</b:if>
</p>
<b:if cond='data:showCmtPopup'>
<div id='comment-popup'>
<iframe allowtransparency='true' frameborder='0' id='comment-actions' name='comment-actions' scrolling='no'>
</iframe>
</div>
</b:if>
<div id='backlinks-container'>
<div expr:id='data:widget.instanceId + "_backlinks-container"'>
<b:if cond='data:post.showBacklinks'>
<b:include data='post' name='backlinks'/>
</b:if>
</div>
</div>
</div>
</b:includable>
Aqui temos o mesmo formulário, cujas linhas são semelhantes ao que já existe. O engraçado é que ele mantem as mesmas medidas que adotei no outro. Para quem acha que eu bebi, há realmente 2 frames, o antigo abaixo de
<b:includable id='comment-form' var='post'>
e o novo conforme a seguir:<b:includable id='threaded-comment-form' var='post'>
<div class='comment-form'>
<a name='comment-form'/>
<b:if cond='data:mobile'>
<p><data:blogCommentMessage/></p>
<data:blogTeamBlogMessage/>
<a expr:href='data:post.commentFormIframeSrc' id='comment-editor-src'/>
<iframe allowtransparency='true' class='blogger-iframe-colorize blogger-comment-from-post' frameborder='0' height='410' id='comment-editor' name='comment-editor' src='' style='display: none' width='100%'/>
<b:else/>
<p><data:blogCommentMessage/></p>
<data:blogTeamBlogMessage/>
<a expr:href='data:post.commentFormIframeSrc' id='comment-editor-src'/>
<iframe allowtransparency='true' class='blogger-iframe-colorize blogger-comment-from-post' frameborder='0' height='410' id='comment-editor' name='comment-editor' src='' width='100%'/>
</b:if>
<data:post.friendConnectJs/>
<data:post.cmtfpIframe/>
<script type='text/javascript'>
BLOG_CMT_createIframe('<data:post.appRpcRelayPath/>', '<data:post.communityId/>');
</script>
</div>
</b:includable>
Nesta outra seqüência, temos o CSS puro dos comentários aninhados:
<b:includable id='threaded_comment_css'> <style> .comments { clear: both; margin-top: 10px; margin-bottom: 0px; line-height: 1em; } .comments .comments-content { font-size: 13px; margin-bottom: 16px; } .comments .comment .comment-actions a { padding-top: 5px; padding-right: 5px; } .comments .comment .comment-actions a:hover { text-decoration: underline; } .comments .comments-content .comment-thread ol { list-style-type: none; padding: 0; text-align: left; } .comments .comments-content .inline-thread { padding: 0.5em 1em; } .comments .comments-content .comment-thread { margin: 8px 0px; } .comments .comments-content .comment-thread:empty { display: none; } .comments .comments-content .comment-replies { margin-top: 1em; margin-left: 36px; } .comments .comments-content .comment { margin-bottom:16px; padding-bottom:8px; } .comments .comments-content .comment:first-child { padding-top:16px; } .comments .comments-content .comment:last-child { border-bottom:0; padding-bottom:0; } .comments .comments-content .comment-body { position:relative; } .comments .comments-content .user { font-style:normal; font-weight:bold; } .comments .comments-content .icon.blog-author { width: 18px; height: 18px; display: inline-block; margin: 0 0 -4px 6px; } .comments .comments-content .datetime { margin-left:6px; } .comments .comments-content .comment-header, .comments .comments-content .comment-content { margin:0 0 8px; } .comments .comments-content .comment-content { text-align:justify; } .comments .comments-content .owner-actions { position:absolute; right:0; top:0; } .comments .comments-replybox { border: none; height: 250px; width: 100%; } .comments .comment-replybox-single { margin-top: 5px; margin-left: 48px; } .comments .comment-replybox-thread { margin-top: 5px; } .comments .comments-content .loadmore a { display: block; padding: 10px 16px; text-align: center; } .comments .thread-toggle { cursor: pointer; display: inline-block; } .comments .continue { cursor: pointer; } .comments .continue a { display: block; padding: 0.5em; font-weight: bold; } .comments .comments-content .loadmore { cursor: pointer; max-height: 3em; margin-top: 3em; } .comments .comments-content .loadmore.loaded { max-height: 0px; opacity: 0; overflow: hidden; } .comments .thread-chrome.thread-collapsed { display: none; } .comments .thread-toggle { display: inline-block; } .comments .thread-toggle .thread-arrow { display: inline-block; height: 6px; width: 7px; overflow: visible; margin: 0.3em; padding-right: 4px; } .comments .thread-expanded .thread-arrow { background: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAcAAAAHCAYAAADEUlfTAAAAG0lEQVR42mNgwAfKy8v/48I4FeA0AacVDFQBAP9wJkE/KhUMAAAAAElFTkSuQmCC") no-repeat scroll 0 0 transparent; } .comments .thread-collapsed .thread-arrow { background: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAcAAAAHCAYAAADEUlfTAAAAJUlEQVR42mNgAILy8vL/DLgASBKnApgkVgXIkhgKiNKJ005s4gDLbCZBiSxfygAAAABJRU5ErkJggg==") no-repeat scroll 0 0 transparent; } .comments .avatar-image-container { float: left; width: 36px; max-height: 36px; overflow: hidden; } .comments .avatar-image-container img { width: 36px; } .comments .comment-block { margin-left: 48px; position: relative; } /* Responsive styles. */ @media screen and (max-device-width: 480px) { .comments .comments-content .comment-replies { margin-left: 0; } } </style> </b:includable>
Abaixo temos o script dos comentários aninhados, feitos em json. Percorrendo as linhas, vemos os recursos de responder(repply), paginação (paginator), mostrar /esconder (more) entre outros:
<b:includable id='threaded_comment_js' var='post'>
<script defer='defer' expr:src='data:post.commentSrc' type='text/javascript'/>
<script type='text/javascript'>
(function() {
var items = <data:post.commentJso/>;
var msgs = <data:post.commentMsgs/>;
var postId = '<data:post.id/>';
var feed = '<data:post.commentFeed/>';
var authorName = '<data:post.author/>';
var authorUrl = '<data:post.authorUrl/>';
var blogId = '<data:top.id/>';
var baseUri = '<data:post.commentBase/>';
// <![CDATA[
feed += '?alt=json&v=2&orderby=published&reverse=false&max-results=50';
var cursor = null;
if (items && items.length > 0) {
cursor = parseInt(items[items.length - 1].timestamp) + 1;
}
var bodyFromEntry = function(entry) {
if (entry.gd$extendedProperty) {
for (var k in entry.gd$extendedProperty) {
if (entry.gd$extendedProperty[k].name == 'blogger.contentRemoved') {
return '<span class="deleted-comment">' + entry.content.$t + '</span>';
}
}
}
return entry.content.$t;
}
var parse = function(data) {
cursor = null;
var comments = [];
if (data && data.feed && data.feed.entry) {
for (var i = 0, entry; entry = data.feed.entry[i]; i++) {
var comment = {};
// comment ID, parsed out of the original id format
var id = /blog-(d+).post-(d+)/.exec(entry.id.$t);
comment.id = id ? id[2] : null;
comment.body = bodyFromEntry(entry);
comment.timestamp = Date.parse(entry.published.$t) + '';
if (entry.author && entry.author.constructor === Array) {
var auth = entry.author[0];
if (auth) {
comment.author = {
name: (auth.name ? auth.name.$t : undefined),
profileUrl: (auth.uri ? auth.uri.$t : undefined),
avatarUrl: (auth.gd$image ? auth.gd$image.src : undefined)
};
}
}
if (entry.link) {
if (entry.link[2]) {
comment.link = comment.permalink = entry.link[2].href;
}
if (entry.link[3]) {
var pid = /.*comments/default/(d+)?.*/.exec(entry.link[3].href);
if (pid && pid[1]) {
comment.parentId = pid[1];
}
}
}
comment.deleteclass = 'item-control blog-admin';
if (entry.gd$extendedProperty) {
for (var k in entry.gd$extendedProperty) {
console.log(entry.gd$extendedProperty[k].name + ' - ' + entry.gd$extendedProperty[k].value);
if (entry.gd$extendedProperty[k].name == 'blogger.itemClass') {
comment.deleteclass += ' ' + entry.gd$extendedProperty[k].value;
}
}
}
comments.push(comment);
}
}
return comments;
};
var paginator = function(callback) {
if (hasMore()) {
var url = feed;
if (cursor) {
url += '&published-min=' + new Date(cursor).toISOString();
}
window.bloggercomments = function(data) {
var parsed = parse(data);
cursor = parsed.length < 50 ? null
: parseInt(parsed[parsed.length - 1].timestamp) + 1
callback(parsed);
window.bloggercomments = null;
}
url += '&callback=bloggercomments';
var script = document.createElement('script');
script.type = 'text/javascript';
script.src = url;
document.getElementsByTagName('head')[0].appendChild(script);
}
};
var hasMore = function() {
return !!cursor;
};
var getMeta = function(key, comment) {
if ('iswriter' == key) {
var matches = !!comment.author
&& comment.author.name == authorName
&& comment.author.profileUrl == authorUrl;
return matches ? 'true' : '';
} else if ('deletelink' == key) {
return baseUri + '/delete-comment.g?blogID=' + blogId + '&postID=' + comment.id;
} else if ('deleteclass' == key) {
return comment.deleteclass;
}
return '';
};
var replybox = null;
var replyUrlParts = null;
var replyParent = undefined;
var onReply = function(commentId, domId) {
if (replybox == null) {
// lazily cache replybox, and adjust to suit this style:
replybox = document.getElementById('comment-editor');
if (replybox != null) {
replybox.height = '250px';
replybox.style.display = 'block';
replyUrlParts = replybox.src.split('#');
}
}
if (replybox && (commentId !== replyParent)) {
document.getElementById(domId).insertBefore(replybox, null);
replybox.src = replyUrlParts[0]
+ (commentId ? '&parentID=' + commentId : '')
+ '#' + replyUrlParts[1];
replyParent = commentId;
}
};
var tok = 'comment-form_';
var hash = window.location.hash || '';
var startThread = hash.indexOf(tok) == 1 ? hash.substring(tok.length + 1) : undefined;
// Configure commenting API:
var configJso = {
'maxDepth': 2
};
var provider = {
'id': postId,
'data': items,
'loadNext': paginator,
'hasMore': hasMore,
'getMeta': getMeta,
'onReply': onReply,
'rendered': true,
'initReplyThread': startThread,
'config': configJso,
'messages': msgs
};
var render = function() {
if (window.goog && window.goog.comments) {
var holder = document.getElementById('comment-holder');
window.goog.comments.render(holder, provider);
}
};
// render now, or queue to render when library loads:
if (window.goog && window.goog.comments) {
render();
} else {
window.goog = window.goog || {};
window.goog.comments = window.goog.comments || {};
window.goog.comments.loadQueue = window.goog.comments.loadQueue || [];
window.goog.comments.loadQueue.push(render);
}
})();
// ]]>
</script>
</b:includable>
A ativação desse novo sistema deve ocorrer neste ano (Espero!) e assim acabar com as reclamações de muitos usuários que odeiam o sistema atual. A única coisa que me deixou triste é que não há (ou se tem, eu não vi...) a separação dos anônimos de nome/url e possibilidade de comentar com outros logins (Twitter, Facebook, etc). Talvez estes deverão ser configurados no painel de controle. De qualquer maneira, esses códigos são a prova que haverá uma mudança. E quem viver, verá!