1 <?xml version="1.0"?>
2 <!-- ***** BEGIN LICENSE BLOCK *****
3 - Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 -
5 - The contents of this file are subject to the Mozilla Public License Version
6 - 1.1 (the "License"); you may not use this file except in compliance with
7 - the License. You may obtain a copy of the License at
8 - http://www.mozilla.org/MPL/
9 -
10 - Software distributed under the License is distributed on an "AS IS" basis,
11 - WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 - for the specific language governing rights and limitations under the
13 - License.
14 -
15 - The Original Code is Sun Microsystems code.
16 -
17 - The Initial Developer of the Original Code is Sun Microsystems.
18 - Portions created by the Initial Developer are Copyright (C) 2006
19 - the Initial Developer. All Rights Reserved.
20 -
21 - Contributor(s):
22 - Michael Buettner <michael.buettner@sun.com>
23 -
24 - Alternatively, the contents of this file may be used under the terms of
25 - either the GNU General Public License Version 2 or later (the "GPL"), or
26 - the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
27 - in which case the provisions of the GPL or the LGPL are applicable instead
28 - of those above. If you wish to allow use of your version of this file only
29 - under the terms of either the GPL or the LGPL, and not to allow others to
30 - use your version of this file under the terms of the MPL, indicate your
31 - decision by deleting the provisions above and replace them with the notice
32 - and other provisions required by the GPL or the LGPL. If you do not delete
33 - the provisions above, a recipient may use your version of this file under
34 - the terms of any one of the MPL, the GPL or the LGPL.
35 -
36 - ***** END LICENSE BLOCK ***** -->
37
38 <bindings xmlns="http://www.mozilla.org/xbl"
39 xmlns:xbl="http://www.mozilla.org/xbl"
40 xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
41
42 <binding id="recurrence-preview" extends="xul:box">
43 <content>
44 <xul:box flex="1" style="overflow: hidden;">
45 <xul:grid flex="1" anonid="mainbox">
46 <xul:columns>
47 <xul:column anonid="column"/>
48 <xul:column flex="1"/>
49 </xul:columns>
50 <xul:rows>
51 <xul:row anonid="row">
52 <xul:minimonth anonid="minimonth" readonly="true"/>
53 <xul:minimonth anonid="minimonth" readonly="true"/>
54 <xul:minimonth anonid="minimonth" readonly="true"/>
55 <xul:spacer/>
56 </xul:row>
57 </xul:rows>
58 </xul:grid>
59 </xul:box>
60 </content>
61
62 <implementation>
63
64 <field name="mRecurrenceInfo">null</field>
65 <field name="mResizeHandler">null</field>
66 <field name="mDateTime">null</field>
67
68 <constructor><![CDATA[
69 var self = this;
70 this.mResizeHandler = function recurrence_preview_resizeHandler() {
71 self.onResize();
72 };
73 window.addEventListener("resize", this.mResizeHandler, true);
74 ]]></constructor>
75
76 <destructor><![CDATA[
77 window.removeEventListener("resize", this.mResizeHandler, true);
78 ]]></destructor>
79
80 <property name="dateTime">
81 <setter><![CDATA[
82 return this.mDateTime = val.clone();
83 ]]></setter>
84 <getter><![CDATA[
85 if (this.mDateTime == null) {
86 this.mDateTime = now();
87 }
88 return this.mDateTime;
89 ]]></getter>
90 </property>
91 <method name="onResize">
92 <body><![CDATA[
93 var mainbox =
94 document.getAnonymousElementByAttribute(
95 this, "anonid", "mainbox");
96 var minimonth =
97 document.getAnonymousElementByAttribute(
98 this, "anonid", "minimonth");
99
100 var row =
101 document.getAnonymousElementByAttribute(
102 this, "anonid", "row");
103 var rows = row.parentNode;
104
105 var contentWidth = minimonth.boxObject.width;
106 var containerWidth =
107 document.getAnonymousNodes(this)[0]
108 .boxObject.width;
109
110 // Now find out how much elements can be displayed.
111 // this is a simple division which always yields a positive integer value.
112 var numHorizontal =
113 (containerWidth -
114 (containerWidth % contentWidth)) /
115 contentWidth;
116
117 var contentHeight = minimonth.boxObject.height;
118 var containerHeight =
119 document.getAnonymousNodes(this)[0]
120 .boxObject.height;
121
122 // Now find out how much elements can be displayed.
123 // this is a simple division which always yields a positive integer value.
124 var numVertical =
125 (containerHeight -
126 (containerHeight % contentHeight)) /
127 contentHeight;
128 numVertical = Math.max(1, numVertical);
129
130 // Count the number of existing rows
131 var numRows = 0;
132 var rowIterator = row;
133 while (rowIterator) {
134 numRows++;
135 rowIterator = rowIterator.nextSibling;
136 }
137
138 // Adjust rows
139 while (numRows < numVertical) {
140 var newNode = row.cloneNode(true);
141 rows.appendChild(newNode);
142 numRows++;
143 }
144 while (numRows > numVertical) {
145 rows.removeChild(rows.firstChild);
146 numRows--
147 }
148
149 // Adjust columns in the grid
150 var column =
151 document.getAnonymousElementByAttribute(
152 this, "anonid", "column");
153 var columns = column.parentNode;
154 while ((columns.childNodes.length - 1) < numHorizontal) {
155 var newColumn = column.cloneNode(false);
156 columns.insertBefore(newColumn, column.nextSibling);
157 }
158 while ((columns.childNodes.length - 1) > numHorizontal) {
159 columns.removeChild(columns.firstChild);
160 }
161
162 // Walk all rows and adjust column elements
163 row = document.getAnonymousElementByAttribute(
164 this, "anonid", "row");
165 while (row) {
166 var firstChild = row.firstChild;
167 while ((row.childNodes.length - 1) < numHorizontal) {
168 var newNode = firstChild.cloneNode(true);
169 firstChild.parentNode.insertBefore(newNode, firstChild);
170 }
171 while ((row.childNodes.length - 1) > numHorizontal) {
172 row.removeChild(row.firstChild);
173 }
174 row = row.nextSibling;
175 }
176
177 this.updateContent();
178 this.updatePreview(this.mRecurrenceInfo);
179 ]]></body>
180 </method>
181
182 <method name="updateContent">
183 <body><![CDATA[
184 var date = this.dateTime.clone().jsDate;
185 var row = document.getAnonymousElementByAttribute(
186 this, "anonid", "row");
187 while (row) {
188 var numChilds = row.childNodes.length - 1;
189 for (var i = 0; i < numChilds; i++) {
190 var minimonth = row.childNodes[i];
191 minimonth.showMonth(date);
192 date.setMonth(date.getMonth() + 1);
193 }
194 row = row.nextSibling;
195 }
196 ]]></body>
197 </method>
198
199 <method name="updatePreview">
200 <parameter name="aRecurrenceInfo"/>
201 <body><![CDATA[
202 this.mRecurrenceInfo = aRecurrenceInfo;
203 var start = this.dateTime.clone();
204 start.day = 1;
205 start.hour = 0;
206 start.minute = 0;
207 start.second = 0;
208 var end = start.clone();
209 end.month++;
210
211 // the 'minimonth' controls are arranged in a
212 // grid, sorted by rows first -> iterate the rows that may exist.
213 var row = document.getAnonymousElementByAttribute(this, "anonid", "row");
214 while (row) {
215
216 // now iterater all the child nodes of this row
217 // in order to visit each minimonth in turn.
218 var numChilds = row.childNodes.length - 1;
219 for (var i = 0; i < numChilds; i++) {
220
221 // we now have one of the minimonth controls while 'start'
222 // and 'end' are set to the interval this minimonth shows.
223 var minimonth = row.childNodes[i];
224 minimonth.showMonth(start.jsDate);
225 if (aRecurrenceInfo) {
226
227 // retrieve an array of dates that represents all occurrences
228 // that fall into this time interval [start,end[.
229 // note: the following loop assumes that this array conains
230 // dates that are strictly monotonically increasing.
231 // should getOccurrenceDates() not enforce this assumption we
232 // need to fall back to some different algorithm.
233 var dates = aRecurrenceInfo.getOccurrenceDates(start, end, 0, {});
234
235 // now run throgh all days of this month and set the
236 // 'busy' attribute with respect to the occurrence array.
237 var index = 0;
238 var occurrence = null;
239 if (index < dates.length) {
240 occurrence =
241 dates[index++]
242 .getInTimezone(start.timezone);
243 }
244 var current = start.clone();
245 while (current.compare(end) < 0) {
246 var box = minimonth.getBoxForDate(current.jsDate);
247 if (box) {
248 if (occurrence &&
249 occurrence.day == current.day &&
250 occurrence.month == current.month &&
251 occurrence.year == current.year) {
252 box.setAttribute("busy", 1);
253 if (index < dates.length) {
254 occurrence =
255 dates[index++]
256 .getInTimezone(start.timezone);
257 // take into account that the very next occurrence
258 // can happen at the same day as the previous one.
259 if (occurrence.day == current.day &&
260 occurrence.month == current.month &&
261 occurrence.year == current.year) {
262 continue;
263 }
264 } else {
265 occurrence = null;
266 }
267 } else {
268 box.removeAttribute("busy");
269 }
270 }
271 current.day++;
272 }
273 }
274 start.month++;
275 end.month++;
276 }
277 row = row.nextSibling;
278 }
279 ]]></body>
280 </method>
281 </implementation>
282 </binding>
283 </bindings>