// ==UserScript== // @name Shack New Comments Marker // @namespace http://www.apartment167.com/overload/greasemonkey // @description Marks which comments are new since your last refresh // @include http://shacknews.com/laryn.x?* // @include http://*.shacknews.com/laryn.x?* // @include http://*.shacknews.com/frame_laryn.x?* // @include http://shacknews.com/frame_laryn.x?* // ==/UserScript== /* Shack New Comments Marker Author: Greg Laabs "OverloadUT" (C)2008 Greg Laabs REVISIONS: 2008-05-07 - Initial Release */ (function() { function getTime() { benchmarkTimer = new Date(); return benchmarkTimer.getTime(); } // TODO: Set back to 400 before release var MAX_NEW_POSTS = 40000; var benchmarkTimer = null; var scriptStartTime = getTime(); function xpath_single(query) { return document.evaluate(query, document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null); } function xpath_single_parent(query) { return parent.document.evaluate(query, parent.document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null); } function xpath(query) { return document.evaluate(query, document, null, XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null); } // Gets the last ID posted on the entire page. // Used to record what the last post was every time the page loads, so we know what is new on the next refresh. function getLastID() { var firstroot = xpath_single('//div[contains(@class, "oneline0")]'); var elem = firstroot.singleNodeValue; var id = elem.parentNode.id; return id.substr(5); } function getLastIDInThread(id) { var firstroot = xpath_single_parent('//div[@id="'+id+'"]//div[contains(@class, "oneline0")]'); var elem = firstroot.singleNodeValue; var id = elem.parentNode.id; return id.substr(5); } function getAllPosts() { var a = xpath('//li[starts-with(@id, "item_")]') return a; } function getAllNewPosts(last_id) { var a = xpath('//li[number(substring-after(@id, "item_"))>'+last_id+']') return a; } unsafeWindow.temptest = getAllNewPosts; function modifyPosts(last_id) { elems = getAllNewPosts(last_id); new_posts = 0; new_myreplies = 0; var aborted = false; //for (var i = 0; i < elems.length; i++) { for (item = null, i = 0; item = elems.snapshotItem(i); i++) { new_posts++; if(new_posts > MAX_NEW_POSTS) { aborted = true; break; } var replytome = false; if(my_id != null && highlightRepliesToMe) { var parentdiv = item.parentNode.parentNode; var parentclass = ''; if(parentdiv.className != "root") { if(parentdiv.className == "capcontainer") { // parent is a root post parentclass = parentdiv.parentNode.childNodes[1].className; } else { // parent is a reply parentclass = parentdiv.childNodes[1].className; } if(parentclass.substr(parentclass.length - my_id.length) == my_id) { new_myreplies++; replytome = true; } } } if(replytome) { if(item.className == 'last') item.className += ' newcommentmarker_newpostlast_tome'; else if (item.className == '') item.className = 'newcommentmarker_newpost_tome'; } else { if(item.className == 'last') item.className += ' newcommentmarker_newpostlast'; else if(item.className == 'sel last') item.className += ' newcommentmarker_newrootpost'; else if (item.className == '') item.className = 'newcommentmarker_newpost'; } // This is a nasty little hack to be sure the veritical lines go all blue when there is long stream of new posts. if (item == item.parentNode.childNodes[1]) { item.parentNode.className = 'newcommentmarker_newulnode'; } } if(aborted) return false; else return true; } function getMyID() { var id = GM_getValue("my_id", null); if(id == null) { var elem = xpath_single('//a[contains(@class,"this_user")]/..'); elem = elem.singleNodeValue; if(elem) { id = elem.className.substr(elem.className.indexOf("olauthor_")+9); GM_setValue("my_id",id); } else { } } return id; } // START var new_posts = 0; var new_myreplies = 0; var my_id = getMyID(); var highlightRepliesToMe = GM_getValue("highlightRepliesToMe", null); if(highlightRepliesToMe == null) { highlightRepliesToMe = true; GM_setValue("highlightRepliesToMe", true); } if (location.pathname == '/laryn.x') { var last_refresh = GM_getValue("last_refresh", null); if (last_refresh != null) { var timer = getTime(); var success = modifyPosts(last_refresh); //if (GM_log) { GM_log('modifyPosts:' + (getTime() - timer) + 'ms'); } var timer = getTime(); GM_addStyle(<>>); //if (GM_log) { GM_log('addStyle:' + (getTime() - timer) + 'ms'); } if(success) { var elem = xpath_single('//p[@class="postcount"]'); elem = elem.singleNodeValue; elem.innerHTML += ' ('+new_posts+' new posts)'; } } var newlastid = getLastID(); if (last_refresh == null || parseInt(newlastid) > parseInt(last_refresh)) { GM_setValue("last_refresh",newlastid); } if (GM_log) { GM_log((getTime() - scriptStartTime) + 'ms ('+new_posts+' new posts processed)'); } } else if (location.pathname == '/frame_laryn.x') { // frame_laryn.x is used when LOADING posts in a thread (loads content, replaces iframe, etc.) if (!unsafeWindow.shacknewcommentmarker_replace_whole_element_from_iframe) { unsafeWindow.shacknewcommentmarker_replace_whole_element_from_iframe = unsafeWindow.replace_whole_element_from_iframe; unsafeWindow.replace_whole_element_from_iframe = function(element_name) { var lastid; if(unsafeWindow.parent.threadwatcher_active && unsafeWindow.parent.threadwatcher_lastReadID){ lastid = unsafeWindow.parent.threadwatcher_lastReadID; } else { lastid = getLastIDInThread(element_name); } var success = modifyPosts(lastid); /* TODO: Need a good place to put the display of how many new posts in a refreshed thread. The capnote idea doesn't work. if(count) { var elem = xpath_single('//div[@class="capcontainer"]'); elem = elem.singleNodeValue; elem.innerHTML = '
'+count+' new posts
' + elem.innerHTML; } */ // Call original function return unsafeWindow.shacknewcommentmarker_replace_whole_element_from_iframe(element_name); } } if (GM_log) { GM_log((getTime() - scriptStartTime) + 'ms ('+new_posts+' new posts processed)'); } } })();