I have two windows; one is inside a frameset and the other is opened from the other in a new window (window.open(...)).
I am trying to move the left edge of the opened window to the right edge of the opener window.
Here are the requirements:
Must work in IE8.
Cannot modify the code in the opener window.
The opened window should be completely visible (See the X in the upper-right hand corner)
I was able to find a solution that gets the correct width and height (with the scroll bars) of a IE8 window. It involves moving the window and checking it's value, but when I run window.opener.moveTo() it moves the frame instead of the actual window and thus doesn't record the correct values.
Here is the code I am currently using:
function moveAway()
{
//Array Style
var main = getWindowSize(window.opener)
var child = getWindowSize(window)
//How to move
var topAvail = main.top;
var bottomAvail = window.opener.screen.availHeight - main.bottom;
var leftAvail = main.left;
var rightAvail = window.opener.screen.availWidth - main.right;
var choice = Math.max(topAvail,bottomAvail,leftAvail,rightAvail)
if(choice == rightAvail)
{
window.moveTo(main.right,main.top)
window.resizeTo(rightAvail,main.bottom)
}else if(choice == bottomAvail)
{
window.moveTo(main.left,main.bottom)
window.resizeTo(window.opener.document.body.clientWidth,bottomAvail-36)
} else if(choice == leftAvail)
{
window.moveTo(0,main.top)
window.resizeTo(leftAvail,main.bottom)
} else if(choice == topAvail)
{
window.moveTo(main.left,0)
window.resizeTo(main.right,topAvail)
}
//return "item\ttop\tleft\tbottom\tright\nmain\t" + main.join("\t") + "\nchild\t" + child.join("\t")
}
function getWindowSize(windowObj) {
var wW, wH;
var wT = windowObj.screenTop;
var wL = windowObj.screenLeft;
if (windowObj.outerWidth) {
wW = windowObj.outerWidth;
wH = windowObj.outerHeight;
} else {
var cW = windowObj.document.body.offsetWidth;
var cH = windowObj.document.body.offsetHeight;
windowObj.resizeTo(500,500);
var barsW = 500 - windowObj.document.body.offsetWidth;
var barsH = 500 - windowObj.document.body.offsetHeight;
wW = barsW + cW;
wH = barsH + cH;
windowObj.resizeTo(wW,wH);
}
return { right: wW, bottom: wH, top : wT, left : wL };
}
How do I get JavaScript to open a popup window on the current monitor deals with positioning popup windows and contains a lot of insight into getting screen and window coordinates and positioning windows
You must beware that many browsers will disallow funny behavior like
Off-screen windows
windows wider than a screen
windows that span multiple screens
With code from my answer on the question mentioned above, you can get started with the following
// Pops a window relative to the current window position
function popup(url, winName, xOffset, yOffset, width, height) {
width = width || 100;
height = height || 100;
var x = (window.screenX || window.screenLeft || 0) + (xOffset || 0);
var y = (window.screenY || window.screenTop || 0) + (yOffset || 0);
return window.open(url, winName, 'top=' +y+ ',left=' +x + ',width=' + width + ',height='+ height);
}
var size = getWindowSize(window);
var popupWin = popup("http://www.google.com", "popup", size.right - size.left);
I'm not addressing your concern that the popup window must all be on screen. That is because I don't know what you could possibly do if the main window is full screen.
Pop windows are passé, I know some people want to use it, but the browsers are really fighting against it (by imposing rules that came out of tabbed windows environments). You're swimming against the current here.
Last point, you shouldn't need to move your window, you can just specify top/left and width/height, instead of having a window that moves around after it has been displayed. See my popup function.
Here's a jsfiddle to get you started showing us your problem
Related
I am building a custom tooltip functionality where I am supposed to show a video as a tooltipo over an image. Now, I have some initial thing working, but I am stuck at finding the area around mouse pointer where I should display the tooltip.
I am having the tooltip always visible at the bottom right of mouse cursor, no matter where mouse currently is in screen, this is what I have so far :
window.onmousemove = function (e) {
var x = e.clientX, y = e.clientY;
tooltipSpan.style.top = (y + 10) + 'px';
tooltipSpan.style.left = (x + 10) + 'px';
};
where tooltip is my target element.
What I am looking for, is, that my code should find the largest area around mouse available on screen, and adjust the tooltip to display there. Any pointers for this would help a lot.
Note: jQuery is not an option, I have to build in core JS.
You can get the width and the dimensions of the viewport using window.innerWidth and window.innerHeight (in my example below this refers to window because the code is running inside window)
Using viewport dimensions and the mouse position using ev.clientX/Y you can determine the pixel space on the left/right and top/bottom side of the cursor as in example below.
Using property offsetWidth and offsetHeight we get the dimensions of the tooltip and we can use that to set the tooltip position relative to cursor position. For example if the topLeft quadrant is the largest, the tooltip will show top left relatively to cursor (meaning the bottom right corner of the tooltip will "touch" the cursor).
I hope this example helps :).
var tooltip = this.document.getElementsByClassName("tooltip")[0];
window.onmousemove = function(ev) {
// Getting pixel space
var leftPixelSpace = ev.clientX;
var rightPixelSpace = this.innerWidth - leftPixelSpace;
var topPixelSpace = ev.clientY;
var bottomPixelSpace = this.innerHeight - topPixelSpace;
// Determining the position of topleft corner of the tooltip
var tooltipPosX = leftPixelSpace > rightPixelSpace ? leftPixelSpace - tooltip.offsetWidth : leftPixelSpace;
var tooltipPosY = topPixelSpace > bottomPixelSpace ? topPixelSpace - tooltip.offsetHeight : topPixelSpace;
// Setting tooltip position
tooltip.style.left = tooltipPosX+"px";
tooltip.style.top = tooltipPosY+"px";
};
.tooltip {
width: 150px;
height: 100px;
border: 1px solid black;
background-color : lightblue;
text-align: center;
position: absolute
}
<div class="tooltip">floating tooltip</div>
Something like this? A switch with conditions for calculating in which quadrant the mouse cursor is.
var wM = window.innerWidth / 2;
var hM = window.innerHeight / 2;
document.addEventListener('mousemove', function(e) {
var w = e.clientX;
var h = e.clientY;
var pos;
switch (true) {
case (w <= wM && h <= hM):
pos = 'top-left';
break;
case (w <= wM && h >= hM):
pos = 'bottom-left';
break;
case (w > wM && h < hM):
pos = 'top-right';
break;
case (w > wM && h > hM):
pos = 'bottom-right';
break;
default:
pos = undefined;//Here you could even assign a default quadrant to relay on, in case any condition is met.
}
console.log(pos);
});
wM for widthMiddle, the middle point in the window's width.
hM: same, but with the height.
w for the mouse width/X position; h for height/Y.
A switch based on conditions according to a quadrant system.
In my vaadin application, user can save a user workspace with multiple browser popup windows and restore the workspace later.
I save the browser window size returned by following vaadin methods.
Page.getBrowserWindowHeight();
Page.getBrowserWindowWidth();
Vaadin returns the content width and height of the browser in above methods, not including title bar and other controls in the top such as the address bar and toolbar.
When restoring a workspace, I use resizeTo() javascript method to set the size of the browser windows.
JavaScript.getCurrent().execute("resizeTo(" + windowWidth + "," + windowHeight + ")");
resizeTo() sets the total width and height of the browser window, not the content area. Due to this, the browser window becomes smaller than the intended size.
Does anyone know of a better method to achieve this?
The methods you are using
Page.getBrowserWindowHeight();
Page.getBrowserWindowWidth();
use the following JavaScript to determine the 'UI' dimensions
// Window height and width
var cw = 0;
var ch = 0;
if (typeof(window.innerWidth) == 'number') {
// Modern browsers
cw = window.innerWidth;
ch = window.innerHeight;
} else {
// IE 8
cw = document.documentElement.clientWidth;
ch = document.documentElement.clientHeight;
}
To do this using resizeTo() (although I think you may run in to some browser compatibility issues) you need to take into account a few other thing:
function doResize(width, height){
// Window height and width
var cw = 0;
var ch = 0;
if(typeof(window.innerWidth) == 'number') {
// Modern browsers
cw = width + (window.outerWidth - window.innerWidth);
ch = height + (window.outerHeight - window.innerHeight);
} else {
// IE 8
cw = width + (document.documentElement.offsetWidth-document.body.offsetWidth);
ch = height + (document.documentElement.offsetHeight-document.body.offsetHeight);
}
window.resizeTo(cw, ch);
}
Another option would be to create a hidden component with RPC to do your own JS browser size calculations.
I want to reset a particular element once the browser window has been resized from any size less than 641px, to a greater size. Here is an example of what I am trying to achieve, written in pseudo code:
if (browser.window <= 641px && browser.window.resizedTo > 641px) {
$( ".foo" ).removeClass( "bar" )
}
Thank you!
I'll assume for the sake of this question that you mean 641px as the width, but I left the innerHeight variable there, too, in case you need it:
// Closure last-height/width
var lastX = window.innerWidth
var lastY = window.innerHeight
function fooOnResize() {
var x = window.innerWidth
var y = window.innerHeight
if (lastX <= 641 && 641 < x) {
$(".foo").removeClass("bar")
}
lastX = x
lastY = y
}
window.addEventListener("resize", fooOnResize)
// Also okay: window.onresize = fooOnResize
The trick is to basically hold the last size in some closure variables, then on resize, you can make your comparison. After you have done the comparison and the work, you store the current x/y as the last ones, for the next resize.
Try the window.onresize event:
https://developer.mozilla.org/en-US/docs/Web/API/GlobalEventHandlers/onresize
You can get the current dimensions of the browser window using window.innerHeight and window.innerWidth:
window.onresize = function() {
console.log('height: ' + window.innerHeight);
console.log('width: ' + window.innerWidth);
}
StackOverflow is loaded with questions about how to check if an element is really visible in the viewport, but they all seek for a boolean answer. I'm interested in getting the element's actual areas that are visible.
function getVisibleAreas(e) {
...
return rectangleSet;
}
Putting it more formally - the visible areas of elements is the set of (preferably non-overlapping) rectangles in CSS coordinates for which elementFromPoint(x, y) will return the element if the point (x, y) is contained in (at least) one of the rectangles in the set.
The outcome of calling this function on all DOM elements (including iframes) should be a set of non-overlapping area sets which union is the entire viewport area.
My goal is to create some kind of a viewport "dump" data structure, which can efficiently return a single element for a given point in the viewport, and vice versa - for a given element in the dump, it will return the set of visible areas.
(The data structure will be passed to a remote client application, so I will not necessarily have access to the actual document when I need to query the viewport structure).
Implementation requirements:
Obviously, the implementation should consider element's hidden state, z-index, header & footer etc.
I am looking for an implementation that works in all common used browsers, especially mobile - Android's Chrome and iOS's Safari.
Preferably doesn't use external libraries.
Of course, I could be naïve and call elementFromPoint for every discrete point in the viewport, But performance is crucial since I iterate over all of the elements, and will do it quite often.
Please direct me as to how I can achieve this goal.
Disclaimer: I'm pretty noob to web programming concepts, so I might have used wrong technical terms.
Progress:
I came up with an implementation. The algorithm is pretty simple:
Iterate over all elements, and add their vertical / horizontal lines to a coordinates map (if the coordinate is within the viewport).
Call `document.elementFromPoint` for each "rectangle" center position. A rectangle is an area between two consecutive vertical and two consecutive horizontal coordinates in the map from step 1.
This produces a set of areas / rectangles, each pointing to a single element.
The problems with my implementation are:
It is inefficient for complicated pages (can take up to 2-4 minutes for a really big screen and gmail inbox).
It produces a large amount of rectangles per a single element, which makes it inefficient to stringify and send over a network, and also inconvenient to work with (I would want to end up with a set with as few rectangles as possible per element).
As much as I can tell, the elementFromPoint call is the one that takes a lot of time and causes my algorithm to be relatively useless...
Can anyone suggest a better approach?
Here is my implementation:
function AreaPortion(l, t, r, b, currentDoc) {
if (!currentDoc) currentDoc = document;
this._x = l;
this._y = t;
this._r = r;
this._b = b;
this._w = r - l;
this._h = b - t;
center = this.getCenter();
this._elem = currentDoc.elementFromPoint(center[0], center[1]);
}
AreaPortion.prototype = {
getName: function() {
return "[x:" + this._x + ",y:" + this._y + ",w:" + this._w + ",h:" + this._h + "]";
},
getCenter: function() {
return [this._x + (this._w / 2), this._y + (this._h / 2)];
}
}
function getViewport() {
var viewPortWidth;
var viewPortHeight;
// IE6 in standards compliant mode (i.e. with a valid doctype as the first line in the document)
if (
typeof document.documentElement != 'undefined' &&
typeof document.documentElement.clientWidth != 'undefined' &&
document.documentElement.clientWidth != 0) {
viewPortWidth = document.documentElement.clientWidth,
viewPortHeight = document.documentElement.clientHeight
}
// the more standards compliant browsers (mozilla/netscape/opera/IE7) use window.innerWidth and window.innerHeight
else if (typeof window.innerWidth != 'undefined') {
viewPortWidth = window.innerWidth,
viewPortHeight = window.innerHeight
}
// older versions of IE
else {
viewPortWidth = document.getElementsByTagName('body')[0].clientWidth,
viewPortHeight = document.getElementsByTagName('body')[0].clientHeight
}
return [viewPortWidth, viewPortHeight];
}
function getLines() {
var onScreen = [];
var viewPort = getViewport();
// TODO: header & footer
var all = document.getElementsByTagName("*");
var vert = {};
var horz = {};
vert["0"] = 0;
vert["" + viewPort[1]] = viewPort[1];
horz["0"] = 0;
horz["" + viewPort[0]] = viewPort[0];
for (i = 0 ; i < all.length ; i++) {
var e = all[i];
// TODO: Get all client rectangles
var rect = e.getBoundingClientRect();
if (rect.width < 1 && rect.height < 1) continue;
var left = Math.floor(rect.left);
var top = Math.floor(rect.top);
var right = Math.floor(rect.right);
var bottom = Math.floor(rect.bottom);
if (top > 0 && top < viewPort[1]) {
vert["" + top] = top;
}
if (bottom > 0 && bottom < viewPort[1]) {
vert["" + bottom] = bottom;
}
if (right > 0 && right < viewPort[0]) {
horz["" + right] = right;
}
if (left > 0 && left < viewPort[0]) {
horz["" + left] = left;
}
}
hCoords = [];
vCoords = [];
//TODO:
for (var v in vert) {
vCoords.push(vert[v]);
}
for (var h in horz) {
hCoords.push(horz[h]);
}
return [hCoords, vCoords];
}
function getAreaPortions() {
var portions = {}
var lines = getLines();
var hCoords = lines[0];
var vCoords = lines[1];
for (i = 1 ; i < hCoords.length ; i++) {
for (j = 1 ; j < vCoords.length ; j++) {
var portion = new AreaPortion(hCoords[i - 1], vCoords[j - 1], hCoords[i], vCoords[j]);
portions[portion.getName()] = portion;
}
}
return portions;
}
Try
var res = [];
$("body *").each(function (i, el) {
if ((el.getBoundingClientRect().bottom <= window.innerHeight
|| el.getBoundingClientRect().top <= window.innerHeight)
&& el.getBoundingClientRect().right <= window.innerWidth) {
res.push([el.tagName.toLowerCase(), el.getBoundingClientRect()]);
};
});
jsfiddle http://jsfiddle.net/guest271314/ueum30g5/
See Element.getBoundingClientRect()
$.each(new Array(180), function () {
$("body").append(
$("<img>"))
});
$.each(new Array(180), function () {
$("body").append(
$("<img>"))
});
var res = [];
$("body *").each(function (i, el) {
if ((el.getBoundingClientRect().bottom <= window.innerHeight || el.getBoundingClientRect().top <= window.innerHeight)
&& el.getBoundingClientRect().right <= window.innerWidth) {
res.push(
[el.tagName.toLowerCase(),
el.getBoundingClientRect()]);
$(el).css(
"outline", "0.15em solid red");
$("body").append(JSON.stringify(res, null, 4));
console.log(res)
};
});
body {
width : 1000px;
height : 1000px;
}
img {
width : 50px;
height : 50px;
background : navy;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
I don't know if the performance will be sufficient (especially on a mobile device), and the result is not quite a rectangle-set as you requested, but did you consider using a bitmap to store the result?
Note some elements may have 3d css transform (eg. skew, rotate), some elements may have border radius, and some elements may have invisible background - if you want to include these features as well for your "element from pixel" function then a rectangle set can't help you - but the bitmap can accommodate all of the visual features.
The solution to generate the bitmap is rather simple (I imagine... not tested):
Create a Canvas the size of the visible screen.
iterate over all the elements recursively, sorted by z-order, ignore hidden
for each element draw a rectangle in the canvas, the color of the of the rectangle is an identifier of the element (eg. could be incremental counter). If you want you can modify the rectangle based on the visual features of the element (skew, rotate, border radius, etc...)
save the canvas as lossless format, eg png not jpg
send the bitmap as the meta data of elements on screen
To query which element is at point (x,y) you could check the color of the bitmap at pixel (x,y) and the color will tell you what is the element.
If you can jettison IE, here's a simple one:
function getElementVisibleRect(el) {
return new Promise((resolve, reject) => {
el.style.overflow = "hidden";
requestAnimationFrame((timeStamp) => {
var br = el.getBoundingClientRect();
el.style.overflow = "";
resolve(br);
});
});
}
Even then, Promises are easily polyfillable and requestAnimationFrame() works as far back as IE 8. And by 2016, the only thing you should bother to give any poor souls on older IE is a legible experience.
I need to have a bottom bg at the bottom of the page all the time, so I came up with a decision to get window height and main content height and calculate if the bottom part should be pushed down or not. The problem came up when the content block was too short and the computer screen was much bigger, so the bottom bg was right at the end of the the content and had nothing after till the end of the bottom screen. Hopefully it makes sense ) I decided to add some height inside of the content to make it longer so it fills up the bottom space and very bottom gap disappear.
Here is the JavaScript I used to fix it:
window.onload=function(){
var winHeight = window.innerHeight;
var fixIt = winHeight - 200;
var divHeight = document.getElementById('bottomDiv').clientHeight;
alert(winHeight - divHeight);
if (divHeight < winHeight) {
var fire = document.getElementById('innerDiv').style.height = fixIt + "px";
}
};
Problem: this script works fine and does its job well in all browsers but not IE7-IE8. Can you please help to get a solution for old IE browsers?
Thanks,
Art
window.onload=function(){
// v---------------------------------------v
var winHeight = window.innerHeight || document.documentElement.clientHeight;
var fixIt = winHeight - 200;
var divHeight = document.getElementById('bottomDiv').clientHeight;
alert(winHeight - divHeight);
if (divHeight < winHeight) {
var fire = document.getElementById('innerDiv').style.height = fixIt + "px";
}
};
Maybe instead you could apply your "bottom" background to the html element, then cover it up with a different background (possibly in your div#content) in the upper region.
Otherwise, it seems innerHeight isn't supported in IE8.
window.innerHeight ie8 alternative
Try
var winHeight = document.documentElement.clientHeight