Absolute positioning breaks in IE8 - javascript

I am working on developing an asp.net control that I need to be able to drop into other applications. The control is basically a custom dropdown in which a div gets displayed or hidden when another element is clicked.
The problem I am having is in trying to get the dynamic div to align below the element that gets clicked. I wrote a javascript function which should, in theory, allow me to specify two elements and the desired alignment and then move the second element to the correct position in relation to the first element.
I have three test cases which relate to places where I currently expect this control will be used, my current markup and javascript work in all three cases for IE7 but fails for one of the cases in FF3.5 and IE8-standards mode. I have been playing with this for a while and have yet to come up with an answer that fixes the problem case without breaking one of the others. (Note that 90+% of my users are on IE7 with a slow migration towards IE8)
I am looking for any suggestions other than adding a compatibility mode directive to the page, that does fix things in IE8 but I would prefer an alternative if one is possible since I may not always have control over where this is used. Here is an HTML doc which illustrates the relevant markup and javascript along with the test cases. Case three is the one which has problems, instead of aligning neatly under the input element the div is overlapping vertically and offset to the right by a distance equivalent to the width of the select element.
(Note that the real pages utilize a reset style sheet adapted from the one published by Eric Meyer, including/omitting this style sheet has no relevant effect on these test cases.)
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head>
<title></title>
</head>
<body>
<script type="text/javascript">
var VAlign = { "top": -1, "center": 0, "bottom": 1 };
var HAlign = { "left": -1, "center": 0, "right": 1 };
function AlignElements(element1, vAlign1, hAlign1, element2, vAlign2, hAlign2) {
var List1 = BuildOffsetList(element1);
var List2 = BuildOffsetList(element2);
var Index1 = List1.length - 1;
var Index2 = List2.length - 1;
while (Index1 >= 0 && Index2 >= 0 && List1[Index1] == List2[Index2]) {
Index1--;
Index2--;
}
element2.style.top = "";
element2.style.left = "";
var OT1 = 0;
var OL1 = 0;
var OT2 = 0;
var OL2 = 0;
while (Index1 >= 0) {
OT1 += List1[Index1].offsetTop;
OL1 += List1[Index1].offsetLeft;
Index1--;
}
while (Index2 >= 0) {
OT2 += List2[Index2].offsetTop;
OL2 += List2[Index2].offsetLeft;
Index2--;
}
var top = (OT1 - OT2);
if (vAlign1 == VAlign.bottom) {
top += element1.offsetHeight;
} else if (vAlign1 == VAlign.center) {
top += (element1.offsetHeight / 2);
}
if (vAlign2 == VAlign.bottom) {
top -= element2.offsetHeight;
} else if (vAlign2 == VAlign.center) {
top -= (element2.offsetHeight / 2);
}
var left = (OL1 - OL2);
if (hAlign1 == HAlign.right) {
left += element1.offsetWidth;
} else if (hAlign1 == HAlign.center) {
left += (element1.offsetWidth / 2);
}
if (hAlign2 == HAlign.right) {
left -= element2.offsetWidth;
} else if (hAlign2 == HAlign.center) {
left -= (element2.offsetWidth / 2);
}
element2.style.top = top + "px";
element2.style.left = left + "px";
}
function BuildOffsetList(elelment) {
var I = 0;
var List = new Array();
var Element = elelment;
while (Element) {
List[I] = Element;
Element = Element.offsetParent;
I++;
}
return List;
}
</script>
Case 1
<div>
<div id="control1" style=" display:inline; position:relative;">
<div id="control1_div1" style="background-color:Blue; height:75px; width:150px; position:absolute;"></div>
<input id="control1_txt1" type="text" style="width:150px;" />
<script type="text/javascript">
AlignElements(document.getElementById("control1_txt1"), VAlign.bottom, HAlign.left, document.getElementById("control1_div1"), VAlign.top, HAlign.left);
</script>
</div>
</div>
<div style="height:100px;"></div>
Case 2
<div>
<div id="Nav" style="float:left; width:200px; height:150px; background-color:Aqua;"></div>
<div id="Content" style="margin-left:200px; height:150px; background-color:#ddd;">
<div style="margin-left:100px;">
<h5 style="float:left; margin-left:-100px; width:90px; margin-right:10px; text-align:right; font-weight:.9em;">Label</h5>
<div id="control2" style=" display:inline; position:relative;">
<div id="control2_div1" style="background-color:Blue; height:75px; width:150px; position:absolute;"></div>
<input id="control2_txt1" type="text" style="width:150px;" />
<script type="text/javascript">
AlignElements(document.getElementById("control2_txt1"), VAlign.bottom, HAlign.left, document.getElementById("control2_div1"), VAlign.top, HAlign.left);
</script>
</div>
</div>
</div>
</div>
<div style="height:100px;"></div>
Case 3
<div>
<select><option>something</option></select>
<br />
<select><option>something else</option></select>
<div id="control3" style=" display:inline; position:relative;">
<div id="control3_div1" style="background-color:Blue; height:75px; width:150px; position:absolute;"></div>
<input id="control3_txt1" type="text" style="width:150px;" />
<script type="text/javascript">
AlignElements(document.getElementById("control3_txt1"), VAlign.bottom, HAlign.left, document.getElementById("control3_div1"), VAlign.top, HAlign.left);
</script>
</div>
</div>
</body>
</html>

