summaryrefslogtreecommitdiffstats
path: root/content/modules/lightning.js
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 06:29:37 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 06:29:37 +0000
commit9355e23a909a7801b3ccdf68ee05b3480be42407 (patch)
tree78220623341b88bd42d16929e2acb3e5ef52e0c8 /content/modules/lightning.js
parentInitial commit. (diff)
downloadtbsync-9355e23a909a7801b3ccdf68ee05b3480be42407.tar.xz
tbsync-9355e23a909a7801b3ccdf68ee05b3480be42407.zip
Adding upstream version 4.7.upstream/4.7
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'content/modules/lightning.js')
-rw-r--r--content/modules/lightning.js774
1 files changed, 774 insertions, 0 deletions
diff --git a/content/modules/lightning.js b/content/modules/lightning.js
new file mode 100644
index 0000000..cd9a383
--- /dev/null
+++ b/content/modules/lightning.js
@@ -0,0 +1,774 @@
+/*
+ * This file is part of TbSync.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+ "use strict";
+
+ var { XPCOMUtils } = ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
+
+ XPCOMUtils.defineLazyModuleGetters(this, {
+ CalAlarm: "resource:///modules/CalAlarm.jsm",
+ CalAttachment: "resource:///modules/CalAttachment.jsm",
+ CalAttendee: "resource:///modules/CalAttendee.jsm",
+ CalEvent: "resource:///modules/CalEvent.jsm",
+ CalTodo: "resource:///modules/CalTodo.jsm",
+});
+
+var lightning = {
+
+ cal: null,
+ ICAL: null,
+
+ load: async function () {
+ try {
+ TbSync.lightning.cal = ChromeUtils.import("resource:///modules/calendar/calUtils.jsm").cal;
+ TbSync.lightning.ICAL = ChromeUtils.import("resource:///modules/calendar/Ical.jsm").ICAL;
+ let manager = TbSync.lightning.cal.manager;
+ manager.addCalendarObserver(this.calendarObserver);
+ manager.addObserver(this.calendarManagerObserver);
+ } catch (e) {
+ TbSync.dump("Check4Lightning","Error during lightning module import: " + e.toString() + "\n" + e.stack);
+ Components.utils.reportError(e);
+ }
+ },
+
+ unload: async function () {
+ //removing global observer
+ let manager = TbSync.lightning.cal.manager;
+ manager.removeCalendarObserver(this.calendarObserver);
+ manager.removeObserver(this.calendarManagerObserver);
+
+ //remove listeners on global sync buttons
+ if (TbSync.window.document.getElementById("calendar-synchronize-button")) {
+ TbSync.window.document.getElementById("calendar-synchronize-button").removeEventListener("click", function(event){Services.obs.notifyObservers(null, 'tbsync.observer.sync', null);}, false);
+ }
+ if (TbSync.window.document.getElementById("task-synchronize-button")) {
+ TbSync.window.document.getElementById("task-synchronize-button").removeEventListener("click", function(event){Services.obs.notifyObservers(null, 'tbsync.observer.sync', null);}, false);
+ }
+ },
+
+
+
+
+
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ // * AdvancedTargetData, an extended TargetData implementation, providers
+ // * can use this as their own TargetData by extending it and just
+ // * defining the extra methods
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+
+ AdvancedTargetData : class {
+ constructor(folderData) {
+ this._folderData = folderData;
+ this._targetObj = null;
+ }
+
+ // Check, if the target exists and return true/false.
+ hasTarget() {
+ let calManager = TbSync.lightning.cal.manager;
+ let target = this._folderData.getFolderProperty("target");
+ let calendar = calManager.getCalendarById(target);
+
+ return calendar ? true : false;
+ }
+
+ // Returns the target obj, which TbSync should return as the target. It can
+ // be whatever you want and is returned by FolderData.targetData.getTarget().
+ // If the target does not exist, it should be created. Throw a simple Error, if that
+ // failed.
+ async getTarget() {
+ let calManager = TbSync.lightning.cal.manager;
+ let target = this._folderData.getFolderProperty("target");
+ let calendar = calManager.getCalendarById(target);
+
+ if (!calendar) {
+ calendar = await TbSync.lightning.prepareAndCreateCalendar(this._folderData);
+ if (!calendar)
+ throw new Error("notargets");
+ }
+
+ if (!this._targetObj || this._targetObj.id != calendar.id)
+ this._targetObj = new TbSync.lightning.TbCalendar(calendar, this._folderData);
+
+ return this._targetObj;
+ }
+
+ /**
+ * Removes the target from the local storage. If it does not exist, return
+ * silently. A call to ``hasTarget()`` should return false, after this has
+ * been executed.
+ *
+ */
+ removeTarget() {
+ let calManager = TbSync.lightning.cal.manager;
+ let target = this._folderData.getFolderProperty("target");
+ let calendar = calManager.getCalendarById(target);
+
+ try {
+ if (calendar) {
+ calManager.removeCalendar(calendar);
+ }
+ } catch (e) {}
+ TbSync.db.clearChangeLog(target);
+ this._folderData.resetFolderProperty("target");
+ }
+
+
+ /**
+ * Disconnects the target in the local storage from this TargetData, but
+ * does not delete it, so it becomes a stale "left over" . A call
+ * to ``hasTarget()`` should return false, after this has been executed.
+ *
+ */
+ disconnectTarget() {
+ let calManager = TbSync.lightning.cal.manager;
+ let target = this._folderData.getFolderProperty("target");
+ let calendar = calManager.getCalendarById(target);
+
+ if (calendar) {
+ let changes = TbSync.db.getItemsFromChangeLog(target, 0, "_by_user");
+ if (changes.length > 0) {
+ this.targetName = this.targetName + " (*)";
+ }
+ calendar.setProperty("disabled", true);
+ calendar.setProperty("tbSyncProvider", "orphaned");
+ calendar.setProperty("tbSyncAccountID", "");
+ }
+ TbSync.db.clearChangeLog(target);
+ this._folderData.resetFolderProperty("target");
+ }
+
+ set targetName(newName) {
+ let calManager = TbSync.lightning.cal.manager;
+ let target = this._folderData.getFolderProperty("target");
+ let calendar = calManager.getCalendarById(target);
+
+ if (calendar) {
+ calendar.name = newName;
+ } else {
+ throw new Error("notargets");
+ }
+ }
+
+ get targetName() {
+ let calManager = TbSync.lightning.cal.manager;
+ let target = this._folderData.getFolderProperty("target");
+ let calendar = calManager.getCalendarById(target);
+
+ if (calendar) {
+ return calendar.name;
+ } else {
+ throw new Error("notargets");
+ }
+ }
+
+ setReadOnly(value) {
+ // hasTarget() can throw an error, ignore that here
+ try {
+ if (this.hasTarget()) {
+ this.getTarget().then(target => target.calendar.setProperty("readOnly", value));
+ }
+ } catch (e) {
+ Components.utils.reportError(e);
+ }
+ }
+
+
+ // * * * * * * * * * * * * * * * * *
+ // * AdvancedTargetData extension *
+ // * * * * * * * * * * * * * * * * *
+
+ get isAdvancedCalendarTargetData() {
+ return true;
+ }
+
+ get folderData() {
+ return this._folderData;
+ }
+
+ // The calendar target does not support a custom primaryKeyField, because
+ // the lightning implementation only allows to search for items via UID.
+ // Like the addressbook target, the calendar target item element has a
+ // primaryKey getter/setter which - however - only works on the UID.
+
+ // enable or disable changelog
+ get logUserChanges(){
+ return true;
+ }
+
+ calendarObserver(aTopic, tbCalendar, aPropertyName, aPropertyValue, aOldPropertyValue) {
+ switch (aTopic) {
+ case "onCalendarPropertyChanged":
+ //Services.console.logStringMessage("["+ aTopic + "] " + tbCalendar.calendar.name + " : " + aPropertyName);
+ break;
+
+ case "onCalendarDeleted":
+ case "onCalendarPropertyDeleted":
+ //Services.console.logStringMessage("["+ aTopic + "] " +tbCalendar.calendar.name);
+ break;
+ }
+ }
+
+ itemObserver(aTopic, tbItem, tbOldItem) {
+ switch (aTopic) {
+ case "onAddItem":
+ case "onModifyItem":
+ case "onDeleteItem":
+ //Services.console.logStringMessage("["+ aTopic + "] " + tbItem.nativeItem.title);
+ break;
+ }
+ }
+
+ // replace this with your own implementation to create the actual addressbook,
+ // when this class is extended
+ async createCalendar(newname) {
+ let calManager = TbSync.lightning.cal.manager;
+ let newCalendar = calManager.createCalendar("storage", Services.io.newURI("moz-storage-calendar://"));
+ newCalendar.id = TbSync.lightning.cal.getUUID();
+ newCalendar.name = newname;
+ return newCalendar
+ }
+
+ },
+
+
+
+
+
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ // * TbItem and TbCalendar Classes
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+
+ TbItem : class {
+ constructor(TbCalendar, item) {
+ if (!TbCalendar)
+ throw new Error("TbItem::constructor is missing its first parameter!");
+
+ if (!item)
+ throw new Error("TbItem::constructor is missing its second parameter!");
+
+ this._tbCalendar = TbCalendar;
+ this._item = item;
+
+ this._isTodo = (item instanceof Ci.calITodo);
+ this._isEvent = (item instanceof Ci.calIEvent);
+ }
+
+ get tbCalendar() {
+ return this._tbCalendar;
+ }
+
+ get isTodo() {
+ return this._isTodo;
+ }
+
+ get isEvent() {
+ return this._isEvent;
+ }
+
+
+
+
+
+ get nativeItem() {
+ return this._item;
+ }
+
+ get UID() {
+ return this._item.id;
+ }
+
+ get primaryKey() {
+ // no custom key possible with lightning, must use the UID
+ return this._item.id;
+ }
+
+ set primaryKey(value) {
+ // no custom key possible with lightning, must use the UID
+ this._item.id = value;
+ }
+
+ clone() {
+ return new TbSync.lightning.TbItem(this._tbCalendar, this._item.clone());
+ }
+
+ toString() {
+ return this._item.icalString;
+ }
+
+ getProperty(property, fallback = "") {
+ return this._item.hasProperty(property) ? this._item.getProperty(property) : fallback;
+ }
+
+ setProperty(property, value) {
+ this._item.setProperty(property, value);
+ }
+
+ deleteProperty(property) {
+ this._item.deleteProperty(property);
+ }
+
+ get changelogData() {
+ return TbSync.db.getItemDataFromChangeLog(this._tbCalendar.UID, this.primaryKey);
+ }
+
+ get changelogStatus() {
+ return TbSync.db.getItemStatusFromChangeLog(this._tbCalendar.UID, this.primaryKey);
+ }
+
+ set changelogStatus(status) {
+ let value = this.primaryKey;
+
+ if (value) {
+ if (!status) {
+ TbSync.db.removeItemFromChangeLog(this._tbCalendar.UID, value);
+ return;
+ }
+
+ if (this._tbCalendar.logUserChanges || status.endsWith("_by_server")) {
+ TbSync.db.addItemToChangeLog(this._tbCalendar.UID, value, status);
+ }
+ }
+ }
+ },
+
+
+ TbCalendar : class {
+ constructor(calendar, folderData) {
+ this._calendar = calendar;
+ this._folderData = folderData;
+ }
+
+ get calendar() {
+ return this._calendar;
+ }
+
+ get promisifyCalendar() {
+ return this._calendar;
+ }
+
+ get logUserChanges() {
+ return this._folderData.targetData.logUserChanges;
+ }
+
+ get primaryKeyField() {
+ // Not supported by lightning. We let the implementation sit here, it may get changed in the future.
+ // In order to support this, lightning needs to implement a proper getItemfromProperty() method.
+ return null;
+ }
+
+ get UID() {
+ return this._calendar.id;
+ }
+
+ createNewEvent() {
+ let event = new CalEvent();
+ return new TbSync.lightning.TbItem(this, event);
+ }
+
+ createNewTodo() {
+ let todo = new CalTodo();
+ return new TbSync.lightning.TbItem(this, todo);
+ }
+
+
+
+
+ async addItem(tbItem, pretagChangelogWithByServerEntry = true) {
+ if (this.primaryKeyField && !tbItem.getProperty(this.primaryKeyField)) {
+ tbItem.setProperty(this.primaryKeyField, this._folderData.targetData.generatePrimaryKey());
+ //Services.console.logStringMessage("[TbCalendar::addItem] Generated primary key!");
+ }
+
+ if (pretagChangelogWithByServerEntry) {
+ tbItem.changelogStatus = "added_by_server";
+ }
+ return await this._calendar.addItem(tbItem._item);
+ }
+
+ async modifyItem(tbNewItem, tbOldItem, pretagChangelogWithByServerEntry = true) {
+ // only add entry if the current entry does not start with _by_user
+ let status = tbNewItem.changelogStatus ? tbNewItem.changelogStatus : "";
+ if (pretagChangelogWithByServerEntry && !status.endsWith("_by_user")) {
+ tbNewItem.changelogStatus = "modified_by_server";
+ }
+
+ return await this._calendar.modifyItem(tbNewItem._item, tbOldItem._item);
+ }
+
+ async deleteItem(tbItem, pretagChangelogWithByServerEntry = true) {
+ if (pretagChangelogWithByServerEntry) {
+ tbItem.changelogStatus = "deleted_by_server";
+ }
+ return await this._calendar.deleteItem(tbItem._item);
+ }
+
+ // searchId is interpreted as the primaryKeyField, which is the UID for this target
+ async getItem (searchId) {
+ let item = await this._calendar.getItem(searchId);
+ if (item) {
+ return new TbSync.lightning.TbItem(this, item);
+ }
+ return null;
+ }
+
+ async getItemFromProperty(property, value) {
+ if (property == "UID") return await this.getItem(value);
+ else throw ("TbSync.lightning.getItemFromProperty: Currently onle the UID property can be used to search for items.");
+ }
+
+ async getAllItems() {
+ return await this._calendar.getItems(Ci.calICalendar.ITEM_FILTER_ALL_ITEMS, 0, null, null);
+ }
+
+ getAddedItemsFromChangeLog(maxitems = 0) {
+ return TbSync.db.getItemsFromChangeLog(this.calendar.id, maxitems, "added_by_user").map(item => item.itemId);
+ }
+
+ getModifiedItemsFromChangeLog(maxitems = 0) {
+ return TbSync.db.getItemsFromChangeLog(this.calendar.id, maxitems, "modified_by_user").map(item => item.itemId);
+ }
+
+ getDeletedItemsFromChangeLog(maxitems = 0) {
+ return TbSync.db.getItemsFromChangeLog(this.calendar.id, maxitems, "deleted_by_user").map(item => item.itemId);
+ }
+
+ getItemsFromChangeLog(maxitems = 0) {
+ return TbSync.db.getItemsFromChangeLog(this.calendar.id, maxitems, "_by_user");
+ }
+
+ removeItemFromChangeLog(id, moveToEndInsteadOfDelete = false) {
+ TbSync.db.removeItemFromChangeLog(this.calendar.id, id, moveToEndInsteadOfDelete);
+ }
+
+ clearChangelog() {
+ TbSync.db.clearChangeLog(this.calendar.id);
+ }
+ },
+
+
+
+
+
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ // * Internal Functions
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+
+ getFolderFromCalendarUID: function(calUID) {
+ let folders = TbSync.db.findFolders({"target": calUID});
+ if (folders.length == 1) {
+ let accountData = new TbSync.AccountData(folders[0].accountID);
+ return new TbSync.FolderData(accountData, folders[0].folderID);
+ }
+ return null;
+ },
+
+ getFolderFromCalendarURL: function(calURL) {
+ let folders = TbSync.db.findFolders({"url": calURL});
+ if (folders.length == 1) {
+ let accountData = new TbSync.AccountData(folders[0].accountID);
+ return new TbSync.FolderData(accountData, folders[0].folderID);
+ }
+ return null;
+ },
+
+ calendarObserver : {
+ onStartBatch : function () {},
+ onEndBatch : function () {},
+ onLoad : function (aCalendar) {},
+ onError : function (aCalendar, aErrNo, aMessage) {},
+
+ onAddItem : function (aAddedItem) {
+ if (!(aAddedItem && aAddedItem.calendar))
+ return;
+
+ let folderData = TbSync.lightning.getFolderFromCalendarUID(aAddedItem.calendar.id);
+ if (folderData
+ && folderData.targetData
+ && folderData.targetData.isAdvancedCalendarTargetData) {
+
+ let tbCalendar = new TbSync.lightning.TbCalendar(aAddedItem.calendar, folderData);
+ let tbItem = new TbSync.lightning.TbItem(tbCalendar, aAddedItem);
+ let itemStatus = tbItem.changelogStatus;
+
+ // if this card was created by us, it will be in the log
+ if (itemStatus && itemStatus.endsWith("_by_server")) {
+ let age = Date.now() - tbItem.changelogData.timestamp;
+ if (age < 1500) {
+ // during freeze, local modifications are not possible
+ return;
+ } else {
+ // remove blocking entry from changelog after freeze time is over (1.5s),
+ // and continue evaluating this event
+ abItem.changelogStatus = "";
+ }
+ }
+
+ if (itemStatus == "deleted_by_user") {
+ // deleted ? user moved item out and back in -> modified
+ tbItem.changelogStatus = "modified_by_user";
+ } else {
+ tbItem.changelogStatus = "added_by_user";
+ }
+
+ if (tbCalendar.logUserChanges) TbSync.core.setTargetModified(folderData);
+ folderData.targetData.itemObserver("onAddItem", tbItem, null);
+ }
+ },
+
+ onModifyItem : function (aNewItem, aOldItem) {
+ //check, if it is a pure modification within the same calendar
+ if (!(aNewItem && aNewItem.calendar && aOldItem && aOldItem.calendar && aNewItem.calendar.id == aOldItem.calendar.id))
+ return;
+
+ let folderData = TbSync.lightning.getFolderFromCalendarUID(aNewItem.calendar.id);
+ if (folderData
+ && folderData.targetData
+ && folderData.targetData.isAdvancedCalendarTargetData) {
+
+ let tbCalendar = new TbSync.lightning.TbCalendar(aNewItem.calendar, folderData);
+ let tbNewItem = new TbSync.lightning.TbItem(tbCalendar, aNewItem);
+ let tbOldItem = new TbSync.lightning.TbItem(tbCalendar, aOldItem);
+ let itemStatus = tbNewItem.changelogStatus;
+
+ // if this card was created by us, it will be in the log
+ if (itemStatus && itemStatus.endsWith("_by_server")) {
+ let age = Date.now() - tbNewItem.changelogData.timestamp;
+ if (age < 1500) {
+ // during freeze, local modifications are not possible
+ return;
+ } else {
+ // remove blocking entry from changelog after freeze time is over (1.5s),
+ // and continue evaluating this event
+ tbNewItem.changelogStatus = "";
+ }
+ }
+
+ if (itemStatus != "added_by_user") {
+ //added_by_user -> it is a local unprocessed add do not re-add it to changelog
+ tbNewItem.changelogStatus = "modified_by_user";
+ }
+
+ if (tbCalendar.logUserChanges) TbSync.core.setTargetModified(folderData);
+ folderData.targetData.itemObserver("onModifyItem", tbNewItem, tbOldItem);
+ }
+ },
+
+ onDeleteItem : function (aDeletedItem) {
+ if (!(aDeletedItem && aDeletedItem.calendar))
+ return;
+
+ let folderData = TbSync.lightning.getFolderFromCalendarUID(aDeletedItem.calendar.id);
+ if (folderData
+ && folderData.targetData
+ && folderData.targetData.isAdvancedCalendarTargetData) {
+
+ let tbCalendar = new TbSync.lightning.TbCalendar(aDeletedItem.calendar, folderData);
+ let tbItem = new TbSync.lightning.TbItem(tbCalendar, aDeletedItem);
+ let itemStatus = tbItem.changelogStatus;
+
+ // if this card was created by us, it will be in the log
+ if (itemStatus && itemStatus.endsWith("_by_server")) {
+ let age = Date.now() - tbItem.changelogData.timestamp;
+ if (age < 1500) {
+ // during freeze, local modifications are not possible
+ return;
+ } else {
+ // remove blocking entry from changelog after freeze time is over (1.5s),
+ // and continue evaluating this event
+ tbItem.changelogStatus = "";
+ }
+ }
+
+ if (itemStatus == "added_by_user") {
+ //a local add, which has not yet been processed (synced) is deleted -> remove all traces
+ tbItem.changelogStatus = "";
+ } else {
+ tbItem.changelogStatus = "deleted_by_user";
+ }
+
+ if (tbCalendar.logUserChanges) TbSync.core.setTargetModified(folderData);
+ folderData.targetData.itemObserver("onDeleteItem", tbItem, null);
+ }
+ },
+
+ //Changed properties of the calendar itself (name, color etc.)
+ onPropertyChanged : function (aCalendar, aName, aValue, aOldValue) {
+ let folderData = TbSync.lightning.getFolderFromCalendarUID(aCalendar.id);
+ if (folderData
+ && folderData.targetData
+ && folderData.targetData.isAdvancedCalendarTargetData) {
+
+ let tbCalendar = new TbSync.lightning.TbCalendar(aCalendar, folderData);
+
+ switch (aName) {
+ case "color":
+ // update stored color to recover after disable
+ folderData.setFolderProperty("targetColor", aValue);
+ break;
+ case "name":
+ // update stored name to recover after disable
+ folderData.setFolderProperty("targetName", aValue);
+ // update settings window, if open
+ Services.obs.notifyObservers(null, "tbsync.observer.manager.updateSyncstate", folderData.accountID);
+ break;
+ }
+
+ folderData.targetData.calendarObserver("onCalendarPropertyChanged", tbCalendar, aName, aValue, aOldValue);
+ }
+ },
+
+ //Deleted properties of the calendar itself (name, color etc.)
+ onPropertyDeleting : function (aCalendar, aName) {
+ let folderData = TbSync.lightning.getFolderFromCalendarUID(aCalendar.id);
+ if (folderData
+ && folderData.targetData
+ && folderData.targetData.isAdvancedCalendarTargetData) {
+
+ let tbCalendar = new TbSync.lightning.TbCalendar(aCalendar, folderData);
+
+ switch (aName) {
+ case "color":
+ case "name":
+ //update settings window, if open
+ Services.obs.notifyObservers(null, "tbsync.observer.manager.updateSyncstate", folderData.accountID);
+ break;
+ }
+
+ folderData.targetData.calendarObserver("onCalendarPropertyDeleted", tbCalendar, aName);
+ }
+ }
+ },
+
+ calendarManagerObserver : {
+ onCalendarRegistered : function (aCalendar) {
+ },
+
+ onCalendarUnregistering : function (aCalendar) {
+ /*let folderData = TbSync.lightning.getFolderFromCalendarUID(aCalendar.id);
+ if (folderData
+ && folderData.targetData
+ && folderData.targetData.isAdvancedCalendarTargetData) {
+
+ folderData.targetData.calendarObserver("onCalendarUnregistered", aCalendar);
+ }*/
+ },
+
+ onCalendarDeleting : async function (aCalendar) {
+ let folderData = TbSync.lightning.getFolderFromCalendarUID(aCalendar.id);
+ if (folderData
+ && folderData.targetData
+ && folderData.targetData.isAdvancedCalendarTargetData) {
+
+ // If the user switches "offline support", the calendar is deleted and recreated. Thus,
+ // we wait a bit and check, if the calendar is back again and ignore the delete event.
+ if (aCalendar.type == "caldav") {
+ await TbSync.tools.sleep(1500);
+ let calManager = TbSync.lightning.cal.manager;
+ for (let calendar of calManager.getCalendars({})) {
+ if (calendar.uri.spec == aCalendar.uri.spec) {
+ // update the target
+ folderData.setFolderProperty("target", calendar.id)
+ return;
+ }
+ }
+ }
+
+ //delete any pending changelog of the deleted calendar
+ TbSync.db.clearChangeLog(aCalendar.id);
+
+ let tbCalendar = new TbSync.lightning.TbCalendar(aCalendar, folderData);
+
+ //unselect calendar if deleted by user and update settings window, if open
+ if (folderData.getFolderProperty("selected")) {
+ folderData.setFolderProperty("selected", false);
+ //update settings window, if open
+ Services.obs.notifyObservers(null, "tbsync.observer.manager.updateSyncstate", folderData.accountID);
+ }
+
+ folderData.resetFolderProperty("target");
+ folderData.targetData.calendarObserver("onCalendarDeleted", tbCalendar);
+
+ }
+ },
+ },
+
+
+
+ //this function actually creates a calendar if missing
+ prepareAndCreateCalendar: async function (folderData) {
+ let calManager = TbSync.lightning.cal.manager;
+ let provider = folderData.accountData.getAccountProperty("provider");
+
+ //check if there is a known/cached name, and use that as starting point to generate unique name for new calendar
+ let cachedName = folderData.getFolderProperty("targetName");
+ let newname = cachedName == "" ? folderData.accountData.getAccountProperty("accountname") + " (" + folderData.getFolderProperty("foldername") + ")" : cachedName;
+
+ //check if there is a cached or preloaded color - if not, chose one
+ if (!folderData.getFolderProperty("targetColor")) {
+ //define color set
+ let allColors = [
+ "#3366CC",
+ "#DC3912",
+ "#FF9900",
+ "#109618",
+ "#990099",
+ "#3B3EAC",
+ "#0099C6",
+ "#DD4477",
+ "#66AA00",
+ "#B82E2E",
+ "#316395",
+ "#994499",
+ "#22AA99",
+ "#AAAA11",
+ "#6633CC",
+ "#E67300",
+ "#8B0707",
+ "#329262",
+ "#5574A6",
+ "#3B3EAC"];
+
+ //find all used colors
+ let usedColors = [];
+ for (let calendar of calManager.getCalendars({})) {
+ if (calendar && calendar.getProperty("color")) {
+ usedColors.push(calendar.getProperty("color").toUpperCase());
+ }
+ }
+
+ //we do not want to change order of colors, we want to FILTER by counts, so we need to find the least count, filter by that and then take the first one
+ let minCount = null;
+ let statColors = [];
+ for (let i=0; i< allColors.length; i++) {
+ let count = usedColors.filter(item => item == allColors[i]).length;
+ if (minCount === null) minCount = count;
+ else if (count < minCount) minCount = count;
+
+ let obj = {};
+ obj.color = allColors[i];
+ obj.count = count;
+ statColors.push(obj);
+ }
+
+ //filter by minCount
+ let freeColors = statColors.filter(item => (minCount == null || item.count == minCount));
+ folderData.setFolderProperty("targetColor", freeColors[0].color);
+ }
+
+ //create and register new calendar
+ let newCalendar = await folderData.targetData.createCalendar(newname);
+ newCalendar.setProperty("tbSyncProvider", provider);
+ newCalendar.setProperty("tbSyncAccountID", folderData.accountData.accountID);
+
+ //store id of calendar as target in DB
+ folderData.setFolderProperty("target", newCalendar.id);
+ folderData.setFolderProperty("targetName", newCalendar.name);
+ folderData.setFolderProperty("targetColor", newCalendar.getProperty("color"));
+ return newCalendar;
+ }
+}