<?xml version="1.0"?> <!-- 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/. --> <!DOCTYPE bindings [ <!ENTITY % datetimepickerDTD SYSTEM "chrome://global/locale/datetimepicker.dtd"> %datetimepickerDTD; ]> <bindings id="timepickerBindings" xmlns="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" xmlns:xbl="http://www.mozilla.org/xbl"> <binding id="datetimepicker-base" extends="chrome://global/content/bindings/general.xml#basecontrol"> <resources> <stylesheet src="chrome://global/content/textbox.css"/> <stylesheet src="chrome://global/skin/textbox.css"/> <stylesheet src="chrome://global/skin/dropmarker.css"/> <stylesheet src="chrome://global/skin/datetimepicker.css"/> </resources> <content align="center"> <xul:hbox class="datetimepicker-input-box" align="center" xbl:inherits="context,disabled,readonly"> <xul:hbox class="textbox-input-box datetimepicker-input-subbox" align="center"> <html:input class="datetimepicker-input textbox-input" anonid="input-one" size="2" maxlength="2" xbl:inherits="disabled,readonly"/> </xul:hbox> <xul:label anonid="sep-first" class="datetimepicker-separator" value=":"/> <xul:hbox class="textbox-input-box datetimepicker-input-subbox" align="center"> <html:input class="datetimepicker-input textbox-input" anonid="input-two" size="2" maxlength="2" xbl:inherits="disabled,readonly"/> </xul:hbox> <xul:label anonid="sep-second" class="datetimepicker-separator" value=":"/> <xul:hbox class="textbox-input-box datetimepicker-input-subbox" align="center"> <html:input class="datetimepicker-input textbox-input" anonid="input-three" size="2" maxlength="2" xbl:inherits="disabled,readonly"/> </xul:hbox> <xul:hbox class="textbox-input-box datetimepicker-input-subbox" align="center"> <html:input class="datetimepicker-input textbox-input" anonid="input-ampm" size="2" maxlength="2" xbl:inherits="disabled,readonly"/> </xul:hbox> </xul:hbox> <xul:spinbuttons anonid="buttons" xbl:inherits="disabled" onup="this.parentNode._increaseOrDecrease(1);" ondown="this.parentNode._increaseOrDecrease(-1);"/> </content> <implementation> <field name="_dateValue">null</field> <field name="_fieldOne"> document.getAnonymousElementByAttribute(this, "anonid", "input-one"); </field> <field name="_fieldTwo"> document.getAnonymousElementByAttribute(this, "anonid", "input-two"); </field> <field name="_fieldThree"> document.getAnonymousElementByAttribute(this, "anonid", "input-three"); </field> <field name="_fieldAMPM"> document.getAnonymousElementByAttribute(this, "anonid", "input-ampm"); </field> <field name="_separatorFirst"> document.getAnonymousElementByAttribute(this, "anonid", "sep-first"); </field> <field name="_separatorSecond"> document.getAnonymousElementByAttribute(this, "anonid", "sep-second"); </field> <field name="_lastFocusedField">null</field> <field name="_hasEntry">true</field> <field name="_valueEntered">false</field> <field name="attachedControl">null</field> <property name="_currentField" readonly="true"> <getter> var focusedInput = document.activeElement; if (focusedInput == this._fieldOne || focusedInput == this._fieldTwo || focusedInput == this._fieldThree || focusedInput == this._fieldAMPM) return focusedInput; return this._lastFocusedField || this._fieldOne; </getter> </property> <property name="dateValue" onget="return new Date(this._dateValue);"> <setter> <![CDATA[ if (!(val instanceof Date)) throw "Invalid Date"; this._setValueNoSync(val); if (this.attachedControl) this.attachedControl._setValueNoSync(val); return val; ]]> </setter> </property> <property name="readOnly" onset="if (val) this.setAttribute('readonly', 'true'); else this.removeAttribute('readonly'); return val;" onget="return this.getAttribute('readonly') == 'true';"/> <method name="_fireEvent"> <parameter name="aEventName"/> <parameter name="aTarget"/> <body> var event = document.createEvent("Events"); event.initEvent(aEventName, true, true); return !aTarget.dispatchEvent(event); </body> </method> <method name="_setValueOnChange"> <parameter name="aField"/> <body> <![CDATA[ if (!this._hasEntry) return; if (aField == this._fieldOne || aField == this._fieldTwo || aField == this._fieldThree) { var value = Number(aField.value); if (isNaN(value)) value = 0; value = this._constrainValue(aField, value, true); this._setFieldValue(aField, value); } ]]> </body> </method> <method name="_init"> <body/> </method> <constructor> this._init(); var cval = this.getAttribute("value"); if (cval) { try { this.value = cval; return; } catch (ex) { } } this.dateValue = new Date(); </constructor> <destructor> if (this.attachedControl) { this.attachedControl.attachedControl = null; this.attachedControl = null; } </destructor> </implementation> <handlers> <handler event="focus" phase="capturing"> <![CDATA[ var target = event.originalTarget; if (target == this._fieldOne || target == this._fieldTwo || target == this._fieldThree || target == this._fieldAMPM) this._lastFocusedField = target; ]]> </handler> <handler event="keypress"> <![CDATA[ if (this._hasEntry && event.charCode && this._currentField != this._fieldAMPM && ! (event.altKey || event.ctrlKey || event.metaKey) && (event.charCode < 48 || event.charCode > 57)) event.preventDefault(); ]]> </handler> <handler event="keypress" keycode="VK_UP"> if (this._hasEntry) this._increaseOrDecrease(1); </handler> <handler event="keypress" keycode="VK_DOWN"> if (this._hasEntry) this._increaseOrDecrease(-1); </handler> <handler event="input"> this._valueEntered = true; </handler> <handler event="change"> this._setValueOnChange(event.originalTarget); </handler> </handlers> </binding> <binding id="timepicker" extends="chrome://global/content/bindings/datetimepicker.xml#datetimepicker-base"> <implementation> <field name="is24HourClock">false</field> <field name="hourLeadingZero">false</field> <field name="minuteLeadingZero">true</field> <field name="secondLeadingZero">true</field> <field name="amIndicator">"AM"</field> <field name="pmIndicator">"PM"</field> <field name="hourField">null</field> <field name="minuteField">null</field> <field name="secondField">null</field> <property name="value"> <getter> <![CDATA[ var minute = this._dateValue.getMinutes(); if (minute < 10) minute = "0" + minute; var second = this._dateValue.getSeconds(); if (second < 10) second = "0" + second; return this._dateValue.getHours() + ":" + minute + ":" + second; ]]> </getter> <setter> <![CDATA[ var items = val.match(/^([0-9]{1,2})\:([0-9]{1,2})\:?([0-9]{1,2})?$/); if (!items) throw "Invalid Time"; var dt = this.dateValue; dt.setHours(items[1]); dt.setMinutes(items[2]); dt.setSeconds(items[3] ? items[3] : 0); this.dateValue = dt; return val; ]]> </setter> </property> <property name="hour" onget="return this._dateValue.getHours();"> <setter> <![CDATA[ var valnum = Number(val); if (isNaN(valnum) || valnum < 0 || valnum > 23) throw "Invalid Hour"; this._setFieldValue(this.hourField, valnum); return val; ]]> </setter> </property> <property name="minute" onget="return this._dateValue.getMinutes();"> <setter> <![CDATA[ var valnum = Number(val); if (isNaN(valnum) || valnum < 0 || valnum > 59) throw "Invalid Minute"; this._setFieldValue(this.minuteField, valnum); return val; ]]> </setter> </property> <property name="second" onget="return this._dateValue.getSeconds();"> <setter> <![CDATA[ var valnum = Number(val); if (isNaN(valnum) || valnum < 0 || valnum > 59) throw "Invalid Second"; this._setFieldValue(this.secondField, valnum); return val; ]]> </setter> </property> <property name="isPM"> <getter> <![CDATA[ return (this.hour >= 12); ]]> </getter> <setter> <![CDATA[ if (val) { if (this.hour < 12) this.hour += 12; } else if (this.hour >= 12) this.hour -= 12; return val; ]]> </setter> </property> <property name="hideSeconds"> <getter> return (this.getAttribute("hideseconds") == "true"); </getter> <setter> if (val) this.setAttribute("hideseconds", "true"); else this.removeAttribute("hideseconds"); if (this.secondField) this.secondField.parentNode.collapsed = val; this._separatorSecond.collapsed = val; return val; </setter> </property> <property name="increment"> <getter> <![CDATA[ var increment = this.getAttribute("increment"); increment = Number(increment); if (isNaN(increment) || increment <= 0 || increment >= 60) return 1; return increment; ]]> </getter> <setter> <![CDATA[ if (typeof val == "number") this.setAttribute("increment", val); return val; ]]> </setter> </property> <method name="_setValueNoSync"> <parameter name="aValue"/> <body> <![CDATA[ var dt = new Date(aValue); if (!isNaN(dt)) { this._dateValue = dt; this.setAttribute("value", this.value); this._updateUI(this.hourField, this.hour); this._updateUI(this.minuteField, this.minute); this._updateUI(this.secondField, this.second); } ]]> </body> </method> <method name="_increaseOrDecrease"> <parameter name="aDir"/> <body> <![CDATA[ if (this.disabled || this.readOnly) return; var field = this._currentField; if (this._valueEntered) this._setValueOnChange(field); if (field == this._fieldAMPM) { this.isPM = !this.isPM; this._fireEvent("change", this); } else { var oldval; var change = aDir; if (field == this.hourField) { oldval = this.hour; } else if (field == this.minuteField) { oldval = this.minute; change *= this.increment; } else if (field == this.secondField) { oldval = this.second; } var newval = this._constrainValue(field, oldval + change, false); if (field == this.hourField) this.hour = newval; else if (field == this.minuteField) this.minute = newval; else if (field == this.secondField) this.second = newval; if (oldval != newval) this._fireEvent("change", this); } field.select(); ]]> </body> </method> <method name="_setFieldValue"> <parameter name="aField"/> <parameter name="aValue"/> <body> <![CDATA[ if (aField == this.hourField) this._dateValue.setHours(aValue); else if (aField == this.minuteField) this._dateValue.setMinutes(aValue); else if (aField == this.secondField) this._dateValue.setSeconds(aValue); this.setAttribute("value", this.value); this._updateUI(aField, aValue); if (this.attachedControl) this.attachedControl._setValueNoSync(this._dateValue); ]]> </body> </method> <method name="_updateUI"> <parameter name="aField"/> <parameter name="aValue"/> <body> <![CDATA[ this._valueEntered = false; var prependZero = false; if (aField == this.hourField) { prependZero = this.hourLeadingZero; if (!this.is24HourClock) { if (aValue >= 12) { if (aValue > 12) aValue -= 12; this._fieldAMPM.value = this.pmIndicator; } else { if (aValue == 0) aValue = 12; this._fieldAMPM.value = this.amIndicator; } } } else if (aField == this.minuteField) { prependZero = this.minuteLeadingZero; } else if (aField == this.secondField) { prependZero = this.secondLeadingZero; } if (prependZero && aValue < 10) aField.value = "0" + aValue; else aField.value = aValue; ]]> </body> </method> <method name="_constrainValue"> <parameter name="aField"/> <parameter name="aValue"/> <parameter name="aNoWrap"/> <body> <![CDATA[ // aNoWrap is true when the user entered a value, so just // constrain within limits. If false, the value is being // incremented or decremented, so wrap around values var max = (aField == this.hourField) ? 24 : 60; if (aValue < 0) return aNoWrap ? 0 : max + aValue; if (aValue >= max) return aNoWrap ? max - 1 : aValue - max; return aValue; ]]> </body> </method> <method name="_init"> <body> <![CDATA[ this.hourField = this._fieldOne; this.minuteField = this._fieldTwo; this.secondField = this._fieldThree; var numberOrder = /^(\D*)\s*(\d+)(\D*)(\d+)(\D*)(\d+)\s*(\D*)$/; var locale = Intl.DateTimeFormat().resolvedOptions().locale + "-u-ca-gregory-nu-latn"; var pmTime = new Date(2000, 0, 1, 16, 7, 9).toLocaleTimeString(locale); var numberFields = pmTime.match(numberOrder); if (numberFields) { this._separatorFirst.value = numberFields[3]; this._separatorSecond.value = numberFields[5]; if (Number(numberFields[2]) > 12) this.is24HourClock = true; else this.pmIndicator = numberFields[1] || numberFields[7]; } var amTime = new Date(2000, 0, 1, 1, 7, 9).toLocaleTimeString(locale); numberFields = amTime.match(numberOrder); if (numberFields) { this.hourLeadingZero = (numberFields[2].length > 1); this.minuteLeadingZero = (numberFields[4].length > 1); this.secondLeadingZero = (numberFields[6].length > 1); if (!this.is24HourClock) { this.amIndicator = numberFields[1] || numberFields[7]; if (numberFields[1]) { var mfield = this._fieldAMPM.parentNode; var mcontainer = mfield.parentNode; mcontainer.insertBefore(mfield, mcontainer.firstChild); } var size = (numberFields[1] || numberFields[7]).length; if (this.pmIndicator.length > size) size = this.pmIndicator.length; this._fieldAMPM.size = size; this._fieldAMPM.maxLength = size; } else { this._fieldAMPM.parentNode.collapsed = true; } } this.hideSeconds = this.hideSeconds; ]]> </body> </method> </implementation> <handlers> <handler event="keypress"> <![CDATA[ // just allow any printable character to switch the AM/PM state if (event.charCode && !this.disabled && !this.readOnly && this._currentField == this._fieldAMPM) { this.isPM = !this.isPM; this._fieldAMPM.select(); this._fireEvent("change", this); event.preventDefault(); } ]]> </handler> </handlers> </binding> <binding id="datepicker" extends="chrome://global/content/bindings/datetimepicker.xml#datetimepicker-base"> <implementation> <field name="yearLeadingZero">false</field> <field name="monthLeadingZero">true</field> <field name="dateLeadingZero">true</field> <field name="yearField"/> <field name="monthField"/> <field name="dateField"/> <property name="value"> <getter> <![CDATA[ var month = this._dateValue.getMonth(); month = (month < 9) ? month = "0" + ++month : month + 1; var date = this._dateValue.getDate(); if (date < 10) date = "0" + date; return this._dateValue.getFullYear() + "-" + month + "-" + date; ]]> </getter> <setter> <![CDATA[ var results = val.match(/^([0-9]{1,4})\-([0-9]{1,2})\-([0-9]{1,2})$/); if (!results) throw "Invalid Date"; this.dateValue = new Date(results[1] + "/" + results[2] + "/" + results[3]); this.setAttribute("value", this.value); return val; ]]> </setter> </property> <property name="year" onget="return this._dateValue.getFullYear();"> <setter> <![CDATA[ var valnum = Number(val); if (isNaN(valnum) || valnum < 1 || valnum > 9999) throw "Invalid Year"; this._setFieldValue(this.yearField, valnum); return val; ]]> </setter> </property> <property name="month" onget="return this._dateValue.getMonth();"> <setter> <![CDATA[ var valnum = Number(val); if (isNaN(valnum) || valnum < 0 || valnum > 11) throw "Invalid Month"; this._setFieldValue(this.monthField, valnum); return val; ]]> </setter> </property> <property name="date" onget="return this._dateValue.getDate();"> <setter> <![CDATA[ var valnum = Number(val); if (isNaN(valnum) || valnum < 1 || valnum > 31) throw "Invalid Date"; this._setFieldValue(this.dateField, valnum); return val; ]]> </setter> </property> <property name="open" onget="return false;" onset="return val;"/> <property name="displayedMonth" onget="return this.month;" onset="this.month = val; return val;"/> <property name="displayedYear" onget="return this.year;" onset="this.year = val; return val;"/> <method name="_setValueNoSync"> <parameter name="aValue"/> <body> <![CDATA[ var dt = new Date(aValue); if (!isNaN(dt)) { this._dateValue = dt; this.setAttribute("value", this.value); this._updateUI(this.yearField, this.year); this._updateUI(this.monthField, this.month); this._updateUI(this.dateField, this.date); } ]]> </body> </method> <method name="_increaseOrDecrease"> <parameter name="aDir"/> <body> <![CDATA[ if (this.disabled || this.readOnly) return; var field = this._currentField; if (this._valueEntered) this._setValueOnChange(field); var oldval; if (field == this.yearField) oldval = this.year; else if (field == this.monthField) oldval = this.month; else if (field == this.dateField) oldval = this.date; var newval = this._constrainValue(field, oldval + aDir, false); if (field == this.yearField) this.year = newval; else if (field == this.monthField) this.month = newval; else if (field == this.dateField) this.date = newval; if (oldval != newval) this._fireEvent("change", this); field.select(); ]]> </body> </method> <method name="_setFieldValue"> <parameter name="aField"/> <parameter name="aValue"/> <body> <![CDATA[ if (aField == this.yearField) { let oldDate = this.date; this._dateValue.setFullYear(aValue); if (oldDate != this.date) { this._dateValue.setDate(0); this._updateUI(this.dateField, this.date); } } else if (aField == this.monthField) { let oldDate = this.date; this._dateValue.setMonth(aValue); if (oldDate != this.date) { this._dateValue.setDate(0); this._updateUI(this.dateField, this.date); } } else if (aField == this.dateField) { this._dateValue.setDate(aValue); } this.setAttribute("value", this.value); this._updateUI(aField, aValue); if (this.attachedControl) this.attachedControl._setValueNoSync(this._dateValue); ]]> </body> </method> <method name="_updateUI"> <parameter name="aField"/> <parameter name="aValue"/> <body> <![CDATA[ this._valueEntered = false; var prependZero = false; if (aField == this.yearField) { if (this.yearLeadingZero) { aField.value = ("000" + aValue).slice(-4); return; } } else if (aField == this.monthField) { aValue++; prependZero = this.monthLeadingZero; } else if (aField == this.dateField) { prependZero = this.dateLeadingZero; } if (prependZero && aValue < 10) aField.value = "0" + aValue; else aField.value = aValue; ]]> </body> </method> <method name="_constrainValue"> <parameter name="aField"/> <parameter name="aValue"/> <parameter name="aNoWrap"/> <body> <![CDATA[ // the month will be 1 to 12 if entered by the user, so subtract 1 if (aNoWrap && aField == this.monthField) aValue--; if (aField == this.dateField) { if (aValue < 1) return new Date(this.year, this.month + 1, 0).getDate(); var currentMonth = this.month; var dt = new Date(this.year, currentMonth, aValue); return (dt.getMonth() != currentMonth ? 1 : aValue); } var min = (aField == this.monthField) ? 0 : 1; var max = (aField == this.monthField) ? 11 : 9999; if (aValue < min) return aNoWrap ? min : max; if (aValue > max) return aNoWrap ? max : min; return aValue; ]]> </body> </method> <method name="_init"> <body> <![CDATA[ // We'll default to YYYY/MM/DD to start. var yfield = "input-one"; var mfield = "input-two"; var dfield = "input-three"; var twoDigitYear = false; this.yearLeadingZero = true; this.monthLeadingZero = true; this.dateLeadingZero = true; var numberOrder = /^(\D*)\s*(\d+)(\D*)(\d+)(\D*)(\d+)\s*(\D*)$/; var locale = Intl.DateTimeFormat().resolvedOptions().locale + "-u-ca-gregory-nu-latn"; var dt = new Date(2002, 9, 4).toLocaleDateString(locale); var numberFields = dt.match(numberOrder); if (numberFields) { this._separatorFirst.value = numberFields[3]; this._separatorSecond.value = numberFields[5]; var yi = 2, mi = 4, di = 6; function fieldForNumber(i) { if (i == 2) return "input-one"; if (i == 4) return "input-two"; return "input-three"; } for (var i = 1; i < numberFields.length; i++) { switch (Number(numberFields[i])) { case 2: twoDigitYear = true; // fall through case 2002: yi = i; yfield = fieldForNumber(i); break; case 9, 10: mi = i; mfield = fieldForNumber(i); break; case 4: di = i; dfield = fieldForNumber(i); break; } } this.yearLeadingZero = (numberFields[yi].length > 1); this.monthLeadingZero = (numberFields[mi].length > 1); this.dateLeadingZero = (numberFields[di].length > 1); } this.yearField = document.getAnonymousElementByAttribute(this, "anonid", yfield); if (!twoDigitYear) this.yearField.parentNode.classList.add("datetimepicker-input-subbox", "datetimepicker-year"); this.monthField = document.getAnonymousElementByAttribute(this, "anonid", mfield); this.dateField = document.getAnonymousElementByAttribute(this, "anonid", dfield); this._fieldAMPM.parentNode.collapsed = true; this.yearField.size = twoDigitYear ? 2 : 4; this.yearField.maxLength = twoDigitYear ? 2 : 4; ]]> </body> </method> </implementation> </binding> <binding id="datepicker-grid" extends="chrome://global/content/bindings/datetimepicker.xml#datepicker"> <content> <vbox class="datepicker-mainbox" xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> <hbox class="datepicker-monthbox" align="center"> <button class="datepicker-previous datepicker-button" type="repeat" xbl:inherits="disabled" oncommand="document.getBindingParent(this)._increaseOrDecreaseMonth(-1);"/> <spacer flex="1"/> <deck anonid="monthlabeldeck"> <label class="datepicker-gridlabel" value=""/> <label class="datepicker-gridlabel" value=""/> <label class="datepicker-gridlabel" value=""/> <label class="datepicker-gridlabel" value=""/> <label class="datepicker-gridlabel" value=""/> <label class="datepicker-gridlabel" value=""/> <label class="datepicker-gridlabel" value=""/> <label class="datepicker-gridlabel" value=""/> <label class="datepicker-gridlabel" value=""/> <label class="datepicker-gridlabel" value=""/> <label class="datepicker-gridlabel" value=""/> <label class="datepicker-gridlabel" value=""/> </deck> <label anonid="yearlabel" class="datepicker-gridlabel"/> <spacer flex="1"/> <button class="datepicker-next datepicker-button" type="repeat" xbl:inherits="disabled" oncommand="document.getBindingParent(this)._increaseOrDecreaseMonth(1);"/> </hbox> <grid class="datepicker-grid" role="grid"> <columns> <column class="datepicker-gridrow" flex="1"/> <column class="datepicker-gridrow" flex="1"/> <column class="datepicker-gridrow" flex="1"/> <column class="datepicker-gridrow" flex="1"/> <column class="datepicker-gridrow" flex="1"/> <column class="datepicker-gridrow" flex="1"/> <column class="datepicker-gridrow" flex="1"/> </columns> <rows anonid="datebox"> <row anonid="dayofweekbox"> <label class="datepicker-weeklabel" role="columnheader"/> <label class="datepicker-weeklabel" role="columnheader"/> <label class="datepicker-weeklabel" role="columnheader"/> <label class="datepicker-weeklabel" role="columnheader"/> <label class="datepicker-weeklabel" role="columnheader"/> <label class="datepicker-weeklabel" role="columnheader"/> <label class="datepicker-weeklabel" role="columnheader"/> </row> <row> <label class="datepicker-gridlabel" role="gridcell"/> <label class="datepicker-gridlabel" role="gridcell"/> <label class="datepicker-gridlabel" role="gridcell"/> <label class="datepicker-gridlabel" role="gridcell"/> <label class="datepicker-gridlabel" role="gridcell"/> <label class="datepicker-gridlabel" role="gridcell"/> <label class="datepicker-gridlabel" role="gridcell"/> </row> <row> <label class="datepicker-gridlabel" role="gridcell"/> <label class="datepicker-gridlabel" role="gridcell"/> <label class="datepicker-gridlabel" role="gridcell"/> <label class="datepicker-gridlabel" role="gridcell"/> <label class="datepicker-gridlabel" role="gridcell"/> <label class="datepicker-gridlabel" role="gridcell"/> <label class="datepicker-gridlabel" role="gridcell"/> </row> <row> <label class="datepicker-gridlabel" role="gridcell"/> <label class="datepicker-gridlabel" role="gridcell"/> <label class="datepicker-gridlabel" role="gridcell"/> <label class="datepicker-gridlabel" role="gridcell"/> <label class="datepicker-gridlabel" role="gridcell"/> <label class="datepicker-gridlabel" role="gridcell"/> <label class="datepicker-gridlabel" role="gridcell"/> </row> <row> <label class="datepicker-gridlabel" role="gridcell"/> <label class="datepicker-gridlabel" role="gridcell"/> <label class="datepicker-gridlabel" role="gridcell"/> <label class="datepicker-gridlabel" role="gridcell"/> <label class="datepicker-gridlabel" role="gridcell"/> <label class="datepicker-gridlabel" role="gridcell"/> <label class="datepicker-gridlabel" role="gridcell"/> </row> <row> <label class="datepicker-gridlabel" role="gridcell"/> <label class="datepicker-gridlabel" role="gridcell"/> <label class="datepicker-gridlabel" role="gridcell"/> <label class="datepicker-gridlabel" role="gridcell"/> <label class="datepicker-gridlabel" role="gridcell"/> <label class="datepicker-gridlabel" role="gridcell"/> <label class="datepicker-gridlabel" role="gridcell"/> </row> <row> <label class="datepicker-gridlabel" role="gridcell"/> <label class="datepicker-gridlabel" role="gridcell"/> <label class="datepicker-gridlabel" role="gridcell"/> <label class="datepicker-gridlabel" role="gridcell"/> <label class="datepicker-gridlabel" role="gridcell"/> <label class="datepicker-gridlabel" role="gridcell"/> <label class="datepicker-gridlabel" role="gridcell"/> </row> </rows> </grid> </vbox> </content> <implementation> <field name="_hasEntry">false</field> <field name="_weekStart">&firstdayofweek.default;</field> <field name="_displayedDate">null</field> <field name="_todayItem">null</field> <field name="yearField"> document.getAnonymousElementByAttribute(this, "anonid", "yearlabel"); </field> <field name="monthField"> document.getAnonymousElementByAttribute(this, "anonid", "monthlabeldeck"); </field> <field name="dateField"> document.getAnonymousElementByAttribute(this, "anonid", "datebox"); </field> <field name="_selectedItem">null</field> <property name="selectedItem" onget="return this._selectedItem"> <setter> <![CDATA[ if (!val.value) return val; if (val.parentNode.parentNode != this.dateField) return val; if (this._selectedItem) this._selectedItem.removeAttribute("selected"); this._selectedItem = val; val.setAttribute("selected", "true"); this._displayedDate.setDate(val.value); return val; ]]> </setter> </property> <property name="displayedMonth"> <getter> return this._displayedDate.getMonth(); </getter> <setter> this._updateUI(this.monthField, val, true); return val; </setter> </property> <property name="displayedYear"> <getter> return this._displayedDate.getFullYear(); </getter> <setter> this._updateUI(this.yearField, val, true); return val; </setter> </property> <method name="_init"> <body> <![CDATA[ var locale = Intl.DateTimeFormat().resolvedOptions().locale + "-u-ca-gregory"; var dtfMonth = Intl.DateTimeFormat(locale, {month: "long", timeZone: "UTC"}); var dtfWeekday = Intl.DateTimeFormat(locale, {weekday: "narrow"}); var monthLabel = this.monthField.firstChild; var tempDate = new Date(Date.UTC(2005, 0, 1)); for (var month = 0; month < 12; month++) { tempDate.setUTCMonth(month); monthLabel.setAttribute("value", dtfMonth.format(tempDate)); monthLabel = monthLabel.nextSibling; } var fdow = Number(this.getAttribute("firstdayofweek")); if (!isNaN(fdow) && fdow >= 0 && fdow <= 6) this._weekStart = fdow; var weekbox = document.getAnonymousElementByAttribute(this, "anonid", "dayofweekbox").childNodes; var date = new Date(); date.setDate(date.getDate() - (date.getDay() - this._weekStart)); for (var i = 0; i < weekbox.length; i++) { weekbox[i].value = dtfWeekday.format(date); date.setDate(date.getDate() + 1); } ]]> </body> </method> <method name="_setValueNoSync"> <parameter name="aValue"/> <body> <![CDATA[ var dt = new Date(aValue); if (!isNaN(dt)) { this._dateValue = dt; this.setAttribute("value", this.value); this._updateUI(); } ]]> </body> </method> <method name="_updateUI"> <parameter name="aField"/> <parameter name="aValue"/> <parameter name="aCheckMonth"/> <body> <![CDATA[ var date; var currentMonth; if (aCheckMonth) { if (!this._displayedDate) this._displayedDate = this.dateValue; var expectedMonth = aValue; if (aField == this.monthField) { this._displayedDate.setMonth(aValue); } else { expectedMonth = this._displayedDate.getMonth(); this._displayedDate.setFullYear(aValue); } if (expectedMonth != -1 && expectedMonth != 12 && expectedMonth != this._displayedDate.getMonth()) { // If the month isn't what was expected, then the month overflowed. // Setting the date to 0 will go back to the last day of the right month. this._displayedDate.setDate(0); } date = new Date(this._displayedDate); currentMonth = this._displayedDate.getMonth(); } else { var samemonth = (this._displayedDate && this._displayedDate.getMonth() == this.month && this._displayedDate.getFullYear() == this.year); if (samemonth) { var items = this.dateField.getElementsByAttribute("value", this.date); if (items.length) this.selectedItem = items[0]; return; } date = this.dateValue; this._displayedDate = new Date(date); currentMonth = this.month; } if (this._todayItem) { this._todayItem.removeAttribute("today"); this._todayItem = null; } if (this._selectedItem) { this._selectedItem.removeAttribute("selected"); this._selectedItem = null; } // Update the month and year title this.monthField.selectedIndex = currentMonth; this.yearField.setAttribute("value", date.getFullYear()); date.setDate(1); var firstWeekday = (7 + date.getDay() - this._weekStart) % 7; date.setDate(date.getDate() - firstWeekday); var today = new Date(); var datebox = this.dateField; for (var k = 1; k < datebox.childNodes.length; k++) { var row = datebox.childNodes[k]; for (var i = 0; i < 7; i++) { var item = row.childNodes[i]; if (currentMonth == date.getMonth()) { item.value = date.getDate(); // highlight today if (this._isSameDay(today, date)) { this._todayItem = item; item.setAttribute("today", "true"); } // highlight the selected date if (this._isSameDay(this._dateValue, date)) { this._selectedItem = item; item.setAttribute("selected", "true"); } } else { item.value = ""; } date.setDate(date.getDate() + 1); } } this._fireEvent("monthchange", this); if (this.hasAttribute("monthchange")) { var fn = new Function("event", aTarget.getAttribute("onmonthchange")); fn.call(aTarget, event); } ]]> </body> </method> <method name="_increaseOrDecreaseDateFromEvent"> <parameter name="aEvent"/> <parameter name="aDiff"/> <body> <![CDATA[ if (aEvent.originalTarget == this && !this.disabled && !this.readOnly) { var newdate = this.dateValue; newdate.setDate(newdate.getDate() + aDiff); this.dateValue = newdate; this._fireEvent("change", this); } aEvent.stopPropagation(); aEvent.preventDefault(); ]]> </body> </method> <method name="_increaseOrDecreaseMonth"> <parameter name="aDir"/> <body> <![CDATA[ if (!this.disabled) { var month = this._displayedDate ? this._displayedDate.getMonth() : this.month; this._updateUI(this.monthField, month + aDir, true); } ]]> </body> </method> <method name="_isSameDay"> <parameter name="aDate1"/> <parameter name="aDate2"/> <body> <![CDATA[ return (aDate1 && aDate2 && aDate1.getDate() == aDate2.getDate() && aDate1.getMonth() == aDate2.getMonth() && aDate1.getFullYear() == aDate2.getFullYear()); ]]> </body> </method> </implementation> <handlers> <handler event="click"> <![CDATA[ if (event.button != 0 || this.disabled || this.readOnly) return; var target = event.originalTarget; if (target.classList.contains("datepicker-gridlabel") && target != this.selectedItem) { this.selectedItem = target; this._dateValue = new Date(this._displayedDate); if (this.attachedControl) this.attachedControl._setValueNoSync(this._dateValue); this._fireEvent("change", this); if (this.attachedControl && "open" in this.attachedControl) this.attachedControl.open = false; // close the popup } ]]> </handler> <handler event="MozMousePixelScroll" preventdefault="true"/> <handler event="DOMMouseScroll" preventdefault="true"> <![CDATA[ this._increaseOrDecreaseMonth(event.detail < 0 ? -1 : 1); ]]> </handler> <handler event="keypress" keycode="VK_LEFT" action="this._increaseOrDecreaseDateFromEvent(event, -1);"/> <handler event="keypress" keycode="VK_RIGHT" action="this._increaseOrDecreaseDateFromEvent(event, 1);"/> <handler event="keypress" keycode="VK_UP" action="this._increaseOrDecreaseDateFromEvent(event, -7);"/> <handler event="keypress" keycode="VK_DOWN" action="this._increaseOrDecreaseDateFromEvent(event, 7);"/> <handler event="keypress" keycode="VK_PAGE_UP" preventdefault="true" action="this._increaseOrDecreaseMonth(-1);"/> <handler event="keypress" keycode="VK_PAGE_DOWN" preventdefault="true" action="this._increaseOrDecreaseMonth(1);"/> </handlers> </binding> <binding id="datepicker-popup" display="xul:menu" extends="chrome://global/content/bindings/datetimepicker.xml#datepicker"> <content align="center"> <xul:hbox class="textbox-input-box datetimepicker-input-box" align="center" allowevents="true" xbl:inherits="context,disabled,readonly"> <xul:hbox class="datetimepicker-input-subbox" align="baseline"> <html:input class="datetimepicker-input textbox-input" anonid="input-one" size="2" maxlength="2" xbl:inherits="disabled,readonly"/> </xul:hbox> <xul:label anonid="sep-first" class="datetimepicker-separator" value=":"/> <xul:hbox class="datetimepicker-input-subbox" align="baseline"> <html:input class="datetimepicker-input textbox-input" anonid="input-two" size="2" maxlength="2" xbl:inherits="disabled,readonly"/> </xul:hbox> <xul:label anonid="sep-second" class="datetimepicker-separator" value=":"/> <xul:hbox class="datetimepicker-input-subbox" align="center"> <html:input class="datetimepicker-input textbox-input" anonid="input-three" size="2" maxlength="2" xbl:inherits="disabled,readonly"/> </xul:hbox> <xul:hbox class="datetimepicker-input-subbox" align="center"> <html:input class="datetimepicker-input textbox-input" anonid="input-ampm" size="2" maxlength="2" xbl:inherits="disabled,readonly"/> </xul:hbox> </xul:hbox> <xul:spinbuttons anonid="buttons" xbl:inherits="disabled" allowevents="true" onup="this.parentNode._increaseOrDecrease(1);" ondown="this.parentNode._increaseOrDecrease(-1);"/> <xul:dropmarker class="datepicker-dropmarker" xbl:inherits="disabled"/> <xul:panel onpopupshown="this.firstChild.focus();" level="top"> <xul:datepicker anonid="grid" type="grid" class="datepicker-popupgrid" xbl:inherits="disabled,readonly,firstdayofweek"/> </xul:panel> </content> <implementation> <constructor> var grid = document.getAnonymousElementByAttribute(this, "anonid", "grid"); this.attachedControl = grid; grid.attachedControl = this; grid._setValueNoSync(this._dateValue); </constructor> <property name="open" onget="return this.hasAttribute('open');"> <setter> <![CDATA[ if (this.boxObject instanceof MenuBoxObject) this.boxObject.openMenu(val); return val; ]]> </setter> </property> <property name="displayedMonth"> <getter> return document.getAnonymousElementByAttribute(this, "anonid", "grid").displayedMonth; </getter> <setter> document.getAnonymousElementByAttribute(this, "anonid", "grid").displayedMonth = val; return val; </setter> </property> <property name="displayedYear"> <getter> return document.getAnonymousElementByAttribute(this, "anonid", "grid").displayedYear; </getter> <setter> document.getAnonymousElementByAttribute(this, "anonid", "grid").displayedYear = val; return val; </setter> </property> </implementation> </binding> </bindings>