Opera 6 & 7 scrolling.

R

Randy Webb

Pete said:
Therefor, if there isn't a better scroll method?, I need an Opera 6/7
detection. I know that object detection is prefered over browser
detection but I don't of any differences to reference between 6 and 7.

Look at the userAgent string. I am sure that Opera 6 doesn't contain
Opera 7.23 in it (which is what my Opera 7 has in it). No matter which
spoof mode I had it in, it contained that snippet.

As well, I am sure there has to be some feature difference between them,
other than the userAgent string.
 
P

Pete

I'm working (playing) on a mouse following script. Yes, the sort no
one likes but I'm having great fun tinkering with it - sad.

Anyway, if there's enough page content to cause scrolling and I want
the objects (colored divs) to scroll with the mouse in Opera 6. I give
the mouse y coords (-) window.pageYOffset and the objects (+)
window.pageYOffset.

However, in Opera 7 it doesn't work. Only the following objects need
(+) window.pageYOffset. The mouse code doesn't need anything and it
works as I want?

Therefor, if there isn't a better scroll method?, I need an Opera 6/7
detection. I know that object detection is prefered over browser
detection but I don't of any differences to reference between 6 and 7.

Pete.
 
R

Richard Cornford

Anyway, if there's enough page content to cause scrolling and
I want the objects (colored divs) to scroll with the mouse in
Opera 6. I give the mouse y coords (-) window.pageYOffset and
the objects (+) window.pageYOffset.

However, in Opera 7 it doesn't work. Only the following objects
need (+) window.pageYOffset. The mouse code doesn't need anything
and it works as I want?

Therefor, if there isn't a better scroll method?, I need an
Opera 6/7 detection. I know that object detection is prefered
over browser detection but I don't of any differences to
reference between 6 and 7.

The simple positioning of CSS position:absolute; DIV elements taking
scrolling into account does not need significantly different handling
between Opera 6 and 7 (apart, possibly from the handling of appending
CSS units to the top and left values).

It is much morel likely that your problem is with the differences in the
reporting of mouse co-ordinates between the two. With Opera 6 only
providing clientX and clientY values but reporting those values as if
they were pageX and pageY, While Opera 7 returns genuine client area
co-ordinates for those values and also provides pageX and pageY as
alternatives.

When reading mouse co-ordinates I prefer the pageX and pageY values and
only fall back to clientX and clientY if they are missing, such as on
IE, IceBrowser and Opera 6. But knowing that Opera 6 values do not need
adjusting by the scroll values I use the presence of the window.opera
object as indicating that the clientX/Y values do not need adjusting by
the scroll (and [root].clientTop/Left) values in order to be equivalent
to the page values. That is the nearest that I have come to needing to
do anything resembling browser detecting.

Richard.
 
P

Pete

Randy Webb said:
Look at the userAgent string. I am sure that Opera 6 doesn't contain
Opera 7.23 in it (which is what my Opera 7 has in it). No matter which
spoof mode I had it in, it contained that snippet.

As well, I am sure there has to be some feature difference between them,
other than the userAgent string.

Yes, I tried that and like you got the required result with all Opera
7.22 spoofs - see code below. However, I don't have versions 5 or 6 to
test with and will it be OK with future versions? Oh well, thanks
anyway. Unless some one comes up with something better I'll use it for
now. Like I said, it's only a bit fun.
Pete.

<script type="text/javascript">
//Main thing------------------------
var ua=navigator.userAgent;
var op=(ua.indexOf("Opera") != -1);
var op7;
var oa=0;
var ob=0;
var oc=0;
var ov=0;
if (op){
oa=ua.indexOf("Opera")+6;
ob=oa+4;
oc=ua.substring(oa,ob);
ov=parseFloat(oc);
}
op7=(op && ov >= 7)?true:false;
//--------------------------------

//Test----------------------------
var a=(op)?"Yes":"No";
var b=(op)?"Is it version 7 or higher\? ":"";
var c;
if (op && ov >= 7) c="Yes";
else if (op && ov < 7) c="No";
else c="";
var d=(op)?"Its\' version " +ov:"";
alert('Is it Opera\? '+a+'\n'+b+c+'\n'+d);
//--------------------------------
</script>
 
R

Richard Cornford

Yes, I tried that and like you got the required result with
all Opera 7.22 spoofs - see code below. However, I don't
have versions 5 or 6 to test with and will it be OK with
future versions? Oh well, thanks anyway. Unless some
one comes up with something better I'll use it for now.
Like I said, it's only a bit fun.
<snip>