The third case is breaking apart because of the inline display of the parent div - it cause the relative position to have no effect as far as I know.
To test such case use float instead, here is working example:
http://jsfiddle.net/yahavbr/estYF/1/

Thanks to Shadow Wizard for getting me thinking in the right direction. Turns out that the issue is that my absolutely positioned elements do not move to their 0,0 point when I clear the top and left properties. If I change the code to explicitly put them at 0,0 before calculating the offset difference then everything works beautifully.
element2.style.top = "";
element2.style.left = "";
becomes
element2.style.top = "0px";
element2.style.left = "0px";

Related

How to retain the position in a div, or a table (tbody) nested in it in order to return to this position after having followed a link

<style type="text/css">
body {margin:5px;}
p {margin:30px 0px 30px 0px;}
<!-- .
.
.-->
#scroller {overflow:auto;height:300px;width:550px;}
</style>
<div id="scroller">
<!-- <div id="toscroll" style="overflow:scroll" align="left"> -->
<div id="toscroll" align="left">
<table id="myOeuvresTable" width="593%" class= "sortable">
<!-- .
.
.-->
</table>
</div>
bellow the table:
Expand-->
<script type="text/javascript">
function openInventaireDesOeuvresExpandTblInNewTab(page)
{
var oScroll = document.getElementById('toscroll');
if (oScroll == null) // TJC: Invalid ID, ignore it
{
alert("myOeuvresTable.scroll not found!");
return "";
}
var versIE = isIE();
var x = oScroll.scrollLeft;
var y = oScroll.scrollTop;
alert(x.toString() + "," + y.toString());
// result of alert 0,0
x.scrollLeft += 100;
y.scrollTop += 100;
// this for testing purpose. The scrollbar does not move.
}
</script>
Can you propose another method than scrollTop, ScrollLeft, not based on the scrollbar and the scroller? To facilitate the understanding of the JS
code above, see www.danielpisters.be/ Select in the menu on the top. Click on bellow the second table.
You can use scrollIntoView method.
$element && $element.scrollIntoView()

How to apply css to overflow:hidden elements?

