vBISpy - AJAX real-time feed of new posts/threads
This modification is in the archives.
After seeing the http://www.digg.com/spy application; I wondered if this could be done for vBulletin as well. I came across this http://blablist.crowdiq.com/iqueue/votespy_howto.jsp which had a "how to" on how they built a similiar application to do the same thing. Taking a page from their book (i.e. the code), I modified it for use with vBulletin.
During development, I also came across this post here on vBulletin.Org where the very subject had already been discussed. So I put this together; a simple ZIP file with a single PHP script, three javascript files and 4 images. Installation . UNZIP the file into your forums directory . That's it! Virtually all the code to customize the page is in the vaispy.php script; there are no plugins, no templates and no phrases. You do not need to do anything further; this should work right out of the box. In your browser, open the URL: http://www.yourforum.com/forum/vaispy.php You can see examples of this at: http://www.viperalley.com/forum/vaispy.php http://www.extremefitness.com/forum/vaispy.php Note: I claim no ownership of this code except for the file vaispy.php - the rest of the files were using 'freely distributable' sources. As such, you may use these files as you wish, but please do not remove the copyrights. This modification is for vBulletin 3.6 only, if you are running vBulletin 3.5 you will need to see this thread. JOIN THE vBIspy Network! Once you have this mod installed, you can join the http://www.vbispy.com to have your threads appear on this site; the vBIspy Network is a great way for people to see what's going on in various vBulletin communities and for forum owners to promote their sites and generate new traffic. Optional add-ons Who's Online mod for this: vBISpy Who's Online resolution plug-in vBAdvanced Module: vBISpy module - live AJAX feed of new threads - for vBAdvanced CMPS UPDATES 1.0.4 Added buro9's code from here Spoiler (click to open)
Another minor thing.
If nothing is returned, you should return the Xml with an empty root node of <events /> This will avoid invalid Xml errors being silently thrown in the JavaScript. Simply change this in the .php file: PHP Code:
if ( $output )
PHP Code:
if ( $output )
Code:
try { events = request.responseXML.getElementsByTagName("events")[0]; event = events.getElementsByTagName("event"); } catch (e) { setTimeout("getXML()", 5000); return; } Code:
try { events = request.responseXML.getElementsByTagName("events")[0]; event = events.getElementsByTagName("event"); if (event.length == 0) { setTimeout("getXML()", 5000); return; } } catch (e) { setTimeout("getXML()", 5000); return; } Close
1.0.5 - 9.9.06 Modified some JavaScript in va_spy.js to remove split strings 1.0.6 - 9.10.06 Added date cuffoff code from here Spoiler (click to open)
All the credit goes to TECK ( Floren )
In order to optimize the code Replace Code:
$getthreads = $db->query_read(" SELECT thread.*, post.pagetext AS preview, post.userid AS lastpuserid FROM ".TABLE_PREFIX."thread AS thread LEFT JOIN ".TABLE_PREFIX."deletionlog AS deletionlog ON(thread.threadid = deletionlog.primaryid AND type = 'thread') LEFT JOIN ".TABLE_PREFIX."post AS post ON(post.postid = thread.lastpostid) WHERE open <> 10 AND thread.lastpostid > $lastpostid AND forumid NOT IN (0$blockforums) AND thread.visible = '1' AND deletionlog.primaryid IS NULL ORDER BY lastpost DESC LIMIT 10"); Code:
// The number of days to scan the table for ... // 86400 represents the number of seconds in 24hrs $daysprune = 1; $datecut = "AND thread.lastpost >= " . (TIMENOW - ($daysprune * 86400)); $getthreads = $db->query_read(" SELECT thread.*, post.pagetext AS preview, post.userid AS lastpuserid FROM " . TABLE_PREFIX . "thread AS thread LEFT JOIN " . TABLE_PREFIX . "deletionlog AS deletionlog ON (thread.threadid = deletionlog.primaryid AND type = 'thread') LEFT JOIN " . TABLE_PREFIX . "post AS post ON (post.postid = thread.lastpostid) WHERE open <> 10 AND thread.lastpostid > $lastpostid AND forumid NOT IN (0$blockforums) AND thread.visible = '1' AND deletionlog.primaryid IS NULL $datecut ORDER BY thread.lastpost DESC LIMIT 10 "); Close
1.0.7 - 9.12.06 va_spy.js: Added a forum url variable to allow for integration with portals or other products outside the forum directory va_spy.js: Added xmldelay variable at top of script for easier configuration or repolling Updated files: vaispy.php, vb_spy.js 1.0.8 - 9.13.06 vaispy.php - changed code for checking for forum permissions to include password protected forums, added javascript tag for script code 1.0.9 - 9.16.06 vaispy.php va_spy.js va_effects.js - modified to allow for proper display in Opera browsers and moved more html into vaispy.php to allow for stylevars, trimmed va_effects.js to remove unused code (ForumDog's suggestions Spoiler (click to open)
Quote by MPDev
Yes, ok ok ok. I'm still getting it up to scratch for my own site. But since you'd like to hear now, I'm not done but these are my changes so far, I will include what I already posted that has not yet currently been added for ease of reading.
The default title length as set by vBulletin is actually 85 characters not 80. In vaispy.php FIND: Code:
(unhtmlspecialchars($thread['title']), 80) Code:
(unhtmlspecialchars($thread['title']), 85) I moved the HTML to a vBulletin template, it's easier to separate code from presentation that way and allows use of template caching more flexibility with conditionals and so on so I'll *assume* that's what you'll want to do. It's very easy to do manually as long as this isn't a plugin which for the time being is unnecessary. FIND: Code:
// pre-cache templates used by all actions $globaltemplates = array(); Code:
// pre-cache templates used by all actions $globaltemplates = array('vaispy'); Now we have to tell the page to fetch the template, and we're also going to add a couple of lines to keep the vBulletin breadcrumb going. In vaispy.php FIND: Code:
eval('$navbar = "' . fetch_template('navbar') . '";'); $headinclude = process_replacement_vars($headinclude); $navbar = process_replacement_vars($navbar); eval('$footer = "' . fetch_template('footer') . '";'); $footer = process_replacement_vars($footer); REPLACE WITH: Code:
$navbits = array(); $navbits[$parent] = 'vaispy'; $navbits = construct_navbits($navbits); eval('$navbar = "' . fetch_template('navbar') . '";'); $navbar = process_replacement_vars($navbar); eval('$headinclude = "' . fetch_template('headinclude') . '";'); $headinclude = process_replacement_vars($headinclude); eval('$footer = "' . fetch_template('footer') . '";'); $footer = process_replacement_vars($footer); eval('print_output("' . fetch_template('vaispy') . '");'); Looking good! Now let's just transfer it over to the template. REMOVE: Code:
echo<<<VAPRINT Code:
VAPRINT; ?> This will allow Microstats to show up in the footer and whitespace strippers, template caches etc, makes the code valid too. In template vaispy: FIND: Code:
$footer Code:
</body> </html> Because we're now in a template there's no reason not to use style-specific directories to allow people with multiple themes not to be forced to create a new top-level directory for the buttons. You must ensure your buttons are copied to each misc directory for every style you have installed. Also added is code to ensure the mouse changes to the hand icon over a button to show it is a clickable link, plus compatibility commenting for inline javascript code. In va_spy.js REMOVE Code:
function pauseSpy() { var playimg = document.getElementById("vaplay"); var pauseimg = document.getElementById("vapause"); playimg.src = "images/misc/play_up.gif"; playimg.alt = "Click to Play"; pauseimg.src = "images/misc/pause_down.gif"; pauseimg.alt = "Paused..."; pause(); } function playSpy() { var playimg = document.getElementById("vaplay"); var pauseimg = document.getElementById("vapause"); playimg.src = "images/misc/play_down.gif"; playimg.alt = "Playing..."; pauseimg.src = "images/misc/pause_up.gif"; pauseimg.alt = "Click to Pause"; resume(); } function pause() { play = 0; } function resume() { play = 1; } In vaispy.php FIND: Code:
<script language="javascript" type="text/javascript"> <!-- spymax = 25; // --> </script> Code:
<script language="javascript" type="text/javascript"> <!-- function pauseSpy() { var playimg = document.getElementById("vaplay"); var pauseimg = document.getElementById("vapause"); playimg.src = "$stylevar[imgdir_misc]/play_up.gif"; playimg.alt = "Click to Play"; pauseimg.src = "$stylevar[imgdir_misc]/pause_down.gif"; pauseimg.alt = "Paused..."; pause(); } function playSpy() { var playimg = document.getElementById("vaplay"); var pauseimg = document.getElementById("vapause"); playimg.src = "$stylevar[imgdir_misc]/play_down.gif"; playimg.alt = "Playing..."; pauseimg.src = "$stylevar[imgdir_misc]/pause_up.gif"; pauseimg.alt = "Click to Pause"; resume(); } function pause() { play = 0; } function resume() { play = 1; } // --> </script> Code:
<img id="vaplay" src="images/misc/play_up.gif" alt="Play" title="Play Comments" onclick="playSpy();" /> <img id="vapause" src="images/misc/pause_up.gif" alt="Pause" title="Pause Comments" onclick="pauseSpy();" /> Code:
<img id="vaplay" src="$stylevar[imgdir_misc]/play_down.gif" style="cursor:pointer;" alt="Play" title="Play Comments" onclick="playSpy();" /> <img id="vapause" src="$stylevar[imgdir_misc]/pause_up.gif" style="cursor:pointer;" alt="Pause" title="Pause Comments" onclick="pauseSpy();" /> Now we're going to make the opacity code which creates the nice fading effect work across all browsers instead of currently very few. I am currently pulling images into the post/thread Spy, so if you/the author decides to do this the fade effect is also already there for them too. FIND: Code:
opacity:.XX REPLACE WITH: Code:
class="spyfadeX" FIND: Code:
$headinclude Code:
<style type="text/css"> .spyfade1 div, .spyfade1 span,, .spyfade1 td, .spyfade1 img { opacity:0.90; filter:alpha(opacity=90); -moz-opacity:0.90; } .spyfade2 div, .spyfade2 span, .spyfade2 td, .spyfade2 img { opacity:0.80; filter:alpha(opacity=80); -moz-opacity:0.80; } .spyfade3 div, .spyfade3 span, .spyfade3 td, .spyfade3 img { opacity:0.70; filter:alpha(opacity=70); -moz-opacity:0.70; } .spyfade4 div, .spyfade4 span, .spyfade4 td, .spyfade4 img { opacity:0.50; filter:alpha(opacity=50); -moz-opacity:0.50; } .spyfade5 div, .spyfade5 span, .spyfade5 td, .spyfade5 img { opacity:0.30; filter:alpha(opacity=30); -moz-opacity:0.30; } </style> Code:
FIND: if (i + 5 > spymax) { document.getElementById("spy_table").rows[i].cells[0].className = 'alpha(opacity=' + (((spymax - i) * 20) + 5) + ')'; document.getElementById("spy_table").rows[i].cells[1].style.filter = 'alpha(opacity=' + (((spymax - i) * 20) + 5) + ')'; document.getElementById("spy_table").rows[i].cells[2].style.filter = 'alpha(opacity=' + (((spymax - i) * 20) + 5) + ')'; document.getElementById("spy_table").rows[i].cells[3].style.filter = 'alpha(opacity=' + (((spymax - i) * 20) + 5) + ')'; } Code:
// if (i + 5 > spymax) { // document.getElementById("spy_table").rows[i].cells[0].className = 'alpha(opacity=' + (((spymax - i) * 20) + 5) + ')'; // document.getElementById("spy_table").rows[i].cells[1].style.filter = 'alpha(opacity=' + (((spymax - i) * 20) + 5) + ')'; // document.getElementById("spy_table").rows[i].cells[2].style.filter = 'alpha(opacity=' + (((spymax - i) * 20) + 5) + ')'; // document.getElementById("spy_table").rows[i].cells[3].style.filter = 'alpha(opacity=' + (((spymax - i) * 20) + 5) + ')'; // } The reason Opera is failing to render properly is because it does not download elements with {display:none;}, unlike other browsers which download them but don't show them. This is actually quite a bandwidth saver at times and usually A Good Thing, but here it is causing problems because the table cells which the javascript is throwing out have no table row structure due to them having the attribute {display:none;}, so they're just piling up as lone cells without a row. MPDev seemed to want this now , but otherwise it's fine. Since IE is already the one having trouble doing...more or less anything...and it can't handle the non-table code, we're going to continue the slightly painful IE-specific code theme. I'm afraid I've already heavily optimised and customised the appearance to match my threadbit so I'm sorry to say this is rather vague. In va_spy.js FIND: Code:
text = '<td class="alt1" align="center"><div class="smallfont"><strong>' + what + '</strong></div></td><td class="alt2"><div class="smallfont">' + poster_clip + '</div></td><td class="alt1Active">' + clip + '</td><td align="center" class="alt1"><div class="smallfont">' + where + '</div></td>'; ***Note: I now have this working on any resolution with Opera & Firefox and hopefully every other browser, BUT I only use three cells not four like the default code so you're going to have to use my code as a template to work out the layout for four. Take note of the clears and floats and make sure you assign a % width to the thread/post section and a px width to all the others. Let me know if you need a hand. Code:
// Did I mention IE is "special"? Help it avoid the scary clever presentation. if (is_ie) { text = '<td class="alt1 smallfont" align="center">' + ITEM + '</td>'; } else { text = '<span class="alt1 smallfont" style="display:inline-block;float:left;width:30px;text-align:center;clear:left;"><img src="' + iconpath + '" alt="" border="0" /></span><span class="alt1 smallfont" style="display:inline-block;float:left;width:90%;clear:none;"><span class="alt1 smallfont" style="display:inline-block;float:right;width:200px;text-align:right;clear:none;">' + where + '</span>' + clip + '</span>'; } Now we have to add the accompanying code to the template to match. Again it's a bit vague because of my template, sorry. This is the general idea. I can only test on Opera, Firefox and IE but it works across all 3, latest release versions, and should be good across other modern browsers as tables are really only used for things like this because IE can't handle anything more complicated. FIND: Code:
<table class="tborder" cellpadding="6" cellspacing="1" border="0" width="100%" align="center" id="spy_table"> <thead> <tr align="center"><td class="thead" width="100">Event</td><td class="thead" width="190">By</td><td class="thead">Thread/Post</td><td class="thead" width="190">Forum</td></tr> </thead> <tbody class="alt1"> <tr id="row1" style="display: none;"> </tr> <tr id="row2" style="display: none;"> </tr> <tr id="row3" style="display: none;"> </tr> <tr id="row4" style="display: none;"> </tr> <tr id="row5" style="display: none;"> </tr> <tr id="row6" style="display: none;"> </tr> <tr id="row7" style="display: none;"> </tr> <tr id="row8" style="display: none;"> </tr> <tr id="row9" style="display: none;"> </tr> <tr id="row10" style="display: none;"> </tr> <tr id="row11" style="display: none;"> </tr> <tr id="row12" style="display: none;"> </tr> <tr id="row13" style="display: none;"> </tr> <tr id="row14" style="display: none;"> </tr> <tr id="row15" style="display: none;"> </tr> <tr id="row16" style="display: none;"> </tr> <tr id="row17" style="display: none;"> </tr> <tr id="row18" style="display: none;"> </tr> <tr id="row19" style="display: none;"> </tr> <tr id="row20" style="display: none;"> </tr> <tr id="row21" style="display: none; opacity:.85"> </tr> <tr id="row22" style="display: none; opacity:.65"> </tr> <tr id="row23" style="display: none; opacity:.45"> </tr> <tr id="row24" style="display: none; opacity:.25"> </tr> <tr id="row25" style="display: none; opacity:.05"> </tr> </tbody> </table> Code:
<if condition="is_browser('ie')"> <table class="tborder" cellpadding="6" cellspacing="0" border="0" width="100%" align="center" id="spy_table"> <thead> <tr align="center"><td class="thead" width="100">Event</td><td class="thead" width="190">By</td><td class="thead">Thread/Post</td><td class="thead" width="190">Forum</td></tr> </thead> <tbody class="alt1"> <tr id="row1" style="display:none;"></tr> <tr id="row2" style="display:none;"></tr> <tr id="row3" style="display:none;"></tr> <tr id="row4" style="display:none;"></tr> <tr id="row5" style="display:none;"></tr> <tr id="row6" style="display:none;"></tr> <tr id="row7" style="display:none;"></tr> <tr id="row8" style="display:none;"></tr> <tr id="row9" style="display:none;"></tr> <tr id="row10" style="display:none;"></tr> <tr id="row11" style="display:none;"></tr> <tr id="row12" style="display:none;"></tr> <tr id="row13" style="display:none;"></tr> <tr id="row14" style="display:none;"></tr> <tr id="row15" style="display:none;"></tr> <tr id="row16" style="display:none;"></tr> <tr id="row17" style="display:none;"></tr> <tr id="row18" style="display:none;"></tr> <tr id="row19" style="display:none;"></tr> <tr id="row20" style="display:none;"></tr> <tr id="row21" style="display:none;" class="spyfade1"></tr> <tr id="row22" style="display:none;" class="spyfade2"></tr> <tr id="row23" style="display:none;" class="spyfade3"></tr> <tr id="row24" style="display:none;" class="spyfade4"></tr> <tr id="row25" style="display:none;" class="spyfade5"></tr> </tbody> </table> <else /> <table class="tborder" cellpadding="6" cellspacing="0" border="0" width="100%" align="center" id="spy_table"> <tr><td class="tcat" width="100%"> <span style="display:inline-block;float:left;width:50px;">Event</span><span style="display:inline-block;float:left;width:50px;">By</span><span style="display:inline-block;float:left;width:90%;">Thread/Post</span><span style="display:inline-block;float:left;width:200px%;">Forum</span> </td></tr> <tr><td> <div id="row1" style="display:none;"></div> <div id="row2" style="display:none;"></div> <div id="row3" style="display:none;"></div> <div id="row4" style="display:none;"></div> <div id="row5" style="display:none;"></div> <div id="row6" style="display:none;"></div> <div id="row7" style="display:none;"></div> <div id="row8" style="display:none;"></div> <div id="row9" style="display:none;"></div> <div id="row10" style="display:none;"></div> <div id="row11" style="display:none;"></div> <div id="row12" style="display:none;"></div> <div id="row13" style="display:none;"></div> <div id="row14" style="display:none;"></div> <div id="row15" style="display:none;"></div> <div id="row16" style="display:none;"></div> <div id="row17" style="display:none;"></div> <div id="row18" style="display:none;"></div> <div id="row19" style="display:none;"></div> <div id="row20" style="display:none;"></div> <div id="row21" style="display:none;" class="spyfade1"></div> <div id="row22" style="display:none;" class="spyfade2"></div> <div id="row23" style="display:none;" class="spyfade3"></div> <div id="row24" style="display:none;" class="spyfade4"></div> <div id="row25" style="display:none;" class="spyfade5"></div> </td></tr> </table> </if> Finally, unless you've looked you won't be aware that the va_effects JS file contains considerably more effects than just the fade-in (called Appear) used by default. I went through most of them, I don't think any consistently worked properly (indeed, neither does the fade-in effect since it doesn't work in IE, this is probably due to the lack of varying opacity code as I mentioned earlier). However, since it's the default and obviously you can only use one effect I removed the other code from the effects file and trimmed it down to just the Appear effect. This saves 20kb from the initial download time. The file is attached for anyone who wants it, to use it just place the attached file in your clientscript folder with the va_effects.js file and in your vaispy template just replace the words va_effects.js with va_appear.js. Phew! Hope that helped. Close
1.0.10 - 9.17.06 va_prototype.js - removed 20kb of unused code 1.1.11 - 9.25.2006 vaispy.php va_spy.js - added SirAdrian's mods for thread status icons and alternating row colors - added code to prepopulate the first 10 rows with existing threads allowing for 5 new ones to be added in scrolling mode (versus scrolling starting from the first thread). - added option to display subscribed threads only 1.1.12 - 9.26.2006 vaispy.php - added code to add empty rows if initial pull has less than 20 rows. Download
This modification is archived, downloads are still allowed. Supporters / CoAuthors
|
Similar Mods
Portal Software vBISpy module - live AJAX feed of new threads - for vBAdvanced CMPS | vBulletin 3.6 Add-ons |
vBISpy - AJAX real-time feed of new posts/threads (for vB3.5) | vBulletin 3.5 Add-ons |