Social Fixer Hacks

All diffs are currently relative to socialfixer.user.js v7.711. For readability, leading whitespace has been trimmed (so they won't apply directly — applying by hand is better anyway as some of these are hackish and might be better done differently — though as it happens there is a full diff at the end of the source of this HTML page).

I'm currently running SFx under the Scriptish extension 0.1.11 in Mozilla SeaMonkey 2.19.

Does not detect any comments for most posts below the fold

Pressing the SFx debug button usually reveals "Comments found=0" for any post that was below the "More Stories" link. Consequently, these posts don't reappear as they should when they have new comments. I surmise that this is because Facebook is loading the comments "lazily", and so they aren't present in the copy of the post that SFx gets to inspect when it arrives.

Curiously, the exceptions to this rule are posts from Pages, which have a little icon bar at the bottom (which FB seems to call the "BlingBox" or the "feedback toggle link") telling you how many likes, comments and shares this post has. In fact, in that case, Facebook seems to send the correct total number of comments with the original post, and then rewrites it so that it contains the number of comment threads. Hence those odd screenshots which show 11 comments in the BlingBox but SFx saying "15 comments total". Such a post would have 4 replies to the 11 top-level comments, making 15 in total, but gives the appearance that SFx had no way of knowing that.

So my solution to this is now a hack of two parts: firstly, save the original post-processing logic in a function and don't run it until FB's scripts have finished processing the post; but secondly, when the post arrives immediately extract the comment count from its BlingBox if it has one, before FB gets to it. (Note: it's not known if this works for a post that has comments or shares but no likes.)

Allowing FB to process the post is accomplished by putting SFx's processing into a setTimeout with zero timeout. This essentially yields control back to FB and queues the SFx processing ready for when FB finishes with it.

--- 7.711/socialfixer.user.js 2013-07-18 15:03:40.000000000 +0100 +++ 7.711-imc/socialfixer.user.js 2013-07-22 14:11:53.000000000 +0100 @@ -3201,6 +3201,6 @@ } return false; } -bind(document,"DOMNodeInserted", function (e) { +function dom_node_inserted(e) { var f,id,selector,el,els; var o = target(e); @@ -3238,6 +3238,15 @@ } +} +bind(document,"DOMNodeInserted", function (e) { + var o = target(e); + var ftl = QS(o,'.feedback_toggle_link .uiBlingBox span.text ~ span.text'); + if (ftl && ftl.innerHTML) { + var count = +ftl.innerHTML; + if (count && !isNaN(count)) o.setAttribute('comment_count',count); + } + setTimeout(function(){dom_node_inserted(e);},0); }); // ==================================================================

However, one side-effect of this is that the event "better_fb_friend_tracker_pagelet" sometimes seems to trigger itself recursively. Right now at the time of writing this it does not seem to be a problem, but it does have a tendency to come back randomly and I am wondering if this is a problem for some of the SFx users who have reported their browser slowing to a crawl or using up too much system memory. Anyway, I'm monitoring it as follows (warning, very hackish indeed):

@@ -5285,7 +5300,8 @@ else { insertAtPosition( feed_right_column, section, 2 ); } - onIdLoad('better_fb_friend_tracker_pagelet', function(){ setTimeout(loadContent,10); }); + var ftpctr=0; + onIdLoad('better_fb_friend_tracker_pagelet', function(){ GM_log("better_fb_friend_tracker_pagelet " + ++ftpctr); if (ftpctr<5)setTimeout(loadContent,10); }); } } } catch(e) { add_error("Friend Tracker Error",e.toString()); }

TypeError: o is null

For some reason, the dom_node_inserted function sometimes seems to trigger with a null target. I imagine this is because the above hack allows FB's scripts to process the event first, and they sometimes destroy the target before SFx can get at it. Anyway, it does no harm to guard against this.

@@ -3205,6 +3205,6 @@ var f,id,selector,el,els; var o = target(e); - if (ignoreMutation(o)) { return; } + if (!o || ignoreMutation(o)) { return; } if (options.get("fix_timestamps")) { fix_timestamps(o);

Does not correctly understand "View x more comments"

A few months ago Facebook stopped saying "View all x comments" and started saying "View x more comments" instead. SFx can't get the total number of comments in the latter case (unless there is a BlingBox).

@@ -4361,5 +4370,11 @@ } return view_all_count + new_comment_count; } + if ( /view ([,.\d]+) more comment/i.test(c.innerHTML) ) { + var comment_count = +(RegExp.$1.replace(/[,.]/g,"")); + var comments = QSA(c,comment_selector); + if (comments) comment_count += comments.length; + return comment_count; + } var pager_row = QS(c,'.UFIPagerRow'); if (pager_row) {

Does not correctly understand "x of y" comments

This seems to be mostly because of typos in the code.

@@ -4364,8 +4373,8 @@ var pager_row = QS(c,'.UFIPagerRow'); if (pager_row) { - var counter = QS(pager_row,'.rfloat,.fcg'); + var counter = QS(pager_row,'.rfloat .fcg'); if (counter) { - var count = match(counter.innerHTML,'/\s+\s+of\s+(\d+)/'); + var count = match(counter.innerHTML,/\d+\s+of\s+(\d+)/); if (count) { return count; }

Live timestamp updates cause browser slowness

Assuming "Fix timestamps to show actual date/time" is not enabled, Facebook periodically sends live timestamp updates for every timestamp currently on the screen. Each of these causes an insertion event that SFx tries to process, and this can eat up processing time, particularly when a lot of posts and comments have been expanded. Telling SFx not to process these events significantly reduces processing time and does not seem to have any adverse effects.

@@ -3191,7 +3191,7 @@ var ignoreMutation = function(o) { var tn = o.tagName; if (o.nodeType==3 || internalUpdate) { return true; } - if (tn=="SCRIPT" || tn=="LINK" || tn=="INPUT" || tn=="BR" || tn=="STYLE" || tn=="META") { return true; } + if (tn=="SCRIPT" || tn=="LINK" || tn=="INPUT" || tn=="BR" || tn=="STYLE" || tn=="META" || tn=="ABBR") { return true; } var cn = o.className, pn=o.parentNode, pcn=""; if (pn&&pn.className) { pcn = pn.className;

Finding the child node count

A comment in the SFx source code says...

// So we stored the childNode length and compare it later when marking as read. Yuck
...but it appears to calculate it wrongly by using QS (return the first comment) instead of QSA (return all comments). It's not clear whether this code is still relevant, but it may as well be less wrong.

@@ -4068,7 +4077,7 @@ // So we stored the childNode length and compare it later when marking as read. Yuck! // cnc = childNodeCount post_data.cnc = 0; - if (c) { post_data.cnc = (QS(c,comment_selector)||[]).length; } + if (c) { post_data.cnc = (QSA(c,comment_selector)||[]).length; } // But not if the user has disabled following of comments var new_comments_exist = false;