1192 lines
38 KiB
XML
1192 lines
38 KiB
XML
<!-- ***** BEGIN LICENSE BLOCK *****
|
|
- Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
|
-
|
|
- The contents of this file are subject to the Mozilla Public License Version
|
|
- 1.1 (the "License"); you may not use this file except in compliance with
|
|
- the License. You may obtain a copy of the License at
|
|
- http://www.mozilla.org/MPL/
|
|
-
|
|
- Software distributed under the License is distributed on an "AS IS" basis,
|
|
- WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
|
- for the specific language governing rights and limitations under the
|
|
- License.
|
|
-
|
|
- The Original Code is Mozilla XForms support.
|
|
-
|
|
- The Initial Developer of the Original Code is
|
|
- IBM Corporation.
|
|
- Portions created by the Initial Developer are Copyright (C) 2006
|
|
- the Initial Developer. All Rights Reserved.
|
|
-
|
|
- Contributor(s):
|
|
- Doron Rosenberg <doronr@us.ibm.com>
|
|
- Alexander Surkov <surkov@dc.baikal.ru>
|
|
- Merle Sterling <msterlin@us.ibm.com>
|
|
-
|
|
- Alternatively, the contents of this file may be used under the terms of
|
|
- either the GNU General Public License Version 2 or later (the "GPL"), or
|
|
- the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
|
- in which case the provisions of the GPL or the LGPL are applicable instead
|
|
- of those above. If you wish to allow use of your version of this file only
|
|
- under the terms of either the GPL or the LGPL, and not to allow others to
|
|
- use your version of this file under the terms of the MPL, indicate your
|
|
- decision by deleting the provisions above and replace them with the notice
|
|
- and other provisions required by the GPL or the LGPL. If you do not delete
|
|
- the provisions above, a recipient may use your version of this file under
|
|
- the terms of any one of the MPL, the GPL or the LGPL.
|
|
-
|
|
- ***** END LICENSE BLOCK ***** -->
|
|
|
|
<!DOCTYPE bindings [
|
|
<!ENTITY % xformsDTD SYSTEM "chrome://xforms/locale/xforms.dtd">
|
|
%xformsDTD;
|
|
]>
|
|
|
|
<bindings id="widgetsBindings"
|
|
xmlns="http://www.mozilla.org/xbl"
|
|
xmlns:xbl="http://www.mozilla.org/xbl">
|
|
|
|
|
|
<!-- CALENDAR WIDGETS -->
|
|
|
|
<!-- CALENDAR BASE
|
|
The widget assumes successor widgets have following interface:
|
|
refresh(aCurrentDay, aDaysRefreshOnly) - update UI, the method is called
|
|
when current date is changed.
|
|
@param aCurrentDay - day of current date
|
|
@param aDaysRefreshOnly - if true then day of current date will be
|
|
updated only.
|
|
focus() - set focus on the widget.
|
|
currentDay - return day of current date.
|
|
-->
|
|
<binding id="calendar-base">
|
|
<implementation implements="nsIAccessibleProvider">
|
|
<!-- nsIAccessibleProvider -->
|
|
<property name="accessibleType" readonly="true">
|
|
<getter>
|
|
return Components.interfaces.nsIAccessibleProvider.XFormsCalendarWidget;
|
|
</getter>
|
|
</property>
|
|
|
|
<!-- interface -->
|
|
<!-- Set/get readonly state -->
|
|
<property name="readonly">
|
|
<getter>
|
|
return this.hasAttribute("readonly");
|
|
</getter>
|
|
<setter>
|
|
if (val)
|
|
this.setAttribute("readonly", "readonly");
|
|
else
|
|
this.removeAttribute("readonly");
|
|
</setter>
|
|
</property>
|
|
|
|
<!-- The following interface methods serve to manage current date (the date
|
|
you see) -->
|
|
|
|
<!-- Return year of current date -->
|
|
<property name="year"
|
|
onget="return parseInt(this.getAttribute('year'));"
|
|
onset="this.setAttribute('year', val); this.refresh();"/>
|
|
|
|
<!-- Return month of current date -->
|
|
<property name="month"
|
|
onget="return parseInt(this.getAttribute('month'));"
|
|
onset="this.setDate(this.year, val);"/>
|
|
|
|
<!-- Set current date-->
|
|
<method name="setDate">
|
|
<parameter name="aYear"/>
|
|
<parameter name="aMonth"/>
|
|
<parameter name="aDay"/>
|
|
<body>
|
|
<![CDATA[
|
|
var month = parseInt(aMonth) - 1;
|
|
var deltayear = parseInt(month / 12);
|
|
if (!deltayear && month < 0)
|
|
deltayear = -1;
|
|
|
|
month %= 12;
|
|
if (month < 0)
|
|
month = (month + 12) % 12;
|
|
|
|
this.setAttribute("year", aYear + deltayear);
|
|
this.setAttribute("month", month + 1);
|
|
this.refresh(aDay);
|
|
]]>
|
|
</body>
|
|
</method>
|
|
|
|
<!-- Return current date -->
|
|
<method name="getDate">
|
|
<body>
|
|
if (this.focusedDay == -1)
|
|
return null;
|
|
return new Date(this.year, this.month - 1, this.currentDay);
|
|
</body>
|
|
</method>
|
|
|
|
<!-- The following methods serve to manage selected date -->
|
|
|
|
<!-- Return/set selected date as string of format 'yyyy-MM-dd' -->
|
|
<property name="value"
|
|
onget="return this.selectedDate ? this.selectedDate.toLocaleFormat('%Y-%m-%d') : null;"
|
|
onset="this.selectedDate = new Date(val.replace(/-/g, '/'));"/>
|
|
|
|
<!-- Return day of selected date -->
|
|
<property name="selectedDay" readonly="true"
|
|
onget="return this._selectedDate ? this._selectedDate.getDate() : null;"/>
|
|
|
|
<!-- Return month of selected date -->
|
|
<property name="selectedMonth" readonly="true"
|
|
onget="return this._selectedDate ? this._selectedDate.getMonth() + 1 : null;"/>
|
|
|
|
<!-- Return year of selected date -->
|
|
<property name="selectedYear" readonly="true"
|
|
onget="return this._selectedDate ? this._selectedDate.getFullYear() : null;"/>
|
|
|
|
<!-- Set/return selected date -->
|
|
<property name="selectedDate">
|
|
<getter>
|
|
return this._selectedDate;
|
|
</getter>
|
|
<setter>
|
|
// if passed date is empty or invalid then we use today date.
|
|
if (!val || String(val) == this.invalidDate)
|
|
val = new Date();
|
|
|
|
this._selectedDate = val;
|
|
if (!this.isSelectedDate())
|
|
this.setDate(this.selectedYear, this.selectedMonth, this.selectedDay);
|
|
else
|
|
this.refresh(this.selectedDay, true);
|
|
</setter>
|
|
</property>
|
|
|
|
<!-- Return true if year and month of current date are the same like for
|
|
selected date -->
|
|
<method name="isSelectedDate">
|
|
<body>
|
|
<![CDATA[
|
|
if (this.selectedYear == this.year && this.selectedMonth == this.month)
|
|
return true;
|
|
return false;
|
|
]]>
|
|
</body>
|
|
</method>
|
|
|
|
<!-- interface for successor widgets -->
|
|
|
|
<!-- Return day of the week of the first day of the month -->
|
|
<property name="dayOffset" readonly="true">
|
|
<getter>
|
|
return new Date(this.year, this.month - 1, 1).getDay();
|
|
</getter>
|
|
</property>
|
|
|
|
<!-- Return days count in current month -->
|
|
<property name="daysCount" readonly="true"
|
|
onget="return this.getDaysCount(this.month, this.year);"/>
|
|
|
|
<!-- Return days count in previous month -->
|
|
<property name="prevDaysCount" readonly="true">
|
|
<getter>
|
|
<![CDATA[
|
|
var month = this.month - 1;
|
|
var year = this.year;
|
|
if (month <= 0) {
|
|
month = 12;
|
|
year--;
|
|
}
|
|
return this.getDaysCount(month, year);
|
|
]]>
|
|
</getter>
|
|
</property>
|
|
|
|
<!-- Return short names of days of the week -->
|
|
<method name="getDaysOfWeekNames">
|
|
<body>
|
|
<![CDATA[
|
|
// shortname defaults
|
|
var dayShort = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
|
|
|
|
// try to get localized short names.
|
|
// May 2005's first day is a Sunday - also, month is 0-indexed in JS
|
|
var day;
|
|
for (var i = 0; i < 7; i++) {
|
|
day = new Date(2005, 4, i+1).toLocaleFormat("%a");
|
|
if (day)
|
|
dayShort[i] = day;
|
|
}
|
|
return dayShort;
|
|
]]>
|
|
</body>
|
|
</method>
|
|
|
|
<!-- Fire 'change' event -->
|
|
<method name="fireChangeEvent">
|
|
<body>
|
|
var event = this.ownerDocument.createEvent("Events");
|
|
event.initEvent("change", true, false);
|
|
this.dispatchEvent(event);
|
|
</body>
|
|
</method>
|
|
|
|
<!-- private -->
|
|
<method name="getDaysCount">
|
|
<parameter name="aMonth"/>
|
|
<parameter name="aYear"/>
|
|
<body>
|
|
<![CDATA[
|
|
switch (aMonth) {
|
|
case 1: case 3: case 5: case 7: case 8: case 10: case 12:
|
|
return 31;
|
|
|
|
case 2:
|
|
if (aYear % 4 == 0 && aYear % 100 != 0 || aYear % 400 == 0)
|
|
return 29; // leap-year
|
|
return 28;
|
|
|
|
case 4: case 6: case 9: case 11:
|
|
return 30;
|
|
}
|
|
return 0;
|
|
]]>
|
|
</body>
|
|
</method>
|
|
|
|
<!-- Selected date -->
|
|
<field name="_selectedDate">null</field>
|
|
|
|
<!-- String presentation of invalid javascript date -->
|
|
<field name="invalidDate">String(new Date(undefined))</field>
|
|
</implementation>
|
|
</binding>
|
|
|
|
|
|
<!-- COMPACT CALENDAR BASE
|
|
The widget is the interface binding for xhtml and xul calendars widgets.
|
|
It assumes that successor widgets have following interface:
|
|
setDayControl(aControl, aType, aLabel) - set type and label for day control
|
|
selectDayControl(aControl) - makes day control selected
|
|
unselectDayControl(aControl) - unselect day control
|
|
isDayControl(aNode) - return true if aNode is a day control
|
|
-->
|
|
<binding id="calendar-compact-base" extends="#calendar-base">
|
|
|
|
<implementation>
|
|
<!-- interface -->
|
|
<!-- Set focus on day element of current date -->
|
|
<method name="focus">
|
|
<body>
|
|
if (this.currentDayIndex != -1)
|
|
this._dayElements[this.currentDayIndex].focus();
|
|
</body>
|
|
</method>
|
|
|
|
<!-- Updates UI -->
|
|
<method name="refresh">
|
|
<parameter name="aCurrentDay"/>
|
|
<parameter name="aDaysRefreshOnly"/>
|
|
<body>
|
|
this.refreshInternal(aCurrentDay, aDaysRefreshOnly);
|
|
</body>
|
|
</method>
|
|
|
|
<!-- Return day of current date -->
|
|
<property name="currentDay" readonly="true">
|
|
<getter>
|
|
<![CDATA[
|
|
var day = this.currentDayIndex - this.dayOffset + 1;
|
|
if (day < 0 || day > this.daysCount)
|
|
return -1;
|
|
return day;
|
|
]]>
|
|
</getter>
|
|
</property>
|
|
|
|
<!-- private -->
|
|
<method name="refreshInternal">
|
|
<parameter name="aCurrentDay"/>
|
|
<parameter name="aDaysRefreshOnly"/>
|
|
<body>
|
|
<![CDATA[
|
|
if (!this._isUIBuilt) {
|
|
this.buildUI();
|
|
this._isUIBuilt = true;
|
|
}
|
|
|
|
if (!aDaysRefreshOnly) {
|
|
// set days for previous month
|
|
var dayOffset = this.dayOffset;
|
|
var prevDayCount = this.prevDaysCount;
|
|
for (var i = 0; i < dayOffset; i++) {
|
|
this.setDayControl(this._dayElements[i], "prevMonth",
|
|
prevDayCount + i - dayOffset + 1);
|
|
}
|
|
|
|
// set days for current month
|
|
var count = this.daysCount + dayOffset;
|
|
for (; i < count; i++) {
|
|
this.setDayControl(this._dayElements[i], "currentMonth",
|
|
i - dayOffset + 1);
|
|
}
|
|
|
|
// set days for next month
|
|
for (var day = 1; i < this._dayElements.length; i++, day++) {
|
|
this.setDayControl(this._dayElements[i], "nextMonth", day);
|
|
}
|
|
}
|
|
|
|
var selectedIndex = this.dayOffset + this.selectedDay - 1;
|
|
var currentIndex = null;
|
|
if (aCurrentDay)
|
|
currentIndex = this.dayOffset + parseInt(aCurrentDay) - 1;
|
|
else
|
|
currentIndex = this.currentDayIndex;
|
|
|
|
this.setSelectedDayByIndex(selectedIndex, currentIndex);
|
|
]]>
|
|
</body>
|
|
</method>
|
|
|
|
<method name="setSelectedDayByIndex">
|
|
<parameter name="aSelectedIndex"/>
|
|
<parameter name="aCurrentIndex"/>
|
|
<body>
|
|
<![CDATA[
|
|
if (!aCurrentIndex)
|
|
aCurrentIndex = aSelectedIndex;
|
|
|
|
if (this._selectedDayIndex != -1) {
|
|
this.unselectDayControl(this._dayElements[this._selectedDayIndex]);
|
|
}
|
|
|
|
if (this.isSelectedDate()) {
|
|
this.selectDayControl(this._dayElements[aSelectedIndex]);
|
|
this._selectedDayIndex = aSelectedIndex;
|
|
} else {
|
|
this._selectedDayIndex = -1;
|
|
}
|
|
|
|
this.currentDayIndex = aCurrentIndex;
|
|
]]>
|
|
</body>
|
|
</method>
|
|
|
|
<property name="currentDayIndex"
|
|
onget="return this._currentDayIndex;"
|
|
onset="this.setCurrentDayByIndex(val);"/>
|
|
|
|
<method name="setCurrentDayByIndex">
|
|
<parameter name="aIndex"/>
|
|
<body>
|
|
if (this._currentDayIndex == aIndex)
|
|
return;
|
|
|
|
var dayElm = null;
|
|
if (this._currentDayIndex != -1) {
|
|
dayElm = this._dayElements[this._currentDayIndex];
|
|
dayElm.setAttribute("tabindex", "-1");
|
|
}
|
|
|
|
dayElm = this._dayElements[aIndex];
|
|
dayElm.setAttribute("tabindex", "1");
|
|
|
|
this._currentDayIndex = aIndex;
|
|
</body>
|
|
</method>
|
|
|
|
<!-- The method alters day of current date on aDay and if
|
|
1) action type is 'currentMonth' then it selects current date.
|
|
2) action type is 'prevMonth' then it alters month of current date on
|
|
previous month.
|
|
3) action type is 'nextMonth' then it alters month of current date on
|
|
next month.
|
|
-->
|
|
<method name="processAction">
|
|
<parameter name="aActionType"/>
|
|
<parameter name="aDay"/>
|
|
<parameter name="aSkipFocus"/>
|
|
<body>
|
|
<![CDATA[
|
|
if (aDay != null)
|
|
aDay = parseInt(aDay);
|
|
|
|
switch (aActionType) {
|
|
case "prevMonth":
|
|
this.setDate(this.year, this.month - 1, aDay);
|
|
break;
|
|
|
|
case "nextMonth":
|
|
this.setDate(this.year, this.month + 1, aDay);
|
|
break;
|
|
|
|
case "currentMonth":
|
|
if (!this.readonly) {
|
|
this.selectedDate = new Date(this.year, this.month - 1, aDay);
|
|
this.fireChangeEvent();
|
|
} else {
|
|
if (aDay != null)
|
|
this.currentDayIndex = this.dayOffset + aDay - 1;
|
|
}
|
|
break;
|
|
}
|
|
|
|
if (!aSkipFocus)
|
|
this.focus();
|
|
]]>
|
|
</body>
|
|
</method>
|
|
|
|
<!-- UI controls array for days -->
|
|
<field name="_dayElements">new Array()</field>
|
|
|
|
<!-- Index of _dayElements array item pointing on day of selected date -->
|
|
<field name="_selectedDayIndex">-1</field>
|
|
|
|
<!-- Index of _dayElements array item pointing on day of current date -->
|
|
<field name="_currentDayIndex">-1</field>
|
|
|
|
<!-- The flag pointing whether UI was builded -->
|
|
<field name="_isUIBuilt">false</field>
|
|
</implementation>
|
|
|
|
<handlers>
|
|
<handler event="keypress" keycode="VK_LEFT" phase="capturing">
|
|
<![CDATA[
|
|
if (!this.isDayControl(event.originalTarget))
|
|
return;
|
|
|
|
if (this.currentDayIndex - 1 >= 0) {
|
|
this.currentDayIndex--;
|
|
this.focus();
|
|
}
|
|
]]>
|
|
</handler>
|
|
<handler event="keypress" keycode="VK_RIGHT" phase="capturing">
|
|
<![CDATA[
|
|
if (!this.isDayControl(event.originalTarget))
|
|
return;
|
|
|
|
if (this.currentDayIndex + 1 < this._dayElements.length) {
|
|
this.currentDayIndex++;
|
|
this.focus();
|
|
}
|
|
]]>
|
|
</handler>
|
|
<handler event="keypress" keycode="VK_UP" phase="capturing">
|
|
<![CDATA[
|
|
if (!this.isDayControl(event.originalTarget))
|
|
return;
|
|
|
|
if (this.currentDayIndex - 7 >= 0) {
|
|
this.currentDayIndex -= 7;
|
|
this.focus();
|
|
}
|
|
]]>
|
|
</handler>
|
|
<handler event="keypress" keycode="VK_DOWN" phase="capturing">
|
|
<![CDATA[
|
|
if (!this.isDayControl(event.originalTarget))
|
|
return;
|
|
|
|
if (this.currentDayIndex + 7 < this._dayElements.length) {
|
|
this.currentDayIndex += 7;
|
|
this.focus();
|
|
}
|
|
]]>
|
|
</handler>
|
|
|
|
<handler event="keypress" keycode="VK_PAGE_UP">
|
|
this.month++;
|
|
</handler>
|
|
<handler event="keypress" keycode="VK_PAGE_DOWN">
|
|
this.month--;
|
|
</handler>
|
|
</handlers>
|
|
</binding>
|
|
|
|
<!-- RANGE
|
|
Interface for range widgets that use one or more spinbuttons/numberbox
|
|
combinations to represent a type. The widget assumes that successor
|
|
widgets have the following interface:
|
|
updateLabels() - Update range start and end labels.
|
|
updateValue() - Update the value by putting together the individual
|
|
values from each spinbutton.
|
|
updateFields() - Update the value of each individual spinbutton.
|
|
This method is called when a new value is set.
|
|
setSpinButtonMinMax() - Set the min and max attributes of the
|
|
spinbuttons.
|
|
isInRange(aValue) - Is aValue between the start and end values?
|
|
-->
|
|
<binding id="range">
|
|
<implementation>
|
|
<!-- Start label separator -->
|
|
<field name="_startSeparator">&xforms.range.start.separator;</field>
|
|
|
|
<!-- End label separator -->
|
|
<field name="_endSeparator">&xforms.range.end.separator;</field>
|
|
|
|
<!-- interface -->
|
|
<!-- Get/set lower bound of values. -->
|
|
<property name="start"
|
|
onget="return this.getAttribute('start');"
|
|
onset="this.setAttribute('start', val);"/>
|
|
|
|
<!-- Get/set upper bound of values. -->
|
|
<property name="end"
|
|
onget="return this.getAttribute('end');"
|
|
onset="this.setAttribute('end', val);"/>
|
|
|
|
<!-- Get/set step of values. -->
|
|
<property name="step"
|
|
onget="return this.getAttribute('step');"
|
|
onset="this.setAttribute('step', val);"/>
|
|
|
|
<!-- Get/set value. -->
|
|
<property name="value">
|
|
<getter>
|
|
return this.getAttribute('value');
|
|
</getter>
|
|
<setter>
|
|
<![CDATA[
|
|
var value = val;
|
|
if (!value)
|
|
value = this.start;
|
|
|
|
this.setAttribute("value", value);
|
|
this.updateFields();
|
|
this.setSpinbuttonMinMax();
|
|
this.fireValueChange();
|
|
]]>
|
|
</setter>
|
|
</property>
|
|
|
|
|
|
<!-- Set start/end/step/value -->
|
|
<method name="set">
|
|
<parameter name="aStart"/>
|
|
<parameter name="aEnd"/>
|
|
<parameter name="aStep"/>
|
|
<parameter name="aValue"/>
|
|
<body>
|
|
this.start = aStart;
|
|
this.end = aEnd;
|
|
this.step = aStep;
|
|
this.value = aValue;
|
|
|
|
this.updateLabels();
|
|
</body>
|
|
</method>
|
|
|
|
<!-- Format a value to the given number of digits by padding with
|
|
leading zeros.
|
|
-->
|
|
<method name="formatValue">
|
|
<parameter name="aValue"/>
|
|
<parameter name="aDigits"/>
|
|
<body>
|
|
<![CDATA[
|
|
var formattedValue = aValue;
|
|
while (formattedValue.length < aDigits) {
|
|
formattedValue = "0" + formattedValue;
|
|
}
|
|
return formattedValue;
|
|
]]>
|
|
</body>
|
|
</method>
|
|
|
|
<!-- Update the text content of range widget labels.
|
|
For example, a range widget may want to have labels
|
|
for the start and end values of the range.
|
|
-->
|
|
<method name="updateLabels">
|
|
<body>
|
|
return true;
|
|
</body>
|
|
</method>
|
|
|
|
<!-- Update the widget's value attribute by putting together the
|
|
individual spinbutton values in the correct format for the type.
|
|
-->
|
|
<method name="updateValue">
|
|
<body>
|
|
return true;
|
|
</body>
|
|
</method>
|
|
|
|
|
|
<!-- Parse the widget's value attribute and update the value of
|
|
of each individual spinbutton.
|
|
-->
|
|
<method name="updateFields">
|
|
<body>
|
|
return true;
|
|
</body>
|
|
</method>
|
|
|
|
<!-- Set the min and max attributes for the spinbuttons.
|
|
If any one of the spinbuttons/numberboxes changes value,
|
|
the valid min and max for one or more of the others may
|
|
have to change too.
|
|
|
|
Example: In a dateTime range, if the current date is 2007-02-28
|
|
and the year is changed to 2008 (a leap year), the max day for
|
|
the month of February will change from 28 to 29. Likewise, if
|
|
the current date were 2007-03-31 and the month is changed to 04,
|
|
the max day will have to change from 31 to 30.
|
|
-->
|
|
<method name="setSpinbuttonMinMax">
|
|
<body>
|
|
return true;
|
|
</body>
|
|
</method>
|
|
|
|
<!-- Is aValue between the start and end values? -->
|
|
<method name="isInRange">
|
|
<parameter name="aValue"/>
|
|
<body>
|
|
return true;
|
|
</body>
|
|
</method>
|
|
|
|
<!-- Increment value -->
|
|
<method name="increment">
|
|
<body>
|
|
this.updateSpinbuttons();
|
|
</body>
|
|
</method>
|
|
|
|
<!-- Decrement value -->
|
|
<method name="decrement">
|
|
<body>
|
|
this.updateSpinbuttons();
|
|
</body>
|
|
</method>
|
|
|
|
<!-- Update the spinbutton min and max attributes and the range
|
|
value when an increment or decrement event occurs.
|
|
-->
|
|
<method name="updateSpinbuttons">
|
|
<body>
|
|
this.setSpinbuttonMinMax();
|
|
this.updateValue();
|
|
this.fireValueChange();
|
|
</body>
|
|
</method>
|
|
|
|
<!-- Fire the 'ValueChange' event.
|
|
Range widgets must fire their own change event because the act of
|
|
incrementing/decrementing one spinbutton may change one or more
|
|
of the others at the same time as SetSpinbuttonMinMax will change
|
|
the min and max attributes on the fly.
|
|
|
|
The range widget updates its value on each 'change' event from the
|
|
spinbuttons and then fires ValueChange after they have all been
|
|
updated so that the range binding can update the instance data.
|
|
-->
|
|
<method name="fireValueChange">
|
|
<body>
|
|
var event = this.ownerDocument.createEvent("Events");
|
|
event.initEvent("ValueChange", true, false);
|
|
this.dispatchEvent(event);
|
|
</body>
|
|
</method>
|
|
|
|
<constructor>
|
|
// Spinup events are generated by the numberbox widget
|
|
// defined in "widgets-xul.xml".
|
|
var upHandler = {
|
|
range: this,
|
|
handleEvent: function(aEvent) {
|
|
this.range.increment();
|
|
}
|
|
};
|
|
// Spindown events are generated by the numberbox widgets
|
|
// defined in "widgets-xul.xml".
|
|
var downHandler = {
|
|
range: this,
|
|
handleEvent: function(aEvent) {
|
|
this.range.decrement();
|
|
}
|
|
};
|
|
// Change events are generated by the numberbox widget
|
|
// defined in "widgets-xul.xml".
|
|
var changeHandler = {
|
|
range: this,
|
|
handleEvent: function(aEvent) {
|
|
this.range.updateValue();
|
|
}
|
|
};
|
|
this.addEventListener("spinup", upHandler, false);
|
|
this.addEventListener("spindown", downHandler, false);
|
|
this.addEventListener("change", changeHandler, false);
|
|
</constructor>
|
|
</implementation>
|
|
</binding>
|
|
|
|
<!-- DATETIME -->
|
|
<binding id="datetime" extends="#range">
|
|
<implementation>
|
|
<!-- interface -->
|
|
<!-- dateTime format: yyyy-mm-ddThh:mm:ss[.s+] -->
|
|
|
|
<!-- Extract the year from a date or dateTime -->
|
|
<method name="getYear">
|
|
<parameter name="aDate"/>
|
|
<body>
|
|
return parseFloat(aDate.substr(0,4));
|
|
</body>
|
|
</method>
|
|
|
|
<!-- Extract the month from a date or dateTime -->
|
|
<method name="getMonth">
|
|
<parameter name="aDate"/>
|
|
<body>
|
|
return parseFloat(aDate.substr(5,2));
|
|
</body>
|
|
</method>
|
|
|
|
<!-- Extract the day from a date or dateTime -->
|
|
<method name="getDay">
|
|
<parameter name="aDate"/>
|
|
<body>
|
|
return parseFloat(aDate.substr(8,2));
|
|
</body>
|
|
</method>
|
|
|
|
<!-- Extract the hours from a dateTime -->
|
|
<method name="getHours">
|
|
<parameter name="aDateTime"/>
|
|
<body>
|
|
return parseFloat(aDateTime.substr(11,2));
|
|
</body>
|
|
</method>
|
|
|
|
<!-- Extract the minutes from a dateTime -->
|
|
<method name="getMinutes">
|
|
<parameter name="aDateTime"/>
|
|
<body>
|
|
return parseFloat(aDateTime.substr(14,2));
|
|
</body>
|
|
</method>
|
|
|
|
<!-- Extract the seconds from a dateTime -->
|
|
<method name="getSeconds">
|
|
<parameter name="aDateTime"/>
|
|
<body>
|
|
return parseFloat(aDateTime.substr(17,2));
|
|
</body>
|
|
</method>
|
|
|
|
<!-- Get the minimum Year value. -->
|
|
<method name="getYearMin">
|
|
<body>
|
|
<![CDATA[
|
|
// The min value for the year spinbutton will always
|
|
// be the year of the start date.
|
|
return this.getYear(this.start);
|
|
]]>
|
|
</body>
|
|
</method>
|
|
|
|
<!-- Get the maximum Year value. -->
|
|
<method name="getYearMax">
|
|
<body>
|
|
<![CDATA[
|
|
// The max value for the year spinbutton will always
|
|
// be the year of the end date.
|
|
return this.getYear(this.end);
|
|
]]>
|
|
</body>
|
|
</method>
|
|
|
|
<!-- Get the minimum Month value. -->
|
|
<method name="getMonthMin">
|
|
<body>
|
|
<![CDATA[
|
|
// The min value for the month spinbutton depends on the year
|
|
// range and the current value of the year.
|
|
var startYear = this.getYear(this.start);
|
|
var endYear = this.getYear(this.end);
|
|
var currentYear = this.getYear(this.value);
|
|
var minMonth = 0;
|
|
|
|
if (startYear == endYear || currentYear == startYear) {
|
|
// Min month is the month of the start date.
|
|
minMonth = this.getMonth(this.start);
|
|
} else {
|
|
// Current year falls between the start and end dates so
|
|
// the minimum month is the first month of the year.
|
|
minMonth = 1;
|
|
}
|
|
return minMonth;
|
|
]]>
|
|
</body>
|
|
</method>
|
|
|
|
<!-- Get the maximum Month value. -->
|
|
<method name="getMonthMax">
|
|
<body>
|
|
<![CDATA[
|
|
// The max value for the month spinbutton depends on the year
|
|
// range and the current value of the year.
|
|
var startYear = this.getYear(this.start);
|
|
var endYear = this.getYear(this.end);
|
|
var currentYear = this.getYear(this.value);
|
|
var maxMonth = 0;
|
|
|
|
if (startYear == endYear || currentYear == endYear) {
|
|
// Max month is the month of the end date.
|
|
maxMonth = this.getMonth(this.end);
|
|
} else {
|
|
// Current year falls between the start and end dates so
|
|
// the maximum month is the last month of the year.
|
|
maxMonth = 12;
|
|
}
|
|
return maxMonth;
|
|
]]>
|
|
</body>
|
|
</method>
|
|
|
|
<!-- Get the minimum Day value. -->
|
|
<method name="getDayMin">
|
|
<body>
|
|
<![CDATA[
|
|
// The min value for the day spinbutton depends on the current
|
|
// month and year but may also be constrained by the day of the
|
|
// start date.
|
|
var startYear = this.getYear(this.start);
|
|
var endYear = this.getYear(this.end);
|
|
var currentYear = this.getYear(this.value);
|
|
var startMonth = this.getMonth(this.start);
|
|
var endMonth = this.getMonth(this.end);
|
|
var currentMonth = this.getMonth(this.value);
|
|
var minDay = 0;
|
|
|
|
if (startYear == endYear) {
|
|
if (startMonth == endMonth || currentMonth == startMonth) {
|
|
// Start and end month are the same month of the same year or
|
|
// the current month is the start month. Min day is the day of
|
|
// the start date.
|
|
minDay = this.getDay(this.start);
|
|
} else {
|
|
// Current month is between the start and end months.
|
|
// Min day is the first day of the month.
|
|
minDay = 1;
|
|
}
|
|
} else {
|
|
// Start and End year span 1 or more years.
|
|
if (currentYear == startYear) {
|
|
if (currentMonth == startMonth) {
|
|
// Current month is the start month of the start year.
|
|
// Min day is the day of the start date.
|
|
minDay = this.getDay(this.start);
|
|
} else {
|
|
// Current month is between the start month and the last
|
|
// month of the current year.
|
|
// Min day is the first day of the month.
|
|
minDay = 1;
|
|
}
|
|
} else {
|
|
// Current year is between the start and end years.
|
|
// Min day is the first day of the month.
|
|
minDay = 1;
|
|
}
|
|
}
|
|
return minDay;
|
|
]]>
|
|
</body>
|
|
</method>
|
|
|
|
<!-- Get the maximum Day value. -->
|
|
<method name="getDayMax">
|
|
<body>
|
|
<![CDATA[
|
|
// The max value for the day spinbutton depends on the current
|
|
// month and year but may also be constrained by the day of the
|
|
// end date.
|
|
var startYear = this.getYear(this.start);
|
|
var endYear = this.getYear(this.end);
|
|
var currentYear = this.getYear(this.value);
|
|
var startMonth = this.getMonth(this.start);
|
|
var endMonth = this.getMonth(this.end);
|
|
var currentMonth = this.getMonth(this.value);
|
|
var currentDay = this.getDay(this.value);
|
|
var daysCount = this.getDaysCount(currentMonth, currentYear);
|
|
var maxDay = 0;
|
|
|
|
if (startYear == endYear) {
|
|
if (startMonth == endMonth || currentMonth == endMonth) {
|
|
// Start and end month are the same month of the same year or
|
|
// the current month is the end month. Max day is the day of
|
|
// the end month.
|
|
maxDay = this.getDay(this.end);
|
|
} else {
|
|
// Current month is between the start and end months.
|
|
// Max day is the number of days in the month.
|
|
maxDay = daysCount;
|
|
}
|
|
} else {
|
|
// Start and End year span 1 or more years.
|
|
if (currentYear == endYear) {
|
|
if (currentMonth == endMonth) {
|
|
// Current month is the end month of the end year.
|
|
// Max day is the day of the end month;
|
|
maxDay = this.getDay(this.end);
|
|
} else {
|
|
// Current month falls between the first month of the
|
|
// current (end) year and the month of the end date.
|
|
// May day is the number of days in the month.
|
|
maxDay = daysCount;
|
|
}
|
|
} else {
|
|
// Current year is between the start and end years.
|
|
// Max day is the number of days in the month.
|
|
maxDay = daysCount;
|
|
}
|
|
}
|
|
return maxDay;
|
|
]]>
|
|
</body>
|
|
</method>
|
|
|
|
<!-- Get the minimum Hours value. -->
|
|
<method name="getHoursMin">
|
|
<body>
|
|
<![CDATA[
|
|
// The min value for the hours spinbutton will always be the
|
|
// hours of the start time.
|
|
return this.getHours(this.start);
|
|
]]>
|
|
</body>
|
|
</method>
|
|
|
|
<!-- Get the maximum Hours value. -->
|
|
<method name="getHoursMax">
|
|
<body>
|
|
<![CDATA[
|
|
// The max value for the hours spinbutton will always be the
|
|
// hours of the end time.
|
|
return this.getHours(this.end);
|
|
]]>
|
|
</body>
|
|
</method>
|
|
|
|
<!-- Get the minimum Minutes value. -->
|
|
<method name="getMinutesMin">
|
|
<body>
|
|
<![CDATA[
|
|
// The min value for the minutes spinbutton depends on the hours
|
|
// range and the current value of the hours.
|
|
var startHours = this.getHours(this.start);
|
|
var endHours = this.getHours(this.end);
|
|
var currentHours = this.getHours(this.value);
|
|
var startMinutes = this.getMinutes(this.start);
|
|
var minMinutes = 0;
|
|
|
|
if (startHours == endHours || currentHours == startHours) {
|
|
// Min minutes is the minutes of the start time.
|
|
minMinutes = startMinutes;
|
|
|
|
} else {
|
|
// Current hours falls between the start and end hours.
|
|
// Min minutes is the first minute of the hour.
|
|
minMinutes = 0;
|
|
}
|
|
return minMinutes;
|
|
]]>
|
|
</body>
|
|
</method>
|
|
|
|
<!-- Get the maximum Minutes value. -->
|
|
<method name="getMinutesMax">
|
|
<body>
|
|
<![CDATA[
|
|
// The max value for the minutes spinbutton depends on the hours
|
|
// range and the current value of the hours.
|
|
var startHours = this.getHours(this.start);
|
|
var endHours = this.getHours(this.end);
|
|
var currentHours = this.getHours(this.value);
|
|
var endMinutes = this.getMinutes(this.end);
|
|
var maxMinutes = 0;
|
|
|
|
if (startHours == endHours || currentHours == endHours) {
|
|
// Max minutes is the minutes of the end time.
|
|
maxMinutes = endMinutes;
|
|
|
|
} else {
|
|
// Current hours falls between start hours and end hours.
|
|
// Max minutes is the last minute of the hour.
|
|
maxMinutes = 59;
|
|
}
|
|
return maxMinutes;
|
|
]]>
|
|
</body>
|
|
</method>
|
|
|
|
<!-- Get the minimum Seconds value. -->
|
|
<method name="getSecondsMin">
|
|
<body>
|
|
<![CDATA[
|
|
// The min value for the seconds spinbutton depends on the current
|
|
// minutes but may also be constrained by the seconds of the start
|
|
// time.
|
|
var startMinutes = this.getMinutes(this.start);
|
|
var endMinutes = this.getMinutes(this.end);
|
|
var currentMinutes = this.getMinutes(this.value);
|
|
var startSeconds = this.getSeconds(this.start);
|
|
var minSeconds = 0;
|
|
|
|
if (startMinutes == endMinutes || currentMinutes == startMinutes) {
|
|
// Min seconds is the seconds of the start time.
|
|
minSeconds = startSeconds;
|
|
} else {
|
|
// Current minutes falls between the start and end minutes.
|
|
// Min seconds is the first second of a minute.
|
|
minSeconds = 0;
|
|
}
|
|
return minSeconds;
|
|
]]>
|
|
</body>
|
|
</method>
|
|
|
|
<!-- Get the maximum Seconds value. -->
|
|
<method name="getSecondsMax">
|
|
<body>
|
|
<![CDATA[
|
|
// The max value for the seconds spinbutton depends on the current
|
|
// minutes but may also be constrained by the seconds of the end
|
|
// time.
|
|
var startMinutes = this.getMinutes(this.start);
|
|
var endMinutes = this.getMinutes(this.end);
|
|
var currentMinutes = this.getMinutes(this.value);
|
|
var endSeconds = this.getSeconds(this.end);
|
|
var maxSeconds = 0;
|
|
|
|
if (startMinutes == endMinutes || currentMinutes == endMinutes) {
|
|
// Max seconds is the seconds of the end time.
|
|
maxSeconds = endSeconds;
|
|
} else {
|
|
// Current minutes falls between the start and end minutes.
|
|
// Max seconds is the last second of a minute.
|
|
maxSeconds = 59;
|
|
}
|
|
return maxSeconds;
|
|
]]>
|
|
</body>
|
|
</method>
|
|
|
|
<!-- Get the number of days in the month for a given year. -->
|
|
<method name="getDaysCount">
|
|
<parameter name="aMonth"/>
|
|
<parameter name="aYear"/>
|
|
<body>
|
|
<![CDATA[
|
|
switch (aMonth) {
|
|
case 1: case 3: case 5: case 7: case 8: case 10: case 12:
|
|
return 31;
|
|
|
|
case 2:
|
|
if (aYear % 4 == 0 && aYear % 100 != 0 || aYear % 400 == 0)
|
|
return 29; // leap-year
|
|
return 28;
|
|
|
|
case 4: case 6: case 9: case 11:
|
|
return 30;
|
|
}
|
|
return 0;
|
|
]]>
|
|
</body>
|
|
</method>
|
|
|
|
<!-- Get a Javacript Date object initialized to the value of aDateTime.
|
|
-->
|
|
<method name="getDate">
|
|
<parameter name="aDateTime"/>
|
|
<body>
|
|
var date = new Date();
|
|
date.setFullYear(this.getYear(aDateTime));
|
|
date.setMonth(this.getMonth(aDateTime));
|
|
date.setDate(this.getDay(aDateTime));
|
|
date.setHours(this.getHours(aDateTime));
|
|
date.setMinutes(this.getMinutes(aDateTime));
|
|
date.setSeconds(this.getSeconds(aDateTime));
|
|
return date;
|
|
</body>
|
|
</method>
|
|
</implementation>
|
|
</binding>
|
|
|
|
<!-- DATE -->
|
|
<binding id="date" extends="#datetime">
|
|
<implementation>
|
|
<!-- interface -->
|
|
<!-- date format: yyyy-mm-dd -->
|
|
|
|
<!-- Get a Javacript Date object initialized to the value of aDate.
|
|
-->
|
|
<method name="getDate">
|
|
<parameter name="aDate"/>
|
|
<body>
|
|
var date = new Date();
|
|
date.setFullYear(this.getYear(aDate));
|
|
date.setMonth(this.getMonth(aDate));
|
|
date.setDate(this.getDay(aDate));
|
|
return date;
|
|
</body>
|
|
</method>
|
|
</implementation>
|
|
</binding>
|
|
|
|
<!-- TIME -->
|
|
<binding id="time" extends="#datetime">
|
|
<implementation>
|
|
<!-- interface -->
|
|
<!-- Time format: hh:mm:ss[.s+] -->
|
|
|
|
<!-- Extract the hours from a time -->
|
|
<method name="getHours">
|
|
<parameter name="aTime"/>
|
|
<body>
|
|
return parseFloat(aTime.substr(0,2));
|
|
</body>
|
|
</method>
|
|
|
|
<!-- Extract the minutes from a time -->
|
|
<method name="getMinutes">
|
|
<parameter name="aTime"/>
|
|
<body>
|
|
return parseFloat(aTime.substr(3,2));
|
|
</body>
|
|
</method>
|
|
|
|
<!-- Extract the seconds from a time -->
|
|
<method name="getSeconds">
|
|
<parameter name="aTime"/>
|
|
<body>
|
|
return parseFloat(aTime.substr(6,2));
|
|
</body>
|
|
</method>
|
|
|
|
<!-- Get a Javacript Date object initialized to the value of aTime.
|
|
A JS Date object also accepts a time and we can use a Date
|
|
initialized with a Time to compare times.
|
|
-->
|
|
<method name="getDate">
|
|
<parameter name="aTime"/>
|
|
<body>
|
|
var date = new Date();
|
|
date.setHours(this.getHours(aTime));
|
|
date.setMinutes(this.getMinutes(aTime));
|
|
date.setSeconds(this.getSeconds(aTime));
|
|
return date;
|
|
</body>
|
|
</method>
|
|
</implementation>
|
|
</binding>
|
|
|
|
</bindings>
|