2008-04-18 06:41:49 -07:00
|
|
|
<?xml version="1.0"?>
|
|
|
|
<!DOCTYPE bindings PUBLIC "-//MOZILLA//DTD XBL V1.0//EN" "http://www.mozilla.org/xbl">
|
|
|
|
|
|
|
|
<bindings
|
|
|
|
xmlns="http://www.mozilla.org/xbl"
|
|
|
|
xmlns:xbl="http://www.mozilla.org/xbl"
|
|
|
|
xmlns:html="http://www.w3.org/1999/xhtml"
|
|
|
|
xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
|
|
|
|
|
|
|
|
<binding id="deckbrowser">
|
|
|
|
<content>
|
2008-06-21 11:51:41 -07:00
|
|
|
<xul:deck flex="1">
|
|
|
|
<xul:stack anonid="cstack" flex="1" style="overflow: hidden;">
|
|
|
|
<html:canvas anonid="ccanvas"
|
|
|
|
moz-opaque="true"
|
|
|
|
style="-moz-stack-sizing: ignore;"/>
|
2008-05-17 23:35:30 -07:00
|
|
|
</xul:stack>
|
2008-06-21 11:51:41 -07:00
|
|
|
<xul:browser anonid="browser"
|
|
|
|
class="deckbrowser-browser"
|
|
|
|
type="content-primary"
|
|
|
|
xbl:inherits="contextmenu,autocompletepopup"
|
|
|
|
style="overflow: hidden; visibility: hidden;"/>
|
|
|
|
</xul:deck>
|
2008-04-18 06:41:49 -07:00
|
|
|
</content>
|
|
|
|
|
|
|
|
<implementation>
|
|
|
|
<constructor>
|
2008-06-21 11:51:41 -07:00
|
|
|
this._zoomLevel = 1;
|
2008-04-18 06:41:49 -07:00
|
|
|
|
2008-06-21 11:51:41 -07:00
|
|
|
// panning
|
|
|
|
this._stack.addEventListener("mousedown", this.stackEventHandler, true);
|
2008-06-24 18:03:37 -07:00
|
|
|
// need mouseup handled on the window to catch mouseups on e.g. the toolbar
|
|
|
|
window.addEventListener("mouseup", this.stackEventHandler, true);
|
2008-06-21 11:51:41 -07:00
|
|
|
this._stack.addEventListener("mousemove", this.stackEventHandler, true);
|
2008-04-18 06:41:49 -07:00
|
|
|
|
2008-06-21 11:51:41 -07:00
|
|
|
// zoom
|
|
|
|
this._stack.addEventListener("dblclick", this.stackEventHandler, true);
|
|
|
|
this._stack.addEventListener("DOMMouseScroll", this.stackEventHandler, true);
|
2008-07-04 00:33:05 -07:00
|
|
|
|
|
|
|
this._scrollStartTimeout = -1;
|
2008-06-21 11:51:41 -07:00
|
|
|
</constructor>
|
|
|
|
|
|
|
|
<field name="dragData">
|
|
|
|
({
|
|
|
|
dragging: false,
|
|
|
|
offX: 0,
|
|
|
|
offY: 0,
|
|
|
|
sX: 0,
|
|
|
|
sY: 0,
|
|
|
|
scrollableWidth: 0,
|
|
|
|
scrollableHeight: 0,
|
|
|
|
canvasH: 0,
|
|
|
|
canvasW: 0,
|
|
|
|
pageX: 0,
|
|
|
|
pageY: 0
|
|
|
|
})
|
2008-05-07 16:57:23 -07:00
|
|
|
</field>
|
|
|
|
|
2008-06-21 11:51:41 -07:00
|
|
|
<field name="_stack">
|
|
|
|
document.getAnonymousElementByAttribute(this, "anonid", "cstack");
|
2008-05-07 16:57:23 -07:00
|
|
|
</field>
|
|
|
|
|
2008-06-21 11:51:41 -07:00
|
|
|
<field name="_canvas">
|
|
|
|
document.getAnonymousElementByAttribute(this, "anonid", "ccanvas");
|
2008-04-18 06:41:49 -07:00
|
|
|
</field>
|
|
|
|
|
|
|
|
<property name="browser" readonly="true">
|
|
|
|
<getter>
|
2008-06-21 11:51:41 -07:00
|
|
|
return document.getAnonymousElementByAttribute(this, "anonid", "browser");
|
2008-04-18 06:41:49 -07:00
|
|
|
</getter>
|
|
|
|
</property>
|
|
|
|
|
2008-06-21 11:51:41 -07:00
|
|
|
<method name="updateCanvasState">
|
|
|
|
<parameter name="aLocationChanged"/>
|
|
|
|
<body><![CDATA[
|
|
|
|
if (aLocationChanged) {
|
|
|
|
this.dragData.pageX = 0;
|
|
|
|
this.dragData.pageY = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (this._updateTimeout)
|
|
|
|
clearTimeout(this._updateTimeout);
|
|
|
|
|
|
|
|
var self = this;
|
|
|
|
this._updateTimeout = setTimeout(function () {
|
2008-06-24 18:18:16 -07:00
|
|
|
if (!self.dragData.dragging)
|
|
|
|
self._browserToCanvas();
|
2008-06-21 11:51:41 -07:00
|
|
|
}, 100);
|
|
|
|
]]></body>
|
2008-04-18 06:41:49 -07:00
|
|
|
</method>
|
|
|
|
|
2008-06-21 11:51:41 -07:00
|
|
|
<method name="_browserToCanvas">
|
|
|
|
<body><![CDATA[
|
|
|
|
this._updateCanvasPosition();
|
|
|
|
|
|
|
|
// FIXME: canvas needs to know it's actual width/height
|
|
|
|
var rect = this._canvas.getBoundingClientRect();
|
|
|
|
var w = rect.right - rect.left;
|
|
|
|
var h = rect.bottom - rect.top;
|
|
|
|
this._canvas.width = w;
|
|
|
|
this._canvas.height = h;
|
|
|
|
|
|
|
|
var ctx = this._canvas.getContext("2d");
|
|
|
|
|
|
|
|
ctx.clearRect(0,0,w,h);
|
|
|
|
|
|
|
|
//dump("x, y: " + this.dragData.pageX + "," + this.dragData.pageY + "\n");
|
|
|
|
ctx.save();
|
|
|
|
ctx.scale(this._zoomLevel, this._zoomLevel);
|
|
|
|
ctx.drawWindow(this.browser.contentWindow,
|
|
|
|
-this.dragData.pageX / this._zoomLevel, -this.dragData.pageY / this._zoomLevel,
|
|
|
|
w / this._zoomLevel, h / this._zoomLevel,
|
|
|
|
"white");
|
|
|
|
ctx.restore();
|
|
|
|
]]></body>
|
2008-04-18 06:41:49 -07:00
|
|
|
</method>
|
|
|
|
|
2008-06-21 11:51:41 -07:00
|
|
|
<method name="_updateCanvasPosition">
|
|
|
|
<body><![CDATA[
|
|
|
|
//dump("setting left/top: " + this.dragData.offX + "/" + this.dragData.offY + "\n");
|
|
|
|
this._canvas.style.marginLeft = this.dragData.offX + "px";
|
|
|
|
this._canvas.style.marginRight = -this.dragData.offX + "px";
|
|
|
|
this._canvas.style.marginTop = this.dragData.offY + "px";
|
|
|
|
this._canvas.style.marginBottom = -this.dragData.offY + "px";
|
2008-04-18 06:41:49 -07:00
|
|
|
|
2008-06-21 11:51:41 -07:00
|
|
|
//window.QueryInterface(Components.interfaces.nsIInterfaceRequestor).getInterface(Components.interfaces.nsIDOMWindowUtils).redraw();
|
|
|
|
]]></body>
|
2008-04-18 06:41:49 -07:00
|
|
|
</method>
|
|
|
|
|
2008-06-21 11:51:41 -07:00
|
|
|
<property name="zoomLevel" readonly="true" onget="return this._zoomLevel;"/>
|
2008-05-08 15:59:16 -07:00
|
|
|
|
2008-06-21 11:51:41 -07:00
|
|
|
<method name="zoom">
|
|
|
|
<parameter name="aDirection"/>
|
|
|
|
<body><![CDATA[
|
|
|
|
if (aDirection >= 0)
|
|
|
|
this._zoomLevel -= 0.05; // 1/20
|
|
|
|
else
|
|
|
|
this._zoomLevel += 0.05;
|
2008-05-17 23:35:30 -07:00
|
|
|
|
2008-06-21 11:51:41 -07:00
|
|
|
const min = 0.2;
|
|
|
|
const max = 2.0;
|
|
|
|
if (this._zoomLevel < min)
|
|
|
|
this._zoomLevel = min;
|
2008-05-17 23:35:30 -07:00
|
|
|
|
2008-06-21 11:51:41 -07:00
|
|
|
if (this._zoomLevel > max)
|
|
|
|
this._zoomLevel = max;
|
2008-05-17 23:35:30 -07:00
|
|
|
|
2008-06-21 11:51:41 -07:00
|
|
|
this._browserToCanvas();
|
|
|
|
]]></body>
|
|
|
|
</method>
|
2008-05-22 13:46:20 -07:00
|
|
|
|
2008-06-21 11:51:41 -07:00
|
|
|
<method name="_redispatchMouseEvent">
|
|
|
|
<parameter name="aEvent"/>
|
|
|
|
<parameter name="aType"/>
|
|
|
|
<body><![CDATA[
|
|
|
|
//return;
|
|
|
|
var cwin = this.browser.contentWindow;
|
2008-06-24 16:36:44 -07:00
|
|
|
|
|
|
|
// Scroll the browser so that the event is targeted properly
|
2008-07-04 00:33:05 -07:00
|
|
|
cwin.scrollTo(-this.dragData.pageX / this._zoomLevel, -this.dragData.pageY / this._zoomLevel);
|
2008-06-24 16:36:44 -07:00
|
|
|
|
|
|
|
var cwu = cwin.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
|
|
|
|
.getInterface(Components.interfaces.nsIDOMWindowUtils);
|
|
|
|
|
|
|
|
// Need to adjust for the toolbar height, etc.
|
2008-06-21 11:51:41 -07:00
|
|
|
var browserTop = this.browser.getBoundingClientRect().top;
|
2008-07-04 00:33:05 -07:00
|
|
|
|
2008-06-21 11:51:41 -07:00
|
|
|
cwu.sendMouseEvent(aType || aEvent.type,
|
2008-06-24 16:36:44 -07:00
|
|
|
(aEvent.clientX) / this._zoomLevel,
|
|
|
|
(aEvent.clientY - browserTop) / this._zoomLevel,
|
2008-06-21 11:51:41 -07:00
|
|
|
aEvent.button || 0,
|
|
|
|
aEvent.clickCount || 1,
|
|
|
|
0);
|
|
|
|
]]></body>
|
2008-05-06 07:56:21 -07:00
|
|
|
</method>
|
|
|
|
|
2008-06-21 11:51:41 -07:00
|
|
|
<method name="_doPan">
|
|
|
|
<parameter name="aDx"/>
|
|
|
|
<parameter name="aDy"/>
|
|
|
|
<body><![CDATA[
|
|
|
|
// constrain offsets to the actual scrollWidth/scrollHeight
|
2008-07-04 00:33:05 -07:00
|
|
|
|
2008-06-21 11:51:41 -07:00
|
|
|
var offscreenWidth = this.dragData.scrollableWidth - this.dragData.canvasW;
|
|
|
|
if (offscreenWidth <= 0) {
|
|
|
|
// Content is narrower than viewport, no need to pan horizontally
|
|
|
|
this.dragData.offX = 0;
|
|
|
|
} else {
|
|
|
|
var newPageX = Math.max(this.dragData.pageX + aDx, -offscreenWidth);
|
|
|
|
newPageX = Math.min(newPageX, 0);
|
|
|
|
var deltaX = newPageX - this.dragData.pageX;
|
2008-07-04 00:33:05 -07:00
|
|
|
this.dragData.offX = deltaX;
|
2008-06-21 11:51:41 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
var offscreenHeight = this.dragData.scrollableHeight - this.dragData.canvasH;
|
|
|
|
if (offscreenHeight <= 0) {
|
|
|
|
// Content is shorter than viewport, no need to pan vertically
|
|
|
|
this.dragData.offY = 0;
|
|
|
|
} else {
|
2008-07-04 00:33:05 -07:00
|
|
|
// min of 0, max of scrollableHeight - canvasHeight
|
2008-06-21 11:51:41 -07:00
|
|
|
var newPageY = Math.max(this.dragData.pageY + aDy, -offscreenHeight);
|
|
|
|
newPageY = Math.min(newPageY, 0);
|
|
|
|
var deltaY = newPageY - this.dragData.pageY;
|
2008-07-04 00:33:05 -07:00
|
|
|
this.dragData.offY = deltaY;
|
2008-06-21 11:51:41 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
this._updateCanvasPosition();
|
|
|
|
]]></body>
|
2008-05-06 07:56:21 -07:00
|
|
|
</method>
|
|
|
|
|
2008-06-21 11:51:41 -07:00
|
|
|
<method name="_dragStartTimer">
|
|
|
|
<body><![CDATA[
|
|
|
|
this.dragData.lastMouseEvent = Date.now() - 10;
|
|
|
|
this.dragData.dragging = true;
|
2008-07-04 00:33:05 -07:00
|
|
|
this._scrollStartTimeout = -1;
|
2008-06-21 11:51:41 -07:00
|
|
|
]]></body>
|
|
|
|
</method>
|
2008-05-17 23:35:30 -07:00
|
|
|
|
2008-06-24 18:03:37 -07:00
|
|
|
<method name="_endPan">
|
|
|
|
<body><![CDATA[
|
|
|
|
// update the pageX/Y coords
|
|
|
|
this.dragData.pageX += this.dragData.offX;
|
|
|
|
this.dragData.pageY += this.dragData.offY;
|
|
|
|
|
|
|
|
// relocate the canvas to 0x0 in the window
|
|
|
|
this.dragData.offX = 0;
|
|
|
|
this.dragData.offY = 0;
|
|
|
|
|
|
|
|
// update canvas position and draw the canvas at the new location
|
|
|
|
this._updateCanvasPosition();
|
|
|
|
this._browserToCanvas();
|
|
|
|
|
|
|
|
this.dragData.dragging = false;
|
|
|
|
]]></body>
|
|
|
|
</method>
|
|
|
|
|
2008-06-21 11:51:41 -07:00
|
|
|
<field name="stackEventHandler">
|
|
|
|
<![CDATA[
|
|
|
|
({
|
|
|
|
deckbrowser: this,
|
2008-05-20 12:58:10 -07:00
|
|
|
|
2008-06-21 11:51:41 -07:00
|
|
|
handleEvent: function seh_handleEvent(aEvent) {
|
|
|
|
if (!aEvent.type in this) {
|
|
|
|
dump("MouseController called with unknown event type " + aEvent.type + "\n");
|
2008-05-22 13:46:20 -07:00
|
|
|
return;
|
|
|
|
}
|
2008-06-21 11:51:41 -07:00
|
|
|
this[aEvent.type](aEvent);
|
|
|
|
},
|
|
|
|
|
|
|
|
mousedown: function seh_mousedown(aEvent) {
|
|
|
|
if (aEvent.button != 0)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
// cancel any pending canvas updates, since we're going to update again
|
|
|
|
if (this._updateTimeout)
|
|
|
|
clearTimeout(this._updateTimeout);
|
|
|
|
|
|
|
|
this.deckbrowser.dragData.canvasW = this.deckbrowser._canvas.width;
|
|
|
|
this.deckbrowser.dragData.canvasH = this.deckbrowser._canvas.height;
|
|
|
|
|
|
|
|
var cdoc = this.deckbrowser.browser.contentDocument;
|
|
|
|
var body = cdoc.body;
|
|
|
|
var html = cdoc.documentElement;
|
|
|
|
this.deckbrowser.dragData.scrollableWidth = Math.max(body.scrollWidth, html.scrollWidth);
|
|
|
|
this.deckbrowser.dragData.scrollableWidth *= this.deckbrowser._zoomLevel;
|
|
|
|
this.deckbrowser.dragData.scrollableHeight = Math.max(body.scrollHeight, html.scrollHeight);
|
|
|
|
this.deckbrowser.dragData.scrollableHeight *= this.deckbrowser._zoomLevel;
|
|
|
|
|
|
|
|
// The start of the current portion drag
|
|
|
|
this.deckbrowser.dragData.sX = aEvent.screenX;
|
|
|
|
this.deckbrowser.dragData.sY = aEvent.screenY;
|
|
|
|
|
|
|
|
// The total delta between current mouse position and sX/sY
|
|
|
|
this.deckbrowser.dragData.offX = 0;
|
|
|
|
this.deckbrowser.dragData.offY = 0;
|
|
|
|
|
|
|
|
//this.deckbrowser._updateCanvasPosition();
|
|
|
|
|
|
|
|
var self = this.deckbrowser;
|
|
|
|
this.deckbrowser._scrollStartTimeout = setTimeout(function () {
|
|
|
|
self._dragStartTimer();
|
|
|
|
}, 200);
|
|
|
|
},
|
|
|
|
|
|
|
|
mouseup: function seh_mouseup(aEvent) {
|
2008-06-24 18:03:37 -07:00
|
|
|
if (aEvent.button == 0 && this.deckbrowser.dragData.dragging) {
|
|
|
|
this.deckbrowser._endPan();
|
|
|
|
} else if (aEvent.originalTarget == this.deckbrowser._canvas) {
|
|
|
|
// Mouseup on canvas that isn't releasing from a drag
|
|
|
|
// cancel scrollStart timer
|
2008-06-21 11:51:41 -07:00
|
|
|
clearTimeout(this.deckbrowser._scrollStartTimeout);
|
2008-07-04 00:33:05 -07:00
|
|
|
this.deckbrowser._scrollStartTimeout = -1;
|
2008-06-21 11:51:41 -07:00
|
|
|
|
2008-06-24 18:03:37 -07:00
|
|
|
// send mousedown & mouseup
|
2008-06-21 11:51:41 -07:00
|
|
|
this.deckbrowser._redispatchMouseEvent(aEvent, "mousedown");
|
|
|
|
this.deckbrowser._redispatchMouseEvent(aEvent);
|
2008-05-08 15:59:16 -07:00
|
|
|
}
|
2008-06-21 11:51:41 -07:00
|
|
|
},
|
|
|
|
|
|
|
|
mousemove: function seh_mousemove(aEvent) {
|
2008-07-04 00:33:05 -07:00
|
|
|
if (!this.deckbrowser.dragData.dragging) {
|
|
|
|
// If we've moved more than N pixels lets go ahead and assume we're dragging
|
|
|
|
// and not wait for the timeout to complete.
|
|
|
|
if (this.deckbrowser._scrollStartTimeout != -1 &&
|
|
|
|
(Math.abs(this.deckbrowser.dragData.sX - aEvent.screenX) > 10 ||
|
|
|
|
Math.abs(this.deckbrowser.dragData.sY - aEvent.screenY) > 10)) {
|
|
|
|
clearTimeout(this.deckbrowser._scrollStartTimeout);
|
|
|
|
this.deckbrowser._dragStartTimer();
|
|
|
|
} else {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
2008-05-06 07:56:21 -07:00
|
|
|
|
2008-06-21 11:51:41 -07:00
|
|
|
var dx = aEvent.screenX - this.deckbrowser.dragData.sX;
|
|
|
|
var dy = aEvent.screenY - this.deckbrowser.dragData.sY;
|
|
|
|
|
|
|
|
this.deckbrowser._doPan(dx, dy);
|
|
|
|
|
|
|
|
if (Date.now() - this.deckbrowser.dragData.lastMouseEvent < 75) { // FIXME: make this a constant
|
|
|
|
//dump("dropping event\n");
|
|
|
|
return false;
|
2008-05-22 13:46:20 -07:00
|
|
|
}
|
|
|
|
|
2008-06-21 11:51:41 -07:00
|
|
|
this.deckbrowser.dragData.lastMouseEvent = Date.now();
|
|
|
|
|
|
|
|
aEvent.preventDefault();
|
|
|
|
return true;
|
|
|
|
},
|
|
|
|
|
|
|
|
DOMMouseScroll: function seh_DOMMouseScroll(aEvent) {
|
|
|
|
this.deckbrowser.zoom(aEvent.detail);
|
|
|
|
},
|
|
|
|
|
|
|
|
dblclick: function seh_dblclick(aEvent) {
|
|
|
|
//dump("Zooming...\n");
|
|
|
|
var x = aEvent.clientX;
|
|
|
|
var y = aEvent.clientY;
|
|
|
|
if (this.deckbrowser._zoomed) {
|
|
|
|
this.deckbrowser._zoomLevel = 1;
|
|
|
|
this.deckbrowser._zoomed = false;
|
|
|
|
} else {
|
|
|
|
this.deckbrowser._zoomLevel = 2;
|
|
|
|
this.deckbrowser._zoomed = true;
|
|
|
|
}
|
2008-05-22 13:46:20 -07:00
|
|
|
|
2008-06-21 11:51:41 -07:00
|
|
|
this.deckbrowser._browserToCanvas();
|
|
|
|
}
|
|
|
|
});
|
|
|
|
]]>
|
|
|
|
</field>
|
2008-04-18 06:41:49 -07:00
|
|
|
</implementation>
|
|
|
|
</binding>
|
|
|
|
|
|
|
|
</bindings>
|