зеркало из https://github.com/mozilla/pjs.git
puggable import/export interfaces for calendar, plus initial implementations.
bug 298772, r=shaver
This commit is contained in:
Родитель
d289323222
Коммит
55fea90a44
|
@ -42,7 +42,7 @@ VPATH = @srcdir@
|
|||
include $(DEPTH)/config/autoconf.mk
|
||||
|
||||
MODULE = calendar
|
||||
DIRS = libical resources base providers xpi
|
||||
DIRS = libical resources base providers xpi import-export
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
|
||||
|
|
|
@ -0,0 +1,242 @@
|
|||
/* -*- Mode: javascript; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* ***** 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 <ajbanck@planet.nl>.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2002
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s): ArentJan Banck <ajbanck@planet.nl>
|
||||
* Steve Hampton <mvgrad78@yahoo.com>
|
||||
* Eric Belhaire <belhaire@ief.u-psud.fr>
|
||||
* Jussi Kukkonen <jussi.kukkonen@welho.com>
|
||||
* Michiel van Leeuwen <mvl@exedo.nl>
|
||||
*
|
||||
* 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 ***** */
|
||||
|
||||
// File constants copied from file-utils.js
|
||||
const MODE_RDONLY = 0x01;
|
||||
const MODE_WRONLY = 0x02;
|
||||
const MODE_RDWR = 0x04;
|
||||
const MODE_CREATE = 0x08;
|
||||
const MODE_APPEND = 0x10;
|
||||
const MODE_TRUNCATE = 0x20;
|
||||
const MODE_SYNC = 0x40;
|
||||
const MODE_EXCL = 0x80;
|
||||
|
||||
|
||||
/**
|
||||
* loadEventsFromFile
|
||||
* shows a file dialog, reads the selected file(s) and tries to parse events from it.
|
||||
*/
|
||||
|
||||
function loadEventsFromFile()
|
||||
{
|
||||
const nsIFilePicker = Components.interfaces.nsIFilePicker;
|
||||
|
||||
var fp = Components.classes["@mozilla.org/filepicker;1"]
|
||||
.createInstance(nsIFilePicker);
|
||||
fp.init(window, getStringBundle().GetStringFromName("Open"),
|
||||
nsIFilePicker.modeOpen);
|
||||
fp.defaultExtension = "ics";
|
||||
|
||||
// Get a list of exporters
|
||||
var contractids = new Array();
|
||||
var catman = Components.classes["@mozilla.org/categorymanager;1"]
|
||||
.getService(Components.interfaces.nsICategoryManager);
|
||||
var catenum = catman.enumerateCategory('cal-importers');
|
||||
while (catenum.hasMoreElements()) {
|
||||
var entry = catenum.getNext();
|
||||
entry = entry.QueryInterface(Components.interfaces.nsISupportsCString);
|
||||
var contractid = catman.getCategoryEntry('cal-importers', entry);
|
||||
var exporter = Components.classes[contractid]
|
||||
.getService(Components.interfaces.calIImporter);
|
||||
var types = exporter.getFileTypes({});
|
||||
var type;
|
||||
for each (type in types) {
|
||||
fp.appendFilter(type.description, "*."+type.extension);
|
||||
contractids.push(contractid);
|
||||
}
|
||||
}
|
||||
|
||||
fp.show();
|
||||
|
||||
var filePath = fp.file.path;
|
||||
|
||||
if (filePath) {
|
||||
var importer = Components.classes[contractids[fp.filterIndex]]
|
||||
.getService(Components.interfaces.calIImporter);
|
||||
|
||||
const nsIFileInputStream = Components.interfaces.nsIFileInputStream;
|
||||
const nsIScriptableInputStream = Components.interfaces.nsIScriptableInputStream;
|
||||
|
||||
var inputStream = Components.classes["@mozilla.org/network/file-input-stream;1"]
|
||||
.createInstance(nsIFileInputStream);
|
||||
var items;
|
||||
try
|
||||
{
|
||||
inputStream.init( fp.file, MODE_RDONLY, 0444, {} );
|
||||
|
||||
var scriptableInputStream =
|
||||
Components.classes["@mozilla.org/scriptableinputstream;1"]
|
||||
.createInstance(nsIScriptableInputStream);
|
||||
scriptableInputStream.init(inputStream);
|
||||
|
||||
// XXX Convert the stream to unicode. Or should the importer do that?
|
||||
items = importer.importStream(inputStream, {});
|
||||
scriptableInputStream.close();
|
||||
inputStream.close();
|
||||
}
|
||||
catch(ex)
|
||||
{
|
||||
alert(getStringBundle().GetStringFromName("unableToRead") + aFilePath + "\n"+ex );
|
||||
}
|
||||
|
||||
// XXX Ask for a calendar to import into
|
||||
var destCal = getDefaultCalendar();
|
||||
|
||||
// XXX This might not work in lighting
|
||||
startBatchTransaction();
|
||||
|
||||
for each (item in items) {
|
||||
// XXX prompt when finding a duplicate.
|
||||
destCal.addItem(item, null);
|
||||
}
|
||||
|
||||
// XXX This might not work in lighting
|
||||
endBatchTransaction();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* saveEventsToFile
|
||||
*
|
||||
* Save data to a file. Create the file or overwrite an existing file.
|
||||
* Input an array of calendar events, or no parameter for selected events.
|
||||
*/
|
||||
|
||||
function saveEventsToFile(calendarEventArray)
|
||||
{
|
||||
if (!calendarEventArray)
|
||||
return;
|
||||
|
||||
if (!calendarEventArray.length)
|
||||
{
|
||||
alert(getStringBundle().GetStringFromName("noEventsToSave"));
|
||||
return;
|
||||
}
|
||||
|
||||
// Show the 'Save As' dialog and ask for a filename to save to
|
||||
const nsIFilePicker = Components.interfaces.nsIFilePicker;
|
||||
|
||||
var fp = Components.classes["@mozilla.org/filepicker;1"]
|
||||
.createInstance(nsIFilePicker);
|
||||
|
||||
fp.init(window, getStringBundle().GetStringFromName("SaveAs"),
|
||||
nsIFilePicker.modeSave);
|
||||
|
||||
if(calendarEventArray.length == 1 && calendarEventArray[0].title)
|
||||
fp.defaultString = calendarEventArray[0].title;
|
||||
else
|
||||
fp.defaultString = getStringBundle().GetStringFromName("defaultFileName");
|
||||
|
||||
fp.defaultExtension = "ics";
|
||||
|
||||
// Get a list of exporters
|
||||
var contractids = new Array();
|
||||
var catman = Components.classes["@mozilla.org/categorymanager;1"]
|
||||
.getService(Components.interfaces.nsICategoryManager);
|
||||
var catenum = catman.enumerateCategory('cal-exporters');
|
||||
while (catenum.hasMoreElements()) {
|
||||
var entry = catenum.getNext();
|
||||
entry = entry.QueryInterface(Components.interfaces.nsISupportsCString);
|
||||
var contractid = catman.getCategoryEntry('cal-exporters', entry);
|
||||
var exporter = Components.classes[contractid]
|
||||
.getService(Components.interfaces.calIExporter);
|
||||
var types = exporter.getFileTypes({});
|
||||
var type;
|
||||
for each (type in types) {
|
||||
fp.appendFilter(type.description, "*."+type.extension);
|
||||
contractids.push(contractid);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fp.show();
|
||||
|
||||
// Now find out as what to save, convert the events and save to file.
|
||||
if (fp.file && fp.file.path.length > 0)
|
||||
{
|
||||
const UTF8 = "UTF-8";
|
||||
var aDataStream;
|
||||
var extension;
|
||||
var charset;
|
||||
|
||||
var exporter = Components.classes[contractids[fp.filterIndex]]
|
||||
.getService(Components.interfaces.calIExporter);
|
||||
|
||||
var filePath = fp.file.path;
|
||||
if(filePath.indexOf(".") == -1 )
|
||||
filePath += "."+exporter.getFileTypes({})[0].extension;
|
||||
|
||||
const LOCALFILE_CTRID = "@mozilla.org/file/local;1";
|
||||
const FILEOUT_CTRID = "@mozilla.org/network/file-output-stream;1";
|
||||
const nsILocalFile = Components.interfaces.nsILocalFile;
|
||||
const nsIFileOutputStream = Components.interfaces.nsIFileOutputStream;
|
||||
|
||||
var outputStream;
|
||||
|
||||
var localFileInstance = Components.classes[LOCALFILE_CTRID]
|
||||
.createInstance(nsILocalFile);
|
||||
localFileInstance.initWithPath(filePath);
|
||||
|
||||
outputStream = Components.classes[FILEOUT_CTRID]
|
||||
.createInstance(nsIFileOutputStream);
|
||||
try
|
||||
{
|
||||
outputStream.init(localFileInstance, MODE_WRONLY | MODE_CREATE | MODE_TRUNCATE, 0664, 0);
|
||||
// XXX Do the right thing with unicode and stuff. Or, again, should the
|
||||
// exporter handle that?
|
||||
exporter.exportStream(outputStream, calendarEventArray.length, calendarEventArray);
|
||||
outputStream.close();
|
||||
}
|
||||
catch(ex)
|
||||
{
|
||||
alert(getStringBundle().GetStringFromName("unableToWrite") + filePath );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function getStringBundle()
|
||||
{
|
||||
var strBundleService =
|
||||
Components.classes["@mozilla.org/intl/stringbundle;1"]
|
||||
.getService(Components.interfaces.nsIStringBundleService);
|
||||
return strBundleService.createBundle("chrome://calendar/locale/calendar.properties");
|
||||
}
|
|
@ -65,6 +65,7 @@ XPIDLSRCS = calIAlarmService.idl \
|
|||
calIRecurrenceDateSet.idl \
|
||||
calIRecurrenceItem.idl \
|
||||
calIRecurrenceRule.idl \
|
||||
calIImportExport.idl \
|
||||
calITodo.idl \
|
||||
$(NULL)
|
||||
|
||||
|
|
|
@ -0,0 +1,81 @@
|
|||
/* -*- Mode: IDL; 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
|
||||
* Michiel van Leeuwen <mvl@exedo.nl>.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2005
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* 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 ***** */
|
||||
|
||||
|
||||
#include "nsISupports.idl"
|
||||
|
||||
interface calIItemBase;
|
||||
interface nsIInputStream;
|
||||
interface nsIOutputStream;
|
||||
|
||||
[scriptable, uuid(efef8333-e995-4f45-bdf7-bfcabbd9793e)]
|
||||
interface calIFileType : nsISupports
|
||||
{
|
||||
/**
|
||||
* The extension to use in the filepicker's filter list
|
||||
*/
|
||||
readonly attribute AString extension;
|
||||
/**
|
||||
* The description to show to the user in the filter list.
|
||||
*/
|
||||
readonly attribute AString description;
|
||||
};
|
||||
|
||||
[scriptable, uuid(dbe262ca-d6c6-4691-8d46-e7f6bbe632ec)]
|
||||
interface calIImporter : nsISupports
|
||||
{
|
||||
void getFileTypes(out unsigned long aCount,
|
||||
[retval, array, size_is(aCount)] out calIFileType aTypes);
|
||||
|
||||
void importFromStream(in nsIInputStream aStream,
|
||||
out unsigned long aCount,
|
||||
[retval, array, size_is(aCount)] out calIItemBase aItems);
|
||||
};
|
||||
|
||||
[scriptable, uuid(18c75bb3-6309-4c33-903f-6055fec39d07)]
|
||||
interface calIExporter : nsISupports
|
||||
{
|
||||
void getFileTypes(out unsigned long aCount,
|
||||
[retval, array, size_is(aCount)] out calIFileType aTypes);
|
||||
|
||||
/**
|
||||
* Export the items into the stream
|
||||
*/
|
||||
void exportToStream(in nsIOutputStream aStream,
|
||||
in unsigned long aCount,
|
||||
[array, size_is(aCount)] in calIItemBase aItems);
|
||||
};
|
|
@ -0,0 +1,52 @@
|
|||
#
|
||||
# ***** 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
|
||||
# Michiel van Leeuwen <mvl@exedo.nl>
|
||||
# Portions created by the Initial Developer are Copyright (C) 2005
|
||||
# the Initial Developer. All Rights Reserved.
|
||||
#
|
||||
# Contributor(s):
|
||||
#
|
||||
# Alternatively, the contents of this file may be used under the terms of
|
||||
# either of 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 *****
|
||||
|
||||
DEPTH = ../..
|
||||
topsrcdir = @top_srcdir@
|
||||
srcdir = @srcdir@
|
||||
VPATH = @srcdir@
|
||||
|
||||
include $(DEPTH)/config/autoconf.mk
|
||||
|
||||
EXTRA_COMPONENTS = \
|
||||
calCsvImportExport.js \
|
||||
calHtmlExport.js \
|
||||
calIcsImportExport.js \
|
||||
calImportExportModule.js \
|
||||
$(NULL)
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
|
@ -0,0 +1,113 @@
|
|||
/* -*- Mode: javascript; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* ***** 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 <ajbanck@planet.nl>.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2002
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Michiel van Leeuwen <mvl@exedo.nl>
|
||||
*
|
||||
* 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 ***** */
|
||||
|
||||
// Export
|
||||
|
||||
function calHtmlExporter() {
|
||||
this.wrappedJSObject = this;
|
||||
}
|
||||
|
||||
calHtmlExporter.prototype.QueryInterface =
|
||||
function QueryInterface(aIID) {
|
||||
if (!aIID.equals(Components.interfaces.nsISupports) &&
|
||||
!aIID.equals(Components.interfaces.calIExporter)) {
|
||||
throw Components.results.NS_ERROR_NO_INTERFACE;
|
||||
}
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
calHtmlExporter.prototype.getFileTypes =
|
||||
function getFileTypes(aCount) {
|
||||
aCount.value = 2;
|
||||
return([{extension:'html',description:'HTML'},
|
||||
{extension:'htm',description:'HTML'}]);
|
||||
};
|
||||
|
||||
// not prototype.export. export is reserved.
|
||||
calHtmlExporter.prototype.exportToStream =
|
||||
function html_exportToStream(aStream, aCount, aItems) {
|
||||
var str =
|
||||
"<html>\n" +
|
||||
"<head>\n" +
|
||||
"<title>HTMLTitle</title>\n" +
|
||||
"<meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\">\n" +
|
||||
"</head>\n"+ "<body bgcolor=\"#FFFFFF\" text=\"#000000\">\n";
|
||||
aStream.write(str, str.length);
|
||||
|
||||
for each (item in aItems) {
|
||||
try {
|
||||
item = item.QueryInterface(Components.interfaces.calIEvent);
|
||||
} catch(e) {
|
||||
continue;
|
||||
}
|
||||
var start = item.startDate.jsDate;
|
||||
var end = item.endDate.jsDate;
|
||||
//var when = dateFormat.formatInterval(start, end, calendarEvent.allDay);
|
||||
var when = item.startDate + " -- " + item.endDate;
|
||||
dump(when+"\n");
|
||||
var desc = item.description;
|
||||
if (desc == null)
|
||||
desc = "";
|
||||
if (desc.length > 0) {
|
||||
if (desc.indexOf("\n ") >= 0 || desc.indexOf("\n\t") >= 0 ||
|
||||
desc.indexOf(" ") == 0 || desc.indexOf("\t") == 0)
|
||||
// (RegExp /^[ \t]/ doesn't work.)
|
||||
// contains indented preformatted text after beginning or newline
|
||||
// so preserve indentation with PRE.
|
||||
desc = "<PRE>"+desc+"</PRE>\n";
|
||||
else
|
||||
// no indentation, so preserve text line breaks in html with BR
|
||||
desc = "<P>"+desc.replace(/\n/g, "<BR>\n")+"</P>\n";
|
||||
}
|
||||
// use div around each event so events are navigable via DOM.
|
||||
str = "<div><p>";
|
||||
str += "<B>Title: </B>\t" + item.title + "<BR>\n";
|
||||
str += "<B>When: </B>\t" + when.replace("--", "–") + "<BR>\n";
|
||||
str += "<B>Where: </B>\t" + item.location + "<BR>\n";
|
||||
// str += "<B>Organiser: </B>\t" + Event.???
|
||||
str += "</p>\n";
|
||||
str += desc; // may be empty
|
||||
str += "</div>\n";
|
||||
aStream.write(str, str.length);
|
||||
}
|
||||
|
||||
str = "\n</body>\n</html>\n";
|
||||
aStream.write(str, str.length);
|
||||
return;
|
||||
};
|
|
@ -0,0 +1,127 @@
|
|||
/* -*- Mode: javascript; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* ***** 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
|
||||
* Michiel van Leeuwen <mvl@exedo.nl>.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2005
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* 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 ***** */
|
||||
|
||||
// Import
|
||||
|
||||
function calIcsImporter() {
|
||||
this.wrappedJSObject = this;
|
||||
}
|
||||
|
||||
calIcsImporter.prototype.QueryInterface =
|
||||
function QueryInterface(aIID) {
|
||||
if (!aIID.equals(Components.interfaces.nsISupports) &&
|
||||
!aIID.equals(Components.interfaces.calIImporter)) {
|
||||
throw Components.results.NS_ERROR_NO_INTERFACE;
|
||||
}
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
calIcsImporter.prototype.getFileTypes =
|
||||
function getFileTypes(aCount) {
|
||||
aCount.value = 1;
|
||||
return([{extension:'ics',description:'iCalendar'}]);
|
||||
};
|
||||
|
||||
calIcsImporter.prototype.importFromStream =
|
||||
function ics_importFromStream(aStream, aCount) {
|
||||
var items = new Array();
|
||||
icssrv = Components.classes["@mozilla.org/calendar/ics-service;1"]
|
||||
.getService(Components.interfaces.calIICSService);
|
||||
var calComp = icssrv.parseICS(aData);
|
||||
var subComp = calComp.getFirstSubcomponent("ANY");
|
||||
while (subComp) {
|
||||
switch (subComp.componentType) {
|
||||
case "VEVENT":
|
||||
var event = createEvent();
|
||||
event.icalComponent = subComp;
|
||||
items.push(event);
|
||||
break;
|
||||
case "VTODO":
|
||||
var todo = createToDo();
|
||||
todo.icalComponent = subComp;
|
||||
items.push(todo);
|
||||
break;
|
||||
default:
|
||||
// Nothing
|
||||
}
|
||||
subComp = calComp.getNextSubcomponent("ANY");
|
||||
}
|
||||
|
||||
aCount.value = items.length;
|
||||
return items;
|
||||
};
|
||||
|
||||
|
||||
// Export
|
||||
|
||||
function calIcsExporter() {
|
||||
this.wrappedJSObject = this;
|
||||
}
|
||||
|
||||
calIcsExporter.prototype.QueryInterface =
|
||||
function QueryInterface(aIID) {
|
||||
if (!aIID.equals(Components.interfaces.nsISupports) &&
|
||||
!aIID.equals(Components.interfaces.calIExporter)) {
|
||||
throw Components.results.NS_ERROR_NO_INTERFACE;
|
||||
}
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
calIcsExporter.prototype.getFileTypes =
|
||||
function getFileTypes(aCount) {
|
||||
aCount.value = 1;
|
||||
return([{extension:'ics',description:'iCalendar'}]);
|
||||
};
|
||||
|
||||
// not prototype.export. export is reserved.
|
||||
calIcsExporter.prototype.exportToStream =
|
||||
function ics_exportToStream(aStream, aCount, aItems) {
|
||||
icssrv = Components.classes["@mozilla.org/calendar/ics-service;1"]
|
||||
.getService(Components.interfaces.calIICSService);
|
||||
var calComp = icssrv.createIcalComponent("VCALENDAR");
|
||||
calComp.version = "2.0";
|
||||
calComp.prodid = "-//Mozilla.org/NONSGML Mozilla Calendar V1.0//EN";
|
||||
|
||||
for each (item in aItems) {
|
||||
calComp.addSubcomponent(item.icalComponent);
|
||||
}
|
||||
var str = calComp.serializeToICS();
|
||||
aStream.write(str, str.length);
|
||||
return;
|
||||
};
|
|
@ -0,0 +1,198 @@
|
|||
/* -*- Mode: javascript; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* ***** 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 Oracle Corporation code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Oracle Corporation
|
||||
* Portions created by the Initial Developer are Copyright (C) 2004
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Vladimir Vukicevic <vladimir.vukicevic@oracle.com>
|
||||
* Mike Shaver <shaver@off.net>
|
||||
*
|
||||
* 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 ***** */
|
||||
|
||||
const componentData =
|
||||
[
|
||||
{cid: Components.ID("{1e3e33dc-445a-49de-b2b6-15b2a050bb9d}"),
|
||||
contractid: "@mozilla.org/calendar/import;1?type=ics",
|
||||
script: "calIcsImportExport.js",
|
||||
constructor: "calIcsImporter",
|
||||
category: "cal-importers",
|
||||
categoryEntry: "cal-ics-importer",
|
||||
service: false},
|
||||
{cid: Components.ID("{a6a524ce-adff-4a0f-bb7d-d1aaad4adc60}"),
|
||||
contractid: "@mozilla.org/calendar/export;1?type=ics",
|
||||
constructor: "calIcsExporter",
|
||||
category: "cal-exporters",
|
||||
categoryEntry: "cal-ics-exporter",
|
||||
service: false},
|
||||
|
||||
{cid: Components.ID("{72d9ab35-9b1b-442a-8cd0-ae49f00b159b}"),
|
||||
contractid: "@mozilla.org/calendar/export;1?type=html",
|
||||
script: "calHtmlExport.js",
|
||||
constructor: "calHtmlExporter",
|
||||
category: "cal-exporters",
|
||||
categoryEntry: "cal-html-exporter",
|
||||
service: false},
|
||||
|
||||
{cid: Components.ID("{64a5d17a-0497-48c5-b54f-72b15c9e9a14}"),
|
||||
contractid: "@mozilla.org/calendar/import;1?type=csv",
|
||||
script: "calOutlookCSVImportExport.js",
|
||||
constructor: "calOutlookCSVImporter",
|
||||
category: "cal-importers",
|
||||
categoryEntry: "cal-outlookcsv-importer",
|
||||
service: false},
|
||||
{cid: Components.ID("{48e6d3a6-b41b-4052-9ed2-40b27800bd4b}"),
|
||||
contractid: "@mozilla.org/calendar/export;1?type=csv",
|
||||
constructor: "calOutlookCSVExporter",
|
||||
category: "cal-exporters",
|
||||
categoryEntry: "cal-outlookcsv-exporter",
|
||||
service: false},
|
||||
|
||||
];
|
||||
|
||||
var calImportExportModule = {
|
||||
mScriptsLoaded: false,
|
||||
loadScripts: function () {
|
||||
if (this.mScriptsLoaded)
|
||||
return;
|
||||
|
||||
const jssslContractID = "@mozilla.org/moz/jssubscript-loader;1";
|
||||
const jssslIID = Components.interfaces.mozIJSSubScriptLoader;
|
||||
|
||||
const dirsvcContractID = "@mozilla.org/file/directory_service;1";
|
||||
const propsIID = Components.interfaces.nsIProperties;
|
||||
|
||||
const iosvcContractID = "@mozilla.org/network/io-service;1";
|
||||
const iosvcIID = Components.interfaces.nsIIOService;
|
||||
|
||||
var loader = Components.classes[jssslContractID].getService(jssslIID);
|
||||
var dirsvc = Components.classes[dirsvcContractID].getService(propsIID);
|
||||
var iosvc = Components.classes[iosvcContractID].getService(iosvcIID);
|
||||
|
||||
// We expect to find the subscripts in our directory.
|
||||
var appdir = __LOCATION__.parent;
|
||||
|
||||
for (var i = 0; i < componentData.length; i++) {
|
||||
var scriptName = componentData[i].script;
|
||||
if (!scriptName)
|
||||
continue;
|
||||
|
||||
var f = appdir.clone();
|
||||
f.append(scriptName);
|
||||
|
||||
try {
|
||||
var fileurl = iosvc.newFileURI(f);
|
||||
loader.loadSubScript(fileurl.spec, null);
|
||||
} catch (e) {
|
||||
dump("Error while loading " + fileurl.spec + "\n");
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
this.mScriptsLoaded = true;
|
||||
},
|
||||
|
||||
registerSelf: function (compMgr, fileSpec, location, type) {
|
||||
compMgr = compMgr.QueryInterface(Components.interfaces.nsIComponentRegistrar);
|
||||
|
||||
var catman = Components.classes["@mozilla.org/categorymanager;1"]
|
||||
.getService(Components.interfaces.nsICategoryManager);
|
||||
for (var i = 0; i < componentData.length; i++) {
|
||||
var comp = componentData[i];
|
||||
if (!comp.cid)
|
||||
continue;
|
||||
dump ("calItemModule: registering " + comp.contractid + "\n");
|
||||
compMgr.registerFactoryLocation(comp.cid,
|
||||
"",
|
||||
comp.contractid,
|
||||
fileSpec,
|
||||
location,
|
||||
type);
|
||||
|
||||
if (comp.category) {
|
||||
var contractid;
|
||||
if (comp.service)
|
||||
contractid = "service," + comp.contractid;
|
||||
else
|
||||
contractid = comp.contractid;
|
||||
catman.addCategoryEntry(comp.category, comp.categoryEntry,
|
||||
contractid, true, true);
|
||||
dump("registering for category stuff\n");
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
makeFactoryFor: function(constructor) {
|
||||
var factory = {
|
||||
QueryInterface: function (aIID) {
|
||||
if (!aIID.equals(Components.interfaces.nsISupports) &&
|
||||
!aIID.equals(Components.interfaces.nsIFactory))
|
||||
throw Components.results.NS_ERROR_NO_INTERFACE;
|
||||
return this;
|
||||
},
|
||||
|
||||
createInstance: function (outer, iid) {
|
||||
if (outer != null)
|
||||
throw Components.results.NS_ERROR_NO_AGGREGATION;
|
||||
return (new constructor()).QueryInterface(iid);
|
||||
}
|
||||
};
|
||||
|
||||
return factory;
|
||||
},
|
||||
|
||||
getClassObject: function (compMgr, cid, iid) {
|
||||
if (!iid.equals(Components.interfaces.nsIFactory))
|
||||
throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
|
||||
|
||||
if (!this.mScriptsLoaded)
|
||||
this.loadScripts();
|
||||
|
||||
for (var i = 0; i < componentData.length; i++) {
|
||||
if (cid.equals(componentData[i].cid)) {
|
||||
if (componentData[i].onComponentLoad) {
|
||||
eval(componentData[i].onComponentLoad);
|
||||
}
|
||||
// eval to get usual scope-walking
|
||||
return this.makeFactoryFor(eval(componentData[i].constructor));
|
||||
}
|
||||
}
|
||||
|
||||
throw Components.results.NS_ERROR_NO_INTERFACE;
|
||||
},
|
||||
|
||||
canUnload: function(compMgr) {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
function NSGetModule(compMgr, fileSpec) {
|
||||
return calImportExportModule;
|
||||
}
|
|
@ -0,0 +1,460 @@
|
|||
/* -*- Mode: javascript; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* ***** 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
|
||||
* Jussi Kukkonen <jussi.kukkonen@welho.com>.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2004
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Michiel van Leeuwen <mvl@exedo.nl>
|
||||
*
|
||||
* 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 ***** */
|
||||
|
||||
// Import
|
||||
|
||||
function calOutlookCSVImporter() {
|
||||
this.wrappedJSObject = this;
|
||||
}
|
||||
|
||||
calOutlookCSVImporter.prototype.QueryInterface =
|
||||
function QueryInterface(aIID) {
|
||||
if (!aIID.equals(Components.interfaces.nsISupports) &&
|
||||
!aIID.equals(Components.interfaces.calIImporter)) {
|
||||
throw Components.results.NS_ERROR_NO_INTERFACE;
|
||||
}
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
calOutlookCSVImporter.prototype.getFileTypes =
|
||||
function getFileTypes(aCount) {
|
||||
aCount.value = 1;
|
||||
return([{extension:'csv',description:'Comma Separated Values (from Outlook)'}]);
|
||||
};
|
||||
|
||||
const localeEn = {
|
||||
headTitle : "Subject",
|
||||
headStartDate : "Start Date",
|
||||
headStartTime : "Start Time",
|
||||
headEndDate : "End Date",
|
||||
headEndTime : "End Time",
|
||||
headAllDayEvent : "All day event",
|
||||
headAlarm : "Reminder on/off",
|
||||
headAlarmDate : "Reminder Date",
|
||||
headAlarmTime : "Reminder Time",
|
||||
headCategories : "Categories",
|
||||
headDescription : "Description",
|
||||
headLocation : "Location",
|
||||
headPrivate : "Private",
|
||||
|
||||
valueTrue : "True",
|
||||
valueFalse : "False",
|
||||
|
||||
dateRe : /^(\d+)\/(\d+)\/(\d+)$/,
|
||||
dateDayIndex : 2,
|
||||
dateMonthIndex : 1,
|
||||
dateYearIndex : 3,
|
||||
dateFormat : "%m/%d/%y",
|
||||
|
||||
timeRe : /^(\d+):(\d+):(\d+) (\w+)$/,
|
||||
timeHourIndex : 1,
|
||||
timeMinuteIndex : 2,
|
||||
timeSecondIndex : 3,
|
||||
timeAmPmIndex : 4,
|
||||
timeAmString : "AM",
|
||||
timePmString : "PM",
|
||||
timeFormat : "%I:%M:%S %p"
|
||||
};
|
||||
|
||||
const localeNl = {
|
||||
headTitle : "Onderwerp",
|
||||
headStartDate : "Begindatum",
|
||||
headStartTime : "Begintijd",
|
||||
headEndDate : "Einddatum",
|
||||
headEndTime : "Eindtijd",
|
||||
headAllDayEvent : "Evenement, duurt hele dag",
|
||||
headAlarm : "Herinneringen aan/uit",
|
||||
headAlarmDate : "Herinneringsdatum",
|
||||
headAlarmTime : "Herinneringstijd",
|
||||
headCategories : "Categorieën",
|
||||
headDescription : "Beschrijving",
|
||||
headLocation : "Locatie",
|
||||
headPrivate : "Privé",
|
||||
|
||||
valueTrue : "Waar",
|
||||
valueFalse : "Onwaar",
|
||||
|
||||
dateRe : /^(\d+)-(\d+)-(\d+)$/,
|
||||
dateDayIndex : 1,
|
||||
dateMonthIndex : 2,
|
||||
dateYearIndex : 3,
|
||||
dateFormat : "%d-%m-%y",
|
||||
|
||||
timeRe : /^(\d+):(\d+):(\d+)$/,
|
||||
timeHourIndex : 1,
|
||||
timeMinuteIndex : 2,
|
||||
timeSecondIndex : 3,
|
||||
timeFormat : "%H:%M:%S"
|
||||
};
|
||||
|
||||
const locales = [localeEn, localeNl];
|
||||
|
||||
/**
|
||||
* Takes a text block of Outlook-exported Comma Separated Values and tries to
|
||||
* parse that into individual events.
|
||||
*
|
||||
* First line is field names, all quoted with double quotes. Field names are
|
||||
* locale dependendent. In English the recognized field names are:
|
||||
* "Title","Start Date","Start Time","End Date","End Time","All day event",
|
||||
* "Reminder on/off","Reminder Date","Reminder Time","Categories",
|
||||
* "Description","Location","Private"
|
||||
* Not all fields are necessary. If some fields do not match known field names,
|
||||
* a dialog is presented to the user to match fields.
|
||||
*
|
||||
* The rest of the lines are events, one event per line, with fields in the
|
||||
* order descibed by the first line. All non-empty values must be quoted.
|
||||
*
|
||||
* Returns: an array of parsed calendarEvents.
|
||||
* If the parse is cancelled, a zero length array is returned.
|
||||
*/
|
||||
|
||||
calOutlookCSVImporter.prototype.importFromStream =
|
||||
function csv_importFromStream(aStream, aCount) {
|
||||
var scriptableInputStream = Components.classes["@mozilla.org/scriptableinputstream;1"]
|
||||
.createInstance(Components.interfaces.nsIScriptableInputStream);
|
||||
scriptableInputStream.init(aStream);
|
||||
var str = scriptableInputStream.read(-1);
|
||||
|
||||
parse: {
|
||||
// parse header line of quoted comma separated column names.
|
||||
var trimEndQuotesRegExp = /^"(.*)"$/m;
|
||||
var trimResults = trimEndQuotesRegExp.exec( str );
|
||||
var header = trimResults && trimResults[1].split(/","/);
|
||||
if (header == null)
|
||||
break parse;
|
||||
|
||||
//strip header from string
|
||||
str = str.slice(trimResults[0].length);
|
||||
|
||||
var args = new Object();
|
||||
//args.fieldList contains the field names from the first row of CSV
|
||||
args.fieldList = header;
|
||||
|
||||
var locale;
|
||||
var i;
|
||||
for (i in locales) {
|
||||
locale = locales[i];
|
||||
var knownIndxs = 0;
|
||||
for (var i = 1; i <= header.length; ++i) {
|
||||
switch( header[i-1] ) {
|
||||
case locale.headTitle: args.titleIndex = i; knownIndxs++; break;
|
||||
case locale.headStartDate: args.startDateIndex = i; knownIndxs++; break;
|
||||
case locale.headStartTime: args.startTimeIndex = i; knownIndxs++; break;
|
||||
case locale.headEndDate: args.endDateIndex = i; knownIndxs++; break;
|
||||
case locale.headEndTime: args.endTimeIndex = i; knownIndxs++; break;
|
||||
case locale.headAllDayEvent: args.allDayIndex = i; knownIndxs++; break;
|
||||
case locale.headAlarm: args.alarmIndex = i; knownIndxs++; break;
|
||||
case locale.headAlarmDate: args.alarmDateIndex = i; knownIndxs++; break;
|
||||
case locale.headAlarmTime: args.alarmTimeIndex = i; knownIndxs++; break;
|
||||
case locale.headCategories: args.categoriesIndex = i; knownIndxs++; break;
|
||||
case locale.headDescription: args.descriptionIndex = i; knownIndxs++; break;
|
||||
case locale.headLocation: args.locationIndex = i; knownIndxs++; break;
|
||||
case locale.headPrivate: args.privateIndex = i; knownIndxs++; break;
|
||||
}
|
||||
}
|
||||
if (knownIndxs >= 13)
|
||||
break;
|
||||
}
|
||||
|
||||
if (knownIndxs == 0 && header.length == 22) {
|
||||
// set default indexes for a default Outlook2000 CSV file
|
||||
args.titleIndex = 1;
|
||||
args.startDateIndex = 2;
|
||||
args.startTimeIndex = 3;
|
||||
args.endDateIndex = 4;
|
||||
args.endTimeIndex = 5;
|
||||
args.allDayIndex = 6;
|
||||
args.alarmIndex = 7;
|
||||
args.alarmDateIndex = 8;
|
||||
args.alarmTimeIndex = 9;
|
||||
args.categoriesIndex = 15;
|
||||
args.descriptionIndex = 16;
|
||||
args.locationIndex = 17;
|
||||
args.privateIndex = 20;
|
||||
}
|
||||
|
||||
// show field select dialog if not all required headers matched
|
||||
if (knownIndxs < 13) {
|
||||
dump("Can't import. Life sucks\n")
|
||||
break parse;
|
||||
}
|
||||
|
||||
// Construct event regexp according to field indexes. The regexp can
|
||||
// be made stricter, if it seems this matches too loosely.
|
||||
var regExpStr = "^";
|
||||
for (i = 1; i <= header.length; i++) {
|
||||
if (i > 1)
|
||||
regExpStr += ",";
|
||||
regExpStr += "(?:\"((?:[^\"]|\"\")*)\")?";
|
||||
}
|
||||
regExpStr += "$";
|
||||
|
||||
// eventRegExp: regexp for reading events (this one'll be constructed on fly)
|
||||
const eventRegExp = new RegExp(regExpStr, "gm");
|
||||
|
||||
// match first line
|
||||
var eventFields = eventRegExp(str);
|
||||
|
||||
if (eventFields == null)
|
||||
break parse;
|
||||
|
||||
args.boolStr = localeEn.valueTrue;
|
||||
args.boolIsTrue = true;
|
||||
|
||||
var dateParseConfirmed = false;
|
||||
var eventArray = new Array();
|
||||
do {
|
||||
// At this point eventFields contains following fields. Position
|
||||
// of fields is in args.[fieldname]Index.
|
||||
// subject, start date, start time, end date, end time,
|
||||
// all day?, alarm?, alarm date, alarm time,
|
||||
// Description, Categories, Location, Private?
|
||||
// Unused fields (could maybe be copied to Description):
|
||||
// Meeting Organizer, Required Attendees, Optional Attendees,
|
||||
// Meeting Resources, Billing Information, Mileage, Priority,
|
||||
// Sensitivity, Show time as
|
||||
|
||||
var title = ("titleIndex" in args
|
||||
? parseTextField(eventFields[args.titleIndex]) : "");
|
||||
var sDate = parseDateTime(eventFields[args.startDateIndex],
|
||||
eventFields[args.startTimeIndex],
|
||||
locale);
|
||||
var eDate = parseDateTime(eventFields[args.endDateIndex],
|
||||
eventFields[args.endTimeIndex],
|
||||
locale);
|
||||
var alarmDate = parseDateTime(eventFields[args.alarmDateIndex],
|
||||
eventFields[args.alarmTimeIndex],
|
||||
locale);
|
||||
if (title || sDate) {
|
||||
var event = Components.classes["@mozilla.org/calendar/event;1"]
|
||||
.createInstance(Components.interfaces.calIEvent);
|
||||
|
||||
event.title = title;
|
||||
event.isAllDay = (localeEn.True == eventFields[args.allDayIndex]);
|
||||
if (localeEn.True == eventFields[args.privateIndex])
|
||||
event.privacy = "PRIVATE";
|
||||
|
||||
if (!eDate && sDate) {
|
||||
eDate = sDate.clone();
|
||||
if (event.isAllDay) {
|
||||
// end date is exclusive, so set to next day after start.
|
||||
eDate.day = eDate.day + 1;
|
||||
}
|
||||
}
|
||||
if (sDate)
|
||||
event.startDate = sDate;
|
||||
if (eDate)
|
||||
event.endDate = eDate;
|
||||
|
||||
if (alarmDate) {
|
||||
var dif = sDate.subtractDate(alarmDate);
|
||||
dump(dif+"\n");
|
||||
/*
|
||||
// XXX Port this once new alarm stuff lands
|
||||
var len, units;
|
||||
var minutes = Math.round( ( sDate - alarmDate ) / kDate_MillisecondsInMinute );
|
||||
var hours = Math.round(minutes / 60 );
|
||||
if (minutes != hours*60) {
|
||||
len = minutes;
|
||||
units = "minutes";
|
||||
} else {
|
||||
var days = Math.round(hours / 24);
|
||||
if (hours != days * 24) {
|
||||
len = hours;
|
||||
units = "hours";
|
||||
} else {
|
||||
len = days;
|
||||
units = "days";
|
||||
}
|
||||
}
|
||||
calendarEvent.alarmLength = len;
|
||||
calendarEvent.alarmUnits = units;
|
||||
calendarEvent.setParameter( "ICAL_RELATED_PARAMETER", "ICAL_RELATED_START" );
|
||||
*/
|
||||
}
|
||||
|
||||
if ("descriptionIndex" in args)
|
||||
event.setProperty("DESCRIPTION", parseTextField(eventFields[args.descriptionIndex]));
|
||||
if ("categoriesIndex" in args)
|
||||
event.setProperty("CATEGORIES", parseTextField(eventFields[args.categoriesIndex]));
|
||||
if ("locationIndex" in args)
|
||||
event.setProperty("LOCATION", parseTextField(eventFields[args.locationIndex]));
|
||||
|
||||
//save the event into return array
|
||||
eventArray.push(event);
|
||||
}
|
||||
|
||||
//get next events fields
|
||||
eventFields = eventRegExp(str);
|
||||
|
||||
} while (eventRegExp.lastIndex != 0);
|
||||
|
||||
// return results
|
||||
aCount.value = eventArray.length;
|
||||
return eventArray;
|
||||
|
||||
} // end parse
|
||||
|
||||
aCount.value = 0;
|
||||
return new Array();
|
||||
};
|
||||
|
||||
function parseDateTime(aDate, aTime, aLocale)
|
||||
{
|
||||
var date = Components.classes["@mozilla.org/calendar/datetime;1"]
|
||||
.createInstance(Components.interfaces.calIDateTime);
|
||||
|
||||
//XXX Can we do better?
|
||||
date.timezone = "floating";
|
||||
|
||||
var rd = aLocale.dateRe.exec(aDate);
|
||||
var rt = aLocale.timeRe.exec(aTime);
|
||||
|
||||
date.year = rd[aLocale.dateYearIndex];
|
||||
date.month = rd[aLocale.dateMonthIndex] - 1;
|
||||
date.day = rd[aLocale.dateDayIndex];
|
||||
if (rt) {
|
||||
date.hour = Number(rt[aLocale.timeHourIndex]);
|
||||
date.minute = rt[aLocale.timeMinuteIndex];
|
||||
date.second = rt[aLocale.timeSecondIndex];
|
||||
} else {
|
||||
date.isDate = true;
|
||||
}
|
||||
|
||||
if (rt && aLocale.timeAmPmIndex)
|
||||
if (rt[aLocale.timeAmPmIndex] != aLocale.timePmString) {
|
||||
// AM
|
||||
if (date.hour == 12)
|
||||
date.hour = 0;
|
||||
} else {
|
||||
// PM
|
||||
if (date.hour < 12)
|
||||
date.hour += 12;
|
||||
}
|
||||
|
||||
date.normalize();
|
||||
dump(date+"\n");
|
||||
return date;
|
||||
}
|
||||
|
||||
function parseTextField(aTextField)
|
||||
{
|
||||
return aTextField ? aTextField.replace(/""/g, "\"") : "";
|
||||
}
|
||||
|
||||
|
||||
// Export
|
||||
|
||||
function calOutlookCSVExporter() {
|
||||
this.wrappedJSObject = this;
|
||||
}
|
||||
|
||||
calOutlookCSVExporter.prototype.QueryInterface =
|
||||
function QueryInterface(aIID) {
|
||||
if (!aIID.equals(Components.interfaces.nsISupports) &&
|
||||
!aIID.equals(Components.interfaces.calIExporter)) {
|
||||
throw Components.results.NS_ERROR_NO_INTERFACE;
|
||||
}
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
calOutlookCSVExporter.prototype.getFileTypes =
|
||||
function getFileTypes(aCount) {
|
||||
aCount.value = 1;
|
||||
return([{extension:'csv',description:'Comma Separated Values (for Outlook)'}]);
|
||||
};
|
||||
|
||||
// not prototype.export. export is reserved.
|
||||
calOutlookCSVExporter.prototype.exportToStream =
|
||||
function csv_exportToStream(aStream, aCount, aItems) {
|
||||
var str = "";
|
||||
var headers = [];
|
||||
// Not using a loop here, since we need to be sure the order here matches
|
||||
// with the orders the field data is added later on
|
||||
headers.push(localeEn['headTitle']);
|
||||
headers.push(localeEn['headStartDate']);
|
||||
headers.push(localeEn['headStartTime']);
|
||||
headers.push(localeEn['headEndDate']);
|
||||
headers.push(localeEn['headEndTime']);
|
||||
headers.push(localeEn['headAllDayEvent']);
|
||||
headers.push(localeEn['headAlarm']);
|
||||
headers.push(localeEn['headAlarmDate']);
|
||||
headers.push(localeEn['headAlarmTime']);
|
||||
headers.push(localeEn['headCategories']);
|
||||
headers.push(localeEn['headDescription']);
|
||||
headers.push(localeEn['headLocation']);
|
||||
headers.push(localeEn['headPrivate']);
|
||||
headers.push(localeEn['headAlarmTime']);
|
||||
str = headers.map(function(v) {return '"'+v+'"';}).join(',')+"\n"
|
||||
aStream.write(str, str.length);
|
||||
|
||||
for each (item in aItems) {
|
||||
var line = [];
|
||||
line.push(item.title);
|
||||
line.push(dateString(item.startDate));
|
||||
line.push(timeString(item.startDate));
|
||||
line.push(dateString(item.endDate));
|
||||
line.push(timeString(item.endDate));
|
||||
line.push(item.isAllDay ? localeEn.valueTrue : localeEn.valueFalse);
|
||||
line.push(""); //XXX add alarm support
|
||||
line.push(""); //XXX add alarm support
|
||||
line.push(""); //XXX add alarm support
|
||||
line.push(item.getProperty("CATEGORIES"));
|
||||
line.push(item.getProperty("LOCATION"));
|
||||
line.push((item.privacy=="PRIVATE") ? localeEn.valueTrue : localeEn.valueFalse);
|
||||
|
||||
line = line.map(function(v) {
|
||||
v = String(v).replace(/"/,'""');
|
||||
return '"'+v+'"';
|
||||
})
|
||||
str = line.join(',')+"\n";
|
||||
aStream.write(str, str.length);
|
||||
}
|
||||
|
||||
return;
|
||||
};
|
||||
|
||||
function dateString(aDateTime) {
|
||||
return aDateTime.jsDate.toLocaleFormat(localeEn.dateFormat);
|
||||
}
|
||||
|
||||
function timeString(aDateTime) {
|
||||
return aDateTime.jsDate.toLocaleFormat(localeEn.timeFormat);
|
||||
}
|
|
@ -115,8 +115,8 @@
|
|||
<command id="month_view_command" oncommand="gCalendarWindow.switchToMonthView()" disabled="true"/>
|
||||
<command id="multiweek_view_command" oncommand="gCalendarWindow.switchToMultiweekView()" disabled="false"/>
|
||||
|
||||
<command id="import_command" oncommand="startImport()"/>
|
||||
<command id="export_command" oncommand="saveEventsToFile()" disabled="true" disabledwhennoeventsselected="true"/>
|
||||
<command id="import_command" oncommand="loadEventsFromFile()"/>
|
||||
<command id="export_command" oncommand="saveEventsToFile(gCalendarWindow.EventSelection.selectedEvents)" disabled="true" disabledwhennoeventsselected="true"/>
|
||||
|
||||
<command id="reload_remote_calendars" oncommand="gCalendarWindow.calendarManager.refreshAllRemoteCalendars()"/>
|
||||
<command id="publish_calendar" oncommand="publishEntireCalendar()"/>
|
||||
|
|
|
@ -40,7 +40,6 @@ calendar.jar:
|
|||
content/calendar/goToDateDialog.xul (content/goToDateDialog.xul)
|
||||
content/calendar/outlookImportDialog.xul (content/outlookImportDialog.xul)
|
||||
content/calendar/outlookImportDialog.js (content/outlookImportDialog.js)
|
||||
content/calendar/importExport.js (content/importExport.js)
|
||||
content/calendar/menuOverlay.xul (content/menuOverlay.xul)
|
||||
content/calendar/monthView.js (content/monthView.js)
|
||||
content/calendar/monthView.xul (content/monthView.xul)
|
||||
|
@ -174,3 +173,4 @@ calendar.jar:
|
|||
skin/modern/calendar/unifinder/priority_header.png (skin/modern/unifinder/priority_header.png)
|
||||
skin/modern/calendar/unifinder/priority_high.png (skin/modern/unifinder/priority_high.png)
|
||||
skin/modern/calendar/unifinder/priority_low.png (skin/modern/unifinder/priority_low.png)
|
||||
content/calendar/import-export.js (/calendar/base/content/import-export.js)
|
||||
|
|
Загрузка…
Ссылка в новой задаче