// ==UserScript== // @name 4chan widescreen // @namespace meh // @description Presents more images and threads at once using columns. // @include http://boards.4chan.org/* // @exclude http://boards.4chan.org/f/* // @require http://code.jquery.com/jquery-1.5.1.min.js // @require http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.10/jquery-ui.min.js // ==/UserScript== const DEBUG = false; const RESIZE_DELAY = 400; const ID_HOLDER = 'navtop'; const ID_TOP_MENU = 'header'; const HREF_NO_HISTORY = 'javascript:void(0)'; const DEF_THUMB_SIZE = 5; // 50% const DEF_TEXT_SIZE = 12; // px const DEF_NUM_COLUMNS = 0;// 0 == auto const BASE_ZINDEX = 999; const GMT_4chan = -4; var columns; var scrollTopBackup; var topSpace, bottomSpace; var pages; var timerResize; var formHtml, formHtmlNext; var isX; var imgReply, imgPopup; // auto settings const MIN_COLS = 3; var colSettings = [ {cols:4, resWidth:960}, {cols:5, resWidth:1300} ]; var thumbSettings = [ {resize:5, resWidth:960}, {resize:4, resWidth:1300}, {resize:5, resWidth:1600}, {resize:7, resWidth:1800} ]; //if not a thread page if(!isThreadPage()){ //add toggle link $('a:contains("@")') .parent() .after( $('<a href="javascript:void(0)" id="wstogglelink">') .html('ws') .css({cursor:'pointer'}) .click(toggle) ) .after(' / '); //autorun if(GM_getValue('autorun')==true) toggle(); } function toggle(evt){ var div = getById('divHoriz'); img(); if(div){//off GM_setValue('autorun',false); window.removeEventListener('resize', resize, false); $(document).unbind('keyup.keys'); document.body.scrollTop = scrollTopBackup; document.body.style.overflow = 'auto'; $('#divHoriz').remove(); $('#divBgHoriz').remove(); $('div.logo').css('visibility','visible'); $(pages).remove(); $('#divMenu').remove(); $('#divPageLeft').remove(); $('#divPageRight').remove(); $('#divTempIsolateScript').remove(); $('#divTempLoadNextPage').remove(); closeForm(); $('.resizedThumb').remove(); $('form[name=post]').unbind('submit.postform'); }else{//on GM_setValue('autorun',true); scrollTopBackup = document.body.scrollTop; document.body.scrollTop = 0; document.body.style.overflow = 'hidden'; isX = ($('#imgControls').length > 0); if(GM_getValue('opt_isolate_script') || isX){ // solve incompatibilities with other scripts if(!formHtml){//avoids making new request when window resized $('<div id="divBgHoriz">').css({ position:'fixed', top: $('#wstogglelink').offset().top + $('#wstogglelink').outerHeight(), left:0,width:window.innerWidth,height:window.innerHeight,backgroundColor:getStyle(document.body,'background-color')}).appendTo(document.body); GM_xmlhttpRequest({ method: 'GET', url: location.href, onload: function(resp){ if(resp.status==200){ formHtml = null; formHtml = resp.responseText.match(/<form[^>]+name\=\"delform\"[^>]*>([\s\S]+)<\/form>/)[1]; create( formHtml ); } } }); }else{ create(formHtml); } }else{ create(null); } window.addEventListener('resize', resize, false); $('div.logo').css('visibility','hidden'); $(document).bind('keyup.keys', keyupHandler); $('form[name=post]').bind('submit.postform',onSubmitFormPost) } if(evt) evt.target.blur(); } function onSubmitFormPost(evt){ var form = $('#divFormPosttt form[name=post]'); var upfile = form.find('input[name=upfile]'); var str, divform, divBlock; //submit page without GM_xmlhttpRequest, if there's a file to upload if(upfile.val() != ''){ return true; } //grab form input data str = ''; form.find('input,textarea').each(function(i,el){ if(el.getAttribute('name')) str += ((str==''?'':'&')) + el.getAttribute('name') +'='+ el.value; }); debug('action:'+form.attr('action')); debug('data: '+str); // hide form before sending request $('<div id="divBlockForm">') .css({width:$('#divFormPosttt').outerWidth(), minWidth:$('#divFormPosttt').outerWidth(), height:$('#divFormPosttt').outerHeight(), minHeight:$('#divFormPosttt').outerHeight(), verticalAlign:'middle', display:'table-cell', fontSize:'16px', color:'#789922'}) .html('<center>\> posting ...</center>') .appendTo($('#divFormPosttt')); form.hide(); // post form request GM_xmlhttpRequest({ method: "POST", url: form.attr('action'), headers: { "Content-type" : "application/x-www-form-urlencoded", "Referer" : location.href }, data: encodeURI(str), onload: function(resp) { $('#divFormPosttt form[name=post]').show(); $('#divBlockForm').remove(); debug(resp.status+': '+resp.statusText) debug(resp.responseText) if(resp.status==200){ var msg = createElement('div',null,null,resp.responseText.match(/\<table[\s\S]+\<\/table\>/)[0]).textContent; if(msg.search(/Post successful/) > -1){ closeForm({target:document.getElementById('closeFormmm')}); }else{ alert( (msg.search(/Return/) > -1 ? msg.replace(/Return/,'') : msg) ); unsafeWindow.Recaptcha.reload(); } }else{ alert(resp.status+': '+resp.statusText) } } }); return false; } function create(html){ var page; //remove any embed try{ $('embed').remove(); }catch(e){} //div background if($('#divBgHoriz').length==0) document.body.appendChild(createElement('div', {id:'divBgHoriz'})); //main div document.body.appendChild(createElement('div', {id:'divHoriz', tabindex:1})); getById('divHoriz').appendChild(createElement('table', {id:'tableHoriz'},null,'<tr id="trHoriz"></tr>')); getById('divHoriz').focus(); document.body.scrollTop = 0; //define num of columns if(GM_getValue('opt_numcolumns') && GM_getValue('opt_numcolumns')!=0){ columns = GM_getValue('opt_numcolumns'); }else{ columns = MIN_COLS; for(var i=0; i<colSettings.length; i++){ if(window.innerWidth >= colSettings[i].resWidth){ columns = colSettings[i].cols; } } } // isolate script from others if(!html){ page = $('form[name="delform"]'); debug('creating... normal mode') }else{ page = $('<div id="divTempIsolateScript">').css('display','none').html(formHtml).appendTo(document.body); debug('creating... isolated mode') } //pages pages = createElement('div'); pages.appendChild(xp('//table[@class="pages"]//td')[1].cloneNode(true)); pages.setAttribute('class', 'tablePages'); document.body.appendChild(pages); //menu $(document.body) .append( $('<div id="divMenu">') .append( $('<a id="linkClose">') .css({cursor:'pointer'}) .html('\>close') .click(toggle) .mouseenter(function(evt){ $('#divMenuHide').show(); $('#divMenu').addClass('shadowww').css('font-size','12px'); }) ) .append( $('<div id="divMenuHide">') .hide() .append( $('<a id="linkOptions">').css({cursor:'pointer'}).html('\>options').click(options) ) .append('<br>') .append( $('<a id="linkNewThread">').css({cursor:'pointer'}).html('\>new thread').click(postForm) ) .append('<br>') .mouseleave(function(evt){ $('#divMenuHide').hide(); $('#divMenu').removeClass('shadowww').css('font-size','11px');; }) ) ) //create threads createThreads(page,false); debug('create() > calling applyOptionsAndEvents()...') applyOptionsAndEvents(); if(GM_getValue('opt_showonlyop') && GM_getValue('opt_loadnextpage')){ loadNextPage(); } } function createThreads(page, isNextPage){ var td, el, cont, id, divThread; cont = 0; page.children('span[id^="nothread"]').each(function(i,x){ //count td if(cont==columns) cont = 0; //thread id id = x.getAttribute('id').match(/\d+$/)[0]; // create div if($('#divHoriz #'+id).length == 0){ divThread = createElement('div', {id:id}); divThread.setAttribute('class','divThread'+((isNextPage==true)?' nextpageee':'')); el = x; while(el && el.previousSibling && el.previousSibling.nodeName!='HR'){ el=el.previousSibling; } if(el && !el.previousSibling){ divThread.appendChild(el.cloneNode(true)); } while(el && el.nextSibling && el.nextSibling.nodeName != 'HR') { divThread.appendChild(el.nextSibling.cloneNode(true)); el = el.nextSibling; } el = getByTag('img',divThread)[0].parentNode; //append div thread to td try{ td = xp('child::td',getById('trHoriz'))[cont]; }catch(e){} if(!td || td=='undefined') td = getById('trHoriz').appendChild(createElement('td',{class:'tdHoriz'})); cont++; td.appendChild(divThread); td.style.zIndex = BASE_ZINDEX+cont;//old code }else{ debug('duplicate thread #'+id) } }); } function applyOptionsAndEvents(){ //cleanup $('#divHoriz input').remove(); $('td .doubledash').remove(); $('#divHoriz a:contains(Reply)').each(function(i,el){ var reply = $(el); reply.parent().contents().filter(function(){return this.nodeType == 3;}).remove(); reply.remove(); }); //show only OP's post if(GM_getValue('opt_showonlyop')){ $('.tdHoriz table').hide(); } //poster name if(!GM_getValue('opt_show_poster')){ $('#divHoriz span.postername').hide(); $('#divHoriz span.postertrip').hide(); $('#divHoriz span.commentpostername').hide(); } //post title if(!GM_getValue('opt_show_title')){ $('#divHoriz span.filetitle').hide(); $('#divHoriz span.replytitle').hide(); } //post number if(!GM_getValue('opt_show_threadnumber')){ $('#divHoriz a.quotejs').hide(); } //file info if(!GM_getValue('opt_show_filesize')){ $('#divHoriz span.filesize').hide(); } //ommited posts info if(!GM_getValue('opt_show_omittedposts')){ $('#divHoriz span.omittedposts').hide(); } //remove <br> from posts $('#divHoriz td.reply').each(function(i,el){ var comment = $(el).children('blockquote'); comment.html(comment.html().replace(/\<br\>\s*\<br\>/ig,'<br>')) if( comment.prev().get(0).nodeName == 'A' && comment.prev().get(0).href && comment.prev().get(0).href.search(/http\:\/\/images.4chan\.org/) > -1) comment = comment.prev(); comment.prevAll().filter('br,a').remove(); }); //wrap date in a span tag $('.divThread td.reply').each(function(i,td){ td.innerHTML = td.innerHTML.replace(/(\d+\/\d+\/\d+\(\S+\)\d+\:\d+)/g, '<span class="posttime">$1</span>'); }); //post date if(!GM_getValue('opt_show_date')) { $('#divHoriz .posttime').hide(); }else if(GM_getValue('opt_showrelativedate')){ toggleRelativeDate(true) } //thread shadow if(!GM_getValue('opt_hideShadows')){ $('#divHoriz .divThread').removeClass('shadowww').addClass('shadowww'); } //thumbnail's resizing and events var resize = getThumbSize(); resize = parseFloat(resize/10); $('#divHoriz img') .each(function(i,el){ var jqel = $(el); if(jqel.parents('.divThreadButtons').length==0 && jqel.attr('src').search(/sticky/) < 0 && jqel.attr('src').search(/closed/) < 0){ jqel.css({ width: parseInt(el.getAttribute('width'))*resize, height: parseInt(el.getAttribute('height'))*resize }) .mouseenter(function(evt) { if(GM_getValue('opt_resize_thumbnail')){ var t = $(evt.target); var os = t.offset(); var clone; $('.resizedThumb').parent().remove(); clone = t.clone(false) .addClass('resizedThumb') .css({ position: 'absolute', zIndex: BASE_ZINDEX+998, border:'1px solid #789922', top: os.top, left: os.left - 20, width: '', height: '' }) .mouseleave(function(evt){ $(evt.target).parent().remove(); //$('.resizedThumb').remove(); }) .appendTo(document.body) .wrap( $('<a>') .attr({target:'_blank', href:t.parent().attr('href')}) .click(function(evt){ $('.resizedThumb').parent().remove(); }) ); //out of bounds if(clone.height() + clone.offset().top > window.innerHeight) clone.css({top: window.innerHeight - clone.height()}); if(clone.width() + clone.offset().left > window.innerWidth) clone.css({left: window.innerWidth - clone.width()}); } }) } }) //css() uses num of columns debug('applyOptions() calling css()...') css(); //pagination edge buttons if( $('#divPageLeft').length == 0 && $('#divPageRight').length == 0 ){ var currentPage = 0; try{ currentPage = parseInt(location.href.match(/(\d+)$/)[1]) }catch(e){} if(currentPage > 0){ $(document.body).append( $('<div id="divPageLeft">') .append( $('<table>').addClass('tablePagination').html('<tr><td><center>'+(currentPage-1)+'</center></tr></td>') ) .mouseenter(function(evt){ if(GM_getValue('opt_hidePaginationEdges')) return; $('#divPageLeft').css('opacity','1') }) .mouseleave(function(evt){ if(GM_getValue('opt_hidePaginationEdges')) return; $('#divPageLeft').css('opacity','0') }) .click(function(evt){ if(GM_getValue('opt_hidePaginationEdges')) return; paginate(37); }) ); } if(currentPage < $('.tablePages').text().match(/\[(\d+)\]\s*$/)[1] ){ $(document.body).append( $('<div id="divPageRight">') .append( $('<table>').addClass('tablePagination').html('<tr><td><center>'+(currentPage+1)+'</center></tr></td>') ) .mouseenter(function(evt){ if(GM_getValue('opt_hidePaginationEdges')) return; $('#divPageRight').css('opacity','0.9')//.animate({width:'100px'}, 'fast') }) .mouseleave(function(evt){ if(GM_getValue('opt_hidePaginationEdges')) return; $('#divPageRight').css('opacity','0') }) .click(function(evt){ if(GM_getValue('opt_hidePaginationEdges')) return; paginate(39); }) ); } } //posts buttons $('#divHoriz .divThread:not(.threadDone) blockquote').each(function(i,el){ if($(el).parent().find('.divThreadButtons').length==0){ $(el).parent().prepend( //quick reply buton $('<div>') .addClass('divThreadButtons') .append( imgReply .clone(true) .attr({id:el.parentNode.getAttribute('id')}) .click(replyThread) ) ) } }); //main thread buttons $('.divThread:not(.threadDone) > .divThreadButtons').each(function(i,el){ $(el).prepend( $('<a>') .attr({ href:'res/'+el.parentNode.getAttribute('id'), target:'_blank'}) .append( imgPopup.clone(true) ) ) //$('<a>GoTo</a>').click(goTo).attr({href:'javascript:void(0)', threadUrl:a.href}) }); $('#divHoriz .divThread').removeClass('threadDone').addClass('threadDone'); //cleanup $('#divTempIsolateScript').remove(); $('#divTempLoadNextPage').remove(); } function img(){ if(!imgReply){ imgReply = $(createElement('img', {src: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAkAAAAJCAYAAADgkQYQAAAAI0lEQVR42mPYsGHDfwZCYJAoQhHHpwguB+Pgw3idQdC9yAoA8aVAPGs+tj4AAAAASUVORK5CYII%3D', title:'quick reply'})).css({cursor:'pointer'}); imgPopup = $(createElement('img', {src:'data:image/gif;base64,R0lGODlhCQAJANEAAP///4CAgAAAAMDAwCH5BAkZAAAALAAAAAAJAAkAAAIUhI8my8ccwhBIxFmDehaNE4VaQhYAOw%3D%3D', title:'open thread in a new tab'})); } } function loadNextPage(){ var currentPage; var nextUrl; try{ currentPage = parseInt(location.href.match(/(\d+)\/?$/)[1]); }catch(e){ currentPage = 0; } if(currentPage==0) nextUrl = location.href + '1'; else nextUrl = location.href.replace(/\d+\/?$/, (currentPage+1)); if(!formHtmlNext){ //avoids requests when resizing and toggling debug('loadNextPage() > requesting next page') GM_xmlhttpRequest({ method: 'GET', url: nextUrl, onload: function(resp){ if(resp.status==200){ formHtmlNext = null; formHtmlNext = resp.responseText.match(/<form[^>]+name\=\"delform\"[^>]*>([\s\S]+)<\/form>/)[1]; page = $('<div id="divTempLoadNextPage">').css('display','none').html(formHtmlNext).appendTo(document.body) createThreads(page,true); debug('loadNextPage() > GM_xmlhttpRequest() > onload > calling applyOptionsAndEvents()...') applyOptionsAndEvents(); } } }); }else{ page = $('<div id="divTempLoadNextPage">').css('display','none').html(formHtmlNext).appendTo(document.body); createThreads(page,true); debug('loadNextPage() > formHtmlNext==true > calling applyOptionsAndEvents()...') applyOptionsAndEvents(); } } function recentMenu(evt){ } function replyThread(evt){ var ta, divform; var t = $(evt.target); var id = t.attr('id'); var thread = t.parents('.divThread'); var threadoffset = thread.offset(); var spaceLeft, spaceRight; debug('replyThread() > id: '+id) //show form postForm(evt); divform = $('#divFormPosttt'); ta = $('#divFormPosttt textarea[name=com]'); //position form horizontally spaceLeft = threadoffset.left; spaceRight = window.innerWidth - threadoffset.left - thread.outerWidth(); if(spaceRight >= spaceLeft*0.8 || spaceRight >= divform.outerWidth()*0.9 ) divform.css({ right:'', left: threadoffset.left + thread.outerWidth() +7}); // right side else divform.css({ right:'', left: threadoffset.left - divform.outerWidth() -7}); // left side //position form vertically divform.css({top:threadoffset.top}); if(window.innerHeight - threadoffset.top < (divform.outerHeight()*0.7)){ divform.css({top:window.innerHeight - (divform.outerHeight()*0.8)}) } debug(divform.css('top')) if(divform.css('top').search(/^-/) > -1){//negative top value ("-33px") divform.css({top:0}); } //set selected thread if(divform.attr('threadid') != thread.attr('id')){ debug('replyThread() > '+divform.attr('threadid')+' != '+thread.attr('id')) //new thread selected, remove previous quotes (format ">>12653625") ta.val(ta.val().replace(/\>\>\d+/ig, '')); divform.find('input[name=resto]').remove(); divform.find('form').prepend($('<input>').attr({type:'hidden', value:thread.attr('id'), name:'resto'})); $('#spanFormPostTopBarTitle').html('Reply to thread <a class="quotelink" href="res/'+thread.attr('id')+'" target="_blank">\>\>'+divform.find('input[name=resto]').val()+'</a>') } divform.attr({threadid: thread.attr('id')}); //add thread number to textarea ta.val(ta.val()+'>>'+id); setCaretToPos(ta.get(0), ta.val().length) //highlight thread or reply $('.classHighlightThread').removeClass('classHighlightThread'); t.parents('.divThread').addClass('classHighlightThread'); } function closeForm(evt){ debug('closeForm()...') if($('#divFormPosttt').lenght==0 || evt==undefined || !evt.target || evt.target.getAttribute('id')!='closeFormmm'){ debug('closeForm() > divForm not found or close link not clicked by the user') return; } //clear fields $('#divFormPosttt').find('input[name=sub]').val(''); $('#divFormPosttt').find('textarea[name=com]').val(''); $('#recaptcha_response_field').val(''); $('#divFormPosttt').find('input[name=upfile]').val(''); //remove thread reference $('#divFormPosttt').find('input[name=resto]').remove(); //re-append form to original pos $('#spanFormPostOriginalPlace').before($('#formPosttt')); //undo highlight $('.classHighlightThread').removeClass('classHighlightThread') //remove div form $('#divFormPosttt').remove(); } function postForm(evt){ var t = $(evt.target); var form = $('form[name="post"]'); var divForm = $('#divFormPosttt'); var placeholder; //create div to append form if(divForm.length==0){ debug('postForm() > creating divForm...') divForm = $('<div id="divFormPosttt">') .append( $('<div id="divFormPostTopBar">') .css({width:'100%', cursor:'move', backgroundColor:'#789922', color:'#000000', display:'inline-block'}) .append( $('<a id="closeFormmm">close</a>') .css({float:'right', cursor:'pointer', margin:'1px 3px'}) .click(closeForm) ) .append( $('<span id="spanFormPostTopBarTitle">') .css({margin:'1px 3px'}) ) ) .css({ position: 'absolute', backgroundColor: $(document.body).css('background-color'), zIndex: BASE_ZINDEX + 999, padding: 0, margin: 0, border:'1px solid #789922' }) .addClass('shadowww') .appendTo(document.body) .draggable({ handle:'#divFormPostTopBar', start: function(event, ui){ $('#divFormPosttt').css({right:'',top:''}); } }) .hide(); //save form original position placeholder = $('#spanFormPostOriginalPlace'); if(placeholder.length==0) placeholder = $('<span id="spanFormPostOriginalPlace">').hide(); form.before( placeholder ); //append form to div form.attr('id','formPosttt').appendTo( divForm ); } divForm.show() //remove reply info if it's new thread if(t.parents('#divMenu').length > 0) $('#spanFormPostTopBarTitle').html('New thread'); if(divForm.attr('threadid')!=undefined && divForm.attr('threadid') != t.parents('.divThread').attr('id')){ debug("1. postForm() > "+divForm.attr('threadid') +' != '+ t.parents('.divThread').attr('id')) divForm.removeAttr('threadid').find('input[name=resto]').remove(); }else{ debug("2. postForm() > "+divForm.attr('threadid') +' != '+ t.parents('.divThread').attr('id')) } //position div form t = $('#linkNewThread'); divForm.css({ top: t.offset().top + t.outerHeight(), right: window.innerWidth - t.offset().left - t.outerWidth(), left:'' }); //get new captcha unsafeWindow.Recaptcha.reload(); } function getThumbSize(){ var res = (GM_getValue('opt_thumbsize') ? GM_getValue('opt_thumbsize') : DEF_THUMB_SIZE); if(res == -1){//auto res = DEF_THUMB_SIZE; for(var i=0; i<thumbSettings.length; i++){ if(window.innerWidth > thumbSettings[i].resWidth) res = thumbSettings[i].resize; } } return res; } function distributeThreads(){ var threads; var data = []; var reverse = false; var t, j, obj, tds, freeHeight, bestTD; if(GM_getValue('opt_showonlyop') && GM_getValue('opt_loadnextpage') && $('#divHoriz .nextpageee').length > 0){ //distribute next page threads threads = $('#divHoriz .nextpageee'); debug('distributeThreads() > next page threads = '+threads.length) }else{ //distribute current page threads threads = $('#divHoriz .divThread').not('.nextpageee'); debug('distributeThreads() > current page threads = '+threads.length) } //sort threads by height in data[] for(var i=0; i<threads.length; i++){ t = $(threads[i]); obj = {thread:t, height:t.outerHeight()} //insertion order by height j=0; while(j<data.length && obj.height >= data[j].height) j++ data.splice(j,0,obj);//insert obj at j } debug('distributeThreads() > data.length = '+data.length) tds = $('.tdHoriz'); tds.removeAttr('freeheight');//cleanup while(data.length > 0){ //insert on empty tds first for(var i=0; i<tds.length; i++){ if(data[0] && tds.eq(i).attr('freeheight')==undefined){ tds.eq(i).append(data[0].thread); tds.eq(i).attr('freeheight', (parseInt(window.innerHeight) - parseInt(topSpace) - parseInt(data[0].height))); data.splice(0,1); } } if(data[0]==undefined) return; if(!reverse){ data = data.reverse(); reverse = true; } //insert on higher free space (data[0] is the higher thread) bestTD = 0; for(var i=0; i<tds.length; i++){ if(parseInt(tds.eq(i).attr('freeheight')) > parseInt(tds.eq(bestTD).attr('freeheight'))){ bestTD = i; } } tds.eq(bestTD).append(data[0].thread); tds.eq(bestTD).attr('freeheight', (parseInt(tds.eq(bestTD).attr('freeheight')) - parseInt(data[0].height))); data.splice(0,1); } } function options(evt){ if($('#options').length == 0){ $('<div id="options">') .appendTo(document.body) .css({position:'absolute', top:'0px', right:'0px', zIndex:BASE_ZINDEX+999, backgroundColor: $(document.body).css('background-color'), color: 'black', border:'1px solid #789922', padding: '13px', minWidth:'200px'}) .mouseleave(function(){ $('#options').hide() }) .append(' Number of columns: ') .append( $('<select id="comboNumColumns">') .css({fontSize:'10px'}) .html('<option value=0>auto</option> <option value=3>3</option> <option value=4>4</option> <option value=5>5</option> <option value=6>6</option> <option value=7>7</option> <option value=8>8</option> <option value=9>9</option> <option value=10>10</option>') .val((GM_getValue('opt_numcolumns') ? GM_getValue('opt_numcolumns') : DEF_NUM_COLUMNS)) .change(function(evt){ GM_setValue('opt_numcolumns', parseInt($(evt.target).val())); columns = parseInt($(evt.target).val()); toggle(); toggle(); css(); }) ) .append('<br>') .append(' Text size: ') .append( $('<select id="comboTextSize">') .css({fontSize:'10px'}) .html('<option value=9>9px</option> <option value=10>10px</option> <option value=11>11px</option> <option value=12>12px</option> <option value=13>13px</option> <option value=14>14px</option> <option value=16>16px</option> <option value=20>20px</option>') .val((GM_getValue('opt_textsize') ? GM_getValue('opt_textsize') : DEF_TEXT_SIZE)) .change(function(evt){ GM_setValue('opt_textsize', parseInt($(evt.target).val())); css(); }) ) .append('<br>') .append(' Thumbnail size: ') .append( $('<select id="comboThumbSize">') .css({fontSize:'10px'}) .html('<option value=-1>auto</option><option value=3>30%</option> <option value=4>40%</option> <option value=5>50%</option> <option value=6>60%</option> <option value=7>70%</option> <option value=8>80%</option> <option value=9>90%</option> <option value=10>100%</option>') .val( (GM_getValue('opt_thumbsize') ? GM_getValue('opt_thumbsize') : DEF_THUMB_SIZE)) .change(function(evt){ var resize = parseInt($(evt.target).val()); GM_setValue('opt_thumbsize', resize); if(resize==-1){//auto resize = getThumbSize(); } resize = parseFloat(resize/10); $('#divHoriz img') .each(function(i,el){ if($(el).attr('src').search(/sticky/) < 0 && $(el).attr('src').search(/closed/) < 0 ){ $(el).css({width: parseInt(el.getAttribute('width')) * resize, height: parseInt(el.getAttribute('height')) * resize}) } }) }) ) .append('<br>') .append( $('<input type="checkbox" id="optResizeThumbnail">') .attr({checked:GM_getValue('opt_resize_thumbnail')}) .click( function(evt){ GM_setValue('opt_resize_thumbnail',evt.target.checked); }) ) .append(' Resize thumbnails on mouse over') .append('<br>') .append( $('<input type="checkbox" id="optSolveIncompatibilities">') .attr({checked:GM_getValue('opt_isolate_script')}) .click( function(evt){ GM_setValue('opt_isolate_script',evt.target.checked); }) ) .append(' Isolate script (solve incompatibilities)') .append('<br>') .append( $('<input type="checkbox" id="optCheckUseArrowKeysToPaginate">') .attr({checked:GM_getValue('opt_useArrowKeysToPaginate')}) .click( function(evt){ GM_setValue('opt_useArrowKeysToPaginate',evt.target.checked); }) ) .append(' Use arrow keys to change pages') .append('<br>') .append( $('<input type="checkbox" id="optCheckHidePagination">') .attr({checked:GM_getValue('opt_hidePaginationEdges')}) .click( function(evt){ GM_setValue('opt_hidePaginationEdges',evt.target.checked); }) ) .append(' Hide pagination edges') .append('<br>') .append( $('<input type="checkbox" id="optCheckHideShadows">') .attr({checked:GM_getValue('opt_hideShadows')}) .click( function(evt){ GM_setValue('opt_hideShadows', evt.target.checked); if(!evt.target.checked) $('#divHoriz .divThread').removeClass('shadowww').addClass('shadowww'); else $('#divHoriz .divThread').removeClass('shadowww'); }) ) .append(' Hide shadows') .append('<br>') .append( $('<input type="checkbox" id="optCheckShowOnlyOP">') .attr({checked:GM_getValue('opt_showonlyop')}) .click( function(evt){ GM_setValue('opt_showonlyop',evt.target.checked); if(evt.target.checked){ //show only OP $('.tdHoriz table').hide(); $('#optSpanLoadNextPage').show(); if(GM_getValue('opt_loadnextpage')){ if($('.nextpageee').length==0) loadNextPage() else $('.nextpageee').show(); } }else{ //show replies $('#optSpanLoadNextPage').hide(); $('.tdHoriz table').show(); $('.nextpageee').hide(); } debug('opt_showonlyop > calling distributeThreads()...') distributeThreads(); }) ) .append(' Show only original post<br>') .append( $('<span>') .attr({id:'optSpanLoadNextPage', checked:GM_getValue('opt_loadnextpage')}) .css({marginLeft:'19px', display:(GM_getValue('opt_showonlyop')?'box':'none')}) .append( $('<input type="checkbox" id="optCheckLoadNextPage">') .attr({checked:GM_getValue('opt_loadnextpage')}) .click(function(evt){ GM_setValue('opt_loadnextpage', evt.target.checked); if(evt.target.checked){ if($('.nextpageee').length==0) loadNextPage() else $('.nextpageee').show(); }else{ $('.nextpageee').hide(); } }) ) .append(' Load next page<br>') ) .append('<hr>') .append( $('<input type="checkbox" id="optCheckShowPoster">') .attr({checked:GM_getValue('opt_show_poster')}) .click( function(evt){ GM_setValue('opt_show_poster',evt.target.checked); if(evt.target.checked){ $('#divHoriz span.postername').show(); $('#divHoriz span.postertrip').show(); $('#divHoriz span.commentpostername').show(); }else{ $('#divHoriz span.postername').hide(); $('#divHoriz span.postertrip').hide(); $('#divHoriz span.commentpostername').hide(); } }) ) .append(' Show post names<br>') .append( $('<input type="checkbox" id="optCheckShowTitle">') .attr({checked:GM_getValue('opt_show_title')}) .click( function(evt){ GM_setValue('opt_show_title',evt.target.checked); if(evt.target.checked){ $('#divHoriz span.filetitle').show(); $('#divHoriz span.replytitle').show(); }else{ $('#divHoriz span.filetitle').hide(); $('#divHoriz span.replytitle').hide(); } }) ) .append(' Show post titles<br>') .append( $('<input type="checkbox" id="optCheckShowFileSize">') .attr({checked:GM_getValue('opt_show_filesize')}) .click( function(evt){ GM_setValue('opt_show_filesize',evt.target.checked); if(evt.target.checked){ $('#divHoriz span.filesize').show(); }else{ $('#divHoriz span.filesize').hide(); } }) ) .append(' Show file info<br>') .append( $('<input type="checkbox" id="optCheckShowThreadNumber">') .attr({checked:GM_getValue('opt_show_threadnumber')}) .click( function(evt){ GM_setValue('opt_show_threadnumber',evt.target.checked); if(evt.target.checked){ $('#divHoriz a.quotejs').show(); }else{ $('#divHoriz a.quotejs').hide(); } }) ) .append(' Show post number<br>') .append( $('<input type="checkbox" id="optCheckShowDate">') .attr({checked:GM_getValue('opt_show_date')}) .click( function(evt){ GM_setValue('opt_show_date',evt.target.checked); if(evt.target.checked){ $('#divHoriz .posttime').show(); $('#optSpanRelativeDate').show(); }else{ $('#divHoriz .posttime').hide(); $('#optSpanRelativeDate').hide(); } }) ) .append(' Show date<br>') .append( $('<span>') .attr({id:'optSpanRelativeDate', checked:GM_getValue('opt_showrelativedate')}) .css({marginLeft:'19px', display:(GM_getValue('opt_show_date')?'box':'none')}) .append( $('<input type="checkbox" id="optCheckRelativeDate">') .attr({checked:GM_getValue('opt_showrelativedate')}) .click(function(evt){ GM_setValue('opt_showrelativedate', evt.target.checked); toggleRelativeDate(evt.target.checked); }) ) .append(' Calculate relative time using ') .append( $('<select>') .attr({id:'optComboDateGMT'}) .css({marginLeft:'4px', fontSize:'10px'}) .html('<option value=-12>GMT-12</option><option value=-11>GMT-11</option><option value=-10>GMT-10</option><option value=-9>GMT-9</option><option value=-8>GMT-8</option><option value=-7>GMT-7</option><option value=-6>GMT-6</option><option value=-5>GMT-5</option><option value=-4>GMT-4</option><option value=-3>GMT-3</option><option value=-2>GMT-2</option><option value=-1>GMT-1</option><option value=0>GMT 0</option><option value=1>GMT+1</option><option value=2>GMT+2</option><option value=3>GMT+3</option><option value=4>GMT+4</option><option value=5>GMT+5</option><option value=6>GMT+6</option><option value=7>GMT+7</option><option value=8>GMT+8</option><option value=9>GMT+9</option><option value=10>GMT+10</option><option value=11>GMT+11</option><option value=12>GMT+12</option>') .val((GM_getValue('opt_gmt') ? GM_getValue('opt_gmt') : GMT_4chan)) .change(function(evt){ GM_setValue('opt_gmt',$('#optComboDateGMT').val()) toggleRelativeDate(false); $('#divHoriz .posttime').removeAttr('originaldate').removeAttr('relativedate'); toggleRelativeDate(true); }) ) .append('<br>') ) .append( $('<input type="checkbox" id="optCheckShowOmittedPosts">') .attr({checked:GM_getValue('opt_show_omittedposts')}) .click( function(evt){ GM_setValue('opt_show_omittedposts',evt.target.checked); if(evt.target.checked){ $('#divHoriz span.omittedposts').show(); }else{ $('#divHoriz span.omittedposts').hide(); } }) ) .append(' Show omitted posts info<br>') }else{ $('#options').show(); } } function toggleRelativeDate(on){ if(on==true){ //show relative date $('#divHoriz .posttime').each(function(i,el){ if(!el.getAttribute('originalDate') && !el.getAttribute('relativeDate')){ // calculate relativeDate, store in attributes var hour, origDate; var arr = el.innerHTML.match(/(\d+)\/(\d+)\/(\d+)[^\d]+(\d+)\:(\d+)/); // 01/19/11(Wed)02:27 var gmt = (GM_getValue('opt_gmt') ? GM_getValue('opt_gmt') : GMT_4chan); hour = parseInt(arr[4],10); if(gmt > GMT_4chan){ hour += Math.abs(gmt - GMT_4chan); }else if(gmt < GMT_4chan){ hour -= Math.abs(gmt - GMT_4chan); }else{ hour = (new Date()).getHours(); } origDate = new Date(20+arr[3], arr[1]-1, arr[2], hour, arr[5]);// new Date(year, month, day, hours, minutes, seconds, milliseconds); el.setAttribute('originalDate', el.innerHTML); el.setAttribute('relativeDate', getRelativeDate(origDate)); } el.innerHTML = el.getAttribute('relativeDate'); }); }else{ //show original date $('#divHoriz .posttime').each(function(i,el){ el.innerHTML = el.getAttribute('originalDate'); }); } } // http://snipplr.com/view/10290/ function getRelativeDate(d){ var dateFunc = new Date(); var timeSince = dateFunc.getTime() - d; var inSeconds = timeSince / 1000; var inMinutes = timeSince / 1000 / 60; var inHours = timeSince / 1000 / 60 / 60; var inDays = timeSince / 1000 / 60 / 60 / 24; var inYears = timeSince / 1000 / 60 / 60 / 24 / 365; var ret = ""; // in seconds if(timeSince < 0 || Math.round(inSeconds) == 1){ ret += "1 second ago"; } else if(inMinutes < 1.01){ ret += Math.round(inSeconds) + " seconds ago"; } // in minutes else if(Math.round(inMinutes) == 1){ ret += "1 minute ago"; } else if(inHours < 1.01){ ret += Math.round(inMinutes) + " minutes ago"; } // in hours else if(Math.round(inHours) == 1){ ret += "1 hour ago"; } else if(inDays < 1.01){ ret += Math.round(inHours) + " hours ago"; } // in days else if(Math.round(inDays) == 1){ ret += "1 day ago"; } else if(inYears < 1.01){ ret += Math.round(inDays) + " days ago"; } // in years else if(Math.round(inYears) == 1){ ret += "1 year ago"; } else { ret += Math.round(inYears) + " years ago"; } return ret+'.'; } function keyupHandler(evt){ //escape key, close ws if(evt.keyCode == 27){ toggle(); return; } // left/right arrow if( (evt.keyCode == 37 || evt.keyCode == 39) && GM_getValue('opt_useArrowKeysToPaginate') && !isFormPostBeingUsed()){ paginate(evt.keyCode); } } function isFormPostBeingUsed(){ if( $('#divFormPosttt').length > 0 && $('#divFormPosttt').find('form').length > 0 ){ return true; }else{ return false; } } function goTo(evt){ toggle(); var href = evt.target.getAttribute('threadUrl').match(/res\/\d+/)[0]; var node = $('a[href^="'+href+'"]'); window.scrollTo( 0, node.offset().top - 50); GM_setValue('autorun',true); } function resize(evt){ if(timerResize) clearTimeout(timerResize); timerResize = setTimeout( function(evt){ //readjust to screen size toggle(); toggle(); //css(); }, RESIZE_DELAY); } function css(){ if(!getById('cssholder')) { getByTag('head')[0].appendChild(createElement('style', {id:'cssholder', type:"text/css"})); } var height = parseInt(window.innerHeight); var width = parseInt(window.innerWidth); topSpace = $('#wstogglelink').offset().top + $('#wstogglelink').outerHeight(); bottomSpace = parseInt(getStyle(pages,'height').match(/\d+/)[0]); getById('cssholder').innerHTML = ''+ ' #divBgHoriz { '+ 'position: fixed; top: '+topSpace+'px; left: 0px; z-index:'+(BASE_ZINDEX+1)+';'+ 'width: 100%;'+ 'height: 100%;'+ 'background-color: '+$('.reply').css('background-color')+';'+ 'vertical-align: middle !important;'+ '}'+ ' #divBgHoriz td{ '+ 'color: #dddddd !important;'+ 'vertical-align: middle !important;'+ 'font-size: 200px !important;'+ '}'+ ' #divHoriz { '+ 'position: fixed; top: '+topSpace+'px; left: 10px; z-index:'+(BASE_ZINDEX+2)+';'+ 'max-height: '+(height - (topSpace+bottomSpace))+'px;'+ 'max-width: '+(width - 20)+'px;'+ 'width: '+(width - 20)+'px;'+ 'overflow: auto;'+ 'background-color: '+$('.reply').css('background-color')+';'+ '}'+ ' #tableHoriz { '+ 'max-height: 100%;'+ 'height: 100%;'+ 'width: 99%;'+ '}'+ ' .tdHoriz { '+ 'vertical-align: top;'+ 'overflow: auto;'+ 'width: '+(100/columns)+'%;'+ 'max-width: '+(100/columns)+'%;'+ '}'+ ' .tablePages { '+ 'position: fixed; bottom: 0px; left: '+parseInt(width/2 - 175)+'px; z-index:'+(BASE_ZINDEX+3)+';'+ '}'+ ' .divThread { '+ 'max-width: '+parseInt(width/columns)+'px;'+ 'background-color: '+$(document.body).css('background-color')+';'+ 'padding: 0 10px;'+ 'margin: 8px 4px'+ '}'+ '.divThread table{ '+ 'max-width: '+((window.innerWidth/columns)-15)+'px;'+ 'clear:left; '+ 'border: 0;'+ 'padding: 0;'+ '}'+ ' .divThread, .divThread .reply, .divThread blockquote { '+ 'font-size: '+(GM_getValue('opt_textsize') ? GM_getValue('opt_textsize') : DEF_TEXT_SIZE)+'px !important;'+ 'word-wrap: break-word !important;'+ 'max-width: '+((window.innerWidth/columns)-15)+'px;'+// must be in pixels or some texts will overflow 'min-width: 50% !important;'+ 'border: 0;'+ '}'+ ' .divThread .reply, .divThread blockquote { '+ 'padding: 0 !important;'+ 'margin:3px !important;'+ '}'+ ' .divThread a img {'+ 'margin: 0 5 !important;'+ '}' +'.divThread .divThreadButtons { float:right; padding:0; margin-top:3; margin-right:3px; }' +'#divHoriz span.omittedposts {font-size:10px !important;}' +'#divHoriz span.postername, #divHoriz span.postertrip, #divHoriz span.commentpostername, #divHoriz span.filetitle, #divHoriz .replytitle, #divHoriz span.filesize, #divHoriz a.quotejs, #divHoriz .posttime { font-size: 11px !important; }' //menu +'#divMenu { position:fixed; right:35px; top: 2px; z-index:'+(BASE_ZINDEX+998)+'; padding:0 10px; margin:3px; font-size:11px; background-color:'+$(document.body).css('background-color')+'; border:1px solid #789922; }' +'#divMenu a:hover, #divMenu a:active { color: #789922 !important; }' +'#divMenu a { float:right; }' //pagination edges +'#divPageLeft, #divPageRight { position:absolute; top:0px; height:100%; width:13px; cursor:pointer; z-index:'+BASE_ZINDEX*2+'; vertical-align: middle; background-color:'+$(document.body).css('background-color')+'; opacity:0; overflow:hidden;}' +'#divPageLeft { left:0px; }' +'#divPageRight { right:0px; }' +'.tablePagination { width:100%; height:100%; color:#000000; overflow:hidden; vertical-align:middle !important;}' +'.tablePagination center { font-size:10px; }' //shadow +'.shadowww {box-shadow: 5px 5px 5px #222222;}' //next page threads +'.nextpageee {background-color: #eeeeee;}' //highlight thread +'.classHighlightThread {border:1px solid #789922;}' // /b/ackwash compatibility +'#backwash_tooltip { z-index:'+(BASE_ZINDEX+999)+' !important;}' +'#divHoriz a.backlink {display:none !important;} '; debug('CSS() calling distributeThreads()... ') distributeThreads(); } function isThreadPage(){ return (location.href.search(/\/res\/\d+/) > -1); } function getThreadIdByUrl(url){ try{ return url.match(/\/res\/(\d+)/)[1]; }catch(e){ return null; } } function storeThread(t, type){ var threads = GM_getValue('threads'); if(!threads){//first insertion threads = {}; threads.t = []; threads.t.push(t); if(type=='posted'){ threads.posted } } //store changes GM_setValue('threads', escape(threads.toSource())) } function paginate(keyCode){ var href, delay, currentPage = 0; try{ currentPage = parseInt(location.href.match(/(\d+)$/)[1]); }catch(e){} //cleanup $(document).unbind('keyup.keys'); $('#divPageLeft').remove(); $('#divPageRight').remove(); if(keyCode==37 && currentPage > 0){ // paginate left if(currentPage<=1) href = location.href.replace(/(\d+)$/, ''); else href = location.href.replace(/(\d+)$/, (currentPage-1)); //animate $('#divBgHoriz').append($('<table>').css({width:'100%',height:'100%'}).html('<tr><td><center></center></tr></td>')); $('#divHoriz').animate( {left: $('#divHoriz').outerWidth()}); //change page delay = $('#divHoriz img').length > 20 ? 250 : 20 ; setTimeout(function(){location.href = href},delay); }else if(keyCode==39 && currentPage < $('.tablePages').text().match(/\[(\d+)\]\s*$/)[1] ){ // paginate right $(document).unbind('keyup.keys'); if(currentPage==0) href = location.href + '1'; else href = location.href.replace(/(\d+)$/, (currentPage+1)); //animate $('#divBgHoriz').append($('<table>').css({width:'100%',height:'100%'}).html('<tr><td><center></center></tr></td>')); $('#divHoriz').animate( {left: -$('#divHoriz').outerWidth()}); //change page delay = $('#divHoriz img').length > 20 ? 250 : 20 ; setTimeout(function(){location.href = href}, delay); } } // http://stackoverflow.com/questions/499126/jquery-set-cursor-position-in-text-area function setSelectionRange(input, selectionStart, selectionEnd) { if (input.setSelectionRange) { input.focus(); input.setSelectionRange(selectionStart, selectionEnd); } else if (input.createTextRange) { var range = input.createTextRange(); range.collapse(true); range.moveEnd('character', selectionEnd); range.moveStart('character', selectionStart); range.select(); } } function setCaretToPos (input, pos) { setSelectionRange(input, pos, pos); } function getStyle(elem, style) { return window.getComputedStyle(elem,null).getPropertyValue(style); } function createElement(type, attrArray, evtListener, html) { var node = document.createElement(type); for (var attr in attrArray) if (attrArray.hasOwnProperty(attr)){ node.setAttribute(attr, attrArray[attr]); } if(evtListener){ var a = evtListener.split(' '); node.addEventListener(a[0], eval(a[1]), eval(a[2])); } if(html) node.innerHTML = html; return node; } function getById(id, parent){ if(!parent) return document.getElementById(id); return parent.getElementById(id); } function getByTag(name, parent){ if(!parent) return document.getElementsByTagName(name); return parent.getElementsByTagName(name); } function xp(p, context, doc) { if (!context) context = document; if (!doc) doc = document; var i, arr = [], xpr = doc.evaluate(p, context, null, XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null); for (i = 0; item = xpr.snapshotItem(i); i++) arr.push(item); return arr; } function debug(str) { if(!DEBUG) return; var d = document.getElementById('debugg'); if(!d){ var div = document.createElement('div'); div.setAttribute('id','divdebug'); div.setAttribute('style', 'background-color:#000000; position:fixed; bottom:3px; left:3px; width:30%; z-index:9999999999999;'); var closeButton = document.createElement('input'); closeButton.setAttribute('id','closedebug'); closeButton.setAttribute('type', 'button'); closeButton.setAttribute('value', 'close'); closeButton.setAttribute('onClick', 'this.parentNode.parentNode.removeChild(this.parentNode);'); d = document.createElement('textarea'); d.setAttribute('id','debugg'); d.setAttribute('style',"height:120px; width:99%; margin:2px; font-size:11px;"); div.appendChild(d); div.appendChild(document.createElement('br')); div.appendChild(closeButton); document.body.appendChild(div); } d.innerHTML += '\n'+str; d.scrollTop = d.scrollHeight; }
0 comments:
Post a Comment