stream4chan

Turn those beastly 4chan threads in an easy to use, easy to watch stream of content, given to you in a gallery-like format. Batteries not included

You will need to install an extension such as Tampermonkey, Greasemonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey or Userscripts to install this script.

You will need to install an extension such as Tampermonkey to install this script.

You will need to install a user script manager extension to install this script.

(I already have a user script manager, let me install it!)

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

(I already have a user style manager, let me install it!)

// ==UserScript==
// @name         stream4chan
// @namespace    http://tampermonkey.net/
// @version      4.3
// @description  Turn those beastly 4chan threads in an easy to use, easy to watch stream of content, given to you in a gallery-like format. Batteries not included
// @author       Lauchlan105
// @match        http://boards.4chan.org/*/thread/*
// @grant        none
// ==/UserScript==

//////////////////
// # Settings # //
//////////////////

//////////////////
// # Settings # //
//////////////////

/*

fix resizing (again)
remove (S) for shuffle
change settings font color
make video size change with gallery
prevent arrow from being pushed outside 

*/

var settingsArray = [
    
    //Loop whole thread
    true,

    //Play automatically
    true,

    //Shuffle on startup
    false,

    //Play Webms
    true,

    //Show Webm controls
    true,

    //Play webm sound
    true,

    //Play Gifs
    true,

    //Gif duration (Seconds)
    3,

    //Play Images
    true,

    //Image duration (Seconds)
    3,

    //Open Stream4chan on startup
    true,

    //Override Individual media?
    true,

    //Select Media randomly
    false
];

///////////////////
// # Variables # //
///////////////////

//Placeholder variables
var globalTimeout;
var webm;
var gif;
var png;
var jpg;
var SOT;
var EOT;
var noneSelected;
var allContent;
var usedContent;
var currentContent;

////////////////////////////
// # Media Object Model # //
////////////////////////////

