1 /* ***** BEGIN LICENSE BLOCK *****
2 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
3 *
4 * The contents of this file are subject to the Mozilla Public License Version
5 * 1.1 (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 * http://www.mozilla.org/MPL/
8 *
9 * Software distributed under the License is distributed on an "AS IS" basis,
10 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
11 * for the specific language governing rights and limitations under the
12 * License.
13 *
14 * The Original Code is Sun Microsystems code.
15 *
16 * The Initial Developer of the Original Code is Sun Microsystems.
17 * Portions created by the Initial Developer are Copyright (C) 2006
18 * the Initial Developer. All Rights Reserved.
19 *
20 * Contributor(s):
21 * Michael Buettner <michael.buettner@sun.com>
22 * Philipp Kewisch <mozilla@kewis.ch>
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 function onLoad() {
39 var args = window.arguments[0];
40 var item = args.calendarEvent;
41 item = (item.isMutable) ? item : item.clone();
42 var calendar = item.calendar;
43 window.item = item;
44
45 // the calling entity provides us with an object that is responsible
46 // for recording details about the initiated modification. the 'finalize'-property
47 // is our hook in order to receive a notification in case the operation needs
48 // to be terminated prematurely. this function will be called if the calling
49 // entity needs to immediately terminate the pending modification. in this
50 // case we serialize the item and close the window.
51 if (args.job) {
52
53 // keep this context...
54 var self = this;
55
56 // store the 'finalize'-functor in the provided job-object.
57 args.job.finalize = function finalize() {
58
59 // store any pending modifications...
60 self.onAccept();
61
62 var item = window.item;
63
64 // ...and close the window.
65 window.close();
66
67 return item;
68 }
69 }
70
71 window.readOnly = calendar.readOnly;
72 if (!window.readOnly) {
73 try {
74 // temporary hack unless all group scheduling features are supported
75 // by the caching facade (calCachedCalendar):
76 var provider = calendar.getProperty("private.wcapCalendar")
77 .QueryInterface(Components.interfaces.calIWcapCalendar);
78 var attendee = provider.getInvitedAttendee(item);
79 if (attendee) {
80 window.attendee = attendee.clone();
81 item.removeAttendee(attendee);
82 item.addAttendee(window.attendee);
83 }
84 }
85 catch(e) {
86 }
87 }
88
89 var formatter = Components.classes[
90 "@mozilla.org/calendar/datetime-formatter;1"]
91 .getService(
92 Components.interfaces.calIDateTimeFormatter);
93
94 document.getElementById("item-title").value = item.title;
95
96 // show the start time of the event
97 var kDefaultTimezone = calendarDefaultTimezone();
98 var start = item.startDate || item.entryDate;
99 if (start) {
100 document.getElementById("item-datetime")
101 .value = formatter.formatDateLong(
102 start.getInTimezone(kDefaultTimezone));
103 }
104
105 if (!window.readOnly) {
106 document.getElementById("item-main-separator")
107 .removeAttribute("hidden");
108 }
109
110 updateInvitationStatus();
111
112 // show reminder if this item is *not* readonly.
113 // this case happens for example if this is an invitation.
114 if (!window.readOnly) {
115 document.getElementById("reminder-row").removeAttribute("hidden");
116 loadReminder(window.item);
117 updateReminderDetails();
118 }
119
120 updateRepeatDetails();
121 updateAttendees();
122
123 var location = item.getProperty("LOCATION");
124 if (location && location.length) {
125 document.getElementById("location-row").removeAttribute("hidden");
126 document.getElementById("item-location").value = location;
127 }
128
129 var category = item.getProperty("CATEGORIES");
130 if (category && category.length) {
131 document.getElementById("category-row").removeAttribute("hidden");
132 document.getElementById("item-category").value = category;
133 }
134
135 var organizer = item.organizer;
136 if (organizer) {
137 if (organizer.commonName && organizer.commonName.length) {
138 document.getElementById("organizer-row")
139 .removeAttribute("hidden");
140 document.getElementById("item-organizer")
141 .value = organizer.commonName;
142 } else if (organizer.id && organizer.id.length) {
143 var email = organizer.id;
144 var re = new RegExp("^mailto:(.*)", "i");
145 var matches = re.exec(email);
146 if (matches) {
147 email = matches[1];
148 }
149 document.getElementById("organizer-row").removeAttribute("hidden");
150 document.getElementById("item-organizer").value = email;
151 }
152 }
153
154 var status = item.getProperty("STATUS");
155 if (status && status.length) {
156 var statusRow = document.getElementById("status-row");
157 for (var i = 0; i < statusRow.childNodes.length; i++) {
158 if (statusRow.childNodes[i].getAttribute("status") == status) {
159 statusRow.removeAttribute("hidden");
160 statusRow.childNodes[i].removeAttribute("hidden");
161 break;
162 }
163 }
164 }
165
166 if (item.hasProperty("DESCRIPTION")) {
167 var description = item.getProperty("DESCRIPTION");
168 if (description && description.length) {
169 document.getElementById("item-description-box")
170 .removeAttribute("hidden");
171 var textbox = document.getElementById("item-description");
172 textbox.value = description;
173 textbox.inputField.readOnly = true;
174 }
175 }
176
177 if (item.hasProperty("URL")) {
178 var url = item.getProperty("URL");
179 if (url && url.length) {
180 document.getElementById("item-link-box").removeAttribute("hidden");
181 document.getElementById("item-link").value = url;
182 }
183 }
184
185 document.title = item.title;
186
187 // If this item is read only we remove the 'cancel' button as users
188 // can't modify anything, thus we go ahead with an 'ok' button only.
189 if (window.readOnly) {
190 document.getElementById("calendar-summary-dialog")
191 .getButton("cancel").setAttribute("collapsed", "true");
192 }
193
194 window.focus();
195 opener.setCursor("auto");
196 }
197
198 function onAccept() {
199 dispose();
200 if (window.readOnly) {
201 return true;
202 }
203 var args = window.arguments[0];
204 var oldItem = args.calendarEvent;
205 var newItem = window.item;
206 var calendar = newItem.calendar;
207 saveReminder(newItem);
208 args.onOk(newItem, calendar, oldItem);
209 window.item = newItem;
210 return true;
211 }
212
213 function onCancel() {
214 dispose();
215 return true;
216 }
217
218 function updateInvitationStatus() {
219 var item = window.item;
220 var calendar = item.calendar;
221 if (!window.readOnly) {
222 if (window.attendee) {
223 var invitationRow =
224 document.getElementById("invitation-row");
225 invitationRow.removeAttribute("hidden");
226 var statusElement =
227 document.getElementById("item-participation");
228 statusElement.value = attendee.participationStatus;
229 }
230 }
231 }
232
233 function updateInvitation() {
234 var statusElement = document.getElementById("item-participation");
235 if (window.attendee) {
236 window.attendee.participationStatus = statusElement.value;
237 }
238 }
239
240 function updateRepeatDetails() {
241 var args = window.arguments[0];
242 var item = args.calendarEvent;
243
244 // step to the parent (in order to show the
245 // recurrence info which is stored at the parent).
246 item = item.parentItem;
247
248 // retrieve a valid recurrence rule from the currently
249 // set recurrence info. bail out if there's more
250 // than a single rule or something other than a rule.
251 var recurrenceInfo = item.recurrenceInfo;
252 if (!recurrenceInfo) {
253 return;
254 }
255
256 document.getElementById("repeat-row").removeAttribute("hidden");
257
258 // First of all collapse the details text. If we fail to
259 // create a details string, we simply don't show anything.
260 // this could happen if the repeat rule is something exotic
261 // we don't have any strings prepared for.
262 var repeatDetails = document.getElementById("repeat-details");
263 repeatDetails.setAttribute("collapsed", "true");
264
265 // Try to create a descriptive string from the rule(s).
266 var kDefaultTimezone = calendarDefaultTimezone();
267 var startDate = item.startDate || item.entryDate;
268 var endDate = item.endDate || item.dueDate;
269 startDate = startDate ? startDate.getInTimezone(kDefaultTimezone) : null;
270 endDate = endDate ? endDate.getInTimezone(kDefaultTimezone) : null;
271 var detailsString = recurrenceRule2String(
272 recurrenceInfo, startDate, endDate, startDate.isDate);
273
274 // Now display the string...
275 if (detailsString) {
276 var lines = detailsString.split("\n");
277 repeatDetails.removeAttribute("collapsed");
278 while (repeatDetails.childNodes.length > lines.length) {
279 repeatDetails.removeChild(repeatDetails.lastChild);
280 }
281 var numChilds = repeatDetails.childNodes.length;
282 for (var i = 0; i < lines.length; i++) {
283 if (i >= numChilds) {
284 var newNode = repeatDetails.childNodes[0]
285 .cloneNode(true);
286 repeatDetails.appendChild(newNode);
287 }
288 repeatDetails.childNodes[i].value = lines[i];
289 }
290 }
291 }
292
293 function updateAttendees() {
294 var args = window.arguments[0];
295 var item = args.calendarEvent;
296 var attendees = item.getAttendees({});
297 if (attendees && attendees.length) {
298 document.getElementById("item-attendees").removeAttribute("hidden");
299 var listbox = document.getElementById("item-attendee-listbox");
300 var itemNode = listbox.getElementsByTagName("listitem")[0];
301 var num_items = Math.ceil(attendees.length/2)-1;
302 while (num_items--) {
303 var newNode = itemNode.cloneNode(true);
304 listbox.appendChild(newNode);
305 }
306 var list = listbox.getElementsByTagName("listitem");
307 var page = 0;
308 var line = 0;
309 var re = new RegExp("^mailto:(.*)", "i");
310 for each (var attendee in attendees) {
311 var name = attendee.commonName;
312 if (!(name && name.length)) {
313 if (attendee.id && attendee.id.length) {
314 var email = attendee.id;
315 if (email && email.length) {
316 var matches = re.exec(email);
317 if (matches) {
318 email = matches[1];
319 }
320 }
321 name = email;
322 }
323 }
324 if (name && name.length) {
325 var itemNode = list[line];
326 var image = itemNode.getElementsByTagName("image")[page];
327 var label = itemNode.getElementsByTagName("label")[page];
328 label.value = name;
329 image.setAttribute("status", attendee.participationStatus);
330 image.removeAttribute("hidden");
331 page++;
332 if (page > 1) {
333 page = 0;
334 line++;
335 }
336 }
337 }
338 }
339 }
340
341 function updateReminder() {
342 commonUpdateReminder();
343 }
344
345 function browseDocument() {
346 var args = window.arguments[0];
347 var item = args.calendarEvent;
348 var url = item.getProperty("URL")
349 launchBrowser(url);
350 }
351
352 function sendMailToOrganizer() {
353 var args = window.arguments[0];
354 var item = args.calendarEvent;
355
356 var organizer = item.organizer;
357 if (organizer) {
358 if (organizer.id && organizer.id.length) {
359 var email = organizer.id;
360 var re = new RegExp("^mailto:(.*)", "i");
361 if (email && email.length) {
362 var matches = re.exec(email);
363 if (matches) {
364 email = matches[1];
365 }
366 }
367
368 // Set up the subject
369 var emailSubject = calGetString("sun-calendar-event-dialog",
370 "emailSubjectReply",
371 [item.title]);
372
373 sendMailTo(email, emailSubject);
374 }
375 }
376 }