/* -*- Mode: javascript; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- * ***** 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 Calendar code. * * The Initial Developer of the Original Code is * ArentJan Banck . * Portions created by the Initial Developer are Copyright (C) 2002 * the Initial Developer. All Rights Reserved. * * Contributor(s): James Maidment * * 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 ***** */ // TODO move nsIDragService definition //const nsIDragService = Components.interfaces.nsIDragService; // function to select whatever what is clicked to start dragging, Mozilla doesn't do this function calendarViewClick ( aEvent ) { var currentTarget = aEvent.currentTarget; var currentTargetFirstClassName = currentTarget.className.split(" ")[0]; if(currentTargetFirstClassName == "day-view-hour-box-class") dayViewHourClick( aEvent ); if(currentTargetFirstClassName == "day-view-event-class") gCalendarWindow.EventSelection.replaceSelection( currentTarget.event ); //dayEventItemClick( aEvent.target, aEvent ); if(currentTargetFirstClassName == "week-view-event-class") gCalendarWindow.EventSelection.replaceSelection( currentTarget.event ); //if (gCalendarWindow.currentView == gCalendarWindow.weekView) //weekViewHourClick( aEvent ); } //var startDateIndex; var calendarViewDNDObserver = { getSupportedFlavours : function () { var flavourSet = new FlavourSet(); flavourSet.appendFlavour("text/unicode"); flavourSet.appendFlavour("text/calendar"); flavourSet.appendFlavour("text/calendar-interval"); // flavourSet.appendFlavour("text/x-moz-message-or-folder"); // not implemented flavourSet.appendFlavour("application/x-moz-file", "nsIFile"); return flavourSet; }, onDragStart: function (aEvent, aXferData, aDragAction){ //Clear any dragged over events left from last drag selection. var liveList = document.getElementsByAttribute( "draggedover", "true" ); // Delete in reverse order. Moz1.8+ getElementsByAttribute list is // 'live', so when attribute is deleted the indexes of later elements // change, but Moz1.7- is not. Reversed order works with both. for (var i = liveList.length - 1; i >= 0; i--) { liveList.item(i).removeAttribute( "draggedover" ); } // select clicked object, Mozilla doesn't do this. calendarViewClick( aEvent ); // aEvent.currentTarget; if( aEvent.target.localName == "splitter" || aEvent.target.localName == "menu") throw Components.results.NS_OK; // not a draggable item var eventIsDragged ; var currentTargetFirstClassName = aEvent.currentTarget.className.split(" ")[0]; switch (currentTargetFirstClassName) { case "day-view-event-class" : eventIsDragged = true ; this.startDragDayIndex = 0 ; break; case "week-view-event-class" : eventIsDragged = true ; this.startDragDayIndex = aEvent.currentTarget.getAttribute( "dayindex" ); break; default : eventIsDragged = false ; } if(eventIsDragged == true) { // We are going to drag an event var dragEvents = gCalendarWindow.EventSelection.selectedEvents; aXferData.data= new TransferData(); aXferData.data.addDataForFlavour("text/calendar", eventArrayToICalString( dragEvents ) ); aXferData.data.addDataForFlavour("text/unicode", eventArrayToICalString( dragEvents, true ) ); //if (aEvent.ctrlKey) // action.action = nsIDragService.DRAGDROP_ACTION_COPY ; aEvent.preventBubble(); } else { // Dragging on the calendar canvas to select an event period // var newDate = gHeaderDateItemArray[dayIndex].getAttribute( "date" ); // var gStartDate = new Date( gCalendarWindow.getSelectedDate() ); // The date the drap action initiated on. var gStartDate; this.startDateIndex = aEvent.target.getAttribute( "day" ); // In the week view, the drag can start on a date different from the currently // selected one. However, in the day view, the event target does not have a 'day' // attribute. if( gCalendarWindow.currentView == gCalendarWindow.weekView ) { //Week view. gStartDate = new Date ( gHeaderDateItemArray[this.startDateIndex].getAttribute( "date" )); } else { //Day view. gStartDate = new Date ( gCalendarWindow.getSelectedDate() ); } gStartDate.setHours( aEvent.target.getAttribute( "hour" ) ); gStartDate.setMinutes( 0 ); gStartDate.setSeconds( 0 ); aXferData.data=new TransferData(); aXferData.data.addDataForFlavour("text/calendar-interval", gStartDate.getTime() ); // aDragAction.action = nsIDragService.DRAGDROP_ACTION_MOVE; aEvent.preventBubble(); } }, onDragOver: function calendarViewOnDragOver(aEvent, aFlavour, aDragSession) { if (aDragSession.isDataFlavorSupported("text/calendar-interval")) { // multiday events not supported. In week view, do not allow more than one day in selection if (gCalendarWindow.currentView == gCalendarWindow.weekView ) { if (aEvent.target.getAttribute( "day" ) != this.startDateIndex) { aDragSession.canDrop = false; return false; } } // if (aDragSession.isDataFlavorSupported("text/calendar-interval")) aEvent.target.setAttribute( "draggedover", "true" ); } return true; }, onDrop: function (aEvent, aXferData, aDragSession) { var trans = Components.classes["@mozilla.org/widget/transferable;1"].createInstance(Components.interfaces.nsITransferable); trans.addDataFlavor("text/calendar"); trans.addDataFlavor("text/calendar-interval"); //trans.addDataFlavor("text/x-moz-message-or-folder"); // not implemented //trans.addDataFlavor("text/x-moz-url"); // not implemented trans.addDataFlavor("application/x-moz-file"); trans.addDataFlavor("text/unicode"); aDragSession.getData (trans, i); var dataObj = new Object(); var bestFlavor = new Object(); var len = new Object(); trans.getAnyTransferData(bestFlavor, dataObj, len); switch (bestFlavor.value) { case "text/calendar": // A calendar object is dropped. ical text data. if (dataObj) { // XXX For MOZILLA10 1.0 this is nsISupportWString dataObj = dataObj.value.QueryInterface(Components.interfaces.nsISupportsString); } var dropEvent = createEvent(); var newEventId = dropEvent.id; // can be used when copying to new event // XXX TODO: Check if there is a function in calendarImportExport to do this var icalStr = dataObj.data.substring(0, len.value); var beginEventIndex = icalStr.indexOf("BEGIN:VEVENT"); var endEventIndex = icalStr.indexOf("END:VEVENT") + 10; var eventData = icalStr.substring(beginEventIndex, endEventIndex); // set the event based on parsing ical data dropEvent.icalString = eventData; // calculate new start/end time for droplocation // use the minutes from the event, and change the hour to the hour dropped in var gDropzoneStartTime = new Date( dropEvent.startDate.jsDate ); if(aEvent.target.getAttribute( "hour" )) gDropzoneStartTime.setHours( aEvent.target.getAttribute( "hour" ) ); else gDropzoneStartTime.setHours( aEvent.target.parentNode.event.startDate.hour ); if(aEvent.target.getAttribute( "day" )) { //We are is the week view, so we check the drop day var theNewDate = gDropzoneStartTime.getDate() - this.startDragDayIndex + parseInt(aEvent.target.getAttribute( "day" )); gDropzoneStartTime.setDate(theNewDate); } var eventDuration = dropEvent.duration; if(aDragSession.dragAction == nsIDragService.DRAGDROP_ACTION_MOVE) { var calendarEvent = null; var operationListener = { onOperationComplete: function(calendar, status, type, id, detail) { var newStartDate = jsDateToDateTime(gDropzoneStartTime); if (calendarEvent) { // if we got a calendar event from onGetResult, then clone it and modify its // time directly and then call modify on it var newEvent = calendarEvent.clone().QueryInterface(Components.interfaces.calIEvent); newEvent.startDate = newStartDate; newEvent.endDate = newStartDate.clone(); newEvent.endDate.addDuration(eventDuration); newEvent.parent.modifyItem(newEvent, null); } else { // if we didn't get a calendar event, then we want to open the edit dialog with // the new event dropEvent.id = newEventId; // XXX TODO Check if stamp/DTSTAMP is correclty set to current time dropEvent.startDate = newStartDate; dropEvent.endDate = newStartDate.clone(); dropEvent.endDate.addDuration(eventDuration); editNewEvent( dropEvent ); } }, onGetResult: function(calendar, status, type, detail, count, items) { if (count == 1) { calendarEvent = items[0].QueryInterface(calIEvent); } } } getCalendar().getItem(dropEvent.id, operationListener); } else { dump("failed\n"); } break; case "text/calendar-interval": // A start time is dragged as start of an event duration // no copy for interval drag // if (dragSession.dragAction == nsIDragService.DRAGDROP_ACTION_COPY) // return false; if (dataObj) dataObj = dataObj.value.QueryInterface(Components.interfaces.nsISupportsString); var dragTime = dataObj.data.substring(0, len.value); gStartDate = new Date( ); gStartDate.setTime( dragTime ); gEndDate = new Date( gStartDate.getTime() ); gEndDate.setHours( aEvent.target.getAttribute( "hour" ) ); if( gEndDate.getTime() < gStartDate.getTime() ) { var Temp = gEndDate; gEndDate = gStartDate; gStartDate = Temp; } newEvent( gStartDate, gEndDate ); break; case "text/x-moz-url": var url = transferUtils.retrieveURLFromData(aXferData.data, aXferData.flavour.contentType); if (!url) return; alert(url); break; case "text/unicode": // text, create new event with text as description if (dataObj) dataObj = dataObj.value.QueryInterface(Components.interfaces.nsISupportsWString); // calculate star and and time's for new event, default event lenght is 1 hour var gStartDate = new Date( gCalendarWindow.getSelectedDate() ); gStartDate.setHours( aEvent.target.getAttribute( "hour" ) ); gStartDate.setMinutes( 0 ); gStartDate.setSeconds( 0 ); gEndDate = new Date( gStartDate.getTime() ); gEndDate.setHours(gStartDate.getHours() + 1); newEvent = createEvent(); newEvent.start.setTime( gStartDate ); newEvent.end.setTime( gEndDate ); newEvent.description = dataObj.data.substring(0, len.value); editNewEvent( newEvent ); break; case "text/x-moz-message-or-folder": // Mozilla mail, work in progress try { if (dataObj) dataObj = dataObj.value.QueryInterface(Components.interfaces.nsISupportsString); // pull the URL out of the data object // sourceDocument nul if from other app var sourceUri = dataObj.data.substring(0, len.value); if (! sourceUri) break; alert("import not implemented " + sourceUri); /* try { sourceResource = RDF.GetResource(sourceUri, true); var folder = sourceResource.QueryInterface(Components.interfaces.nsIFolder); if (folder) dragFolder = true; } catch(ex) { sourceResource = null; var isServer = GetFolderAttribute(folderTree, targetResource, "IsServer"); if (isServer == "true") { debugDump("***isServer == true\n"); return false; } // canFileMessages checks no select, and acl, for imap. var canFileMessages = GetFolderAttribute(folderTree, targetResource, "CanFileMessages"); if (canFileMessages != "true") { debugDump("***canFileMessages == false\n"); return false; } var hdr = messenger.messageServiceFromURI(sourceUri).messageURIToMsgHdr(sourceUri); alert(hdr); if (hdr.folder == targetFolder) return false; break; } */ } catch(ex) { alert(ex.message); } break; case "application/x-moz-file": // file from OS, we expect it to be iCalendar data try { var fileObj = dataObj.value.QueryInterface(Components.interfaces.nsIFile); var aDataStream = readDataFromFile( fileObj.path ); var calendarEventArray = parseIcalEvents( aDataStream ); // LINAGORA (- TODO Move to calendarImportExport to have the option to turn off dialogs) addEventsToCalendar( calendarEventArray, 1 ); } catch(ex) { alert(ex.message); } break; } // cleanup var liveList = document.getElementsByAttribute( "draggedover", "true" ); // Delete in reverse order. Moz1.8+ getElementsByAttribute list is // 'live', so when attribute is deleted the indexes of later elements // change, but Moz1.7- is not. Reversed order works with both. for (var i = liveList.length - 1; i >= 0; i--) { liveList.item(i).removeAttribute( "draggedover" ); } }, onDragExit: function (aEvent, aDragSession) { // nothing, doesn't fire for cancel? needed for interval-drag cleanup } };