Discussions » Development

Help positioning an element according to the cursor position?

§
Posted: 23 November 2016

Help positioning an element according to the cursor position?

I've been using an extension called Youhover which is pretty cool. It embeds Youtube videos in a floating div when links are hovered. The problem is the positioning. My res is 1366x768, so the viewport height isn't much more than 600px. The positioning of the div is always to the right of the mouse and above or below depending on the vertical mouse position. Neither is good. On really long links (hovered toward the right), it sometimes appears off the right edge of the page, and since the viewport height isn't 2x+ the div height, links hovered vertically in the middle cause the div to appear off the bottom edge of the screen. I'd like to fix the positioning and sideload the extension if possible. Since the viewport width is 2x+ the width of the div, it'd work better if it was always vertically centered and switched left or right opposite the mouse position. Its position is already set to absolute and I believe the code that needs to be altered is this:

function setPlayerToMouse(){
    var playerHeight = $("#ytplayer").height();
    var textHeight = $("#ytplayeroverlay").height();
    var space = 20 + textHeight;
    var topLength;
    if((playerHeight+space) > (event.pageY - $(window).scrollTop())){
        topLength = event.pageY+space;
    }else{
        topLength = event.pageY-playerHeight-space;
    }
    $("#ytdiv").css({top: topLength, left: event.pageX});
    $("#ytplayeroverlay").css({top: topLength-textHeight, left: event.pageX});
}

Unfortunately, I don't have a clue how to fix it. Any help would be appreciated. TIA

§
Posted: 24 November 2016
Edited: 24 November 2016

Sometime I wrote code on this subject. Look, maybe you'll find something useful.

function belowCursor(evt,ho,vo,lr){
  var p={t:'', l:'auto', r:'auto'};
  p.t=(evt.clientY+window.pageYOffset+vo)+'px';
  var l=(evt.clientX+window.pageXOffset+ho)+'px';
  if(lr && lr=='r')
  { p.l=l; return  p; }
  var w = window.innerWidth;
  var r=(w-(evt.clientX+window.pageXOffset)+ho);
// Q: How to detect visibility & thickess of vertical scrollbar?
  r-=8; // 
  if(r<0) r= w/4;
  r+='px';
  if(lr && lr=='l')
  { p.r=r; return  p; }
  if(evt.clientX < w/2)
   p.l=l;
  else
   p.r=r;
  return p;
}
...
// code inside event handler 
  p = belowCursor(evt,10,10);
    divLookup = buildEl('div', {id:'divLookup', style: 'z-index:100000'+
   ';border: none;' +
   ';top:'  + p.t  +';left:' + p.l  +';right:' + p.r  +';bottom: auto'
  }, null, null);
§
Posted: 24 November 2016
Edited: 05 Mei 2017

--- ? :wink:

§
Posted: 24 November 2016

Look, maybe you'll find something useful.

Thanks for the response trespassersW. Unfortunately, I wouldn't know something useful if I was looking at it. Short of copying and replacing, I don't have a clue how to go about it.

I figured a few values changed in that function would suffice, but what do I know. Here's the whole code if it's more enlightening:

var hoverDebugging = true;

function hoverDebugLog(inputTitle, inputString){
	if(hoverDebugging){
		console.log("Hover Debug Begin: " + inputTitle);
		console.log(inputString);
		console.log("Hover Debug End");
	}
}