class Media{
    constructor(thumb, source, id){

    	// local scope variable for object access via video/thumbnail elements
        var obj = this;

        this.position = 0;
        this.playcount = 0;
        this.prevMedia = noneSelected;
        this.nextMedia = noneSelected;

        this.id = id === undefined ? "" : id;

        this.thumb = document.createElement('img');
        this.thumb.src = thumb;
        this.thumb.setAttribute('class','sfc-slide-preview');

        this.type = mediaType(source);

        this.resizeTimeout = setTimeout(function(){}, 0);

        //Handles deleted files/invalid media
        if(this.type === undefined || this.type === null){

        	//Force null for simpler conditionals
        	this.type = null;

        	console.log('Media could not be made. One or more of the following are invalid...');
        	console.log('	Given Arguments:');
        	console.log('		thumb: ' + thumb);
        	console.log('		source: ' + source);
        	console.log('		id: ' + id);
        	console.log('');
        	console.log('	All functions will be assigned placeholders');

        	function placeHolderFunction(calledFunction){
                el_stage.innerHTML = calledFunction + ' cannot be called on comment with id ' + this.id;
        		console.log(calledFunction + ' cannot be called on object with id ' + this.id);
        		return;
    		}

			this.unhighlight = function(){ placeHolderFunction('unhiglight'); };
			this.highlight   = function(){ placeHolderFunction('highlight'); };
       	    this.deselect    = function(){ placeHolderFunction('deselect'); };
       	   	this.resize      = function(){ placeHolderFunction('resize'); };
       	    this.select      = function(){ placeHolderFunction('select'); };
			this.pause       = function(){ placeHolderFunction('pause'); };
     	    this.play        = function(){ placeHolderFunction('play'); };
			
        	return false;
        }

    	if(this.type === webm){
            this.media = document.createElement('video');

            this.media.setAttribute("id", "sfc-webm");

            this.media.setAttribute("controls","");

            this.media.setAttribute("loop","");
            this.media.loop = true;

            this.media.setAttribute("autoplay","");
            this.media.autoplay = false;

            this.media.setAttribute("preload","");
            this.media.preload = "none";

        }else if(this.type === png || this.type === gif || this.type === jpg){
            this.media = document.createElement('img');
            this.media.setAttribute("id","sfc-img");
            this.media.alt = source;
        }

    	this.media.setAttribute("class", "sfc-media");
    	this.media.src = source;


        ///////////////////
        //MEDIA FUNCTIONS//
        ///////////////////
    	this.play = function(){

        	if(obj !== SOT && obj !== EOT && obj !== noneSelected){
        		if(obj.type == webm){
	                obj.media.volume = op_playSound.checked ? obj.media.volume : 0;
	                obj.media.play();
	            }else if(obj.type == gif || obj.type == jpg || obj.type == png){
                    obj.media.src = obj.media.alt;
                    updateAutoplay();
                }

        	}
        };

        this.pause = function(){

            clearTimeout(globalTimeout);
            if(obj.type == webm){
                obj.media.pause();
            }else if(obj.type == gif || obj.type == jpg || obj.type == png){
                obj.media.src = obj.thumb.src;
            }
        };

        ///////////////////////
        //THUMBNAIL FUNCTIONS//
        ///////////////////////

        var highlight = function(){

            obj.thumb.style.border = "2px solid gainsboro";

            /*

			//Scroll into view
	        var pc = document.getElementById('pc' + id.substr(id.lastIndexOf('p') + 1));
  	 		pc.scrollIntoView();

			//Set container style to mimic focused content 
  			pc.style.background = '#f0e0d6';
    		pc.style.border = '1px solid #D99F91!important';

    		*/
        };

        var unhighlight = function(){

            obj.thumb.style.border = "2px solid transparent";

			/*

			//Remove focused content styles           
 			var pc = document.getElementById('pc' + id.substr(id.lastIndexOf('p') + 1));
  			pc.style.background = '#F0C0B0!important';
    		pc.style.border = '1px solid #D9BFB7';

    		*/
        };

        ///////////////////////////
        //MISCELLANEOUS FUNCTIONS//
        ///////////////////////////

        this.select = function(){

        	obj.playcount++;

            //Deselect active content
            if(currentContent !== null){
                currentContent.deselect();
            }

            //Set currentContent to this object
            currentContent = obj;

            //Highlight thumbnail border
            highlight();

            //Add media to stage
            obj.media.controls = op_controls.checked;
            el_stage.appendChild(obj.media);

            //Play Media
            obj.play();

            //resize media
            obj.resize();

            //Update auto playing
            updateAutoplay();

            //Moves gallery so selected object is centered
            obj.slideGallery();
            
            //Update counter in top right
            updateCounter();

            //Assign and load neighbouring media
            obj.getNeighbours();

            if(obj.prevMedia.type === webm){
                obj.prevMedia.media.load();
            }else if(obj.nextMedia.type === webm){
                obj.nextMedia.media.load();
            }
        };

        this.deselect = function(){
            obj.pause();
            obj.media.currentTime = 0;
            unhighlight();
            el_stage.innerHTML = "";
            currentContent = null;

            //Reset prev and next media
            obj.prevMedia = noneSelected;
            obj.nextMedia = noneSelected;
        };

        this.thumb.onclick = function(){
        	if(obj.thumb.style.border == "2px solid gainsboro"){
        		obj.deselect();
        	}else{
        		obj.select();
        	}
        };

        this.resize = function(){

            clearTimeout(obj.resizeTimeout);

        	//Recursive resize function
        	//repeats every {interval} seconds
        	//if interval is undefined or < 0.01, default to 0.01
        	function execResize(interval){

        		//if interval is below 0.01, set to minimum 0.01
        		if(interval){
        			if(interval < 0.05)
        				interval = 0.05;
        		}

                if(isShown(el_sfc)){
                    if(obj === currentContent){
                        var setByWidth = true;

                        console.log('resizing');

                        //Set to max width
                        obj.media.style.width = window.innerWidth - (el_stagePrev.clientWidth + el_stageNext.clientWidth) + 'px';
                        obj.media.style.height = 'auto';

                        //if media height exceeds the stage height
                        if(obj.media.clientHeight > el_stage.clientHeight){
                            //Set to max height instead
                            obj.media.style.height = el_stage.clientHeight + 'px';
                            obj.media.style.width = 'auto';
                            setByWidth = false;
                        }

                        if(setByWidth){
                            // if full width, set height padding
                            obj.media.style.marginLeft = '0px';
                            var difHeight = (el_stage.clientHeight - obj.media.clientHeight)/2;
                            var topMarg = (difHeight) - ( difHeight%1 ); //Minus any decimals
                            obj.media.style.marginTop = topMarg  + 'px';
                        }else{
                            // if full height, set width padding
                            obj.media.style.marginTop = '0px';
                            var difWidth = (el_stage.clientWidth - obj.media.clientWidth)/2;
                            var leftMarg = (difWidth) - ( difWidth%1 ); //Minus any decimals
                            obj.media.style.marginLeft = leftMarg  + 'px';
                        }

                        if(interval){
                            obj.resizeTimeout = setTimeout(function(){
                                execResize(interval);
                            }, interval*1000);
                        }else{
                            return;
                        }
                    }else{
                        clearTimeout(obj.resizeTimeout);
                    }  
                }else{
                    clearTimeout(obj.resizeTimeout);
                }
        		
        		return;
        	}

        	//Continue resizing every 1 second till video ends
        	execResize(0.2);

        };

        this.slideGallery = function(){

            //resets slider transform
            el_internalSlider.style.transform = '';

            //distance from the left of the browser to the middle of the thumbnail
            var middleOfThumb = getPageTopLeft(obj.thumb).left + (obj.thumb.clientWidth*1.5);

            //The distance between left side of browser and vertical middle of browser
            var middleOfWindow = window.innerWidth/2;

            //Displacement from middle
            var displacement = middleOfWindow - middleOfThumb;

            //Include the current position of the internal slider
            var crntSliderValue = getPageTopLeft(el_internalSlider).left;
            displacement += crntSliderValue;

            //Apply change
            el_internalSlider.style.transform = 'translateX( ' + displacement + 'px)';

        }

        this.previous = function(){
            obj.prevMedia.select();
        }

        this.next = function(){
            obj.nextMedia.select();
        }

        this.getNeighbours = function(){
            if(!canPlay(obj)){
                //If the current object isn't in usedContent -> prev = last in used content, next = first in used content
                obj.prevMedia = usedContent[usedContent.length - 1].select();
                obj.nextMedia = usedContent[0].select();
            }else if(op_random.checked){
                obj.prevMedia = getRandom();
                obj.nextMedia = getRandom(obj.prevMedia);
            }else if(op_loopAll.checked){
                obj.prevMedia = obj.position === 0 ? usedContent[usedContent.length - 1] : usedContent[obj.position - 1];
                obj.nextMedia = obj.position === usedContent.length - 1 ? usedContent[0] : usedContent[obj.position + 1];
            }else if(!op_loopAll.checked){
                obj.prevMedia = obj.position === 0 ? obj : usedContent[obj.position - 1];
                obj.nextMedia = obj.position === usedContent.length - 1 ? obj : usedContent[obj.position + 1];
            }
        }

        this.media.getObj = function(){ return obj; };
        this.thumb.getObj = function(){ return obj; };

        return true;
    }
}

//////////////
// # Main # //
//////////////

(function(){

    //Removes default padding
    document.body.style.padding = "0px";

    insertElements();
    initVars();
    initPlaceholders();
    startInteractions();
    startEventListeners();
    
    var validSettings = applyDefaulSettings();
    if( !validSettings.valid ){
        console.log(validSettings.valid);
        for(var i = 0; i < validSettings.messages.length; i++){
        	console.log(validSettings.messages[i]);
            el_stage.innerHTML = '<h1>' + validSettings.messages[i] + '</h1>';    
        }
        return;
    }

    //Show and hide gallery to force load thumbnails
    //without this .select() does not work until gallery is shown
    showGallery(true);
    showGallery(false);

    magicMouse(false);
    sfc.style.display = "none"; //Force hide SFC
    showSFC(false);             //Force styles to be ready for fade in 

    //If shuffled on start up  -> shuffle
    if(settingsArray[2]){
    	shuffle(true);
    }

    //If open on startup is selected -> open on startup
    if(settingsArray[10]){
        showSFC(true);
        usedContent[0].select();
    }
})();

/////////////////////////////////
// # Initial Setup Functions # //
/////////////////////////////////

