--- a/toolkit/content/browser-content.js
+++ b/toolkit/content/browser-content.js
@@ -1718,28 +1718,32 @@ let DateTimePickerListener = {
/**
* Called after picker is opened to start listening for input box update
* events.
*/
addListeners() {
addEventListener("MozUpdateDateTimePicker", this);
addEventListener("MozCloseDateTimePicker", this);
addEventListener("pagehide", this);
+ addEventListener("TextZoomChange", this);
+ addEventListener("FullZoomChange", this);
addMessageListener("FormDateTime:PickerValueChanged", this);
addMessageListener("FormDateTime:PickerClosed", this);
},
/**
* Stop listeneing for events when picker is closed.
*/
removeListeners() {
removeEventListener("MozUpdateDateTimePicker", this);
removeEventListener("MozCloseDateTimePicker", this);
removeEventListener("pagehide", this);
+ removeEventListener("TextZoomChange", this);
+ removeEventListener("FullZoomChange", this);
removeMessageListener("FormDateTime:PickerValueChanged", this);
removeMessageListener("FormDateTime:PickerClosed", this);
},
/**
* Helper function that returns the CSS direction property of the element.
*/
@@ -1826,16 +1830,24 @@ let DateTimePickerListener = {
case "pagehide": {
if (this._inputElement &&
this._inputElement.ownerDocument == aEvent.target) {
sendAsyncMessage("FormDateTime:ClosePicker");
this.close();
}
break;
}
+ case "TextZoomChange": {
+ sendAsyncMessage("FormDateTime:SetZoom");
+ break;
+ }
+ case "FullZoomChange": {
+ sendAsyncMessage("FormDateTime:SetZoom");
+ break;
+ }
default:
break;
}
},
}
DateTimePickerListener.init();
--- a/toolkit/content/widgets/datepicker.js
+++ b/toolkit/content/widgets/datepicker.js
@@ -43,27 +43,29 @@ function DatePicker(context) {
document.dispatchEvent(new CustomEvent("PickerReady"));
},
/*
* Set initial date picker states.
*/
_setDefaultState() {
const { year, month, day, min, max, step, stepBase, firstDayOfWeek, weekends,
- monthStrings, weekdayStrings, locale, dir } = this.props;
+ monthStrings, weekdayStrings, locale, dir, zoom } = this.props;
const dateKeeper = new DateKeeper({
year, month, day, min, max, step, stepBase, firstDayOfWeek, weekends,
calViewSize: CAL_VIEW_SIZE
});
document.dir = dir;
this.state = {
dateKeeper,
locale,
+ zoom,
+ textSize: 10,
isMonthPickerVisible: false,
datetimeOrders: new Intl.DateTimeFormat(locale)
.formatToParts(new Date(0)).map(part => part.type),
getDayString: day => day ? new Intl.NumberFormat(locale).format(day) : "",
getWeekHeaderString: weekday => weekdayStrings[weekday],
getMonthString: month => monthStrings[month],
setSelection: date => {
dateKeeper.setSelection({
@@ -117,43 +119,47 @@ function DatePicker(context) {
weekHeader: this.context.weekHeader,
daysView: this.context.daysView
}),
monthYear: new MonthYear({
setYear: this.state.setYear,
setMonth: this.state.setMonth,
getMonthString: this.state.getMonthString,
datetimeOrders: this.state.datetimeOrders,
- locale: this.state.locale
+ locale: this.state.locale,
+ rootFontSize: this.state.textSize * this.state.zoom,
}, {
monthYear: this.context.monthYear,
monthYearView: this.context.monthYearView
})
};
},
/**
* Update date picker and its components.
*/
_update() {
- const { dateKeeper, isMonthPickerVisible } = this.state;
+ const { dateKeeper, isMonthPickerVisible, zoom } = this.state;
if (isMonthPickerVisible) {
this.state.months = dateKeeper.getMonths();
this.state.years = dateKeeper.getYears();
} else {
this.state.days = dateKeeper.getDays();
}
+ this.zoom({ zoom });
+
this.components.monthYear.setProps({
isVisible: isMonthPickerVisible,
dateObj: dateKeeper.state.dateObj,
months: this.state.months,
years: this.state.years,
- toggleMonthPicker: this.state.toggleMonthPicker
+ toggleMonthPicker: this.state.toggleMonthPicker,
+ rootFontSize: this.state.zoom * this.state.textSize,
});
this.components.calendar.setProps({
isVisible: !isMonthPickerVisible,
days: this.state.days,
weekHeaders: dateKeeper.state.weekHeaders
});
isMonthPickerVisible ?
@@ -242,16 +248,20 @@ function DatePicker(context) {
case "PickerSetValue": {
this.set(event.data.detail);
break;
}
case "PickerInit": {
this.init(event.data.detail);
break;
}
+ case "PickerZoom": {
+ this.zoom(event.data.detail);
+ break;
+ }
}
},
/**
* Set the date state and update the components with the new state.
*
* @param {Object} dateState
* {
@@ -265,17 +275,22 @@ function DatePicker(context) {
dateKeeper.setCalendarMonth({
year, month
});
dateKeeper.setSelection({
year, month, day
});
this._update();
- }
+ },
+
+ zoom({ zoom }) {
+ this.state.zoom = zoom;
+ document.documentElement.style.fontSize = this.state.textSize * zoom + "px";
+ },
};
/**
* MonthYear is a component that handles the month & year spinners
*
* @param {Object} options
* {
* {String} locale
@@ -305,26 +320,28 @@ function DatePicker(context) {
this.components = {
month: new Spinner({
id: "spinner-month",
setValue: month => {
this.state.isMonthSet = true;
options.setMonth(month);
},
getDisplayString: options.getMonthString,
- viewportSize: spinnerSize
+ viewportSize: spinnerSize,
+ rootFontSize: options.rootFontSize,
}, context.monthYearView),
year: new Spinner({
id: "spinner-year",
setValue: year => {
this.state.isYearSet = true;
options.setYear(year);
},
getDisplayString: year => yearFormat(new Date(new Date(0).setUTCFullYear(year))),
- viewportSize: spinnerSize
+ viewportSize: spinnerSize,
+ rootFontSize: options.rootFontSize,
}, context.monthYearView)
};
this._attachEventListeners();
}
MonthYear.prototype = {
@@ -345,23 +362,25 @@ function DatePicker(context) {
if (props.isVisible) {
this.context.monthYear.classList.add("active");
this.components.month.setState({
value: props.dateObj.getUTCMonth(),
items: props.months,
isInfiniteScroll: true,
isValueSet: this.state.isMonthSet,
+ rootFontSize: props.rootFontSize,
smoothScroll: !this.state.firstOpened
});
this.components.year.setState({
value: props.dateObj.getUTCFullYear(),
items: props.years,
isInfiniteScroll: false,
isValueSet: this.state.isYearSet,
+ rootFontSize: props.rootFontSize,
smoothScroll: !this.state.firstOpened
});
this.state.firstOpened = false;
} else {
this.context.monthYear.classList.remove("active");
this.state.isMonthSet = false;
this.state.isYearSet = false;
this.state.firstOpened = true;
--- a/toolkit/content/widgets/datetimepopup.xml
+++ b/toolkit/content/widgets/datetimepopup.xml
@@ -21,35 +21,37 @@
if (!frame) {
frame = this.ownerDocument.createElement("iframe");
frame.id = "dateTimePopupFrame";
this.appendChild(frame);
}
return frame;
</getter>
</property>
+ <field name="zoom">1</field>
<field name="TIME_PICKER_WIDTH" readonly="true">"12em"</field>
<field name="TIME_PICKER_HEIGHT" readonly="true">"21em"</field>
<field name="DATE_PICKER_WIDTH" readonly="true">"23.1em"</field>
<field name="DATE_PICKER_HEIGHT" readonly="true">"20.7em"</field>
<constructor><![CDATA[
this.mozIntl = Components.classes["@mozilla.org/mozintl;1"]
.getService(Components.interfaces.mozIMozIntl);
// Notify DateTimePickerHelper.jsm that binding is ready.
this.dispatchEvent(new CustomEvent("DateTimePickerBindingReady"));
]]></constructor>
<method name="openPicker">
<parameter name="type"/>
<parameter name="anchor"/>
<parameter name="detail"/>
+ <parameter name="zoom"/>
<body><![CDATA[
this.type = type;
this.pickerState = {};
- // TODO: Resize picker according to content zoom level
- this.style.fontSize = "10px";
+ this.zoom = zoom;
+ this.style.fontSize = zoom * 10 + "px";
switch (type) {
case "time": {
this.detail = detail;
this.dateTimePopupFrame.addEventListener("load", this, true);
this.dateTimePopupFrame.setAttribute("src", "chrome://global/content/timepicker.xhtml");
this.dateTimePopupFrame.style.width = this.TIME_PICKER_WIDTH;
this.dateTimePopupFrame.style.height = this.TIME_PICKER_HEIGHT;
break;
@@ -171,16 +173,17 @@
month: month == undefined ? undefined : month - 1,
day,
firstDayOfWeek,
weekends,
monthStrings,
weekdayStrings,
locale,
dir,
+ zoom: this.zoom,
min: detail.min,
max: detail.max,
step: detail.step,
stepBase: detail.stepBase,
}
});
break;
}
@@ -209,16 +212,29 @@
}
case "date": {
this.sendPickerValueChanged(this.pickerState);
break;
}
}
]]></body>
</method>
+ <method name="setZoom">
+ <parameter name="zoom"/>
+ <body><![CDATA[
+ this.zoom = zoom;
+ this.style.fontSize = zoom * 10 + "px";
+ this.postMessageToPicker({
+ name: "PickerZoom",
+ detail: {
+ zoom,
+ }
+ });
+ ]]></body>
+ </method>
<method name="sendPickerValueChanged">
<parameter name="value"/>
<body><![CDATA[
switch (this.type) {
case "time": {
this.dispatchEvent(new CustomEvent("DateTimePickerValueChanged", {
detail: {
hour: value.hour,
--- a/toolkit/content/widgets/spinner.js
+++ b/toolkit/content/widgets/spinner.js
@@ -48,20 +48,21 @@ function Spinner(props, context) {
const spinnerElement = document.importNode(spinnerTemplate.content, true);
// Make sure viewportSize is an odd number because we want to have the selected
// item in the center. If it's an even number, use the default size instead.
const viewportSize = props.viewportSize % 2 ? props.viewportSize : VIEWPORT_SIZE;
this.state = {
items: [],
- isScrolling: false
+ isScrolling: false,
+ rootFontSize,
};
this.props = {
- setValue, getDisplayString, viewportSize, rootFontSize,
+ setValue, getDisplayString, viewportSize,
// We can assume that the viewportSize is an odd number. Calculate how many
// items we need to insert on top of the spinner so that the selected is at
// the center. Ex: if viewportSize is 5, we need 2 items on top.
viewportTopOffset: (viewportSize - 1) / 2
};
this.elements = {
container: spinnerElement.querySelector(".spinner-container"),
spinner: spinnerElement.querySelector(".spinner"),
@@ -358,17 +359,17 @@ function Spinner(props, context) {
},
/**
* Find the index by offset
* @param {Number} offset: Offset value in pixel.
* @return {Number} Index number
*/
_getIndexByOffset(offset) {
- return Math.round(offset / (ITEM_HEIGHT * this.props.rootFontSize));
+ return Math.round(offset / (ITEM_HEIGHT * this.state.rootFontSize));
},
/**
* Find the index of a value that is the closest to the current position.
* If centering is true, find the index closest to the center.
*
* @param {Number/String} value: The value to find
* @param {Boolean} centering: Whether or not to find the value closest to center
@@ -413,17 +414,17 @@ function Spinner(props, context) {
* @param {Number/String} value: Value to scroll to
* @param {Boolean} centering: Whether or not to scroll to center location
*/
_scrollTo(value, centering) {
const index = this._getScrollIndex(value, centering);
// Do nothing if the value is not found
if (index > -1) {
this.state.index = index;
- this.elements.spinner.scrollTop = this.state.index * ITEM_HEIGHT * this.props.rootFontSize;
+ this.elements.spinner.scrollTop = this.state.index * ITEM_HEIGHT * this.state.rootFontSize;
}
},
/**
* Smooth scroll to a value.
*
* @param {Number/String} value: Value to scroll to
*/
--- a/toolkit/modules/DateTimePickerHelper.jsm
+++ b/toolkit/modules/DateTimePickerHelper.jsm
@@ -30,17 +30,18 @@ Cu.import("resource://gre/modules/Servic
*/
this.DateTimePickerHelper = {
picker: null,
weakBrowser: null,
MESSAGES: [
"FormDateTime:OpenPicker",
"FormDateTime:ClosePicker",
- "FormDateTime:UpdatePicker"
+ "FormDateTime:UpdatePicker",
+ "FormDateTime:SetZoom",
],
init() {
for (let msg of this.MESSAGES) {
Services.mm.addMessageListener(msg, this);
}
},
@@ -67,16 +68,21 @@ this.DateTimePickerHelper = {
}
case "FormDateTime:UpdatePicker": {
if (!this.picker) {
return;
}
this.picker.setPopupValue(aMessage.data);
break;
}
+ case "FormDateTime:SetZoom": {
+ debug("zoom: " + this.getZoom(aMessage.target));
+ this.picker.setZoom(this.getZoom(aMessage.target));
+ break;
+ }
default:
break;
}
},
// nsIDOMEventListener
handleEvent(aEvent) {
debug("handleEvent: " + aEvent.type);
@@ -85,16 +91,17 @@ this.DateTimePickerHelper = {
this.updateInputBoxValue(aEvent);
break;
}
case "popuphidden": {
let browser = this.weakBrowser ? this.weakBrowser.get() : null;
if (browser) {
browser.messageManager.sendAsyncMessage("FormDateTime:PickerClosed");
}
+ this.picker.closePicker();
this.close();
break;
}
default:
break;
}
},
@@ -145,21 +152,25 @@ this.DateTimePickerHelper = {
this.picker.addEventListener("DateTimePickerBindingReady",
resolve, {once: true});
});
this.picker.setAttribute("active", true);
await bindingPromise;
}
// The arrow panel needs an anchor to work. The popupAnchor (this._anchor)
// is a transparent div that the arrow can point to.
- this.picker.openPicker(type, this._anchor, detail);
+ this.picker.openPicker(type, this._anchor, detail, this.getZoom(aBrowser));
this.addPickerListeners();
},
+ getZoom(browser) {
+ return Services.prefs.getBoolPref("browser.zoom.full") ? browser.fullZoom : browser.textZoom;
+ },
+
// Picker is closed, do some cleanup.
close() {
this.removePickerListeners();
this.picker = null;
this.weakBrowser = null;
this._anchor.hidden = true;
},