Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- // ==UserScript==
- // @name Thread Page Finder
- // @namespace tpf
- // @description Find's the thread's page number. Can also auto-update.
- // @include http://boards.4chan.org/*/res/*
- // @include https://boards.4chan.org/*/res/*
- // @version 1.4.11.05142012
- // @copyright 05092011, tpf
- // @compatibility Firefox 4, Chrome 11 (with Tampermonkey 2.0)
- // ==/UserScript==
- /*Changelog
- 1.4.11.05142012 - updated regex for the new HTML
- 1.4.10.03262012 - included Auto to saved variables
- 1.4.9.05142011 - changed init trigger
- 1.4.8.05142011 - release, no records
- */
- (function(){
- //Please use the GM registered menus if present
- //clearSettings();//Reset defaults
- //toggleTitles(false);//Turn off titles/hover messages
- var Frontpage = {
- url: location.href.match(/(^.*\/)res\//i)[1],
- board: null,
- lastmodify: null,
- is_f: false,
- rx_threadnos: null,
- rx_pages: null,
- init: function(){
- this.is_f = /\.org\/f\//i.test(this.url);
- this.board = Frontpage.url.replace(/.*\.org/i,'');
- this.rx_threadnos = (this.is_f ?
- /<a\shref=(?:["']|)res\/(\d+)(?:["']|)>/gi : //f
- /<a\shref=(?:["']|)res\/(\d+)(?:["']|)\sclass=(?:["']|)replylink(?:["']|)/gi );
- this.rx_pages = /\[<a\shref=(?:["']|)(\d+)(?:["']|)>\1<\/a>\]/gi;
- this.check(); //Initialize lastmodify
- },
- check:function(chklastdate, callfunc){
- function chkStatus(res){
- if(res.status == 200)
- Frontpage.lastmodify = new Date(
- res.getResponseHeader('Last-Modified')
- );
- if(callfunc)
- callfunc(res);
- }
- xhr(
- this.url,
- chkStatus,
- 'head',
- (chklastdate? this.lastmodify.toUTCString() : null)
- );
- }
- }//Frontpage
- var Thread = {
- id: location.href.match(/\/res\/(\d+)/i)[1],
- rx_id: null,
- init: function(){
- //this.rx_id = RegExp('((nothread|res\/)'+this.id+')[^\d]');
- this.rx_id = RegExp('(res\/'+this.id+')[^\d]');
- },
- check: function(callfunc){
- xhr(Frontpage.url+'res/'+this.id, callfunc, 'head');
- }
- }//Thread
- function container(outer){
- this.outer = outer;
- this.add = function(id, element, title, parent){
- this[id] = document.createElement(element);
- this[id].id = id;
- if(title){
- if(Box.showTitles) this[id].title = title;
- this[id].temptitle = title;
- }
- if(parent)
- this[parent].appendChild(this[id]);
- else
- this.outer.appendChild(this[id]);
- }
- }
- function createContainer(){
- var con = new container(document.createElement('div'));
- con.outer.id = Box.uid;
- con.add('msg', 'span');
- con.add('pin', 'a', 'Pin/Unpin');
- con.add('drag', 'a', 'Move');
- con.add('mini', 'a', 'Full/Mini');
- con.add('upd', 'a', 'Update Now');
- con.add('af', 'span');
- //<!--af
- con.add('auto', 'a', 'Enable Auto-update', 'af');
- //<!--uif
- con.add('uif', 'span', null, 'af');
- con.add('set', 'span', null, 'uif');
- con.add('inp', 'input', 'Update interval [enter]', 'uif');
- con.inp.type = 'text';
- //form-->
- //af-->
- con.add('stat', 'span');
- document.body.insertBefore(con.outer, document.body.firstChild);
- return con;
- }//createContainer
- function setCustomStyle(css){
- var customStyle = [
- ' #', Box.uid, ' { ',
- (Box.isMini?'':'border: 1px solid black; '),
- (Box.isMini?'':'padding: 5px 8px 5px 8px; '),
- 'z-index: ', (Math.pow(2, 31)-1), '; ',
- ' }',
- ' #', Box.uid, ' > * { ',//defaults
- 'clear: none; ',
- 'white-space: nowrap; ',
- 'margin: 0 0; ',
- 'border: 0 none; ',
- 'padding: 0 0; ',
- ' }',
- //p,d,m
- '\n #', Box.uid, '> #pin, ',
- ' #', Box.uid, '> #drag, ',
- ' #', Box.uid, '> #mini { ',
- 'position:', (Box.isMini?'static; ':'absolute; '),
- (Box.isMini?'margin: 0 2px; ':''),
- 'top: -5px; ',
- 'font-weight: bold; ',
- 'font-size: 1.1em; ',
- 'cursor: pointer; ',
- 'background: none; ',
- 'display: none; ',
- ' }',
- '\n #', Box.uid, '> #mini { right:1px; }',
- '\n #', Box.uid, '> #drag { ',
- 'left: 10px; ',
- 'cursor: move; ',
- 'width: 80%; ',
- ' }',
- '\n #', Box.uid, '> #pin { ',
- 'left: 1px; ',
- 'top: -2px; ',
- 'font-size: 0.8em; ',
- ' }',
- '\n #', Box.uid, ':hover > #pin, ',
- ' #', Box.uid, ':hover > #drag, ',
- ' #', Box.uid, ':hover > #mini { display: inline; }',
- //ms,st
- '\n #', Box.uid, '> #msg { ',
- 'display:', (Box.isMini?'inline; ':'block; '),
- 'font-size:', (Box.isMini?'1.01em; ':'1.2em; '),
- 'font-variant: small-caps; ',
- (Box.isMini?'margin: 0 5px; ':''),
- (Box.isMini ?'':'clear: both; '),
- ' }',
- '\n #', Box.uid, '> #stat { ',
- 'font-size: 0.9em; ',
- 'font-style: italic; ',
- 'color: #555555; ',
- 'display:', (Box.isMini?'none; ':'block; '),
- 'clear: both; ',
- ' }',
- '\n #', Box.uid, '.left > #msg, ',
- ' #', Box.uid, '.left > #stat { ',
- 'text-align: left; ', //(Box.isMini ?'float: left; ':''),
- ' }',
- '\n #', Box.uid, '.right > #msg, ',
- ' #', Box.uid, '.right > #stat { ',
- 'text-align: right; ', //(Box.isMini ?'float: right; ':''),
- ' }',
- //up,af
- '\n #', Box.uid, '> #upd, ',
- ' #', Box.uid, '> #af > #auto { ',
- 'margin: 0 ', (Box.isMini?'2':'1'), 'px; ',
- 'cursor: pointer; ',
- 'font-size: 1em; ',
- 'font-variant: small-caps; ',
- 'font-weight: bold; ',
- 'display: none; ',
- ' }',//bca.style.color = Box.isAuto? '#119911':'';
- '\n #', Box.uid, '> #af > #auto.on { ',
- ' color: #119911; ',
- (Box.isMini?' display: inline; ':' '),
- ' }',
- '\n #', Box.uid, '> #af > #uif { ',
- 'clear: none; ',
- 'position: relative; ', //(Box.isMini?'':'top: 3px; '),
- ' }',
- '\n #', Box.uid, '> #af > #uif > #inp { ',
- 'font-size: 0.9em; ',
- 'text-align: right; ',
- 'width: 40px; ',
- 'padding: 0 0; ',//'margin: 0 2px; ',
- ' }',
- '\n #', Box.uid, '> #af > #uif > #set { ',
- 'font-size: 0.9em; ',
- 'color: #555555; ',
- 'margin: 0 3px; ',
- 'position: relative; ',
- (Box.isMini?'':'top: 2px; '),
- ' }',
- '\n #', Box.uid, '> #af > #uif { ',
- 'display: none; ',
- 'margin: 2px 0; ',
- 'clear: none; ',
- ' }',
- '\n #', Box.uid, ':hover > #upd, ',
- ' #', Box.uid, ':hover > #af > #auto { display: inline; }',
- '\n #', Box.uid, '> #af:hover > #uif { display: inline; }',
- '\n #', Box.uid, '.left > #upd, ', //' #', Box.uid, '.left > #af, ',
- ' #', Box.uid, '.left > #af > *, ',
- ' #', Box.uid, '.left > #af > #uif > * { float: left; }',
- '\n #', Box.uid, '.right > #upd, ', //' #', Box.uid, '.right > #af, ',
- ' #', Box.uid, '.right > #af > *, ',
- ' #', Box.uid, '.right > #af > #uif > * { float: right; }',
- ].join('');
- if(!css){
- var css = document.createElement('style');
- css.id = Box.uid+'_css';
- css.type = 'text/css';
- document.getElementsByTagName('head')[0].appendChild(css);
- }
- css.innerHTML = customStyle;
- }
- var Box = {
- uid:'thread_page_finder',
- con:null, //container
- toh:null,
- lastdetails:null,
- pagelastfound:0,
- interval:60, //In seconds
- isAuto:false,
- isMini:false,
- isPinned:true,
- showTitles: true,
- init: function(){
- this.isAuto = GM_getValue('_isAuto', this.isAuto);
- this.isMini = GM_getValue('_isMini', this.isMini);
- this.isPinned = GM_getValue('_isPinned', this.isPinned);
- this.interval = GM_getValue('_interval', this.interval);
- this.showTitles = GM_getValue('_showTitles', this.showTitles);
- setCustomStyle();
- this.con = createContainer();
- var tc = this.con;
- var tcos = tc.outer.style;
- document.body.style.position = 'relative';
- tcos.position = this.isPinned?'fixed':'absolute',
- tcos.left = GM_getValue('_offset_left', null);
- tcos.top = GM_getValue('_offset_top', null);
- tcos.right = GM_getValue('_offset_right', '0px');
- tcos.bottom = GM_getValue('_offset_bottom', '0px');
- this.toggleAuto(null, true);
- this.setLabels();
- tc.msg.innerHTML = [
- '<span style="font-variant:normal;">',
- Frontpage.url, '</span>',
- '<b>', Thread.id, '</b>',
- ].join('');
- listen(tc.pin, 'click', Box.togglePin);
- listen(tc.mini, 'click', Box.toggleMinimal);
- listen(tc.upd, 'click', Box.forceUpdate);
- listen(tc.auto, 'click', Box.toggleAuto);
- //listen(tc.uif, 'submit', function(e){ Box.setInterval(e); });
- listen(tc.inp, 'keypress', function(e){ Box.validateInput(e); });
- listen(tc.drag, 'mousedown', Box.dragStart);
- },
- saveValues: function(){
- GM_setValue('_isAuto', Box.isAuto);
- GM_setValue('_isMini', Box.isMini);
- GM_setValue('_isPinned', Box.isPinned);
- GM_setValue('_interval', Box.interval);
- var bcos = Box.con.outer.style;
- GM_setValue('_offset_left', bcos.left);
- GM_setValue('_offset_top', bcos.top);
- GM_setValue('_offset_right', bcos.right);
- GM_setValue('_offset_bottom', bcos.bottom);
- },
- setLabels: function(opt){
- opt = opt?opt:'111'; //If opt is omitted/null, do all;
- var bc = Box.con;
- var bim = Box.isMini;
- var align = bc.outer.style.left?'left':'right';
- bc.outer.className = bim?'':'reply ' + align;
- if(opt[0]){//Full/mini
- bc.upd.innerHTML = bim?'U':'[update]';
- bc.auto.innerHTML = bim?'A':'[auto]';
- bc.drag.innerHTML = bim?'+':' ';
- bc.mini.innerHTML = bim?'\u53E3':'\u2013';//\u039e
- bc.mini.temptitle = bim?'Full':'Mini';
- if(Box.showTitles) bc.mini.title = bc.mini.temptitle;
- }//
- if(opt[1]){//Pinned/unpinned
- bc.pin.innerHTML = Box.isPinned?'\u51fa':'\u4e2d';//\u00a4':'\u00f8';//d7';
- bc.pin.temptitle = Box.isPinned?'Unpin':'Pin';
- if(Box.showTitles) bc.pin.title = bc.pin.temptitle;
- }
- if(opt[2]){//Update interval
- bc.inp.value = Box.interval;
- bc.set.innerHTML = Box.interval+'sec'+
- ((Box.interval>1)?'s':null);
- }
- },
- //Buttons/input
- toggleMinimal: function(){
- Box.isMini = !Box.isMini;
- Box.saveValues();
- setCustomStyle(document.getElementById(Box.uid+'_css'));
- Box.setLabels('1');
- Box.updateMsg();
- },
- recalcYOffset: function(){//fixed(px)/absolute(%) offset conversion
- var bco = Box.con.outer;
- var bcos = bco.style;
- var wih = window.innerHeight;
- var wpyo = window.pageYOffset;
- var pageh = document.documentElement.scrollHeight; //wsmy + wih
- var wsmy = pageh - wih; //window.scrollMaxY
- var fixedoffset = Box.isPinned;
- var top, btm;
- function cvt(val, offset){
- return fixedoffset?
- parseInt(val) + offset:
- Math.round(pageh * parseFloat(val)/100) - offset;
- }
- if(bcos.top){
- top = cvt(bcos.top, wpyo);
- btm = (fixedoffset?pageh:wih) - top - bco.offsetHeight;
- }else{
- btm = cvt(bcos.bottom, wsmy - wpyo);
- top = (fixedoffset?pageh:wih) - btm - bco.offsetHeight;
- }
- function suffix(val){
- val = val<10?0:val;
- return fixedoffset?
- Math.round(((val/pageh) * 100)) + '%' :
- val + 'px';
- }
- bcos.top = (top<=btm)? suffix(top) :null;
- bcos.bottom = (top<=btm)? null: suffix(btm);
- },
- togglePin: function(){
- Box.recalcYOffset();
- Box.isPinned = !Box.isPinned;
- Box.con.outer.style.position = Box.isPinned?'fixed':'absolute';
- Box.saveValues();
- Box.setLabels('01');
- },
- setInterval: function(evt){
- //evt.preventDefault();
- Box.interval = parseInt(Box.con.inp.value);
- Box.saveValues();
- Box.setLabels('001');
- },
- validateInput: function(evt){
- if(evt.keyCode == 13) //Enter
- Box.setInterval(evt);
- if(!evt.charCode) return;
- if(
- evt.charCode < 48 ||
- evt.charCode > 57 ||
- evt.target.value.toString().length >= 5
- )
- evt.preventDefault();
- },
- toggleAuto: function(set, load){
- if(!load){
- Box.isAuto = ((set == 'off')? false : !Box.isAuto);
- Box.saveValues();
- }
- var bca = Box.con.auto;
- //bca.style.color = Box.isAuto? '#119911':'';
- bca.className = Box.isAuto? 'on':'';
- bca.temptitle = (Box.isAuto?'Disable':'Enable') +' Auto-update';
- if(Box.showTitles) bca.title = bca.temptitle;
- if(Box.isAuto && !load) Box.searchProcess(0);
- },
- //Move/drag
- offset:{ left:0, top:0, unpin: false,
- tempShow:function(dis){
- var el = ['pin', 'mini', 'drag', 'upd', 'af'];
- for(i in el)
- Box.con[el[i]].style.display = dis?'inline':'';
- }
- },
- dragStart: function(evt){
- if(!Box.isPinned){ //Pin temporarily (Todo: Full page dragging.)
- Box.togglePin();
- Box.offset.unpin = true;;
- }
- Box.offset.tempShow(true);
- var bco = Box.con.outer
- var bcos = bco.style;
- Box.offset.left = evt.clientX -
- (bcos.left? parseInt(bcos.left) :
- (window.innerWidth -
- parseInt(bcos.right) -
- bco.offsetWidth));
- Box.offset.top = evt.clientY -
- (bcos.top? parseInt(bcos.top) :
- (window.innerHeight -
- parseInt(bcos.bottom) -
- bco.offsetHeight));
- listen(document, 'mousemove', Box.doDrag);
- listen(document, 'mouseup', Box.dragStop);
- document.body.focus();
- },
- doDrag: function(evt){
- var bco = Box.con.outer;
- var bcos = bco.style;
- var left = evt.clientX - Box.offset.left;
- var right = window.innerWidth - left - bco.offsetWidth;
- var top = evt.clientY - Box.offset.top;
- var bottom = window.innerHeight - top - bco.offsetHeight;
- bcos.left = (left<=right)? ((left<10?0:left)+'px') :null;
- bcos.right = (left<=right)? null: ((right<10?0:right)+'px');
- bcos.top = (top<=bottom)? ((top<10?0:top)+'px') :null;
- bcos.bottom = (top<=bottom)? null: ((bottom<10?0:bottom)+'px');
- },
- dragStop: function(evt){
- if(Box.offset.unpin){ //Return pin-state (Todo)
- Box.togglePin();
- Box.offset.unpin = false;
- }
- Box.offset.tempShow(false);
- listen(document, 'mousemove', Box.doDrag, 'remove');
- listen(document, 'mouseup', Box.dragStop, 'remove');
- Box.setLabels('000');
- Box.saveValues();
- },
- //Text display
- updateStat: function(msg, clear){
- if(clear) this.con.stat.innerHTML = '';
- this.con.stat.innerHTML += msg;
- },
- updateMsg: function(details){
- if(!details){
- if(!Box.lastdetails) return;
- else details = Box.lastdetails;
- }else Box.lastdetails = details;
- details.page = details.page?details.page:'0';
- if(Box.isMini)
- this.con.msg.innerHTML = [
- 'Pg ', details.page,
- '/', details.lastpage,
- ' Th ', details.threadpos,
- '/', details.threadtotal
- ].join('');
- else
- this.con.msg.innerHTML = [
- 'Page: <b>', details.page,
- '</b>/', details.lastpage,
- '<br>Thread: <b>', details.threadpos,
- '</b>/', details.threadtotal
- ].join('');
- if(!details) return;
- var suff = 'th';
- if(details.threadpos == 1) suff = 'st';
- if(details.threadpos == 2) suff = 'nd';
- if(details.threadpos == 3) suff = 'rd';
- var tcm = this.con.msg;
- tcm.temptitle = [
- Thread.id,
- ' is the ', details.threadpos, suff,
- ' of ', details.threadtotal,
- ' thread', ((details.threadtotal>1)?'s':''),
- ' on page ', details.page,
- ' of ', (details.lastpage?
- ('all '+ (parseInt(details.lastpage)+1) + ' pages'):
- 'a page'),
- ' on ', Frontpage.board, '.',
- ].join('');
- if(Box.showTitles) tcm.title = tcm.temptitle;
- },
- //Searching
- forceUpdate: function(){
- Box.updateStat('', true);
- Box.searchProcess(2);
- },
- searchProcess: function(stage){
- switch(stage){
- case 0:
- var count = Box.interval;
- function countDown(){
- //if(!Box.isAuto) return;
- if(!count)
- Box.searchProcess(1);
- else {
- Box.updateStat([
- 'Updating in ',
- count, 'sec', (count>1?'s':'')].join(''),
- true);
- count--;
- clearTimeout(Box.toh);
- Box.toh = window.setTimeout(countDown, 1000);
- }
- }
- countDown();
- break;
- case 1:
- Box.updateStat('Checking frontpage... ', true);
- Frontpage.check(true, function(res){
- Box.updateStat(res.statusText);
- switch(res.status){
- case 200: //Frontpage changed. Do next stage
- Box.updateStat('<br>');
- Box.searchProcess(2);
- break;
- case 304: //No change on frontpage. Restart.
- if(Box.isAuto){
- window.setTimeout(function(){
- Box.searchProcess(0);
- }, 1500); //Show status message for 1.5sec
- }
- break;
- default: Box.toggleAuto('off');
- }
- });
- break;
- case 2:
- Box.updateStat('Checking thread... ');
- Thread.check(function(res){
- Box.updateStat(res.statusText);
- if(res.status == 200){ //Thread still up. Do next stage.
- Box.updateStat('<br>');
- Box.searchProcess(3);
- }else Box.toggleAuto('off');
- });
- break;
- case 3:
- Box.updateStat('Finding thread\'s page... ');
- clearTimeout(Box.toh);
- findThread(Box.pagelastfound, function(details){
- if(details){
- Box.updateStat('', true); //Clear status message
- Box.updateMsg(details);
- Box.pagelastfound = details.page;
- if(Box.isAuto) Box.searchProcess(0);
- }else{
- Box.updateStat('Can\'t find thread');
- if(!Frontpage.is_f){
- Box.updateStat('<br>');
- Box.searchProcess(2);
- }else{
- Box.updateStat('<br>(Marked for deletion?)');
- Box.toggleAuto('off');
- }
- }
- });
- }
- }
- }//Box
- function findThread(lastfound, callfunc){
- var nextpage = lastfound;
- var lastpage = 15;
- if(Frontpage.is_f){
- lastpage = 0;
- searchPages();
- }
- else
- xhr(Frontpage.url, function(res){
- var pages = res.responseText.match(Frontpage.rx_pages);
- lastpage = pages.length? (/>(\d+)</.exec(pages[pages.length - 1])[1]) : 0;
- searchPages();
- });
- /*function getLastpage(res){
- if(!res){
- xhr(Frontpage.url+lastpage, getLastpage, 'head');
- }else{
- if(res.status == 200 || !lastpage){
- searchPages();
- }else{
- lastpage--;
- getLastpage(null);
- }}}*/
- function searchPages(res){
- if(res && res.status == 200){
- var threadnos = res.responseText.match(Frontpage.rx_threadnos);
- for(var i = 0; i < threadnos.length; i++){
- if(Thread.rx_id.test(threadnos[i])){
- var details = {
- page: res.url.replace(Frontpage.url, ''),
- lastpage: lastpage,
- threadpos: (i+1),
- threadtotal: threadnos.length
- }
- callfunc(details);
- return;
- }
- }
- if(nextpage >= lastpage) nextpage = 0;
- else nextpage++;
- if(nextpage == lastfound || !lastpage){
- callfunc(null);
- return;
- }
- }
- xhr(Frontpage.url+(nextpage?nextpage:''), searchPages);
- //xhr(Frontpage.url+nextpage, searchPages);
- }
- }
- function clearSettings(){
- GM_deleteValue('_isAuto');
- GM_deleteValue('_isMini');
- GM_deleteValue('_isPinned');
- GM_deleteValue('_interval');
- GM_deleteValue('_offset_left');
- GM_deleteValue('_offset_top');
- GM_deleteValue('_offset_right');
- GM_deleteValue('_offset_bottom');
- GM_deleteValue('_showTitles');
- //GM_deleteValue('_records');
- try{
- var ui = document.getElementById(Box.uid);
- ui.parentNode.removeChild(ui);
- }catch(e){console.log(e);}
- init();
- }
- function toggleTitles(off){
- var bc = Box.con;
- var show = (typeof off === 'boolean')? off : !Box.showTitles;
- for(i in bc){
- var title = bc[i].temptitle;
- if( title ) bc[i].title = show?title:'';
- }
- Box.showTitles = show;
- GM_setValue('_showTitles', show);
- alert(Box.uid+':\nTitles/hover messages '+(show?'enabled':'disabled'));
- }
- try{
- GM_registerMenuCommand(
- 'ThreadPageFinder: Reset/restore settings',
- clearSettings, 'R');
- GM_registerMenuCommand(
- 'ThreadPageFinder: Enable/disable titles (hover messages)',
- toggleTitles, 'E');
- }catch(e){console.log(e);}
- //Utilities
- if(GM_setValue === undefined){
- GM_setValue = function(key, val){
- val = (typeof val)[0] + val;
- localStorage.setItem(Box.uid+key, val);
- }
- GM_getValue = function(key, defval){
- var val = localStorage.getItem(Box.uid+key);
- if(!val) return defval;
- var type = val[0];
- val = val.substring(1);
- if(type == 'b') return val == 'true';
- if(type == 'n') return parseInt(val);
- return val;
- }
- GM_deleteValue = function(key){
- localStorage.removeItem(Box.uid+key);
- }
- }
- function listen(item, type, func, remove){
- if(remove) item.removeEventListener(type, func, false);
- else item.addEventListener(type, func, false);
- }
- function xhr(url, callfunc, type, lastdate){
- type = type || 'get';
- var xhr = new XMLHttpRequest();
- xhr.url = url; //For page checking.
- xhr.onreadystatechange = function(){
- if(xhr.readyState == 4)
- callfunc(xhr);
- }
- xhr.open(type, url, true);
- if(lastdate)
- xhr.setRequestHeader('If-Modified-Since', lastdate);
- xhr.send();
- }
- //Begin
- function init(){
- Box.init();
- Thread.init();
- Frontpage.init();
- Box.searchProcess(3);
- }
- if (document.addEventListener)
- document.addEventListener('DOMContentLoaded', init, false);
- else window.addEventListener('load', init, false);
- //
- })();
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement