mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
b6b202b6bb
The -*- file variable lines -*- establish per-file settings that Emacs will pick up. This patch makes the following changes to those lines (and touches nothing else): - Never set the buffer's mode. Years ago, Emacs did not have a good JavaScript mode, so it made sense to use Java or C++ mode in .js files. However, Emacs has had js-mode for years now; it's perfectly serviceable, and is available and enabled by default in all major Emacs packagings. Selecting a mode in the -*- file variable line -*- is almost always the wrong thing to do anyway. It overrides Emacs's default choice, which is (now) reasonable; and even worse, it overrides settings the user might have made in their '.emacs' file for that file extension. It's only useful when there's something specific about that particular file that makes a particular mode appropriate. - Correctly propagate settings that establish the correct indentation level for this file: c-basic-offset and js2-basic-offset should be js-indent-level. Whatever value they're given should be preserved; different parts of our tree use different indentation styles. - We don't use tabs in Mozilla JS code. Always set indent-tabs-mode: nil. Remove tab-width: settings, at least in files that don't contain tab characters. - Remove js2-mode settings that belong in the user's .emacs file, like js2-skip-preprocessor-directives.
342 lines
11 KiB
JavaScript
342 lines
11 KiB
JavaScript
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
|
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
|
|
let Cc = Components.classes;
|
|
let Ci = Components.interfaces;
|
|
let Cu = Components.utils;
|
|
|
|
Cu.import("resource://gre/modules/Services.jsm");
|
|
|
|
var global = this;
|
|
|
|
let ClickEventHandler = {
|
|
init: function init() {
|
|
this._scrollable = null;
|
|
this._scrolldir = "";
|
|
this._startX = null;
|
|
this._startY = null;
|
|
this._screenX = null;
|
|
this._screenY = null;
|
|
this._lastFrame = null;
|
|
|
|
Cc["@mozilla.org/eventlistenerservice;1"]
|
|
.getService(Ci.nsIEventListenerService)
|
|
.addSystemEventListener(global, "mousedown", this, true);
|
|
|
|
addMessageListener("Autoscroll:Stop", this);
|
|
},
|
|
|
|
isAutoscrollBlocker: function(node) {
|
|
let mmPaste = Services.prefs.getBoolPref("middlemouse.paste");
|
|
let mmScrollbarPosition = Services.prefs.getBoolPref("middlemouse.scrollbarPosition");
|
|
|
|
while (node) {
|
|
if ((node instanceof content.HTMLAnchorElement || node instanceof content.HTMLAreaElement) &&
|
|
node.hasAttribute("href")) {
|
|
return true;
|
|
}
|
|
|
|
if (mmPaste && (node instanceof content.HTMLInputElement ||
|
|
node instanceof content.HTMLTextAreaElement)) {
|
|
return true;
|
|
}
|
|
|
|
if (node instanceof content.XULElement && mmScrollbarPosition
|
|
&& (node.localName == "scrollbar" || node.localName == "scrollcorner")) {
|
|
return true;
|
|
}
|
|
|
|
node = node.parentNode;
|
|
}
|
|
return false;
|
|
},
|
|
|
|
startScroll: function(event) {
|
|
// this is a list of overflow property values that allow scrolling
|
|
const scrollingAllowed = ['scroll', 'auto'];
|
|
|
|
// go upward in the DOM and find any parent element that has a overflow
|
|
// area and can therefore be scrolled
|
|
for (this._scrollable = event.originalTarget; this._scrollable;
|
|
this._scrollable = this._scrollable.parentNode) {
|
|
// do not use overflow based autoscroll for <html> and <body>
|
|
// Elements or non-html elements such as svg or Document nodes
|
|
// also make sure to skip select elements that are not multiline
|
|
if (!(this._scrollable instanceof content.HTMLElement) ||
|
|
((this._scrollable instanceof content.HTMLSelectElement) && !this._scrollable.multiple)) {
|
|
continue;
|
|
}
|
|
|
|
var overflowx = this._scrollable.ownerDocument.defaultView
|
|
.getComputedStyle(this._scrollable, '')
|
|
.getPropertyValue('overflow-x');
|
|
var overflowy = this._scrollable.ownerDocument.defaultView
|
|
.getComputedStyle(this._scrollable, '')
|
|
.getPropertyValue('overflow-y');
|
|
// we already discarded non-multiline selects so allow vertical
|
|
// scroll for multiline ones directly without checking for a
|
|
// overflow property
|
|
var scrollVert = this._scrollable.scrollTopMax &&
|
|
(this._scrollable instanceof content.HTMLSelectElement ||
|
|
scrollingAllowed.indexOf(overflowy) >= 0);
|
|
|
|
// do not allow horizontal scrolling for select elements, it leads
|
|
// to visual artifacts and is not the expected behavior anyway
|
|
if (!(this._scrollable instanceof content.HTMLSelectElement) &&
|
|
this._scrollable.scrollLeftMax &&
|
|
scrollingAllowed.indexOf(overflowx) >= 0) {
|
|
this._scrolldir = scrollVert ? "NSEW" : "EW";
|
|
break;
|
|
} else if (scrollVert) {
|
|
this._scrolldir = "NS";
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!this._scrollable) {
|
|
this._scrollable = event.originalTarget.ownerDocument.defaultView;
|
|
if (this._scrollable.scrollMaxX > 0) {
|
|
this._scrolldir = this._scrollable.scrollMaxY > 0 ? "NSEW" : "EW";
|
|
} else if (this._scrollable.scrollMaxY > 0) {
|
|
this._scrolldir = "NS";
|
|
} else {
|
|
this._scrollable = null; // abort scrolling
|
|
return;
|
|
}
|
|
}
|
|
|
|
let [enabled] = sendSyncMessage("Autoscroll:Start",
|
|
{scrolldir: this._scrolldir,
|
|
screenX: event.screenX,
|
|
screenY: event.screenY});
|
|
if (!enabled) {
|
|
this._scrollable = null;
|
|
return;
|
|
}
|
|
|
|
Cc["@mozilla.org/eventlistenerservice;1"]
|
|
.getService(Ci.nsIEventListenerService)
|
|
.addSystemEventListener(global, "mousemove", this, true);
|
|
addEventListener("pagehide", this, true);
|
|
|
|
this._ignoreMouseEvents = true;
|
|
this._startX = event.screenX;
|
|
this._startY = event.screenY;
|
|
this._screenX = event.screenX;
|
|
this._screenY = event.screenY;
|
|
this._scrollErrorX = 0;
|
|
this._scrollErrorY = 0;
|
|
this._lastFrame = content.mozAnimationStartTime;
|
|
|
|
content.mozRequestAnimationFrame(this);
|
|
},
|
|
|
|
stopScroll: function() {
|
|
if (this._scrollable) {
|
|
this._scrollable = null;
|
|
|
|
Cc["@mozilla.org/eventlistenerservice;1"]
|
|
.getService(Ci.nsIEventListenerService)
|
|
.removeSystemEventListener(global, "mousemove", this, true);
|
|
removeEventListener("pagehide", this, true);
|
|
}
|
|
},
|
|
|
|
accelerate: function(curr, start) {
|
|
const speed = 12;
|
|
var val = (curr - start) / speed;
|
|
|
|
if (val > 1)
|
|
return val * Math.sqrt(val) - 1;
|
|
if (val < -1)
|
|
return val * Math.sqrt(-val) + 1;
|
|
return 0;
|
|
},
|
|
|
|
roundToZero: function(num) {
|
|
if (num > 0)
|
|
return Math.floor(num);
|
|
return Math.ceil(num);
|
|
},
|
|
|
|
autoscrollLoop: function(timestamp) {
|
|
if (!this._scrollable) {
|
|
// Scrolling has been canceled
|
|
return;
|
|
}
|
|
|
|
// avoid long jumps when the browser hangs for more than
|
|
// |maxTimeDelta| ms
|
|
const maxTimeDelta = 100;
|
|
var timeDelta = Math.min(maxTimeDelta, timestamp - this._lastFrame);
|
|
// we used to scroll |accelerate()| pixels every 20ms (50fps)
|
|
var timeCompensation = timeDelta / 20;
|
|
this._lastFrame = timestamp;
|
|
|
|
var actualScrollX = 0;
|
|
var actualScrollY = 0;
|
|
// don't bother scrolling vertically when the scrolldir is only horizontal
|
|
// and the other way around
|
|
if (this._scrolldir != 'EW') {
|
|
var y = this.accelerate(this._screenY, this._startY) * timeCompensation;
|
|
var desiredScrollY = this._scrollErrorY + y;
|
|
actualScrollY = this.roundToZero(desiredScrollY);
|
|
this._scrollErrorY = (desiredScrollY - actualScrollY);
|
|
}
|
|
if (this._scrolldir != 'NS') {
|
|
var x = this.accelerate(this._screenX, this._startX) * timeCompensation;
|
|
var desiredScrollX = this._scrollErrorX + x;
|
|
actualScrollX = this.roundToZero(desiredScrollX);
|
|
this._scrollErrorX = (desiredScrollX - actualScrollX);
|
|
}
|
|
|
|
if (this._scrollable instanceof content.Window) {
|
|
this._scrollable.scrollBy(actualScrollX, actualScrollY);
|
|
} else { // an element with overflow
|
|
this._scrollable.scrollLeft += actualScrollX;
|
|
this._scrollable.scrollTop += actualScrollY;
|
|
}
|
|
content.mozRequestAnimationFrame(this);
|
|
},
|
|
|
|
sample: function(timestamp) {
|
|
this.autoscrollLoop(timestamp);
|
|
},
|
|
|
|
handleEvent: function(event) {
|
|
if (event.type == "mousemove") {
|
|
this._screenX = event.screenX;
|
|
this._screenY = event.screenY;
|
|
} else if (event.type == "mousedown") {
|
|
if (event.isTrusted &
|
|
!event.defaultPrevented &&
|
|
event.button == 1 &&
|
|
!this._scrollable &&
|
|
!this.isAutoscrollBlocker(event.originalTarget)) {
|
|
this.startScroll(event);
|
|
}
|
|
} else if (event.type == "pagehide") {
|
|
if (this._scrollable) {
|
|
var doc =
|
|
this._scrollable.ownerDocument || this._scrollable.document;
|
|
if (doc == event.target) {
|
|
sendAsyncMessage("Autoscroll:Cancel");
|
|
}
|
|
}
|
|
}
|
|
},
|
|
|
|
receiveMessage: function(msg) {
|
|
switch (msg.name) {
|
|
case "Autoscroll:Stop": {
|
|
this.stopScroll();
|
|
break;
|
|
}
|
|
}
|
|
},
|
|
};
|
|
ClickEventHandler.init();
|
|
|
|
let PopupBlocking = {
|
|
popupData: null,
|
|
popupDataInternal: null,
|
|
|
|
init: function() {
|
|
addEventListener("DOMPopupBlocked", this, true);
|
|
addEventListener("pageshow", this, true);
|
|
addEventListener("pagehide", this, true);
|
|
|
|
addMessageListener("PopupBlocking:UnblockPopup", this);
|
|
},
|
|
|
|
receiveMessage: function(msg) {
|
|
switch (msg.name) {
|
|
case "PopupBlocking:UnblockPopup": {
|
|
let i = msg.data.index;
|
|
if (this.popupData && this.popupData[i]) {
|
|
let data = this.popupData[i];
|
|
let internals = this.popupDataInternal[i];
|
|
let dwi = internals.requestingWindow;
|
|
|
|
// If we have a requesting window and the requesting document is
|
|
// still the current document, open the popup.
|
|
if (dwi && dwi.document == internals.requestingDocument) {
|
|
dwi.open(data.popupWindowURI, data.popupWindowName, data.popupWindowFeatures);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
},
|
|
|
|
handleEvent: function(ev) {
|
|
switch (ev.type) {
|
|
case "DOMPopupBlocked":
|
|
return this.onPopupBlocked(ev);
|
|
case "pageshow":
|
|
return this.onPageShow(ev);
|
|
case "pagehide":
|
|
return this.onPageHide(ev);
|
|
}
|
|
},
|
|
|
|
onPopupBlocked: function(ev) {
|
|
if (!this.popupData) {
|
|
this.popupData = new Array();
|
|
this.popupDataInternal = new Array();
|
|
}
|
|
|
|
let obj = {
|
|
popupWindowURI: ev.popupWindowURI.spec,
|
|
popupWindowFeatures: ev.popupWindowFeatures,
|
|
popupWindowName: ev.popupWindowName
|
|
};
|
|
|
|
let internals = {
|
|
requestingWindow: ev.requestingWindow,
|
|
requestingDocument: ev.requestingWindow.document,
|
|
};
|
|
|
|
this.popupData.push(obj);
|
|
this.popupDataInternal.push(internals);
|
|
this.updateBlockedPopups(true);
|
|
},
|
|
|
|
onPageShow: function(ev) {
|
|
if (this.popupData) {
|
|
let i = 0;
|
|
while (i < this.popupData.length) {
|
|
// Filter out irrelevant reports.
|
|
if (this.popupDataInternal[i].requestingWindow &&
|
|
(this.popupDataInternal[i].requestingWindow.document ==
|
|
this.popupDataInternal[i].requestingDocument)) {
|
|
i++;
|
|
} else {
|
|
this.popupData.splice(i, 1);
|
|
this.popupDataInternal.splice(i, 1);
|
|
}
|
|
}
|
|
if (this.popupData.length == 0) {
|
|
this.popupData = null;
|
|
this.popupDataInternal = null;
|
|
}
|
|
this.updateBlockedPopups(false);
|
|
}
|
|
},
|
|
|
|
onPageHide: function(ev) {
|
|
if (this.popupData) {
|
|
this.popupData = null;
|
|
this.popupDataInternal = null;
|
|
this.updateBlockedPopups(false);
|
|
}
|
|
},
|
|
|
|
updateBlockedPopups: function(freshPopup) {
|
|
sendAsyncMessage("PopupBlocking:UpdateBlockedPopups",
|
|
{blockedPopups: this.popupData, freshPopup: freshPopup});
|
|
},
|
|
};
|
|
PopupBlocking.init(); |