//Insert html for buttons and modal
function insertElements(){

    //Start Button
    var btn1 = '[<a id="sfc-start" href="#">start</a>]';
    var btn2 = '[<a id="sfc-resume" href="#">resume</a>]';

    //Add span to nav
    var nav = document.getElementsByClassName('navLinks desktop');
    for(var i = 0; i < nav.length; i++){
        var span = document.createElement('span');
        span.innerHTML = btn1 + " " + btn2;

        span.className = 'sfc-nav';
        span.style.display = nav[i].style.display;

        nav[i].parentNode.insertBefore(span, nav[i]);
        nav[i].parentNode.insertBefore(document.getElementById('op'), nav[i]);
    }

    var html = '<!-- SETTINGS --> <link href="https://fonts.googleapis.com/css?family=Montserrat" rel="stylesheet"> <div id="sfc-settings-column"> <div id="sfc-settings-row"> <div id="sfc-settings-panel"> Settings <div id="sfc-settings-exit"></div> <!-- GENERAL SETTINGS --> <div> <p class="sfc-settings-title"> General </p> <div id="sfc-option"> <input id="stream4chan-loopAll" class="SFC-input" type="checkbox"> Loop whole thread (L) </div> <div id="sfc-option"> <input id="stream4chan-auto" class="SFC-input" type="checkbox"> Play Automatically (A) </div> <div id="sfc-option"> <input id="stream4chan-random" class="SFC-input" type="checkbox"> Random (R) </div> <div id="sfc-option"> <input id="stream4chan-shuffle" class="SFC-input" type="button" value=" Shuffle "> (S) </div> </div> <!-- WEBM SETTINGS --> <div> <p class="sfc-settings-title"> Webm </p> <div id="sfc-option"> <input id="stream4chan-webms" class="SFC-input" type="checkbox"> Play Webms (W) </div> <div id="sfc-option"> <input id="stream4chan-controls" class="SFC-input" type="checkbox"> Show Controls (C) </div> <div id="sfc-option"> <input id="stream4chan-playSound" class="SFC-input" type="checkbox"> Play sound (S) </div> </div> <!-- GIF SETTINGS --> <div> <p class="sfc-settings-title"> Gif </p> <div id="sfc-option"> <input id="stream4chan-gifs" class="SFC-input" type="checkbox"> Play Gifs (G) </div> <div id="sfc-option"> <input id="stream4chan-gif-duration" class="SFC-input" type="number" min="1" max="60" value="3" step="1"> Gif Duration (up/down) </div> </div> <!-- IMG SETTINGS --> <div> <p class="sfc-settings-title"> Images </p> <div id="sfc-option"> <input id="stream4chan-imgs" class="SFC-input" type="checkbox"> Play Images (I) </div> <div id="sfc-option"> <input id="stream4chan-img-duration" class="SFC-input" type="number" min="1" max="60" value="3" step="1"> Image Duration (Shift + up/down) </div> </div> </div> </div> </div> <!-- Main --> <div id="sfc-main"> <div id="sfc-main-prev" class="sfc-util prev"></div> <div id="sfc-stage"> </div> <div id="sfc-utility"> <div id="sfc-main-settings" class="sfc-util settings"></div> <div id="sfc-main-gallery" class="sfc-util gallery"></div> </div> <div id="sfc-counter"> <p id="sfc-counter-first">1</p> / <p id="sfc-counter-second">2</p> </div> <div id="sfc-main-next" class="sfc-util next"></div> </div> <!-- Gallery Slider --> <div id="sfc-gallery"> <div id="sfc-gallery-prev" class="sfc-util prev"></div> <div id="sfc-slider"> <div id="sfc-slider-internal"> </div> </div> <div id="sfc-gallery-next" class="sfc-util next"></div> </div> <!-- Hidden Cursor Overlay --> <span id="sfc-magicMouse"> </span>';
    // var html = '<!-- SETTINGS --> <div id="sfc-settings-column"><div id="sfc-settings-row"> <div id="sfc-settings-panel"> Settings <div id="sfc-settings-exit"></div> <!-- GENERAL SETTINGS --> <div> <p class="sfc-settings-title"> General </p> <div id="sfc-option"> <input id="stream4chan-loopAll" class="SFC-input" type="checkbox"> Loop whole thread (L) </div> <div id="sfc-option"> <input id="stream4chan-auto" class="SFC-input" type="checkbox"> Play Automatically (A) </div> <div id="sfc-option"> <input id="stream4chan-random" class="SFC-input" type="checkbox"> Random (R) </div> <div id="sfc-option"> <input id="stream4chan-shuffle" class="SFC-input" type="button" value=" Shuffle "> (S) </div> </div> <!-- WEBM SETTINGS --> <div> <p class="sfc-settings-title"> Webm </p> <div id="sfc-option"> <input id="stream4chan-webms" class="SFC-input" type="checkbox"> Play Webms (W) </div> <div id="sfc-option"> <input id="stream4chan-controls" class="SFC-input" type="checkbox"> Show Controls (C) </div> <div id="sfc-option"> <input id="stream4chan-playSound" class="SFC-input" type="checkbox"> Play sound (S) </div> </div> <!-- GIF SETTINGS --> <div> <p class="sfc-settings-title"> Gif </p> <div id="sfc-option"> <input id="stream4chan-gifs" class="SFC-input" type="checkbox"> Play Gifs (G) </div> <div id="sfc-option"> <input id="stream4chan-gif-duration" class="SFC-input" type="number" min="1" max="60" value="3" step="1"> Gif Duration (up/down) </div> </div> <!-- IMG SETTINGS --> <div> <p class="sfc-settings-title"> Images </p> <div id="sfc-option"> <input id="stream4chan-imgs" class="SFC-input" type="checkbox"> Play Images (I) </div> <div id="sfc-option"> <input id="stream4chan-img-duration" class="SFC-input" type="number" min="1" max="60" value="3" step="1"> Image Duration (Shift + up/down) </div> </div> </div> </div> </div> <!-- Main --> <div id="sfc-main"> <div id="sfc-main-prev" class="sfc-util prev"></div> <div id="sfc-stage"> </div> <div id="sfc-utility"> <div id="sfc-main-settings" class="sfc-util settings"></div> <div id="sfc-main-gallery" class="sfc-util gallery"></div> </div> <div id="sfc-main-next" class="sfc-util next"></div> </div> <!-- Gallery Slider --> <div id="sfc-gallery"> <div id="sfc-gallery-prev" class="sfc-util prev"></div> <div id="sfc-slider"> <div id="sfc-slider-internal"> </div> </div> <div id="sfc-gallery-next" class="sfc-util next"></div> </div>';
    // var css = '<!-- CSS --> <style> body, div, img, a, span, html, p{ margin: 0px; border: 0px; padding: 0px; } .sfc-nav{ height: auto; width: auto; } #sfc{ opacity: 1; -moz-transition: opacity 0.50s ease-in-out; -webkit-transition: opacity 0.50s ease-in-out; -o-transition: opacity 0.50s ease-in-out; -ms-transition: opacity 0.50s ease-in-out; transition: opacity 0.50s ease-in-out; } #sfc-main { width: 100%; height: 100%; z-index: 500; position: fixed; top: 0; display: flex; flex-flow: row; background-color: rgba(0,0,0,0.9 ); -webkit-box-shadow: inset 0px 0px 300px 28px rgba(0,0,0,1); -moz-box-shadow: inset 0px 0px 300px 28px rgba(0,0,0,1); box-shadow: inset 0px 0px 300px 28px rgba(0,0,0,1); } #sfc-gallery{ width: 100%; height: auto; z-index: 1000; position: fixed; bottom: 0; display: flex; flex-flow: row; background-color: rgba(0,0,0,0.35); transform: translateY(100%); -webkit-transition: transform 0.4s ease-in-out 0.05s; transition: transform 0.4s ease-in-out 0.05s; } #sfc-settings-column{ height: 100vh; z-index: 1500; top: 0; display: none; flex-flow: column; position: fixed; background-color: rgba(0,0,0,0.7); font-family: "PT Sans", sans-serif; font-size: 16pt; } #sfc-settings-row{ width: 100vw; display: flex; flex-flow: row; flex: 1 1 auto; } #sfc-settings-panel{ margin: auto; padding: 20px; flex: 0 1 auto; background-color: rgba(255,255,255,0.8); } .sfc-settings-title{ margin-top: 7%; text-decoration: underline; } #sfc-settings-exit { width: 20px; height: 20px; opacity: 0.3; float: right; background-image: url("http://www.myiconfinder.com/uploads/iconsets/4c515d45f6a8c4fe16e448a692a9370d.png"); background-size: contain; -webkit-transition: opacity 0.2s linear 0.05s, visibility 0s; transition: opacity 0.2s linear 0.05s, visibility 0s; } #sfc-settings-exit:hover{ opacity: 1; } #sfc-stage, #sfc-slider{ flex: 1 1 auto; margin: 5px; } #sfc-slider-internal{ width: 0px; } #sfc-utility{ position: fixed; bottom: 0; -webkit-transition: transform 0.4s ease-in-out 0.05s; transition: transform 0.4s ease-in-out 0.05s; } .sfc-util{ opacity: 0.1; width: 3vw; height: 3vw; background-color: rgba(255,255,255,0.6); background-clip: content-box; border-radius: 50%; background-size: 1.5vw; background-repeat: no-repeat; background-position:center; margin: auto; padding: 5px; -webkit-transition: opacity 0.2s linear 0.05s, visibility 0s; transition: opacity 0.2s linear 0.05s, visibility 0s; } .sfc-util:hover{ opacity: 1; } .gallery, .settings{ background-size: 2.2vw; } .gallery{ background-image: url("https://maxcdn.icons8.com/Android_L/PNG/24/Photo_Video/gallery-24.png"); } .settings{ background-image: url("https://maxcdn.icons8.com/Android_L/PNG/24/Very_Basic/settings-24.png"); } .prev, .next { flex: 0 0 3vw; background-image: url("http://www.dsetechnology.co.uk/images/disclose-arrow.png"); } .prev{ transform: rotate(180deg); } .sfc-slide-preview{ height: 6vh; width: auto; border: 2px solid transparent; -webkit-transition: border 0.2s linear 0.05s, visibility 0s; transition: border 0.2s linear 0.05s, visibility 0s; } .sfc-slide-preview:hover { border: 2px solid white; } </style> ';
    var css = '<style> <!-- CSS --> <style> body, div, img, a, span, html, p{ margin: 0px; border: 0px; padding: 0px; } #sfc-magicMouse { z-index: 1000; position: fixed; top: 0px; height: 100vh; width: 100vw; cursor: none; } #sfc-counter { min-height: ; position: fixed; top: 0px; right: 0px; color: rgba(255,255,255,0.3); font-family: \'Montserrat\', sans-serif; } #sfc-counter p { display: inline; } .sfc-nav{ height: auto; width: auto; } #sfc{ opacity: 1; -moz-transition: opacity 0.50s ease-in-out; -webkit-transition: opacity 0.50s ease-in-out; -o-transition: opacity 0.50s ease-in-out; -ms-transition: opacity 0.50s ease-in-out; transition: opacity 0.50s ease-in-out; } #sfc-main { width: 100%; height: 100%; z-index: 500; position: fixed; top: 0; display: flex; flex-flow: row; background-color: rgba(0,0,0,0.9 ); -webkit-box-shadow: inset 0px 0px 300px 28px rgba(0,0,0,1); -moz-box-shadow: inset 0px 0px 300px 28px rgba(0,0,0,1); box-shadow: inset 0px 0px 300px 28px rgba(0,0,0,1); } #sfc-gallery{ width: 100%; height: auto; z-index: 1000; position: fixed; bottom: 0; display: flex; flex-flow: row; background-color:rgba(0,0,0,0.35); transform: translateY(100%); -webkit-transition: transform 0.4s ease-in-out 0.05s; transition: transform 0.4s ease-in-out 0.05s; } #sfc-settings-column{ height: 100vh; z-index: 1500; top: 0; display: none; flex-flow: column; position: fixed; background-color: rgba(0,0,0,0.7); font-family: "PT Sans", sans-serif; font-size: 16pt; } #sfc-settings-row{ width: 100vw; display: flex; flex-flow: row; flex: 1 1 auto; } #sfc-settings-panel{ margin: auto; padding: 20px; flex: 0 1 auto; background-color: rgba(255,255,255,0.8); } .sfc-settings-title{ margin-top: 7%; text-decoration: underline; } #sfc-settings-exit { width: 20px; height: 20px; opacity: 0.3; float: right; background-image: url("http://www.myiconfinder.com/uploads/iconsets/4c515d45f6a8c4fe16e448a692a9370d.png"); background-size: contain; -webkit-transition: opacity 0.2s linear 0.05s, visibility 0s; transition: opacity 0.2s linear 0.05s, visibility 0s; } #sfc-settings-exit:hover{ opacity: 1; } #sfc-stage, #sfc-slider{ flex: 1 1 auto; margin: 5px; } #sfc-slider-internal{ width: 0px; -webkit-transition: transform 0.4s ease-in-out 0.05s; transition: transform 0.4s ease-in-out 0.05s; } #sfc-utility{ position: fixed; bottom: 0; -webkit-transition: transform 0.4s ease-in-out 0.05s; transition: transform 0.4s ease-in-out 0.05s; } .sfc-util{ opacity: 0.1; width: 3vw; height: 3vw; background-color: rgba(255,255,255,0.6); background-clip: content-box; border-radius: 50%; background-size: 1.5vw; background-repeat: no-repeat; background-position:center; margin: auto; padding: 5px; -webkit-transition: opacity 0.2s linear 0.05s, visibility 0s; transition: opacity 0.2s linear 0.05s, visibility 0s; } .sfc-util:hover{ opacity: 1; } .gallery, .settings{ background-size: 2.2vw; } .gallery{ background-image: url("https://maxcdn.icons8.com/Android_L/PNG/24/Photo_Video/gallery-24.png"); } .settings{ background-image: url("https://maxcdn.icons8.com/Android_L/PNG/24/Very_Basic/settings-24.png"); } .prev, .next { flex: 0 0 3vw; background-image: url("http://www.dsetechnology.co.uk/images/disclose-arrow.png"); } .prev{ transform: rotate(180deg); } .sfc-slide-preview{ height: 6vh; width: auto; border: 2px solid transparent; -webkit-transition: border 0.2s linear 0.05s, visibility 0s; transition: border 0.2s linear 0.05s, visibility 0s; } .sfc-slide-preview:hover { border: 2px solid white; } </style>';

    var sfc = document.createElement('div');
    sfc.setAttribute('id','sfc');
    sfc.innerHTML = html + css;

    var target = document.getElementsByClassName('thread');
    for(i = 0; i < target.length; i++){
        target[i].prepend(sfc);
    }
}