Being able to tell the difference between two versions of Opera
regardless of their spoofing modes does not solve the problem as you
still cannot tell the difference between Opera and another browser
spoofing Opera. There was a time when I don't think any other browser
would spoof Opera (couldn't see much point) but I was wrong and there
are browsers out there that offer an option to spoof the Opera UA string
in their preferences.

But the script you are describing can be (and has been) implemented in a
cross-browser form without the need to be interested in the UA string at
all. You would probably benefit more in the long run by finding out what
it is you are doing wrong that is provoking you apparent problem and
fixing that than setting off in a direction (UA string testing) that has
already been demonstrated to be worthless.

Richard.
 
P

Pete

Richard Cornford said:
The simple positioning of CSS position:absolute; DIV elements taking
scrolling into account does not need significantly different handling
between Opera 6 and 7 (apart, possibly from the handling of appending
CSS units to the top and left values).

I wouldn't have thought so either but it's what I'm getting. Maybe it
would be better if I include the script. It's stripped down just for
Opera and the pageYOffset thing.

Copy and paste some more <p>'s to cause scrolling then alternate the
pageYOffset's. As is - it works in 7 but not 6 and vice-versa.

<html><head><title>test</title>
<style type="text/css">
#box{
position:absolute;top:0px;left:0px;
width:20px;height:20px;background:blue;
}
</style>
</head><body>

<div id="box"></div>

<script type="text/javascript">
var y1=x1=y2=x2=y3=x3=0;
var temp=document.getElementById("box").style;

function mouse(){
y1 = event.clientY;// - window.pageYOffset;
x1 = event.clientX;
}
document.onmousemove=mouse;

function move_these(){
temp.top = y2 + window.pageYOffset;
temp.left = x2;
}

function delay(){
y2 = y3 += (y1 - y3) * 0.1;
x2 = x3 += (x1 - x3) * 0.1;
move_these();
setTimeout('delay()',50);
}

window.onload=delay;
</script>

<p>&nbsp;</p>
<p>&nbsp;</p> more....

</body>
It is much morel likely that your problem is with the differences in the
reporting of mouse co-ordinates between the two. With Opera 6 only
providing clientX and clientY values but reporting those values as if
they were pageX and pageY, While Opera 7 returns genuine client area
co-ordinates for those values and also provides pageX and pageY as
alternatives.

I didn't know that. Would..
((event.clientY)||(event.pageY&&event.clientY))
?event.clientY:event.clientY-window.pageYOffset;
...do?
When reading mouse co-ordinates I prefer the pageX and pageY values and
only fall back to clientX and clientY if they are missing, such as on
IE, IceBrowser and Opera 6. But knowing that Opera 6 values do not need
adjusting by the scroll values I use the presence of the window.opera
object as indicating that the clientX/Y values do not need adjusting by
the scroll (and [root].clientTop/Left) values in order to be equivalent
to the page values. That is the nearest that I have come to needing to
do anything resembling browser detecting.

Richard.
 
R

Richard Cornford

I wouldn't have thought so either but it's what I'm
getting. Maybe it would be better if I include the
script.

It almost always is.

function mouse(){
y1 = event.clientY;// - window.pageYOffset;
x1 = event.clientX;
}

There you go, Opera 6 returns co-ordinates relative to the page for
clientX/Y while Opera 7 (correctly) returns co-ordinates relative to the
client area.
document.onmousemove=mouse;

Netscape 4 (but preferably not later Netscape versions (though they do
support the function)) requires calls to document.captureEvents if you
want to follow mouse movement at the document level.
function move_these(){
temp.top = y2 + window.pageYOffset;
temp.left = x2;
}

If the mouse co-ordinates you are using are page relative you do not
need to adjust for the scrolling values at this point, if you use client
co-ordinates then you do need to adjust.

But the CSS units value comes in at this point. On standards compliant
browsers a string value should be assigned to the top and left style
properties with appended units. OTOH older browsers prefer the values to
be provided as numbers. My strategy for dealing with this problem is
based on using typeof to test one of style.top or style.left to see if
it is of string type or numeric. If it is a string then it is best to
provide CSS units, if it is a number then it is best to assign a number.
I do this by assigning a value to a suitably scoped variable based on
the typeof test:-

var posMod = (typeof temp.top == 'string')?'px':0;

-and then when a value is to be assigned to top or left (or any other
style value that need similar handling) I use the + operator:-

temp.top = y2 + posMod;

- the - y2 - value is a number and - posMod - is either the number zero
or it is the string 'px' so the action of the + operator depends on the
type of posMod. If - posMod - is zero then - + - does addition and
adding zero to a number results in an unchanged number, and that is
assigned to the style property. But if - posMod - is the string 'px'
the - + - operator does string concatenation, type-converting the - y2 -
value to a string and then appending 'px' to it, providing the desired
string value with the CSS units.
function delay(){
y2 = y3 += (y1 - y3) * 0.1;
x2 = x3 += (x1 - x3) * 0.1;
move_these();
setTimeout('delay()',50);
}

If - delay - always calls - delay - (without the option of being
cancelled) it would be wroth looking into the setInterval function as an
alternative.

I didn't know that. Would..
((event.clientY)||(event.pageY&&event.clientY))
?event.clientY:event.clientY-window.pageYOffset;
..do?

Over the years I have tried out various strategies for reading the mouse
co-ordinates, the following is the latest version of my cross browser
document.onmousemove following object:-

