Jeg har en lille test-side her. Bemærk at et af dine krav, nemlig kravet til markering af tekst ikke er opfyldt i denne test, af den simple grund at det er upraktisk. Det er nu ikke svært at genaktivere. Du skal blot fjerne return false; i dragElement, og så får event'et lov til lystigt at boble ned til andre eventhandlers.
Med hensyn til getter og setter så har jeg aldrig hørt at det er et krav begge er defineret. Jeg har aldrig set noget på skrift, men jeg har set meget professionelle gamle Mozilla scripts hvor der er ensidig definition. Et eventuelt link til en kilde ville være rart.
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "
http://www.w3.org/TR/html4/loose.dtd"> <html>
<head>
<title>Pure Test</title>
<style>
div { position:relative; cursor:default; }
</style>
<script type="text/javascript">
if (window.Node) {
// Moz extensions
Event.prototype.__defineGetter__("clientX", function() { return this.pageX; } );
Event.prototype.__defineGetter__("clientY", function() { return this.pageY; } );
Event.prototype.__defineGetter__("offsetX", function () { return this.layerX; } );
Event.prototype.__defineGetter__("offsetY", function () { return this.layerY; } );
Event.prototype.__defineGetter__("srcElement", function () {
var node = this.target;
while (node.nodeType != 1) node = node.parentNode;
return node;
});
}
function DragManager() {
this.registeredElements = new Array();
this.register = function(element) {
// see if any removed element slots are available
for (i=0;i!=this.registeredElements.length;i++) {
if(this.registeredElements[i]==null) {
this.registeredElements[i]=element;
return;
}
}
// Otherwise expand the register by one
this.registeredElements[this.registeredElements.length]=element;
// update
this.update();
// mark the element so we don't register twice
element.markedForDrag = true;
}
this.remove = function(element) {
// locate and remove the element if present.
for (i=0;i!=this.registeredElements.length;i++) {
if(this.registeredElements[i]==element)
this.registeredElements[i]=null;
}
this.update();
// demark the element
element.markedForDrag = false;
}
this.grabElement = function(e) {
// See if the source is registered and select if so
if(e)event=e;
for (i=0;i!=this.registeredElements.length;i++) {
if(this.registeredElements[i]==event.srcElement) {
this.selected=event.srcElement;
break;
}
}
if (this.selected!=null) {
this.selected = (this.selected.proxy)?this.selected.proxy:this.selected;
this.selected.style.zIndex = this.zIndex++;
this.offsetX = event.clientX-(isNaN(parseInt(this.selected.style.left))?0:parseInt(this.selected.style.left));
this.offsetY = event.clientY-(isNaN(parseInt(this.selected.style.top))?0:parseInt(this.selected.style.top));
if (this.selected.invokeOnGrab!=null)
this.selected.invokeOnGrab(event);
}
}
this.dragElement = function(e) {
if(e)event=e;
if(this.selected) {
if(this.selected.isAnchored) return;
theoreticalLeft = event.clientX-this.offsetX;
theoreticalTop = event.clientY-this.offsetY;
if(!this.selected.verticalLock) {
if (this.selected.topBound!=null||this.selected.topBound==0)
theoreticalTop=(theoreticalTop<this.selected.topBound)?this.selected.topBound:theoreticalTop;
if (this.selected.bottomBound!=null||this.selected.bottomBound==0)
theoreticalTop=(theoreticalTop>this.selected.bottomBound)?this.selected.bottomBound:theoreticalTop;
this.selected.style.top = theoreticalTop+"px";
if (this.selected.invokeOnMove)
this.selected.invokeOnMove(event);
}
if(!this.selected.horizontalLock) {
if (this.selected.leftBound||this.selected.leftBound==0)
theoreticalLeft=(theoreticalLeft<this.selected.leftBound)?this.selected.leftBound:theoreticalLeft;
if (this.selected.rightBound||this.selected.rightBound==0)
theoreticalLeft=(theoreticalLeft>this.selected.rightBound)?this.selected.rightBound:theoreticalLeft;
this.selected.style.left = theoreticalLeft+"px";
if (this.selected.invokeOnMove)
this.selected.invokeOnMove(event);
}
}
return false; // avoid event propagation downwards.
}
this.releaseElement = function(e) {
if(e)event=e;
if(this.selected) {
if (this.selected.invokeOnRelease)
this.selected.invokeOnRelease(event);
this.selected=null;
}
}
}
DragManager.prototype.init = function() {
if (!window.Element) {
document.zIndex = 0;
document.onmousedown = this.grabElement;
document.onmousemove = this.dragElement;
document.onmouseup = this.releaseElement;
this.owner = document;
} else {
window.zIndex = 0;
window.onmousedown = this.grabElement;
window.onmousemove = this.dragElement;
window.onmouseup = this.releaseElement;
this.owner = window
}
}
DragManager.prototype.update = function() {
if (!window.Element) {
document.registeredElements = this.registeredElements;
} else {
window.registeredElements = this.registeredElements;
}
}
onload = function() {
// DragManager tilbyder en masse drag funktionalitet.
// Først skal vi oprette en DragManager. Der bør være en DragManager pr. window/document object
// selvom den i princippet kan afregistreres og registrere sig i en iframe.
myDrag = new DragManager();
myDrag.init(); // binder den til document (for IE) eller window (for NS)
// Goody. Lad os få fingre i en div at lege med
myObj = document.getElementById("Nr1");
myDrag.register(myObj); // tilføjer myObj til myDrags register over objekter, der skal kunne trækkes
// Det virker jo fint, men vi kan mere. Hvad med at få en div inden i en anden div til at flytte hele moletjavsen
myObj = document.getElementById("Nr3");
// Nu har vi det objekt der TRÆKKES. Det objekt der FLYTTES erklæres som oObject.proxy
myObj.proxy = document.getElementById("Nr2");
myDrag.register(myObj);
// Nogle gange er det nødvendigt at layers kun kan flyttes inden for et afgrænset område. Det gør vi ved at erklære
// følgende varible: topBound, bottomBound, leftBound og rightBound.
// Det er et vidunder til virtuelle scrollbars.
myObj = document.getElementById("Nr4");
myObj.leftBound = 0; // kan ikke flyttes mere end 0 pixels til venstre
myObj.rightBound = 300; // kan ikke flyttes mere end 300 pixels til højre
myObj.topBound = 0; // kan ikke flyttes mere end 0 pixels til op
myObj.bottomBound = 300; // ken ikke flyttes mere end 300 pixels nedad
myDrag.register(myObj);
// Endeligt kan det nogle gange være rart at kunne udføre et eller andet under klik, drag eller slip.
// Dette gøres ved at tilføje funktionerne invokeOnGrab, invokeOnMove og invokeOnRelease
myObj = document.getElementById("Nr5");
myObj.invokeOnGrab=function(e) { this.innerHTML="You got me."; }
myObj.invokeOnRelease=function(e) { this.innerHTML=(this.wasAborted)?"Hah. Got away.":"Awaiting your command"; }
myObj.invokeOnMove=function(e) {
this.innerHTML="Venstre: "+this.style.left+" Top: "+this.style.top;
if (parseInt(this.style.left)>400) {
// Vi fjerner objektet fra manageren med remove
// Bemærk at vi først "slipper" objektet når musen løftes
this.wasAborted=true;
myDrag.remove(this);
// Det løser vi med:
myDrag.owner.onmouseup();
}
}
myDrag.register(myObj);
// Sluttelig kan vi låsei vertikal eller horisontal retning (og i princippet i begge retninger selvom det virker meningsløs)
// Denne gang opretter vi en div til formålet
myObj = document.createElement("DIV");
myObj.style.width="100px";
myObj.style.height="100px";
myObj.style.backgroundColor="silver";
myObj.appendChild(document.createTextNode("I'm locked vertically"));
document.body.appendChild(myObj);
myObj.verticalLock=true;
myDrag.register(myObj);
}
</script>
</head>
<body>
<h1>Nogle DIV's at lege med. Bemærk de er RELATIVE</h1>
<div id="Nr1">En Div, der kan trækkes</div>
<div id="Nr2">
<div id="Nr3">En Div, der trækker en anden Div</div>
En Div, der trækkes
</div>
<div id="Nr4">En Div, der ikke kan slippe væk</div>
<div id="Nr5">Sladrehanken</div>
</body>
</html>