//Create and initialize global variables for easy access to HTML elements
function initVars(){

    //Custom function to find elements while 
        //alerting console of errors in case of null || undefined
    function getEl(elName){
        var temp = document.getElementById(elName);
        if(temp === null || temp === undefined){
            temp = document.getElementsByClassName(elName)[0];
            if(temp === null || temp === undefined){
                console.log('### ERROR ###');
                console.log('initVars: getEl(\'' + elName +'\') returned... ');
                console.log(temp);
            }
        }
        return temp;
    }

    //Main Page
    el_startBtn = getEl('sfc-start');
    el_resumeBtn = getEl('sfc-resume');

    //Modal
    el_sfc = getEl('sfc');
    el_magicMouse = getEl('sfc-magicMouse');

    //Stage Area
    el_stage = getEl('sfc-stage');
    el_stagePrev = getEl('sfc-main-prev');
    el_stageNext = getEl('sfc-main-next');

    //Utility buttons
    el_util = getEl("sfc-utility");
    el_galleryBtn = getEl("sfc-main-gallery");
    el_settingsBtn = getEl("sfc-main-settings");
    el_counter_first = getEl("sfc-counter-first");
    el_counter_second = getEl("sfc-counter-second");

    //Gallery Area
    el_gallery = getEl("sfc-gallery");
    el_slider = getEl('sfc-slider');
    el_internalSlider = getEl('sfc-slider-internal');
    el_internalSlider.style.transform = "translateX(0px)";
    el_sliderPrev = getEl('sfc-gallery-prev');
    el_sliderNext = getEl('sfc-gallery-next');

    //Settings and option area
    el_settings = getEl("sfc-settings-column");
    el_settingsExit = getEl("sfc-settings-exit");
    op_loopAll = getEl('stream4chan-loopAll');
    op_auto = getEl('stream4chan-auto');
    op_random = getEl('stream4chan-random');
    op_shuffle = getEl('stream4chan-shuffle');

    op_webms = getEl('stream4chan-webms');
    op_controls = getEl('stream4chan-controls');
    op_playSound = getEl('stream4chan-playSound');

    op_gifs = getEl('stream4chan-gifs');
    op_gif_duration = getEl('stream4chan-gif-duration');

    op_imgs = getEl('stream4chan-imgs');
    op_img_duration = getEl('stream4chan-img-duration');
}

