зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1516266 - Part 2 - Unify the "arrowscrollbox" and "arrowscrollbox-clicktoscroll" bindings. r=bgrins
Differential Revision: https://phabricator.services.mozilla.com/D15302 --HG-- extra : rebase_source : 59943ee24426d39375b1d0eb7f0fc454ba6f00ab
This commit is contained in:
Родитель
357da38a59
Коммит
5dca426062
|
@ -9,7 +9,7 @@
|
||||||
xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
|
xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
|
||||||
xmlns:xbl="http://www.mozilla.org/xbl">
|
xmlns:xbl="http://www.mozilla.org/xbl">
|
||||||
|
|
||||||
<binding id="tabbrowser-arrowscrollbox" extends="chrome://global/content/bindings/scrollbox.xml#arrowscrollbox-clicktoscroll">
|
<binding id="tabbrowser-arrowscrollbox" extends="chrome://global/content/bindings/scrollbox.xml#arrowscrollbox">
|
||||||
<implementation>
|
<implementation>
|
||||||
<!-- Override scrollbox.xml method, since our scrollbox's children are
|
<!-- Override scrollbox.xml method, since our scrollbox's children are
|
||||||
inherited from the binding parent -->
|
inherited from the binding parent -->
|
||||||
|
|
|
@ -76,6 +76,49 @@
|
||||||
document.getAnonymousElementByAttribute(this, "anonid", "scrollbutton-down");
|
document.getAnonymousElementByAttribute(this, "anonid", "scrollbutton-down");
|
||||||
</field>
|
</field>
|
||||||
|
|
||||||
|
<field name="_scrollIndex">0</field>
|
||||||
|
|
||||||
|
<field name="_arrowScrollAnim"><![CDATA[({
|
||||||
|
scrollbox: this,
|
||||||
|
requestHandle: 0, /* 0 indicates there is no pending request */
|
||||||
|
start: function arrowSmoothScroll_start() {
|
||||||
|
this.lastFrameTime = window.performance.now();
|
||||||
|
if (!this.requestHandle)
|
||||||
|
this.requestHandle = window.requestAnimationFrame(this.sample.bind(this));
|
||||||
|
},
|
||||||
|
stop: function arrowSmoothScroll_stop() {
|
||||||
|
window.cancelAnimationFrame(this.requestHandle);
|
||||||
|
this.requestHandle = 0;
|
||||||
|
},
|
||||||
|
sample: function arrowSmoothScroll_handleEvent(timeStamp) {
|
||||||
|
const scrollIndex = this.scrollbox._scrollIndex;
|
||||||
|
const timePassed = timeStamp - this.lastFrameTime;
|
||||||
|
this.lastFrameTime = timeStamp;
|
||||||
|
|
||||||
|
const scrollDelta = 0.5 * timePassed * scrollIndex;
|
||||||
|
this.scrollbox.scrollByPixels(scrollDelta, true);
|
||||||
|
this.requestHandle = window.requestAnimationFrame(this.sample.bind(this));
|
||||||
|
},
|
||||||
|
})]]></field>
|
||||||
|
|
||||||
|
<property name="_clickToScroll" readonly="true">
|
||||||
|
<getter><![CDATA[
|
||||||
|
return this.hasAttribute("clicktoscroll");
|
||||||
|
]]></getter>
|
||||||
|
</property>
|
||||||
|
|
||||||
|
<property name="_scrollDelay" readonly="true">
|
||||||
|
<getter><![CDATA[
|
||||||
|
if (this._clickToScroll) {
|
||||||
|
return this._prefBranch.getIntPref(
|
||||||
|
"toolkit.scrollbox.clickToScroll.scrollDelay", 150);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Use the same REPEAT_DELAY as "nsRepeatService.h".
|
||||||
|
return /Mac/.test(navigator.platform) ? 25 : 50;
|
||||||
|
]]></getter>
|
||||||
|
</property>
|
||||||
|
|
||||||
<field name="__prefBranch">null</field>
|
<field name="__prefBranch">null</field>
|
||||||
<property name="_prefBranch" readonly="true">
|
<property name="_prefBranch" readonly="true">
|
||||||
<getter><![CDATA[
|
<getter><![CDATA[
|
||||||
|
@ -167,6 +210,9 @@
|
||||||
<method name="_onButtonClick">
|
<method name="_onButtonClick">
|
||||||
<parameter name="event"/>
|
<parameter name="event"/>
|
||||||
<body><![CDATA[
|
<body><![CDATA[
|
||||||
|
if (this._clickToScroll) {
|
||||||
|
this._distanceScroll(event);
|
||||||
|
}
|
||||||
]]></body>
|
]]></body>
|
||||||
</method>
|
</method>
|
||||||
|
|
||||||
|
@ -174,26 +220,40 @@
|
||||||
<parameter name="event"/>
|
<parameter name="event"/>
|
||||||
<parameter name="index"/>
|
<parameter name="index"/>
|
||||||
<body><![CDATA[
|
<body><![CDATA[
|
||||||
|
if (this._clickToScroll && event.button == 0) {
|
||||||
|
this._startScroll(index);
|
||||||
|
}
|
||||||
]]></body>
|
]]></body>
|
||||||
</method>
|
</method>
|
||||||
|
|
||||||
<method name="_onButtonMouseUp">
|
<method name="_onButtonMouseUp">
|
||||||
<parameter name="event"/>
|
<parameter name="event"/>
|
||||||
<body><![CDATA[
|
<body><![CDATA[
|
||||||
|
if (this._clickToScroll && event.button == 0) {
|
||||||
|
this._stopScroll();
|
||||||
|
}
|
||||||
]]></body>
|
]]></body>
|
||||||
</method>
|
</method>
|
||||||
|
|
||||||
<method name="_onButtonMouseOver">
|
<method name="_onButtonMouseOver">
|
||||||
<parameter name="index"/>
|
<parameter name="index"/>
|
||||||
<body><![CDATA[
|
<body><![CDATA[
|
||||||
|
if (this._clickToScroll) {
|
||||||
|
this._continueScroll(index);
|
||||||
|
} else {
|
||||||
this._startScroll(index);
|
this._startScroll(index);
|
||||||
|
}
|
||||||
]]></body>
|
]]></body>
|
||||||
</method>
|
</method>
|
||||||
|
|
||||||
<method name="_onButtonMouseOut">
|
<method name="_onButtonMouseOut">
|
||||||
<parameter name="index"/>
|
<parameter name="index"/>
|
||||||
<body><![CDATA[
|
<body><![CDATA[
|
||||||
|
if (this._clickToScroll) {
|
||||||
|
this._pauseScroll();
|
||||||
|
} else {
|
||||||
this._stopScroll();
|
this._stopScroll();
|
||||||
|
}
|
||||||
]]></body>
|
]]></body>
|
||||||
</method>
|
</method>
|
||||||
|
|
||||||
|
@ -347,19 +407,37 @@
|
||||||
index *= -1;
|
index *= -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (this._clickToScroll) {
|
||||||
|
this._scrollIndex = index;
|
||||||
|
this._mousedown = true;
|
||||||
|
|
||||||
|
if (this.smoothScroll) {
|
||||||
|
this._arrowScrollAnim.start();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!this._scrollTimer) {
|
if (!this._scrollTimer) {
|
||||||
this._scrollTimer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
|
this._scrollTimer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
|
||||||
} else {
|
} else {
|
||||||
this._scrollTimer.cancel();
|
this._scrollTimer.cancel();
|
||||||
}
|
}
|
||||||
|
|
||||||
let callback = () => this.scrollByPixels(this.scrollIncrement * index);
|
let callback;
|
||||||
|
if (this._clickToScroll) {
|
||||||
|
callback = () => {
|
||||||
|
if (!document && this._scrollTimer) {
|
||||||
|
this._scrollTimer.cancel();
|
||||||
|
}
|
||||||
|
this.scrollByIndex(this._scrollIndex);
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
callback = () => this.scrollByPixels(this.scrollIncrement * index);
|
||||||
|
}
|
||||||
|
|
||||||
// Use the same REPEAT_DELAY as "nsRepeatService.h".
|
this._scrollTimer.initWithCallback(callback, this._scrollDelay,
|
||||||
let scrollDelay = /Mac/.test(navigator.platform) ? 25 : 50;
|
|
||||||
|
|
||||||
this._scrollTimer.initWithCallback(callback, scrollDelay,
|
|
||||||
Ci.nsITimer.TYPE_REPEATING_SLACK);
|
Ci.nsITimer.TYPE_REPEATING_SLACK);
|
||||||
|
|
||||||
callback();
|
callback();
|
||||||
]]>
|
]]>
|
||||||
</body>
|
</body>
|
||||||
|
@ -369,6 +447,88 @@
|
||||||
<body><![CDATA[
|
<body><![CDATA[
|
||||||
if (this._scrollTimer)
|
if (this._scrollTimer)
|
||||||
this._scrollTimer.cancel();
|
this._scrollTimer.cancel();
|
||||||
|
|
||||||
|
if (this._clickToScroll) {
|
||||||
|
this._mousedown = false;
|
||||||
|
if (!this._scrollIndex || !this.smoothScroll)
|
||||||
|
return;
|
||||||
|
|
||||||
|
this.scrollByIndex(this._scrollIndex);
|
||||||
|
this._scrollIndex = 0;
|
||||||
|
|
||||||
|
this._arrowScrollAnim.stop();
|
||||||
|
}
|
||||||
|
]]></body>
|
||||||
|
</method>
|
||||||
|
|
||||||
|
<method name="_pauseScroll">
|
||||||
|
<body><![CDATA[
|
||||||
|
if (this._mousedown) {
|
||||||
|
this._stopScroll();
|
||||||
|
this._mousedown = true;
|
||||||
|
document.addEventListener("mouseup", this);
|
||||||
|
document.addEventListener("blur", this, true);
|
||||||
|
}
|
||||||
|
]]></body>
|
||||||
|
</method>
|
||||||
|
|
||||||
|
<method name="_continueScroll">
|
||||||
|
<parameter name="index"/>
|
||||||
|
<body><![CDATA[
|
||||||
|
if (this._mousedown)
|
||||||
|
this._startScroll(index);
|
||||||
|
]]></body>
|
||||||
|
</method>
|
||||||
|
|
||||||
|
<method name="_distanceScroll">
|
||||||
|
<parameter name="aEvent"/>
|
||||||
|
<body><![CDATA[
|
||||||
|
if (aEvent.detail < 2 || aEvent.detail > 3)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var scrollBack = (aEvent.originalTarget == this._scrollButtonUp);
|
||||||
|
var scrollLeftOrUp = this._isRTLScrollbox ? !scrollBack : scrollBack;
|
||||||
|
var targetElement;
|
||||||
|
|
||||||
|
if (aEvent.detail == 2) {
|
||||||
|
// scroll by the size of the scrollbox
|
||||||
|
let [start, end] = this._startEndProps;
|
||||||
|
let x;
|
||||||
|
if (scrollLeftOrUp)
|
||||||
|
x = this.scrollClientRect[start] - this.scrollClientSize;
|
||||||
|
else
|
||||||
|
x = this.scrollClientRect[end] + this.scrollClientSize;
|
||||||
|
targetElement = this._elementFromPoint(x, scrollLeftOrUp ? -1 : 1);
|
||||||
|
|
||||||
|
// the next partly-hidden element will become fully visible,
|
||||||
|
// so don't scroll too far
|
||||||
|
if (targetElement)
|
||||||
|
targetElement = scrollBack ?
|
||||||
|
targetElement.nextElementSibling :
|
||||||
|
targetElement.previousElementSibling;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!targetElement) {
|
||||||
|
// scroll to the first resp. last element
|
||||||
|
let elements = this._getScrollableElements();
|
||||||
|
targetElement = scrollBack ?
|
||||||
|
elements[0] :
|
||||||
|
elements[elements.length - 1];
|
||||||
|
}
|
||||||
|
|
||||||
|
this.ensureElementIsVisible(targetElement);
|
||||||
|
]]></body>
|
||||||
|
</method>
|
||||||
|
|
||||||
|
<method name="handleEvent">
|
||||||
|
<parameter name="aEvent"/>
|
||||||
|
<body><![CDATA[
|
||||||
|
if (aEvent.type == "mouseup" ||
|
||||||
|
aEvent.type == "blur" && aEvent.target == document) {
|
||||||
|
this._mousedown = false;
|
||||||
|
document.removeEventListener("mouseup", this);
|
||||||
|
document.removeEventListener("blur", this, true);
|
||||||
|
}
|
||||||
]]></body>
|
]]></body>
|
||||||
</method>
|
</method>
|
||||||
|
|
||||||
|
@ -618,208 +778,4 @@
|
||||||
]]></handler>
|
]]></handler>
|
||||||
</handlers>
|
</handlers>
|
||||||
</binding>
|
</binding>
|
||||||
|
|
||||||
<binding id="arrowscrollbox-clicktoscroll" extends="chrome://global/content/bindings/scrollbox.xml#arrowscrollbox">
|
|
||||||
<implementation>
|
|
||||||
<constructor><![CDATA[
|
|
||||||
this._scrollDelay =
|
|
||||||
this._prefBranch.getIntPref("toolkit.scrollbox.clickToScroll.scrollDelay",
|
|
||||||
this._scrollDelay);
|
|
||||||
]]></constructor>
|
|
||||||
|
|
||||||
<destructor><![CDATA[
|
|
||||||
// Release timer to avoid reference cycles.
|
|
||||||
if (this._scrollTimer) {
|
|
||||||
this._scrollTimer.cancel();
|
|
||||||
this._scrollTimer = null;
|
|
||||||
}
|
|
||||||
]]></destructor>
|
|
||||||
|
|
||||||
<field name="_scrollIndex">0</field>
|
|
||||||
<field name="_scrollDelay">150</field>
|
|
||||||
|
|
||||||
<field name="_arrowScrollAnim"><![CDATA[({
|
|
||||||
scrollbox: this,
|
|
||||||
requestHandle: 0, /* 0 indicates there is no pending request */
|
|
||||||
start: function arrowSmoothScroll_start() {
|
|
||||||
this.lastFrameTime = window.performance.now();
|
|
||||||
if (!this.requestHandle)
|
|
||||||
this.requestHandle = window.requestAnimationFrame(this.sample.bind(this));
|
|
||||||
},
|
|
||||||
stop: function arrowSmoothScroll_stop() {
|
|
||||||
window.cancelAnimationFrame(this.requestHandle);
|
|
||||||
this.requestHandle = 0;
|
|
||||||
},
|
|
||||||
sample: function arrowSmoothScroll_handleEvent(timeStamp) {
|
|
||||||
const scrollIndex = this.scrollbox._scrollIndex;
|
|
||||||
const timePassed = timeStamp - this.lastFrameTime;
|
|
||||||
this.lastFrameTime = timeStamp;
|
|
||||||
|
|
||||||
const scrollDelta = 0.5 * timePassed * scrollIndex;
|
|
||||||
this.scrollbox.scrollByPixels(scrollDelta, true);
|
|
||||||
this.requestHandle = window.requestAnimationFrame(this.sample.bind(this));
|
|
||||||
},
|
|
||||||
})]]></field>
|
|
||||||
|
|
||||||
<method name="_onButtonClick">
|
|
||||||
<parameter name="event"/>
|
|
||||||
<body><![CDATA[
|
|
||||||
this._distanceScroll(event);
|
|
||||||
]]></body>
|
|
||||||
</method>
|
|
||||||
|
|
||||||
<method name="_onButtonMouseDown">
|
|
||||||
<parameter name="event"/>
|
|
||||||
<parameter name="index"/>
|
|
||||||
<body><![CDATA[
|
|
||||||
if (event.button == 0) {
|
|
||||||
this._startScroll(index);
|
|
||||||
}
|
|
||||||
]]></body>
|
|
||||||
</method>
|
|
||||||
|
|
||||||
<method name="_onButtonMouseUp">
|
|
||||||
<parameter name="event"/>
|
|
||||||
<body><![CDATA[
|
|
||||||
if (event.button == 0) {
|
|
||||||
this._stopScroll();
|
|
||||||
}
|
|
||||||
]]></body>
|
|
||||||
</method>
|
|
||||||
|
|
||||||
<method name="_onButtonMouseOver">
|
|
||||||
<parameter name="index"/>
|
|
||||||
<body><![CDATA[
|
|
||||||
this._continueScroll(index);
|
|
||||||
]]></body>
|
|
||||||
</method>
|
|
||||||
|
|
||||||
<method name="_onButtonMouseOut">
|
|
||||||
<body><![CDATA[
|
|
||||||
this._pauseScroll();
|
|
||||||
]]></body>
|
|
||||||
</method>
|
|
||||||
|
|
||||||
<method name="_startScroll">
|
|
||||||
<parameter name="index"/>
|
|
||||||
<body><![CDATA[
|
|
||||||
if (this._isRTLScrollbox)
|
|
||||||
index *= -1;
|
|
||||||
this._scrollIndex = index;
|
|
||||||
this._mousedown = true;
|
|
||||||
|
|
||||||
if (this.smoothScroll) {
|
|
||||||
this._arrowScrollAnim.start();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!this._scrollTimer)
|
|
||||||
this._scrollTimer =
|
|
||||||
Cc["@mozilla.org/timer;1"]
|
|
||||||
.createInstance(Ci.nsITimer);
|
|
||||||
else
|
|
||||||
this._scrollTimer.cancel();
|
|
||||||
|
|
||||||
let callback = () => {
|
|
||||||
if (!document && this._scrollTimer) {
|
|
||||||
this._scrollTimer.cancel();
|
|
||||||
}
|
|
||||||
this.scrollByIndex(this._scrollIndex);
|
|
||||||
};
|
|
||||||
|
|
||||||
this._scrollTimer.initWithCallback(callback, this._scrollDelay,
|
|
||||||
this._scrollTimer.TYPE_REPEATING_SLACK);
|
|
||||||
callback();
|
|
||||||
]]>
|
|
||||||
</body>
|
|
||||||
</method>
|
|
||||||
|
|
||||||
<method name="_stopScroll">
|
|
||||||
<body><![CDATA[
|
|
||||||
if (this._scrollTimer)
|
|
||||||
this._scrollTimer.cancel();
|
|
||||||
this._mousedown = false;
|
|
||||||
if (!this._scrollIndex || !this.smoothScroll)
|
|
||||||
return;
|
|
||||||
|
|
||||||
this.scrollByIndex(this._scrollIndex);
|
|
||||||
this._scrollIndex = 0;
|
|
||||||
|
|
||||||
this._arrowScrollAnim.stop();
|
|
||||||
]]></body>
|
|
||||||
</method>
|
|
||||||
|
|
||||||
<method name="_pauseScroll">
|
|
||||||
<body><![CDATA[
|
|
||||||
if (this._mousedown) {
|
|
||||||
this._stopScroll();
|
|
||||||
this._mousedown = true;
|
|
||||||
document.addEventListener("mouseup", this);
|
|
||||||
document.addEventListener("blur", this, true);
|
|
||||||
}
|
|
||||||
]]></body>
|
|
||||||
</method>
|
|
||||||
|
|
||||||
<method name="_continueScroll">
|
|
||||||
<parameter name="index"/>
|
|
||||||
<body><![CDATA[
|
|
||||||
if (this._mousedown)
|
|
||||||
this._startScroll(index);
|
|
||||||
]]></body>
|
|
||||||
</method>
|
|
||||||
|
|
||||||
<method name="handleEvent">
|
|
||||||
<parameter name="aEvent"/>
|
|
||||||
<body><![CDATA[
|
|
||||||
if (aEvent.type == "mouseup" ||
|
|
||||||
aEvent.type == "blur" && aEvent.target == document) {
|
|
||||||
this._mousedown = false;
|
|
||||||
document.removeEventListener("mouseup", this);
|
|
||||||
document.removeEventListener("blur", this, true);
|
|
||||||
}
|
|
||||||
]]></body>
|
|
||||||
</method>
|
|
||||||
|
|
||||||
<method name="_distanceScroll">
|
|
||||||
<parameter name="aEvent"/>
|
|
||||||
<body><![CDATA[
|
|
||||||
if (aEvent.detail < 2 || aEvent.detail > 3)
|
|
||||||
return;
|
|
||||||
|
|
||||||
var scrollBack = (aEvent.originalTarget == this._scrollButtonUp);
|
|
||||||
var scrollLeftOrUp = this._isRTLScrollbox ? !scrollBack : scrollBack;
|
|
||||||
var targetElement;
|
|
||||||
|
|
||||||
if (aEvent.detail == 2) {
|
|
||||||
// scroll by the size of the scrollbox
|
|
||||||
let [start, end] = this._startEndProps;
|
|
||||||
let x;
|
|
||||||
if (scrollLeftOrUp)
|
|
||||||
x = this.scrollClientRect[start] - this.scrollClientSize;
|
|
||||||
else
|
|
||||||
x = this.scrollClientRect[end] + this.scrollClientSize;
|
|
||||||
targetElement = this._elementFromPoint(x, scrollLeftOrUp ? -1 : 1);
|
|
||||||
|
|
||||||
// the next partly-hidden element will become fully visible,
|
|
||||||
// so don't scroll too far
|
|
||||||
if (targetElement)
|
|
||||||
targetElement = scrollBack ?
|
|
||||||
targetElement.nextElementSibling :
|
|
||||||
targetElement.previousElementSibling;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!targetElement) {
|
|
||||||
// scroll to the first resp. last element
|
|
||||||
let elements = this._getScrollableElements();
|
|
||||||
targetElement = scrollBack ?
|
|
||||||
elements[0] :
|
|
||||||
elements[elements.length - 1];
|
|
||||||
}
|
|
||||||
|
|
||||||
this.ensureElementIsVisible(targetElement);
|
|
||||||
]]></body>
|
|
||||||
</method>
|
|
||||||
|
|
||||||
</implementation>
|
|
||||||
</binding>
|
|
||||||
</bindings>
|
</bindings>
|
||||||
|
|
|
@ -678,10 +678,6 @@ arrowscrollbox {
|
||||||
-moz-binding: url("chrome://global/content/bindings/scrollbox.xml#arrowscrollbox");
|
-moz-binding: url("chrome://global/content/bindings/scrollbox.xml#arrowscrollbox");
|
||||||
}
|
}
|
||||||
|
|
||||||
arrowscrollbox[clicktoscroll="true"] {
|
|
||||||
-moz-binding: url("chrome://global/content/bindings/scrollbox.xml#arrowscrollbox-clicktoscroll");
|
|
||||||
}
|
|
||||||
|
|
||||||
/********** stringbundle **********/
|
/********** stringbundle **********/
|
||||||
|
|
||||||
stringbundle,
|
stringbundle,
|
||||||
|
|
Загрузка…
Ссылка в новой задаче