here i want to apply some css to those divs are not visible because if its height. So i want to apply some css dynamically which are not showing here(sanjana, giri, santhosh divs)
<!DOCTYPE html>
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
</head>
<body>
<div style="height:100px;overflow:hidden;background:red;border:2px dashed #000;">
<div>Ganesh</div>
<div>Om shankar</div>
<div>Sai</div>
<div>venkat</div>
<div>Sireesha</div>
<div>Sanjana</div>
<div>Giri</div>
<div>Santhosh</div>
</div>
</body>
</html>
If it's inline defined, you can use this:
[style*="overflow:hidden;"],[style*="overflow: hidden;"]
What it does is looking for ANY type of tag,
that has a style attribute set
and that style attribute contains: overflow:hidden; or overflow: hidden;
then applies relevant styles.
var value = 'initial';
var old = 'hidden';
function toggle() {
$('div[style]').css({'overflow':value});
var tmp = value;
value = old;
old = tmp;
}
[style*="overflow:hidden;"],[style*="overflow: hidden;"] {
color:white;
}
<!DOCTYPE html>
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
</head>
<body>
<input type="button" onclick="toggle()" value="toggle values">
<div style="height:100px;overflow:hidden;background:red;border:2px dashed #000;">
<div>Ganesh</div>
<div>Om shankar</div>
<div>Sai</div>
<div>venkat</div>
<div>Sireesha</div>
<div>Sanjana</div>
<div>Giri</div>
<div>Santhosh</div>
</div>
</body>
</html>
Now if you only wish to do something to the NOT visible divs, you need to use javascript, and you can use Bounding boxes to test if something is visible:
Also see How to check if an element is overlapping other elements?
$('[style*="overflow:hidden"],[style*="overflow: hidden;"]').children().each(function(index, element) {
var $el = $(element);
var $parent = $el.parent();
// get the bounding boxes.
var rect1 = $parent.get(0).getBoundingClientRect();
var rect2 = element.getBoundingClientRect();
// check for overlap(if it's visible)
if(!(rect1.right < rect2.left ||
rect1.left > rect2.right ||
rect1.bottom < rect2.top ||
rect1.top > rect2.bottom)) {
$el.removeClass('hidden');
}
else {
// it's hidden!
console.log('found hidden div '+$el.text());
$el.addClass("hidden");
}
});
<!DOCTYPE html>
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
</head>
<body>
<div style="height:100px;overflow:hidden;background:red;border:2px dashed #000;">
<div>Ganesh</div>
<div>Om shankar</div>
<div>Sai</div>
<div>venkat</div>
<div>Sireesha</div>
<div>Sanjana</div>
<div>Giri</div>
<div>Santhosh</div>
</div>
</body>
</html>
You can check the height from the wrapper via javascript and then add a class to all the elements which are not fully visible inside the wrapper. Added a class wrap to the wrapper to make it more obvious.
var wrap = document.querySelector('.wrap');
var wrapHeight = wrap.offsetHeight; // just in case it's not known and set by CSS
wrap.querySelectorAll('div').forEach(function(element){
var elementBottomPosition = element.offsetTop + element.offsetHeight;
if(elementBottomPosition >= wrapHeight) {
element.classList.add('some-class');
}
});
.wrap {
height:100px;
overflow:hidden;
background:red;
border:2px dashed #000;
}
.some-class {
color: lime;
}
<div class="wrap">
<div>Ganesh</div>
<div>Om shankar</div>
<div>Sai</div>
<div>venkat</div>
<div>Sireesha</div>
<div>Sanjana</div>
<div>Giri</div>
<div>Santhosh</div>
</div>

HTML / JS horizontal scrolling DIV "list"

What I want to make is an horizontally scrolling DIV "list" just like pretty much every big web site in the internet(netflix for example).
I tried to make it using a main DIV which would be some kind of container, a 2nd div which holds all the content and is inside the first DIV and a lot of DIVs, one for each content module, that go inside the 2nd div.
the parts of the 2nd DIV that overflow the main one should hide, and the content could be shown by moving it(the 2nd DIV).
this is the best I could come up with, but it still doesn't work jsfiddle
This is my HTML
<button onmouseover="left=1" onmouseout="left=0">
<</button>
<div class="container">
<div id="filler" style="left:0px">
<div class="module" style="background:coral;">testing</div>
<div class="module" style="background:lightblue;">testing</div>
<div class="module" style="background:lightgreen;">testing</div>
<div class="module" style="background:salmon;">testing</div>
<div class="module" style="background:lightyellow;">testing</div>
</div>
</div>
<button onmouseover="right=1" onmouseout="right=0">></button>
CSS
.container {
height:50px;
width:200px;
overflow:hidden;
}
#filler {
height:50px;
width:250px;
position:relative;
border-radius:10px;
background:crimson;
}
.module {
width:50px;
height:50px;
border-radius:5px;
float:left;
line-height:50px;
text-align:center;
}
JavaScript:
var feft = 0
//feft stands for filler left
var right = 0
var left = 0
var loaded = 0
window.onload=function(){
loaded=1
}
function move() {
if(loaded == 1){
if (left == 1 && feft <= 250) {
//left == 1 && feft <= filler width
document.getElementById("filler").style.left = feft + 1
}
if (right == 1 && feft >= 0) {
//right == 1 && feft >= 0
document.getElementById("filler").style.left = feft - 1
} //these IFs tests if the filler should move
feft = document.getElementById("filler").style.left
//this sets the feft variable to what it needs to be for the next run of the function
}}
window.setInterval(move(), 100)
I have made a fiddle for you.
demo
HTML code
<button onmouseover="left=1" onClick="move(-1)"><</button>
<div class="container">
<div id="filler" style="left:0px">
<div class="module" style="background:coral;">testing</div>
<div class="module" style="background:lightblue;">testing</div>
<div class="module" style="background:lightgreen;">testing</div>
<div class="module" style="background:salmon;">testing</div>
<div class="module" style="background:lightyellow;">testing</div>
</div>
</div>
<button onmouseover="right=1" onClick="move(1)">></button>
JS Code
var position = 0;
var moduleCount = document.querySelector(".module").length;
window.move = function(number) {
if (number) {
position += number;
if (number == 0 || number > moduleCount) {
position = 0;
}
} else {
if (position <= 4) {
position++;
} else {
position = 0;
}
}
moduleOffset = document.querySelector(".module").offsetWidth;
filler = document.querySelector("#filler");
filler.style.left = -( position* moduleOffset) + "px";
}
setInterval(window.move, 3000);
What you want to do is called "Carousel". I suggest to use bootstrap for example and implement it then in your site.
http://getbootstrap.com/javascript/#carousel
Try adding overflow: scroll as a CSS property to your container div.