//Inititialize values to placeholder variables
function initPlaceholders(){
    //Type placeholders. Less quotations in code
    webm = 'webm';
    gif = 'gif';
    png = 'png';
    jpg ='jpg';

    //Start of thread
    //Object based placeholder for the beginning of the thread (used when loopAll is unchecked)
    SOT = new Media("https://dummyimage.com/1920x1080/000000/ffffff.png","https://dummyimage.com/1920x1080/000000/ffffff.png");
    SOT.media.src = "https://dummyimage.com/1920x1080/000000/ffffff.png&text=Start+of+thread"; 
    SOT.thumb.src = "https://dummyimage.com/480x270/000000/ffffff.png&text=Start+of+thread";
    SOT.type = "SOT";

    //End of thread
    //Object based placeholder for the end of the thread (used when loopAll is unchecked)
    EOT = new Media("https://dummyimage.com/1920x1080/000000/ffffff.png","https://dummyimage.com/1920x1080/000000/ffffff.png");
    EOT.media.src = "https://dummyimage.com/1920x1080/000000/ffffff.png&text=End+of+thread";
    EOT.thumb.src = "https://dummyimage.com/480x270/000000/ffffff.png&text=End+of+thread";
    EOT.type = "EOT";

    //Object based placeholder for when there is no applicable media found or nothing is selected
    noneSelected = new Media("https://dummyimage.com/1920x1080/000000/ffffff.png","https://dummyimage.com/1920x1080/000000/ffffff.png");
    noneSelected.media.src = "https://dummyimage.com/1920x1080/000000/ffffff.png&text=No+Media+Selected";
    noneSelected.thumb.src = "https://dummyimage.com/480x270/000000/ffffff.png&text=No+Media+Selected";

    allContent = getContent();
    usedContent = getUsedContent();
    currentContent = noneSelected;
}