var MoveFollow = (function(){
var global = this;
var theOne = {
getPageX:function(){
return ((readScroll.scrollLeft|0) -
(readScroll.clientLeft|0) + XY.x);
},
getPageY:function(){
return ((readScroll.scrollTop|0) -
(readScroll.clientTop|0) + XY.y);
},
getPageXY:function(){
return {x:this.getPageX(),y:this.getPageY()};
},
upDate:function(ev){
mm(ev);
}
};
var XY = {x:0,y:0};
var readScroll = {scrollTop:0,scrollLeft:0,
clientLeft:0,clientTop:0};
var eventInited = false;
var posReadX = 'pageX';
var posReadY = 'pageY';
function mm(e){
e = e||global.event;
XY.x = e[posReadX];
XY.y = e[posReadY];
};
function initEvent(ev){
ev = ev||global.event;
if(ev){
if(typeof ev.pageX != 'number'){ //Opera 7 has pageX
posReadX = 'clientX';
posReadY = 'clientY';
if(!global.opera){ //Not an Opera browser
if((typeof document.compatMode == 'string')&&
(document.compatMode.indexOf('CSS') != -1)&&
(document.documentElement)){
readScroll = document.documentElement;
}else if(document.body){
readScroll = document.body;
}
}
}
setUpOnMouse(mm);
mm(ev);
eventInited = true;
}else{
setUpOnMouse(initEvent);
}
};
function setUpOnMouse(f){
if(document.onmousemove != f){
document.onmousemove = f;
if((document.captureEvents)&&(global.Event)&&
(document.layers)&&(typeof Layer == 'function')){
document.captureEvents(Event.MOUSEMOVE);
}
}
};
initEvent();
return (function(){
return theOne;
});
})(); //simultaneously define and call (one-off)!

The - MoveFollow - global variable is assigned a function and once it
has been assigned any other code can call the - MoveFollow - function,
which will return a reference to an object that represents a common
interface to the onmousemove events (cross-browser). The bulk of the
testing and configuration work is done as this script initialises itself
so once it is running it is very efficient.

The reference to the interface is acquired as:-

var mouseMoveFollower = MoveFollow();

-the the latest mouse X and Y co-ordinates (relative to the HTML page)
are retrieved using the interface's getPageX/Y methods:-

var pageXcord = mouseMoveFollower.getPageX();
/* and */
var pageYcord = mouseMoveFollower.getPageY();

If you can understand the code (with its inline function expression
call, nested functions, and so on) you should be able to understand how
the code decides which values to read from the event objects. It is the
only code that I use that has any interest in which browser is on use
specifically in order to cope with the incorrect reporting of clientX/Y
in Opera 6. Which is done by checking Opera's global - opera - property.
That isn't a problem for Opera 7, which has the pageX/Y properties on
the event object and the code prefers to use those if available.

Richard.
 
P

Pete

Richard Cornford:

Thanks for the script and the obvious effort put in to it, you
certainly know your onions. Also, thanks for introducing me to the
"typeof". Had loads of fun with that and very handy. I see what you
mean about pageY vs. clientY in Opera 7. pageY/X definitely from now
on. This eliminated my original 6/7 problem.

I do know about the document.captureEvents etc for Netscape 4 but
deliberately didn't write for it. It would be nice to write for older
browsers but I think you have to draw the line somewhere. Nothing of
importance depends on my efforts so I'm just going to concentrate on
the present, future and, hopefully, standards.

Anyway, although yours is excellent, I never feel right if I haven't
put the effort in and written something myself so here's my 'lesser'
effort. I managed to fix up my old PC with 6 and the script works OK
and on the new one with Explorer 6, Netscape 7.1 and Opera 7.22 with
various and no doctypes.

One thing I didn't understand was your setInterval over setTimeout but
I'll look that up my self.
Thanks again,
Pete.


Doctype just for show.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html
PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<title>Modern</title>
<style type="text/css">
#box{
position:absolute;top:0px;left:0px;
width:20px;height:20px;background:blue;
}
</style>
</head>
<body>

<div id="box"></div>

<script type="text/javascript">
<!--
if (document.getElementById){

var y1=x1=y2=x2=y3=x3=0;
var temp=document.getElementById("box").style;

function mouse(e){
var msy = (typeof window.pageYOffset ==
'number')?window.pageYOffset:0;
if (!e) e = window.event;
if (typeof e.pageY == 'number'){
y1 = e.pageY - msy;
x1 = e.pageX;
}
else{
y1 = e.clientY - msy;
x1 = e.clientX;
}
}
document.onmousemove=mouse;

function apply_to_these(){
var osy = (typeof window.pageYOffset == 'number')
?window.pageYOffset:(document.compatMode && document.compatMode ==
'CSS1Compat')?
document.documentElement.scrollTop:document.body.scrollTop;

//Above might have a wrap problem when posted.

temp.top = y2 + osy + "px";
temp.left = x2 + "px";
}

function delay(){
y2 = y3 += (y1 - y3) * 0.1;
x2 = x3 += (x1 - x3) * 0.1;
apply_to_these();
setTimeout('delay()',50);//Will investigate this.
}
window.onload=delay;

}
//-->
</script>

<p>&nbsp;</p><p>&nbsp;</p>
Lots more....

</body>
</html>
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,997
Messages
2,570,241
Members
46,831
Latest member
RusselWill

Latest Threads

Top