Synchronizing span and textarea scrollbars - scrollbar slightly off and pasting issue

I have a table set up in the following way, with each cell containing a span and a textarea:
<table>
<tr><td class="title">Original File</td></tr>
<tr><td><span id='ogline' onscroll="og.scrollTop=scrollTop"></span><span><textarea onscroll="ogline.scrollTop=scrollTop" onkeyup="linenumber()" id='og' onfocusout="linenumber()"></textarea></span></td></tr>
</table>
Along with that I have the following CSS:
<style>
span {
width:93%;
height: 100%;
}
textarea {
width:92%;
height: 100%;
border-style:solid;
border-color:black;
border-width:2px;
font-size:13px;
}
table {
width:100%;
height:100%;
}
.title {
height:5%;
text-align:center;
background-color:#009;
color:white;
}
#ogline {
padding-top:4px;
overflow:auto;
font-size:12px;
line-height:14.99px;
width:6%;
}
</style>
What I am trying to do is have the scroll bar of the span and the scroll bar of the textarea synch up. I've somewhat accomplished this using the onscroll event listener with the following code:
onscroll="og.scrollTop=scrollTop"
onscroll="ogline.scrollTop = scrollTop
This has somewhat accomplished what I want it to, with the span being about a line off of where it should be. The greatest problem I am having though is when I paste a large amount of text into the textarea. This almost completely doesn't work, with both scrollbars being completely off until I hold one of the scrollbars down for a significant amount of time before the other scrollbar will try to play catch up with the other.
Any suggestions? Is there maybe a better approach to this issue that I should try? Any help would be appreciated.
This could work:
var scrolling=false;
function og_scroll(el)
{
if (scrolling && el!=scrolling) {
return;
}
scrolling = el;
var textareas = document.getElementsByTagName('textarea');
for (var i=0; i<textareas.length; i++) {
if (textareas[i].id.indexOf('og')==0) { // searching for id==og*
textareas[i].scrollTop=el.scrollTop;
}
}
scrolling = false;
}
function up(num)
{
var area = document.getElementById('og'+num);
if (area.scrollTop > 0) {
area.scrollTop -= 15;
}
}
function down(num)
{
var area = document.getElementById('og'+num);
if (area.scrollTop < area.scrollHeight) {
area.scrollTop += 15;
}
}
function fix_mouse_scroll() {
var textareas = document.getElementsByTagName('textarea');
for (var i=0; i<textareas.length; i++) {
if (textareas[i].id.indexOf('og')==0) {
if ("onmousewheel" in document) {
textareas[i].onmousewheel = fixscroll;
} else {
textareas[i].addEventListener('DOMMouseScroll', fixscroll, false);
}
}
}
}
function fixscroll(event){
var delta=event.detail? event.detail : event.wheelDelta; // positive or negative number
delta = delta>0 ? 15 : -15;
event.target.scrollTop += delta;
//console.log(delta, ' with ',event.target.scrollTop);
}
Html part:
<tr><td> <span onmousedown='up(1)'>[UP]</span> <span onmousedown='down(1)'>[DOWN]</span> <textarea id='og1' onscroll="og_scroll(this);"></textarea></td></tr>
<tr><td> <span onmousedown='up(2)'>[UP]</span> <span onmousedown='down(2)'>[DOWN]</span> <textarea id='og2' onscroll="og_scroll(this);"></textarea></td></tr>
<tr><td> <span onmousedown='up(3)'>[UP]</span> <span onmousedown='down(3)'>[DOWN]</span> <textarea id='og3' onscroll="og_scroll(this);"></textarea></td></tr>
The full html code is here.