//Links keyboard controls with functions and updates sfc accordinglys
function startEventListeners(){

    window.onresize = function(){
        // updateGallery();
        currentContent.resize();
        currentContent.slideGallery();
    }

    op_loopAll.onchange = updateGallery;
    
    op_controls.onchange = function(){
        if(currentContent.type == webm){
            currentContent.media.controls = op_controls.checked;
        }
    };

    op_playSound.onchange = function(){
        if(currentContent.type == webm){
            currentContent.media.volume = op_playSound.checked ? 1 : 0;
        }
    };

    op_webms.onchange = updateGallery;
    op_gifs.onchange = updateGallery;
    op_imgs.onchange = updateGallery;
    op_auto.onchange = updateAutoplay;
    op_shuffle.onclick = shuffle;

    el_stagePrev.onclick = previous;
    el_stageNext.onclick = next;

    document.onkeydown = function(event){
        switch(event.keyCode){

            //Space Key
            case 32:
                if(currentContent !== null){
                    //if paused
                    if(currentContent.type == webm){
                        if(currentContent.media.paused){
                            currentContent.play();
                        }else{
                            currentContent.pause();
                        }
                    }else{
                        if(currentContent.media.src == currentContent.thumb.src){
                            currentContent.play();
                        }else{
                            currentContent.pause();
                        }
                    }
                }
                break;

            //Enter Key
            case 13:
                if(event.ctrlKey)
                    return;

                if(!isShown(el_sfc)){

                    if(event.altKey){
                        el_resumeBtn.onclick();                        
                    }else{
                        el_startBtn.onclick();
                    }

                }
                break;    

            //Esc Key
            case 27:
                if(isShown(el_settings)){
                    showSettings(false);
                }else if(isShown(el_gallery)){
                    showGallery(false);
                }else if(isShown(el_sfc)){
                    showSFC(false);
                }
                break;

            //Left arrow Key
            case 37:
                if(!event.altKey)
                    previous();
                break;

            //Right arrow Key
            case 39:
                if(!event.altKey)
                    next();
                break;

            //Up arrow Key
            case 38:
                if(event.shiftKey){
                    op_img_duration.value++;
                }else{
                    op_gif_duration.value++;
                }
                break;

            //Down arrow Key
            case 40:
                if(event.shiftKey){
                    op_img_duration.value--;
                }else{
                    op_gif_duration.value--;
                }
                break;

            //L Key
            case 76:
                op_loopAll.checked = !op_loopAll.checked;
                op_loopAll.onchange();
                break;

             //A Key
            case 65:
                op_auto.checked = !op_auto.checked;
                op_auto.onchange();
                break;

            //R Key
            case 82:
                if(!event.ctrlKey)
                    op_random.checked = !op_random.checked;
                break;

            //Q Key
            case 81:
                break;

            //S Key
            case 83:
                op_playSound.checked = !op_playSound.checked;
                op_playSound.onchange();
                break;

            //W Key
            case 87:
                op_webms.checked = !op_webms.checked;
                op_webms.onchange();
                break;

            //C Key
            case 67:
                op_controls.checked = !op_controls.checked;
                op_controls.onchange();
                break;

            //G Key
            case 71:
                op_gifs.checked = !op_gifs.checked;
                op_gifs.onchange();
                break;

            //I Key
            case 73:
                op_imgs.checked = !op_imgs.checked;
                op_imgs.onchange();
                break;

             //Backspace
             case 8:
                settingsArray[11] = !settingsArray[11];
                break;

            //Print what was typed into console
            default:
                var temp = "";
                
                if(event.shiftKey){
                    temp += "Shift + ";
                }

                if(event.altKey){
                    temp += "Alt + ";
                }

                if(event.ctrlKey){
                    temp += "Ctrl + ";
                }

                temp += event.keyCode;

                console.log(temp);
        }
    }

    el_gallery.onwheel = function(event){

        //This number, when used with 
        // if(event.wheelDelta > 0 ){
                        
        // }else{
        //     console.log('scrolling down');
        //     el_internalSlider.style.transform = 'translateX(' + (getPageTopLeft(el_internalSlider).left) + 'px)';    
        // }
        
    }

    el_stage.onclick = function(e) {
        if (e.target === this){
            currentContent.pause();
            showSFC(false);
            return;
        }
    };
}

//////////////////////////////////////////////
// # SFC Control  and Animation Functions # //
//////////////////////////////////////////////

//Links functions with page controllers
//eg: making gallery button show/hide gallery
function startInteractions(){

    //Apply functionality: click start to show modal and play first media item
    el_startBtn.onclick = function(){
        showSFC(true);
        if(op_auto.checked){
            usedContent[0].select();
        }
    };

    el_resumeBtn.onclick = function(){
        showSFC(true);
        currentContent.resize();
        currentContent.play();
        updateAutoplay();
    };

    //Apply functionality: click gallery button to show/hide gallery
    el_gallery.style.transform = "translateY(100%)";
    el_galleryBtn.onclick = showGallery;

    //Apply functionality: click settings button to show settings
        //Click exit button to exit settings
    el_settingsBtn.onclick = function(){ showSettings(true); };
    el_settingsExit.onclick = function(){ showSettings(false); };
}

//Applies default settings
//  • Default settings are on line 5
function applyDefaulSettings(){

    var messages = Array();

    //Loop whole thread
    if(settingsArray[0] !== true && settingsArray[0] !== false){
        messages.push("Loop whole thread");
    }else{
        op_loopAll.checked = settingsArray[0];
    }

    //Play automatically
    if(settingsArray[1] !== true && settingsArray[1] !== false){
        messages.push("Play automatically");
    }else{
        op_auto.checked = settingsArray[1];       
    }

    //Shuffle on startup
    if(settingsArray[2] !== true && settingsArray[2] !== false){
        messages.push("Shuffle on startup");
    }else{
        op_shuffle.value = settingsArray[2] ? "Unshuffle" : "Shuffle";
    }

    //Play Webms
    if(settingsArray[3] !== true && settingsArray[3] !== false){
        messages.push("Play Webms");
    }else{
        op_webms.checked = settingsArray[3];       
    }

    //Show Webm controls
    if(settingsArray[4] !== true && settingsArray[4] !== false){
        messages.push("Show Webm controls");
    }else{
        op_controls.checked = settingsArray[4];      
    }

    //Play webm sound
    if(settingsArray[5] !== true && settingsArray[5] !== false){
        messages.push("Play webm sound");
    }else{
        op_playSound.checked = settingsArray[5];       
    }

    //Play Gifs
    if(settingsArray[6] !== true && settingsArray[6] !== false){
        messages.push("Play Gifs");
    }else{
        op_gifs.checked = settingsArray[6];
    }

    //Gif duration (Seconds)
    if( isNaN(settingsArray[7]) ){
        messages.push("Gif duration (Seconds)");
    }else{
        op_gif_duration.value = settingsArray[7];
    }

    //Play Images
    if(settingsArray[8] !== true && settingsArray[8] !== false){
        messages.push("Play Images");
    }else{
        op_imgs.checked = settingsArray[8];
    }

    //Image duration (Seconds)
    if( isNaN(settingsArray[9]) ){
        messages.push("Image duration (Seconds)");
    }else{
        op_img_duration.value = settingsArray[9];
    }
    
    //Open Stream4chan on startup
    if(settingsArray[10] !== true && settingsArray[10] !== false){
        messages.push("Open Stream4chan on startup");
    }

    //Override Individual Media
    if(settingsArray[11] !== true && settingsArray[11] !== false){
    	messages.push("Override Individual Media");
    }

    //Select Media randomly
    if(settingsArray[12] !== true && settingsArray[12] !== false){
    	messages.push("Select Media Randomly");
    }else{
    	op_random.checked = settingsArray[12];
    }
    
    return {
        valid: (messages.length <= 0),
        messages: messages
    };
}