function hoverYoutube(){
	hoverDebugLog("","Begin Loading");
	
	//youtube config

	var tag = document.createElement('script');
        //changed tag.src to avoid embed
	tag.src = "https:///www.youtube.com/player_api";
	var firstScriptTag = document.getElementsByTagName('script')[0];
	firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
	var player;

	//rest of code
	
	var showingPlayer = false;
	var hoveringOverYoutubeLink = false;
	var hoveringOverYoutubePlayer= false;
	var hoveringUrl = "";
	var keysDown = {};
	var forceOpenKey = 17; //ctrl key
	var toggleOpenKey = 16; //shift key
	

	function parseYoutubeUrl(inputUrl){
		var regExp = /^.*((youtu.be\/)|(v\/)|(\/u\/\w\/)|(embed\/)|(watch\?))\??v?=?([^#\&\?]*).*/;
		var match = inputUrl.match(regExp);
		if ( match && match[7].length == 11 ){
			return match[7];
		}else{
			return "";
		}
		//https://ctrlq.org/code/19797-regex-youtube-id Amit Agarwal
	}

	function getYoutubeParameters(inputUrl){
		var params = inputUrl.substring(1).split('&');
		var paramsDict = {};
		$.each(params,function(index,value){
			var keyPairArr = value.split('=');
			var seconds = 0;
			if(keyPairArr[0]=="t"){
				if(keyPairArr[1].indexOf("m") != -1){
					seconds += keyPairArr[1].split("m")[0]*60;
					if(keyPairArr[1].indexOf("s") != -1){
						seconds += keyPairArr[1].split("m")[1].split("s")[0]*1;
					}
				}else if(keyPairArr[1].indexOf("s") != -1){
					seconds += keyPairArr[1].split("s")[0]*1;
				}else{
					seconds += keyPairArr[1]*1;
				}
				paramsDict["start"] = seconds;
			}		
		});
		delete paramsDict["v"];
		return paramsDict;
	}

	function isYoutubeUrl(inputTarget){
		return inputTarget.hostname.indexOf('youtube.com') != -1 || inputTarget.hostname.indexOf('youtu.be') != -1;
	}
	
	function isKeyDown(toggleButton, optionalEvent){
		if((typeof optionalEvent) === "undefined"){
			return toggleButton ? (keysDown[toggleOpenKey]||false) : (keysDown[forceOpenKey]||false);
		}else{
			return toggleButton ? optionalEvent.shiftKey : optionalEvent.ctrlKey;
		}
		
	}

	function removePlayer(){
		$("#ytdiv").remove();
		$("#ytplayeroverlay").remove();
		showingPlayer = false;
	}

	function onYouTubePlayerAPIReady(videoID, params) {
		currentPlayerVars = { 'autoplay': 1, 'origin': location.href};
		params = $.extend({}, params, currentPlayerVars);
		player = new YT.Player('ytplayer', {
		  height: '390',
		  width: '640',
		  videoId: videoID,
		  playerVars: params
		});
	  }
	  
	  function setStatus(){
		  //!isKeyDown(false, event) && !isKeyDown(true)
		  if(isKeyDown(true)){
			  $("#ytplayeroverlay").text("Player Status: Locked (toggle)");
		  }else if(isKeyDown(false)){
			  $("#ytplayeroverlay").text("Player Status: Locked (non-toggle)");
		  }else{
			  $("#ytplayeroverlay").text("Player Status: Normal");
		  }
	  }
	  
	function setPlayerToMouse(){
		var playerHeight = $("#ytplayer").height();
		var textHeight = $("#ytplayeroverlay").height();
		var space = 20 + textHeight;
		var topLength;
		if((playerHeight+space) > (event.pageY - $(window).scrollTop())){
			topLength = event.pageY+space;
		}else{
			topLength = event.pageY-playerHeight-space;
		}
		$("#ytdiv").css({top: topLength, left: event.pageX});
		$("#ytplayeroverlay").css({top: topLength-textHeight, left: event.pageX});
	}

	$(document)
	.on("mouseenter","a",
			function(event){
				var isYoutube = isYoutubeUrl(event.currentTarget);
				var extractedID = "";
				if(isYoutube){
					extractedID = parseYoutubeUrl(this.href);
					if(extractedID!=""){
						hoveringOverYoutubeLink = true;
						currentHoverUrl = event.currentTarget.href;
					}else{
						return;
					}
				}
				var urlChanged = false;
				if(currentHoverUrl!='' && currentHoverUrl!=hoveringUrl){
					urlChanged = true;
					removePlayer();
				}
				hoveringUrl = currentHoverUrl;
				if(showingPlayer && !urlChanged){
					return;
				}
				if(extractedID != ""){
					var ytplayer = $('
').attr("id", "ytplayer"); var ytdiv = $('
').attr("id", "ytdiv").addClass("ytdiv").append(ytplayer); $(document.body).prepend(ytdiv); var ytplayeroverlay = $('
').attr("id", "ytplayeroverlay").addClass("ytplayeroverlay"); $(document.body).prepend(ytplayeroverlay); setStatus(); var params = getYoutubeParameters(event.currentTarget.search); onYouTubePlayerAPIReady(extractedID, params); showingPlayer = true; setPlayerToMouse(); } } ) .on("mouseleave","a", function(event){ if(hoveringOverYoutubeLink){ hoveringOverYoutubeLink = false; } if(isKeyDown(false) || isKeyDown(true)){ return; } if(showingPlayer){ removePlayer(); } } ) ; $(document) .on("mouseenter","#ytdiv", function(event){ hoveringOverYoutubeLink = false; hoveringOverYoutubePlayer = true; } ) .on("mouseleave","#ytdiv", function(event){ hoveringOverYoutubePlayer = false; if(!hoveringOverYoutubeLink && !isKeyDown(false, event) && !isKeyDown(true)){ removePlayer(); } } ) ; $(document).keydown(function (event) { if(event.which == forceOpenKey){ keysDown[forceOpenKey] = true; }else if(event.which == toggleOpenKey){ if(isKeyDown(false)){ keysDown[toggleOpenKey] = !(keysDown[toggleOpenKey] || false); } } setStatus(); }); $(document).keyup(function (event) { if(event.which == forceOpenKey){ keysDown[forceOpenKey] = false; } if(showingPlayer && !hoveringOverYoutubeLink && !isKeyDown(true)){ removePlayer(); } setStatus(); }); $(window).mousemove(function(event){ $(window).focus(); if(showingPlayer && !isKeyDown(false) && !isKeyDown(true)){ setPlayerToMouse(); } }); } if((typeof $) !== "undefined"){ hoverYoutube(); }else{ hoverDebugLog("","jQuery is undefined"); }
§
Posted: 03 Desember 2016
Edited: 08 Desember 2016

Maybe this does what you want:

function setPlayerToMouse(){
	var topLength = $(window).height()/2+$(window).scrollTop()-$("#ytplayer").height()/2+"px";
	var leftLength;
	if (event.pageX() > $(window).width()/2) {
		leftLength = "10px";
	} else {
		leftLength = $(window).width()-$("#ytplayer").width()-10+"px";
	}
	$("#ytdiv").css({top: topLength, left: leftLength});
	$("#ytplayeroverlay").css({top: topLength-$("#ytplayeroverlay").height(), left: leftLength}); // I really don't know what this does
}
§
Posted: 03 Desember 2016

Thanks for the response Tom. Unfortunately, I couldn't get it working. When the positioning gets broken altogether, the div appears in the upper left of the header (no matter how far you've scrolled), which is what happened when I switched the function code.

I'll attach the .crx if you, or anyone else is inclined to unzip it and sideload it. The file that needs to be altered is named "hover".

§
Posted: 04 Desember 2016
Edited: 08 Desember 2016

I just fixed a little mistake I made, try this one?

function setPlayerToMouse(){
	var topLength = $(window).height()/2+$(window).scrollTop()-$("#ytplayer").height()/2;
	var leftLength;
	if (event.pageX() > $(window).width()/2) {
		leftLength = "10px";
	} else {
		leftLength = $(window).width()-$("#ytplayer").width()-10+"px";
	}
	$("#ytdiv").css({top: topLength+"px", left: leftLength});
	$("#ytplayeroverlay").css({top: topLength-$("#ytplayeroverlay").height()+"px", left: leftLength}); // I really don't know what this does
}
§
Posted: 04 Desember 2016
Edited: 04 Desember 2016

No joy. Again, I appreciate the effort though. Positioning was broken in the same manner, stuck in the upper left header. You can unzip the .crx and sideload it as an "unpacked extension" to check any alterations. It's pretty simple, although you might have to remove the underscore that gets inadvertently added to the metadata folder when it's unzipped.

§
Posted: 04 Desember 2016

I loaded the extension, fixed a completely unrelated error, and fixed another minor mistake I made. It now works for me as expected. Please replace the Hover.js script with this one:

§
Posted: 04 Desember 2016

image

Works like a charm. Really appreciate it, thanks Tom.

§
Posted: 04 Desember 2016

Interesting...
ps
An equivalent extension of "YouHover for Chrome" for firefox ?

§
Posted: 05 Desember 2016
Edited: 05 Desember 2016

@decembre I don't think so. From the description, it seems like a personal utility someone quickly wrote for himself to work in Chrome.

@Tom%20Burris2 This script is most useful for Reddit and a couple other sites, but there's now a bug on Reddit. Now, when the extension is enabled, the expando buttons don't work at all. Not just the Youtube ones, which wouldn't really matter, but the text and image expandos are both broken as well. If there's any way to rectify that, it'd be helpful.

Edit: How tf do you "mention" someone with a space in their username? The built in method with quotes doesn't seem to work. Nothing else did either. I finally copied it from the url, but I don't know if it works. Even if it does, that's pretty terrible.

§
Posted: 05 Desember 2016
Edited: 05 Desember 2016

lmao I'll check it out right now. Could you clarify what buttons you're talking about? Maybe with screenshots? I have no clue what "expando" buttons are..

§
Posted: 05 Desember 2016
Edited: 05 Desember 2016

Okay I squished the last bug, working demo here: https://jsfiddle.net/w5vgsyep/6/

@anagrammar Oh, you'll probably want to style it how you want, maybe like underline the word when you hover over it? If you need help just ask. :)

If you were curious what the last bug was, it is that when you remove a child node, it's .nextSibling property is set to null, but that's to be expected. The weird part is, the .nextSibling property of a deleted node is always null. So even if you explicitly set that property to something, it goes back to null. Pretty annoying. :/


Um, woops... this is the wrong thread.. sorry.

§
Posted: 05 Desember 2016
Edited: 05 Desember 2016

Of course. Expando buttons:

image

Do you know which "mention" works with your username? The ridiculous method I used can't be right.

§
Posted: 05 Desember 2016

It's not just those buttons either. It seems to be interfering with a lot of javascript buttons. To be clear, it isn't anything you changed. I went back and tried the version from the WebStore, and has the same issue. Damn. With the new positioning it was pretty sweet. Maybe it's not only the positioning that wasn't written well.

§
Posted: 05 Desember 2016
Edited: 05 Desember 2016

I tried fixing it but couldn't figure out why the error is happening or how to fix it. :/
I think it would be better to ask the original programmer.

Also, you don't need to "mention" me, greasyfork takes care of it.

Edit: Holy cow you have a lot of extensions and favorited tabs! 0.0

§
Posted: 06 Desember 2016

I figured that'd probably be the case. You fixed what I asked for anyway. It wasn't till I started keeping it enabled all the time that I noticed the other bug. The original dev hasn't updated or responded at all since he published it, so that's probably a dead end. It's a shame, because it's a pretty convenient utility.

If anyone can fix it or get something like it working, please let me know. Thanks again for taking a look Tom.

§
Posted: 09 Desember 2016
Edited: 09 Desember 2016

I was just playing around with this trying to see if I could work out what was causing the bug. Knowing next to nothing, I figured maybe I'd try updating the jQuery file and the manifest file pointing to it. To my surprise, the bug with Reddit buttons was gone.

Being skeptical, I went back and installed the WebStore version, and that one worked fine on Reddit as well. So I didn't fix it, but the bug is gone. Chromium hasn't updated (that I remember), and I tested before with/without RES, so that wasn't a factor.

Am I going crazy? Didn't you test and see the same bug a few days ago?

For the time-being I'm just glad it's working. I encountered another button it was screwing with previously, but I don't remember where, so I can't test it.

Either way, I find it incredibly odd. Broken things don't usually start working for no reason. I'm curious to know if the bug is fixed for you now too.

Now that it's working right (hopefully), I had another question about the "include". I'm occasionally coming across links that're missed. They use "attribution links" like:

(https)://www.youtube.com/attribution_link?
a=GliSdkJSioI&u=%2Fwatch%3Fv%3D5_YUw7KxrZk%26feature%3Dshare

for example:

https://www.reddit.com/r/videos/comments/5h8ou3/my_house_was_broken_into_yesterday_my_cameras/

I'm assuming the regex in the hover.js doesn't account for them, but haven't had any luck trying to alter it.

§
Posted: 09 Desember 2016

Hm. Weird. The bug with the expando buttons is still happening for me, I looked into getting the script to work with attribution links, but couldn't make it work. :/ sorry.

§
Posted: 09 Desember 2016
Edited: 09 Desember 2016

Alright. I was in a rush when I was checking it earlier, but going back and testing in a clean profile, I believe it was updating the jQuery file that fixed it. I guess not 100% of the buttons were broken, so when I tested the WebStore version for comparison, I must've hit a couple that worked. Testing again, a couple worked, most failed.

Shame about the links it's missing, but they're few and far between.

Does this version work for you also?

§
Posted: 10 Desember 2016

Yea it works.

§
Posted: 10 Desember 2016

Appreciate you confirming. Updating the jQuery file was just a shot in the dark, basically because it was the only thing I was capable of troubleshooting. Can't believe it worked. With the positioning fixed, I'm really enjoying it. Thanks again.

§
Posted: 19 Maret 2017

@decembre The version discussed here had too many bugs to be modified adequately, but a dev I'm friendly with was nice enough to rewrite one from scratch. He made extensions for all major browsers, including Firefox. It works great and has a ton of options for customizing behavior and positioning. Figured I'd let you know:

http://add0n.com/youtube-hover.html

Post reply

Sign in to post a reply.