Set absolute height (offsetHeight) of HTML containers that use CSS padding, margin and border by Javascript

I want to do something like setting offsetHeight (offsetHeight is a read only property) - fit 3 div ("d1", "d2", "d3") into one container ("c"):
<!DOCTYPE HTML>
<html>
<body>
<style type="text/css">
.c {
background-color:#FF0000;
overflow:hidden;
}
.d {
left:10px;
border:9px solid black;
padding:13px;
margin:7px;
background-color:#FFFF00;
}
</style>
<div class="c" id="c">
<div id="d1" class="d">text text text</div>
<div id="d2" class="d">text text text</div>
<div id="d3" class="d">text text text</div>
</div>
<script type='text/javascript'>
var h=600;
var hd = Math.floor(h/3);
var c = document.getElementById("c");
var d1 = document.getElementById("d1");
var d2 = document.getElementById("d2");
var d3 = document.getElementById("d3");
c.style.height=h +"px";
d1.style.height=hd +"px";
var hd2 = (2 * hd - d1.offsetHeight) +"px";
d1.style.height=hd2;
d2.style.height=hd2;
d3.style.height=hd2;
</script>
</body>
</html>
but - first: the boxes doesn’t fit perfect :-( and secondly the style is bad. Do you have a idea how to fit the 3 div ("d1", "d2", "d3") into one container ("c")?
=> also I dont know how to read the css properties "padding" and "margin"
alert(d1.style.paddingTop);
doesn't work (maybe because it is defined by css-class and not direct)
Thank you :-)
Best regards Thomas
Which browser your using and what DOCTYPE you have determines the default box model for block elements. Usually, the default is content-box, which means that the padding, border, and margin all add to the height/width, so you'll need to factor that into your calculations if you have the box model as content-box.
Another options is, you can change the box model to border-box using the box-sizing CSS property. This means that the padding and border are included in the height and width, and only the margin adds to them. In my opinion, this box model is usually a more convenient one for doing what I want, so I usually end up switching.
Reference:
https://developer.mozilla.org/En/CSS/Box-sizing
https://developer.mozilla.org/en/CSS/box_model
After some testing I figure out this solution:
(works with: Opera, Firefox and Google Chrome)
(box-sizing: doesn't work on Firefox when used JavaScript?!)
<!DOCTYPE HTML>
<html>
<body>
<style type="text/css">
.c {
background-color:#FF0000;
overflow:hidden;
margin:0px;
padding:0px;
}
.d {
left:10px;
border:13px solid black;
padding:7px;
margin-bottom:13px;
margin-top:4px;
background-color:#FFFF00;
}
</style>
<div class="c" id="c">
<div id="d1" class="d">text text text</div>
<div id="d2" class="d">text text text</div>
<div id="d3" class="d">text text text</div>
</div>
<script type='text/javascript'>
///////////////////////////////////////////
// see: http://stackoverflow.com/questions/1601928/incrementing-the-css-padding-top-property-in-javascript
function getStyle(elem, name) {
if (elem.style[name]) {
return elem.style[name];
}
else if (elem.currentStyle) {
return elem.currentStyle[name];
}
else if (document.defaultView && document.defaultView.getComputedStyle) {
name = name.replace(/([A-Z])/g, "-$1");
name = name.toLowerCase();
s = document.defaultView.getComputedStyle(elem, "");
return s && s.getPropertyValue(name);
}
else {
return null;
}
}
///////////////////////////////////////////
var c = document.getElementById("c");
var d1 = document.getElementById("d1");
var d2 = document.getElementById("d2");
var d3 = document.getElementById("d3");
var paddingY = parseInt(getStyle(d1, 'paddingTop'),10) + parseInt(getStyle(d1, 'paddingBottom'), 10);
var marginTop = parseInt(getStyle(d1, 'marginTop'),10);
var marginBottom = parseInt(getStyle(d1, 'marginBottom'),10);
var marginMax = Math.max(marginTop, marginBottom);
var borderY = parseInt(getStyle(d1, 'borderTopWidth'),10) + parseInt(getStyle(d1, 'borderBottomWidth'), 10);
var h=600;
var count=3;
var hd = Math.floor((h-marginMax*(count-1) - marginTop - marginBottom - (paddingY + borderY) *count) / count) ;
c.style.height=h +"px";
d1.style.height=hd +"px";
d2.style.height=hd +"px";
d3.style.height=hd +"px";
</script>
</body>
</html>

Categories