//Toggles showing the modal
function showSFC(bool){

    function show(){
        document.body.style.overflow = "hidden";
        el_sfc.style.display = "block";
        setTimeout(function(){
            el_sfc.style.opacity = 1;
            magicMouse(true);
        }, 40);
        return true;
    }

    function hide(){
        showGallery(false);
        showSettings(false);
        currentContent.pause();
        el_sfc.style.opacity = 0;
        el_sfc.addEventListener("transitionend", function() {
            if(el_sfc.style.opacity == 0){
                el_sfc.style.display = "none";
                el_sfc.removeEventListener("transitionend", function(){}, false);
                document.body.style.overflow = "auto";
                showMouse(false);
            }
        }, false);

        return true;
    }

    if(bool === true){
        show();
    }else if (bool === false){
        hide();
    }else if (isShown(el_sfc)){
        show();
    }else{
        hide();
    }

    return false;
}

//Toggles showing the gallery
function showGallery(bool){
    

    function show(){

        //Sets internal gallery slider to appropriate width
        //'if' statements causes this to only fire once
        updateGallery();

        el_gallery.style.transform = "translateY(0px)";
        el_util.style.transform = "translateY(-" + el_gallery.clientHeight + "px)";

        return true;
    }

    function hide(){
        el_gallery.style.transform = "translateY(100%)";
        el_util.style.transform = "translateY(0)";
        return true;
    }

    if(bool === true){
        show();
    }else if(bool === false){
        hide();
    }else if(el_gallery.style.transform == "translateY(100%)"){
        show();
    }else{
        hide();
    }

    return false;
}

//Toggles showing the settings
function showSettings(bool){

    function show(){
        el_settings.style.display = "flex";
        return true;
    }

    function hide(){
        el_settings.style.display = "none";
        return true;
    }

    if(bool === true){
        show();
    }else if(bool === false){
        hide();
    }else if(el_settings.style.display == "none" || el_settings.style.display === ""){
        show();
    }else{
        hide();
    }

    return false;
}

//Parse through el_sfc, el_settings or el_gallery
//Return boolean indicating it's state
function isShown(el){
    if(el === el_sfc){
        return !(el_sfc.style.display == "none");
    }

    if(el === el_settings){
        return !(el_settings.style.display == "none" || el_settings.style.display === "");
    }

    if(el === el_gallery){
        return !(el_gallery.style.transform == "translateY(100%)");
    }
}

/////////////////////////////////////////
// # Media and Media Array Functions # //
/////////////////////////////////////////

function previous(){

    currentContent.previous();
}

function next(){

    currentContent.next();
}

//Updates usedContent array, populates gallery and re-adjusts width
function updateGallery(contentToUse){

    //Update contents of usedContent array
    var validParams = contentToUse !== null && contentToUse !== undefined;
    usedContent = validParams ? contentToUse : getUsedContent();

    //Recalculate the previous and next media
    currentContent.getNeighbours();

    //Change currentContent to closest valid content
    if(currentContent !== noneSelected && currentContent !== null){

        if(!canPlay(currentContent)){

            var newContent = null;
            var crntContentFound = false;

            //Find currentContent in allContent array and set newContent to next valid content
            for(var i = 0; i <= allContent.length; i++){

            	//Keep i within bounds if settingsArray[0] (loop whole thread)
            	i = settingsArray[0] ? i%allContent.length : i;

            	//Terminates loop if out of bounds
            	if( i === allContent.length)
            		break;

            	//If crntContent is reached again, nothing was found
            	if(crntContentFound && allContent[i] === currentContent)
            		break;

            	//If content matches, crntContent has been found
                if(allContent[i] === currentContent)
                    crntContentFound = true;

                //If playable content has been found after crntcontent, save to newContent
                if(crntContentFound && canPlay(allContent[i])){
                	newContent = allContent[i];
                	break;
                }
            }
            
            //If newContent is null, change to noneSelected
            newContent = newContent === null ? noneSelected : newContent;

            newContent.select();
        }
    }

    //Clear contents and width of internalSlider
    el_internalSlider.innerHTML = "";
    el_internalSlider.style.width = "-1px";

    //Add all thumbnails to internalSlider
    for(var i = 0; i < usedContent.length; i++){
        el_internalSlider.appendChild(usedContent[i].thumb);
        el_internalSlider.style.width = (el_internalSlider.clientWidth + (usedContent[i].thumb.clientWidth*1.2) ) + "px";
    }

    //Scroll seleceted media into gallery view again
    currentContent.slideGallery();

    updateCounter();
    //Trigger height calculations without changing gallery state
    // showGallery(isShown(el_gallery));
}

//Returns media type when given source
function mediaType(input){
	if(input === undefined){
		console.log('Error: mediaType input argument was undefined');
	}else if(input === null){
		console.log('Error: mediaType input argument was null');
	}else{
		var temp = input.toString();

	    temp = temp.substr(temp.lastIndexOf('.') + 1);

	    if(temp == webm) return webm;
	    if(temp == gif)   return gif;
	    if(temp == png)  return png;
	    if(temp == jpg)  return jpg;
	}

	//Last Resort    
    return null;
}

//Returns if current user settings permits the playing of parsed object
function canPlay(mediaObj){
    var objType = mediaObj.type;

    var canPlay = false;

    //Return 'checked' value of checkbox corresponding to the object type
    switch(objType){

    	case webm:
    		return op_webms.checked;
    	case gif:
    		return op_gifs.checked;
    	case png:
    	case jpg:
    		return op_imgs.checked;
    	case "SOT":
    	case "EOT":
    		return !op_loopAll.checked;
    		break;
    	default:
    		return false;
    }

    // return (objType == webm && op_webms.checked) || (objType == gif && op_gifs.checked) || ( (objType == png || objType == jpg) && op_imgs.checked ) || (objType == "SOT" && !op_loopAll.checked) || (objType == "EOT" && !op_loopAll.checked);
}

//Applies autoplay based on user settings
function updateAutoplay(){

    //Clear timeout to avoid timeout overlaps and
    //unwanted function calls
    clearTimeout(globalTimeout);

    if(currentContent.type == webm){

        //Loop media (incase auto is not turned on)
        currentContent.media.loop = true;

        //If it is turned on, set to false and await end of video
        if(op_auto.checked){
            currentContent.media.loop = false;
            currentContent.media.onended = next;
        }
    }else if(currentContent.type == gif){

        //If auto is checked apply according timeout
        if(op_auto.checked){
            globalTimeout = setTimeout(next, op_gif_duration.value*1000);
        }
    }else if(currentContent.type == png || currentContent.type == jpg){

        //If auto is checked apply according timeout
        if(op_auto.checked){
            globalTimeout = setTimeout(next, op_img_duration.value*1000);
        }
    }
}

//Returns array of ALL elemnts. Including SOT, EOT and noneSelected
//Also sets the onclick method for the thumbnail in the default thread
function getContent(){

    var temp = [];

    var elements = document.getElementsByClassName('fileThumb');

    //Pushes 'start of thread' placeholder
    temp.push(SOT);

    //Loops over all media elements in thread
    //and pushes them to temp array
    for(var i = 0; i < elements.length; i++){

        var vidSrc = elements[i].href;
        var imgSrc = elements[i].getElementsByTagName('img')[0].src;
        var id = elements[i].parentNode.parentNode.id;

        var x = new Media(imgSrc, vidSrc, id);

        function playThis(){
        	showSFC(true);
        	x.select();
        }

        temp.push(x);

        //Change clicking the video element to open SFC
        var href = elements[i].getElementsByTagName('img')[0].parentNode;
        href.setAttribute('oldHref', href.href);
        href.oldHref = href.href;
        href.setAttribute('imgSrc', imgSrc);
        href.imgSrc = imgSrc;
        href.href = imgSrc;
    	href.onclick = function(event){
    		inThreadClick(event);
    	};
    }

    //Pushes 'end of thread' placeholder
    temp.push(EOT);

    return temp;
}

//Returns all media permitted to play by user settings
function getUsedContent(){
    var temp = [];
    var count = 0;

    for(var i = 0; i < allContent.length; i++){
        if(canPlay(allContent[i])){
            temp.push(allContent[i]);
            temp[count].position = count;
            count++;
        }
    }
    return temp;
}

//Shuffles the usedContent array
function shuffle(){

	//Direction is shuffle/unshuffle
	var shuffled = op_shuffle.value === "Unshuffled";

	if(!shuffled){
		var newUsedContent = [];
		var max, min = 0;

		//Push a random index from the usedContent into a new array
		while(usedContent.length > 0){

			//Get random index
			max = usedContent.length - 1;
			var rand = Math.floor(Math.random() * (max - min + 1)) + min;

			//remove one from old and add to new
			newUsedContent.push(usedContent.splice(rand, 1)[0]);

			//Update positions
			newUsedContent[newUsedContent.length - 1].position = newUsedContent.length - 1;

		}
		
		//Overwrite the old and update gallery
		usedContent = newUsedContent;
		updateGallery(usedContent);

		op_shuffle.value = "Unshuffle";

	}else {
		updateGallery();
		op_shuffle.value = "Shuffle";
	}
}

function getRandom(exclude){

	//Array of media with lowest view count
	var lowestPlayCount = [];

	//Fill array with least viewed content
	for(var i = 0; i < usedContent.length; i++){

		//If placeholder media -> continue
		if(usedContent[i] === SOT || usedContent[i] === EOT || usedContent[i] === exclude){
			continue;
		}

		//If array is empty -> add current media
		if(lowestPlayCount.length === 0){
			lowestPlayCount.push(usedContent[i]);
			continue;
		}

		//If new lowest found -> erase and push
		if(usedContent[i].playcount < lowestPlayCount[0].playcount){
			lowestPlayCount = [];
			lowestPlayCount.push(usedContent[i]);
			continue;
		}

		//If matching view count -> push
		if(usedContent[i].playcount === lowestPlayCount[0].playcount){
			lowestPlayCount.push(usedContent[i]);
			continue;
		}
	}

	//Select random media from array
	var min = 0;
	var max = lowestPlayCount.length - 1;
	var rand = Math.floor(Math.random() * (max - min + 1)) + min;
    console.log("Random");
    console.log(lowestPlayCount);
    console.log("");
	return lowestPlayCount[rand];
}

function updateCounter(){
	el_counter_first.innerHTML = currentContent.position + 1;
	el_counter_second.innerHTML = usedContent.length;
}


///////////////////////
// # Miscellaneous # //
///////////////////////

//This function is called when a thumbnail in the thread is clicked
function inThreadClick(event, videoHref){
	if(event.target === null)
		return;

	if(settingsArray[11]){

    	var hrefContainer = event.target.parentNode;
    	var currentID = hrefContainer.parentNode.parentNode.id;

    	setTimeout( function(){
    		hrefContainer.parentNode.classList.remove("image-expanded");	
    	}, 0.0001);

    	for(var j = 0; j < allContent.length; j++){
    		if(allContent[j].id === currentID){
    			showSFC(true);
    			allContent[j].select();
    		}
    	}
        	
	}else{
		event.target.href = event.target.oldHref;
		event.target.click();
	}
}

function magicMouse(bool){

    var timer = setTimeout(function(){},0);

    var showMouse = function(){
        console.log("showing");
        el_magicMouse.style.display = "none";
    }

    var hideMouse = function(){
        console.log("hiding");
        el_magicMouse.style.display = "block";
        document.body.style.cursor = "auto";
    }

    var resetTimer = function(){
        console.log("resetting");

        showMouse();
        clearTimeout(timer);
        timer = setTimeout(hideMouse, 500);
    }

    if(bool === true){
        document.body.onmousemove = resetTimer;
    }else{
        document.body.onmousemove = null;
    }
}

function getPageTopLeft(el) {
    var rect = el.getBoundingClientRect();
    var docEl = document.documentElement;
    return {
        left: rect.left + (window.pageXOffset || docEl.scrollLeft || 0),
        top: rect.top + (window.pageYOffset || docEl.scrollTop || 0)    
    };
}

//Convert css style strings to integer values (top, right, bottom and left)
function getCSSValues(styleStr){

	var values = [];

	do{
		//Find match 
		var match = styleStr.match("\\d+[a-zA-Z]{2}");
		var foundString = match[0];

		//Remove all characters before and including the match
		styleStr = styleStr.substr( match.index + foundString.length, styleStr.length - 1);

		values.push(parseInt(foundString, 10));

	}while(styleStr.length > 3); //If below 3 than it's not a valid style value

	return values;
}