Merged comma fix with 10-11-2019 tip, 080bed041a01 draft comma-in-foldername-fix
authorGene Smith <gds@chartertn.net>
Sat, 12 Oct 2019 17:18:39 -0400
branchcomma-in-foldername-fix
changeset 87297 d5e5840acc1bf1040c2c95dfd6e6db184ce3f985
parent 87293 4d51dc9d0f326f6e821278254e6b0faf5201db21 (current diff)
parent 80040 080bed041a01c876b8330a87cd3dab526b1f7dc9 (diff)
push id10879
push usergds@chartertn.net
push dateWed, 22 Apr 2020 03:01:34 +0000
treeherdertry-comm-central@b33b4dd87b67 [default view] [failures only]
Merged comma fix with 10-11-2019 tip, 080bed041a01
calendar/base/content/calendar-bindings.css
calendar/base/content/calendar-common-sets.xul
calendar/base/content/calendar-month-view.xml
calendar/base/content/calendar-multiday-view.xml
calendar/base/content/calendar-unifinder-todo.js
calendar/base/content/calendar-unifinder-todo.xul
calendar/base/content/calendar-view-bindings.css
calendar/base/content/calendar-view-core.xml
calendar/lightning/content/lightning-calendar-creation.xul
calendar/lightning/content/lightning-calendar-properties.xul
calendar/lightning/content/lightning-item-iframe.js
calendar/locales/en-US/chrome/calendar/providers/gdata/amo.properties
calendar/locales/en-US/chrome/calendar/providers/gdata/gdata.dtd
calendar/locales/en-US/chrome/calendar/providers/gdata/gdata.properties
calendar/providers/caldav/content/caldav-lightning-calendar-creation.xul
calendar/providers/caldav/content/caldav-lightning-calendar-properties.xul
calendar/providers/gdata/Makefile.in
calendar/providers/gdata/components/calGoogleCalendar.js
calendar/providers/gdata/components/calGoogleCalendar.manifest
calendar/providers/gdata/content/browserRequest.css
calendar/providers/gdata/content/browserRequest.js
calendar/providers/gdata/content/browserRequest.xul
calendar/providers/gdata/content/gcal.png
calendar/providers/gdata/content/gdata-bindings.css
calendar/providers/gdata/content/gdata-calendar-creation.js
calendar/providers/gdata/content/gdata-calendar-creation.xul
calendar/providers/gdata/content/gdata-calendar-properties.js
calendar/providers/gdata/content/gdata-calendar-properties.xul
calendar/providers/gdata/content/gdata-event-dialog-reminder.css
calendar/providers/gdata/content/gdata-event-dialog-reminder.js
calendar/providers/gdata/content/gdata-event-dialog-reminder.xul
calendar/providers/gdata/content/gdata-event-dialog.js
calendar/providers/gdata/content/gdata-event-dialog.xul
calendar/providers/gdata/content/gdata-lightning-item-iframe.js
calendar/providers/gdata/content/gdata-lightning-item-iframe.xul
calendar/providers/gdata/content/gdata-lightning-item-toolbar.xul
calendar/providers/gdata/content/gdata-migration-overlay.xul
calendar/providers/gdata/content/gdata-migration-wizard.xul
calendar/providers/gdata/content/gdata-migration.js
calendar/providers/gdata/content/reminder-action-sms.svg
calendar/providers/gdata/defaults/preferences.js
calendar/providers/gdata/jar.mn
calendar/providers/gdata/manifest.json
calendar/providers/gdata/modules/OAuth2.jsm
calendar/providers/gdata/modules/gdataLogging.jsm
calendar/providers/gdata/modules/gdataRequest.jsm
calendar/providers/gdata/modules/gdataSession.jsm
calendar/providers/gdata/modules/gdataUtils.jsm
calendar/providers/gdata/modules/timezoneMap.jsm
calendar/providers/gdata/moz.build
calendar/test/mozmill/.eslintrc.js
calendar/test/mozmill/Makefile.in
calendar/test/mozmill/cal-recurrence/testAnnualRecurrence.js
calendar/test/mozmill/cal-recurrence/testBiweeklyRecurrence.js
calendar/test/mozmill/cal-recurrence/testDailyRecurrence.js
calendar/test/mozmill/cal-recurrence/testLastDayOfMonthRecurrence.js
calendar/test/mozmill/cal-recurrence/testWeeklyNRecurrence.js
calendar/test/mozmill/cal-recurrence/testWeeklyUntilRecurrence.js
calendar/test/mozmill/cal-recurrence/testWeeklyWithExceptionRecurrence.js
calendar/test/mozmill/eventDialog/testAlarmDialog.js
calendar/test/mozmill/eventDialog/testEventDialog.js
calendar/test/mozmill/eventDialog/testEventDialogModificationPrompt.js
calendar/test/mozmill/eventDialog/testEventDialogSize.js
calendar/test/mozmill/eventDialog/testUTF8.js
calendar/test/mozmill/invitations/message-containing-event.eml
calendar/test/mozmill/invitations/test-imip-bar-eml.js
calendar/test/mozmill/moz.build
calendar/test/mozmill/mozmilltests.list
calendar/test/mozmill/preferences/testAlarmDefaultValue.js
calendar/test/mozmill/preferences/testCategoryColors.js
calendar/test/mozmill/recurrenceRotated/testAnnualRecurrence.js
calendar/test/mozmill/recurrenceRotated/testBiweeklyRecurrence.js
calendar/test/mozmill/recurrenceRotated/testDailyRecurrence.js
calendar/test/mozmill/recurrenceRotated/testLastDayOfMonthRecurrence.js
calendar/test/mozmill/recurrenceRotated/testWeeklyNRecurrence.js
calendar/test/mozmill/recurrenceRotated/testWeeklyUntilRecurrence.js
calendar/test/mozmill/recurrenceRotated/testWeeklyWithExceptionRecurrence.js
calendar/test/mozmill/shared-modules/moz.build
calendar/test/mozmill/shared-modules/test-calendar-utils.js
calendar/test/mozmill/shared-modules/test-item-editing-helpers.js
calendar/test/mozmill/testBasicFunctionality.js
calendar/test/mozmill/testLocalICS.js
calendar/test/mozmill/testTimezones.js
calendar/test/mozmill/testTodayPane.js
calendar/test/mozmill/views/testDayView.js
calendar/test/mozmill/views/testMonthView.js
calendar/test/mozmill/views/testMultiweekView.js
calendar/test/mozmill/views/testTaskView.js
calendar/test/mozmill/views/testWeekView.js
calendar/test/unit/test_gdata_provider.js
chat/.eslintrc.js
chat/content/imtooltip.xml
common/bindings/generalBindings.js
editor/ui/dialogs/content/EdLinkChecker.js
editor/ui/dialogs/content/EdLinkChecker.xul
editor/ui/locales/en-US/chrome/dialogs/EdLinkChecker.dtd
mail/base/content/search.xml
mail/components/preferences/doctype.inc.xul
mail/test/mozmill/folder-display/test-displaying-messages-in-folder-tabs.js
mail/test/mozmill/shared-modules/test-account-manager-helpers.js
mail/test/mozmill/shared-modules/test-address-book-helpers.js
mail/test/mozmill/shared-modules/test-attachment-helpers.js
mail/test/mozmill/shared-modules/test-cloudfile-backend-helpers.js
mail/test/mozmill/shared-modules/test-cloudfile-helpers.js
mail/test/mozmill/shared-modules/test-compose-helpers.js
mail/test/mozmill/shared-modules/test-content-tab-helpers.js
mail/test/mozmill/shared-modules/test-customization-helpers.js
mail/test/mozmill/shared-modules/test-dom-helpers.js
mail/test/mozmill/shared-modules/test-folder-display-helpers.js
mail/test/mozmill/shared-modules/test-junk-helpers.js
mail/test/mozmill/shared-modules/test-keyboard-helpers.js
mail/test/mozmill/shared-modules/test-message-helpers.js
mail/test/mozmill/shared-modules/test-mock-object-helpers.js
mail/test/mozmill/shared-modules/test-mouse-event-helpers.js
mail/test/mozmill/shared-modules/test-newmailaccount-helpers.js
mail/test/mozmill/shared-modules/test-nntp-helpers.js
mail/test/mozmill/shared-modules/test-notificationbox-helpers.js
mail/test/mozmill/shared-modules/test-observer-helpers.js
mail/test/mozmill/shared-modules/test-pref-window-helpers.js
mail/test/mozmill/shared-modules/test-prompt-helpers.js
mail/test/mozmill/shared-modules/test-quick-filter-bar-helpers.js
mail/test/mozmill/shared-modules/test-search-window-helpers.js
mail/test/mozmill/shared-modules/test-subscribe-window-helpers.js
mail/test/mozmill/shared-modules/test-window-helpers.js
mail/themes/linux/mail/filefield.css
mail/themes/osx/mail/filefield.css
mail/themes/shared/mail/icons/check.svg
mail/themes/windows/mail/filefield.css
mailnews/addrbook/test/unit/test_bug_448165.js
mailnews/base/content/msgFolderPickerOverlay.js
mailnews/base/src/nsMsgRDFUtils.cpp
mailnews/base/src/nsMsgRDFUtils.h
mailnews/compose/src/nsMsgCompose.cpp
mailnews/mime/test/unit/test_parseHeadersWithArray.js
rdf/base/moz.build
rdf/base/nsCompositeDataSource.cpp
rdf/base/nsContainerEnumerator.cpp
rdf/base/nsDefaultResourceFactory.cpp
rdf/base/nsIRDFCompositeDataSource.idl
rdf/base/nsIRDFContainer.idl
rdf/base/nsIRDFContainerUtils.idl
rdf/base/nsIRDFContentSink.h
rdf/base/nsIRDFDataSource.idl
rdf/base/nsIRDFDelegateFactory.idl
rdf/base/nsIRDFInMemoryDataSource.idl
rdf/base/nsIRDFInferDataSource.idl
rdf/base/nsIRDFLiteral.idl
rdf/base/nsIRDFNode.idl
rdf/base/nsIRDFObserver.idl
rdf/base/nsIRDFPropagatableDataSource.idl
rdf/base/nsIRDFPurgeableDataSource.idl
rdf/base/nsIRDFRemoteDataSource.idl
rdf/base/nsIRDFResource.idl
rdf/base/nsIRDFService.idl
rdf/base/nsIRDFXMLParser.idl
rdf/base/nsIRDFXMLSerializer.idl
rdf/base/nsIRDFXMLSink.idl
rdf/base/nsIRDFXMLSource.idl
rdf/base/nsInMemoryDataSource.cpp
rdf/base/nsNameSpaceMap.cpp
rdf/base/nsNameSpaceMap.h
rdf/base/nsRDFBaseDataSources.h
rdf/base/nsRDFContainer.cpp
rdf/base/nsRDFContainerUtils.cpp
rdf/base/nsRDFContentSink.cpp
rdf/base/nsRDFResource.cpp
rdf/base/nsRDFResource.h
rdf/base/nsRDFService.cpp
rdf/base/nsRDFService.h
rdf/base/nsRDFXMLDataSource.cpp
rdf/base/nsRDFXMLParser.cpp
rdf/base/nsRDFXMLParser.h
rdf/base/nsRDFXMLSerializer.cpp
rdf/base/nsRDFXMLSerializer.h
rdf/base/rdf.h
rdf/base/rdfIDataSource.idl
rdf/base/rdfITripleVisitor.idl
rdf/base/rdfutil.cpp
rdf/base/rdfutil.h
rdf/build/moz.build
rdf/build/nsRDFCID.h
rdf/build/nsRDFModule.cpp
rdf/datasource/moz.build
rdf/datasource/nsILocalStore.h
rdf/datasource/nsIRDFFTP.h
rdf/datasource/nsLocalStore.cpp
rdf/datasource/nsRDFBuiltInDataSources.h
rdf/moz.build
suite/branding/seamonkey/content/aboutRights.js
suite/browser/Makefile.in
suite/browser/browser-prefs.js
suite/browser/channel-prefs.js
suite/components/permissions/content/treeUtils.js
taskcluster/ci/beetmover-l10n/kind.yml
taskcluster/ci/checksums-signing/kind.yml
third_party/libgcrypt/autogen.sh
third_party/libgcrypt/build-aux/compile
third_party/libgcrypt/build-aux/config.guess
third_party/libgcrypt/build-aux/config.rpath
third_party/libgcrypt/build-aux/config.sub
third_party/libgcrypt/build-aux/depcomp
third_party/libgcrypt/build-aux/install-sh
third_party/libgcrypt/build-aux/mdate-sh
third_party/libgcrypt/build-aux/missing
third_party/libgcrypt/configure
third_party/libgcrypt/mkinstalldirs
third_party/libgcrypt/tests/basic_all_hwfeature_combinations.sh
third_party/libgcrypt/tests/cavs_driver.pl
third_party/libgcrypt/tests/cavs_tests.sh
third_party/libgcrypt/tests/hashtest-256g.in
third_party/libgpg-error/autogen.sh
third_party/libgpg-error/build-aux/compile
third_party/libgpg-error/build-aux/config.guess
third_party/libgpg-error/build-aux/config.rpath
third_party/libgpg-error/build-aux/config.sub
third_party/libgpg-error/build-aux/depcomp
third_party/libgpg-error/build-aux/install-sh
third_party/libgpg-error/build-aux/mdate-sh
third_party/libgpg-error/build-aux/missing
third_party/libgpg-error/configure
third_party/libgpg-error/mkinstalldirs
third_party/libgpg-error/potomo
third_party/libgpg-error/src/gpg-error-config-test.sh
third_party/libgpg-error/src/gpgrt-config
third_party/libotr/bootstrap
third_party/libotr/config.guess
third_party/libotr/config.sub
third_party/libotr/config/compile
third_party/libotr/config/config.guess
third_party/libotr/config/config.sub
third_party/libotr/config/depcomp
third_party/libotr/config/install-sh
third_party/libotr/config/missing
third_party/libotr/configure
third_party/libotr/install-sh
third_party/libotr/tests/regression/random-msg-auth.sh
third_party/libotr/tests/regression/random-msg-disconnect-auth.sh
third_party/libotr/tests/regression/random-msg-disconnect-frag-auth.sh
third_party/libotr/tests/regression/random-msg-disconnect-frag.sh
third_party/libotr/tests/regression/random-msg-disconnect.sh
third_party/libotr/tests/regression/random-msg-fast.sh
third_party/libotr/tests/regression/random-msg-frag.sh
third_party/libotr/tests/regression/random-msg.sh
third_party/libotr/tests/run.sh
third_party/libotr/tests/utils/tap/tap.sh
--- a/.eslintignore
+++ b/.eslintignore
@@ -71,16 +71,18 @@ mail/base/content/protovis-r2.6-modded.j
 mail/branding/nightly/thunderbird-branding.js
 mail/branding/thunderbird/thunderbird-branding.js
 # This file is split into two in order to keep it as a valid json file
 # for documentation purposes (policies.json) but to be accessed by the
 # code as a .jsm (schema.jsm)
 mail/components/enterprisepolicies/schemas/schema.jsm
 mail/components/im/all-im.js
 mail/locales/en-US/all-l10n.js
+mail/components/compose/texzilla/**
+mail/components/compose/composer.js
 
 # calendar/ exclusions
 
 # prefs files
 calendar/lightning/content/lightning.js
 calendar/providers/gdata/defaults/preferences.js
 calendar/timezones/preferences.js
 
--- a/.eslintrc.js
+++ b/.eslintrc.js
@@ -3,198 +3,115 @@
 const xpcshellTestConfig = require("eslint-plugin-mozilla/lib/configs/xpcshell-test.js");
 const browserTestConfig = require("eslint-plugin-mozilla/lib/configs/browser-test.js");
 
 /**
  * Some configurations have overrides, which can't be specified within overrides,
  * so we need to remove them.
  */
 function removeOverrides(config) {
-  config = {...config};
+  config = { ...config };
   delete config.overrides;
   return config;
 }
 
 const xpcshellTestPaths = [
   "**/test*/unit*/",
   "**/test*/xpcshell/",
   "chat/**/test*/",
 ];
 
-const browserTestPaths = [
-  "**/test*/**/browser/",
-];
+const browserTestPaths = ["**/test*/**/browser/"];
 
 module.exports = {
-  "root": true,
+  root: true,
 
   // We would like the same base rules as provided by
   // mozilla/tools/lint/eslint/eslint-plugin-mozilla/lib/configs/recommended.js
-  "extends": [
-    "plugin:mozilla/recommended",
-  ],
+  extends: ["plugin:mozilla/recommended"],
 
   // When adding items to this file please check for effects on sub-directories.
-  "plugins": [
-    "html",
-    "mozilla",
-  ],
-
-  "rules": {
-    "func-names": ["error", "never"],
-    "no-multi-spaces": ["error", {
-      exceptions: {
-        "ArrayExpression": true,
-        "AssignmentExpression": true,
-        "ObjectExpression": true,
-        "VariableDeclarator": true,
-      },
-      ignoreEOLComments: true,
-    }],
-    "prettier/prettier": "off",
-    "semi-spacing": ["error", {"before": false, "after": true}],
-    "space-in-parens": ["error", "never"],
-
-
-    // Require spacing around =>
-    "arrow-spacing": "error",
-
-    // Always require spacing around a single line block
-    "block-spacing": "error",
-
-    // No newline before open brace for a block
-    "brace-style": ["error", "1tbs", { "allowSingleLine": true }],
-
-    // Require trailing commas for easy list extension and consistent style.
-    "comma-dangle": ["error", "always-multiline"],
-
-    // No space before always a space after a comma
-    "comma-spacing": ["error", {"after": true, "before": false}],
-
-    // Commas at the end of the line not the start
-    "comma-style": "error",
-
-    // Don't require spaces around computed properties
-    "computed-property-spacing": ["error", "never"],
-
-    // Note that this rule is likely to be overridden on a per-directory basis
-    // very frequently.
-    "curly": "off",
-
-    // Always require a trailing EOL
-    "eol-last": "error",
-
-    // No spaces between function name and parentheses
-    "func-call-spacing": "error",
-
-    // Require function* name()
-    "generator-star-spacing": ["error", {"after": true, "before": false}],
+  plugins: ["html", "mozilla"],
 
-    // Space after colon not before in property declarations
-    "key-spacing": ["error", {
-      "afterColon": true,
-      "beforeColon": false,
-      "mode": "minimum",
-    }],
-
-    // Require spaces before and after keywords
-    "keyword-spacing": "error",
-
-    // Unix linebreaks
-    "linebreak-style": ["error", "unix"],
-
-    // Disallow tabs.
-    "no-tabs": "error",
-
-    // No trailing whitespace
-    "no-trailing-spaces": "error",
-
-    // Disallow whitespace before properties.
-    "no-whitespace-before-property": "error",
-
-    // Prohibit blank lines at the beginning and end of blocks.
-    "padded-blocks": ["error", "never"],
-
-    // Require double-quotes everywhere, except where quotes are escaped
-    // or template literals are used.
-    "quotes": ["error", "double", {
-      "allowTemplateLiterals": true,
-      "avoidEscape": true,
-    }],
+  rules: {
+    "func-names": ["error", "never"],
+    "no-multi-spaces": [
+      "error",
+      {
+        exceptions: {
+          ArrayExpression: true,
+          AssignmentExpression: true,
+          ObjectExpression: true,
+          VariableDeclarator: true,
+        },
+        ignoreEOLComments: true,
+      },
+    ],
+    "semi-spacing": ["error", { before: false, after: true }],
+    "space-in-parens": ["error", "never"],
+    curly: ["error", "all"],
 
-    // No spacing inside rest or spread expressions
-    "rest-spread-spacing": "error",
-
-    // Always require semicolon at end of statement
-    "semi": ["error", "always"],
-
-    // Require space before blocks
-    "space-before-blocks": "error",
-
-    // Never use spaces before function parentheses
-    "space-before-function-paren": ["error", {
-      "anonymous": "never",
-      "asyncArrow": "always",
-      "named": "never",
-    }],
-
-    // No space padding in parentheses
-    // "space-in-parens": ["error", "never"],
-
-    // Require spaces around operators
-    "space-infix-ops": ["error", { "int32Hint": true }],
-
-    // ++ and -- should not need spacing
-    "space-unary-ops": ["error", {
-      "nonwords": false,
-      "overrides": {
-        "typeof": false, // We tend to use typeof as a function call
-      },
-      "words": true,
-    }],
-
-    // Requires or disallows a whitespace (space or tab) beginning a comment
-    "spaced-comment": ["error", "always", { "markers": ["#"] }],
+    // Use brace-style because Prettier covers most brace issues but not this:
+    //
+    //     }
+    //     // a comment
+    //     else {
+    //
+    // Allow single line for inline JS in XUL files.
+    "brace-style": ["error", "1tbs", { allowSingleLine: true }],
   },
 
   // To avoid bad interactions of the html plugin with the xml preprocessor in
   // eslint-plugin-mozilla, we turn off processing of the html plugin for .xml
   // files.
-  "settings": {
-    "html/xml-extensions": [ ".xhtml" ],
+  settings: {
+    "html/xml-extensions": [".xhtml"],
   },
 
-  "overrides": [{
-    // eslint-plugin-html handles eol-last slightly different - it applies to
-    // each set of script tags, so we turn it off here.
-    "files": "**/*.*html",
-    "rules": {
-      "eol-last": "off",
+  overrides: [
+    {
+      // eslint-plugin-html handles eol-last slightly different - it applies to
+      // each set of script tags, so we turn it off here.
+      files: "**/*.*html",
+      rules: {
+        "eol-last": "off",
+      },
     },
-  }, {
-    "files": "**/.eslintrc.js",
-    "env": {
-      "node": true,
+    {
+      files: "**/.eslintrc.js",
+      env: {
+        node: true,
+      },
+    },
+    {
+      ...removeOverrides(xpcshellTestConfig),
+      files: xpcshellTestPaths.map(path => `${path}**`),
+      rules: {
+        "func-names": "off",
+        "mozilla/import-headjs-globals": "error",
+      },
     },
-  }, {
-    ...removeOverrides(xpcshellTestConfig),
-    "files": xpcshellTestPaths.map(path => `${path}**`),
-    "rules": {
-      "func-names": "off",
-      "mozilla/import-headjs-globals": "error",
+    {
+      // If it is an xpcshell head file, we turn off global unused variable checks, as it
+      // would require searching the other test files to know if they are used or not.
+      // This would be expensive and slow, and it isn't worth it for head files.
+      // We could get developers to declare as exported, but that doesn't seem worth it.
+      files: xpcshellTestPaths.map(path => `${path}head*.js`),
+      rules: {
+        "no-unused-vars": [
+          "error",
+          {
+            args: "none",
+            vars: "local",
+          },
+        ],
+      },
     },
-  }, {
-    // If it is an xpcshell head file, we turn off global unused variable checks, as it
-    // would require searching the other test files to know if they are used or not.
-    // This would be expensive and slow, and it isn't worth it for head files.
-    // We could get developers to declare as exported, but that doesn't seem worth it.
-    "files": xpcshellTestPaths.map(path => `${path}head*.js`),
-    "rules": {
-      "no-unused-vars": ["error", {
-        "args": "none",
-        "vars": "local",
-      }],
+    {
+      ...browserTestConfig,
+      files: browserTestPaths.map(path => `${path}**`),
+      rules: {
+        "func-names": "off",
+        "mozilla/import-headjs-globals": "error",
+      },
     },
-  }, {
-    ...browserTestConfig,
-    "files": browserTestPaths.map(path => `${path}**`),
-  }],
+  ],
 };
new file mode 100644
--- /dev/null
+++ b/.hg-annotate-ignore-revs
@@ -0,0 +1,7 @@
+53a946e223427462aa507710ba2ae238aad9676c - Paul Morris - Bug 1577606 - Reformat calendar code with eslint and Prettier. r=darktrojan
+e5737872508567abf8b0444f43eb4ee4ce211c75 - Paul Morris - Bug 1577835 - Reformat chat/ code with eslint and Prettier. r=mkmelin
+ab9b63f9d2266b4607b926ba227d89ae117bb3f9 - Paul Morris - Bug 1577835 - Reformat common/ and ldap/ code. r=mkmelin
+8d3544b6352837c58cc4984fdd0412800f863e7c - Paul Morris - Bug 1577835 - Reformat editor/ code with eslint and Prettier. r=mkmelin
+883449e17f9dc912d4f5487faac540db61850ca1 - Paul Morris - Bug 1577835 - Reformat mail/ code with eslint and Prettier. r=mkmelin
+5b47088d84e77f42fd810d0c68c9518be20bc6f5 - Paul Morris - Bug 1577835 - Reformat mailnews/ code with eslint and Prettier. r=mkmelin
+8177b85d18db77c4787461cd6db9575ef9935aea - Paul Morris - Bug 1577835 - Reformat the .eslintrc.js files with Prettier. r=mkmelin
--- a/.hgignore
+++ b/.hgignore
@@ -35,8 +35,12 @@ mozilla
 
 # Git repositories
 .git/
 
 # Ignore the files and directory that Eclipse IDE creates
 \.project$
 \.cproject$
 \.settings/
+
+# Ignore the files and directory that JetBrains IDEs create.
+\.idea/
+\.iml$
--- a/.hgtags
+++ b/.hgtags
@@ -73,8 +73,9 @@ e6f416a808ebe94ed625e25410b0f83abe3283d4
 1f00110035a07df9aa9246ab56941c5edb03b93a BETA_BASE_20180625
 88de6bc9d1116a00ffe6907e8f84ee09fdd93ae5 BETA_BASE_20180904
 5a8c03dfb2ac10a53f0c16ff87e39c8787ef0cb4 BETA_BASE_20181022
 0b7555f983a525273e921e3b1553f366f58ddb84 BETA_BASE_20181210
 79eb92913221762b56402ea04150ed32fedbb008 BETA_BASE_20190128
 063e8f6bc499ea617db4c411a4ad054b9849a67c BETA_BASE_20190318
 1fb0d1a549f3dd9562f6404be18ca14573eac527 BETA_BASE_20190520
 de3ab615492a27edd3d14d116785dc79d30877ec BETA_BASE_20190708
+86e0e08f619fc722527b1ec8140ab65dc15671e0 BETA_BASE_20190902
new file mode 100644
--- /dev/null
+++ b/.prettierignore
@@ -0,0 +1,11 @@
+# This list automatically picks up exclusions from .eslintignore
+
+# These files are disabled due to parsing errors when using Prettier.
+# Bug 1560186
+*.html
+*.xhtml
+*.xul
+*.xml
+
+# Ignore SeaMonkey files.
+suite/**
new file mode 100644
--- /dev/null
+++ b/README.md
@@ -0,0 +1,194 @@
+# Thunderbird
+Thunderbird is a powerful and customizable open source email client with lots of users. It is based on the same platform that Firefox uses.
+
+## Getting Started
+This README will try and give you the basics that you need to get started, more comprehensive documentation is available on the [Thunderbird Developer Website](https://developer.thunderbird.net).
+
+### Mozilla Code Base
+Thunderbird is built on the Mozilla platform, the same base that Firefox is built from. As such the two projects share a lot of code and much of the documentation for one will apply, in many ways, to the other.
+
+In order to be able to build Thunderbird - you will need the mozilla-central repository as well as the comm-central repository (where this README lives). Check out our [Getting Started documentation](https://developer.thunderbird.net/the-basics/getting-started) for instructions on how and where to get the source code.
+
+### mozilla-central vs. comm-central
+
+The mozilla-central repostitory contains the Firefox codebase and all of the platform code. The comm-central repository is added as a subdirectory "comm/" under mozilla-central. This contains the code for Thunderbird.
+
+## Building Thunderbird
+
+### Build Prerequisites
+
+This README assumes that you already have the prerequisite software required to build Thunderbird. If you have not already done so, please complete the instructions for your operating system and then continue following this guide:
+
+- [Windows Build Prerequisites](https://developer.thunderbird.net/the-basics/building-thunderbird/windows-build-prerequisites)
+- [Linux Build Prerequisites](https://developer.thunderbird.net/the-basics/building-thunderbird/linux-build-prerequisites)
+- [macOS Build Prerequisites](https://developer.thunderbird.net/the-basics/building-thunderbird/macos-build-prerequisites)
+
+### Build Configuration
+
+To build Thunderbird, you need to create a file named `mozconfig` (can also be `.mozconfig`) to the root directory of the mozilla-central checkout that contains the option `comm/mail` enabled. You can create a file with this line by doing this in the root source directory:
+
+```text
+echo 'ac_add_options --enable-application=comm/mail' > mozconfig
+```
+
+**If you omit this line, the build system will build Firefox instead**. Other build configuration options can be added to this file, although it's **strongly recommended** that you only use options that you fully understand. For example, to create a debug build instead of a release build, that file would also contain the line:
+
+```text
+ac_add_options --enable-debug
+```
+
+_Each of these ac\_add\_options entries needs to be on its own line._
+
+For more on configuration options, see the page [Configuring build options](https://developer.mozilla.org/en/Configuring_Build_Options). Note that if you use an MOZ\_OBJDIR it cannot be a sibling folder to the root source directory. Use an absolute path to be sure!
+
+### Build the Lightning Calendar when building Thunderbird
+
+Add the following line to your `mozconfig` file:
+
+```text
+ac_add_options --enable-calendar
+```
+
+### Building
+
+**Before you start**, make sure that the version you checked out is not busted. For `hg` tip, you should see green Bs on [https://treeherder.mozilla.org/\#/jobs?repo=comm-central](https://treeherder.mozilla.org/#/jobs?repo=comm-central)
+
+To start the build, cd into the root source directory, and run:
+
+```text
+./mach build
+```
+
+mach is our command-line tool to streamline common developer tasks. See the [mach](https://developer.mozilla.org/en-US/docs/Mozilla/Developer_guide/mach) article for more.
+
+Building can take a significant amount of time, depending on your system, OS, and chosen build options. Linux builds on a fast box may take under _15 minutes_, but Windows builds on a slow box may take _several hours_.
+
+### Make Your Build Faster
+
+Follow this guide to rely on `ccache` and other [Tips for making builds faster](../getting-started.md).
+
+## Running Thunderbird
+
+To run your build, you can use:
+
+```text
+./mach run
+```
+
+There are various command line parameters you can add, e.g. to specify a profile, such as: -no-remote -P testing --purgecaches
+
+Various temporary files, libraries, and the Thunderbird executable will be found in your object directory \(under `comm-central/`\), which is prefixed with `obj-`. The exact name depends on your system and OS. For example, a Mac user may get an object directory name of `obj-x86_64-apple-darwin10.7.3/`.
+
+The Thunderbird executable in particular, and its dependencies are located under the `dist/bin` folder under the object directory. To run the executable from your `comm-central` working directory:
+
+* Windows: `obj-.../dist/bin/thunderbird.exe`
+* Linux: `obj-.../dist/bin/thunderbird`
+* macOS: `obj-.../dist/Daily.app/Contents/MacOS/thunderbird`
+
+## Update and Build Again
+
+To pull down the latest changes, in the mozilla directory run the following commands:
+
+```text
+hg pull -u
+cd comm
+hg pull -u
+cd ..
+```
+
+or to do it via one command:
+
+```text
+hg pull -u && cd comm && hg pull -u
+```
+
+The just run the `./mach build` command detailed in the [Building](./#building)instructions above. This will only recompile files that changed, but it may still take a long time.
+
+## Rebuilding
+
+To build after changes you can simply run:
+
+```text
+./mach build
+```
+
+### Rebuilding Specific Parts
+
+If you have made many changes, but only want to rebuild specific parts, you may run the following commands.
+
+#### C or C++ Files:
+
+```text
+./mach build binaries
+```
+
+#### JavaScript or XUL Files \(Windows Only\):
+
+```text
+./mach build path/to/dir
+```
+
+
+Replace `path/to/dir` with the directory with the files changed.
+
+This is the tricky bit since you need to specify the directory that installs the files, which may be a parent directory of the changed file's directory. For example, to just rebuild the Lightning calendar extension:
+
+```text
+./mach build comm/calendar/lightning
+```
+
+
+## Contributing
+
+### Getting Plugged into the Community
+
+We have a complete listing of the ways in which you can get involved with Thunderbird [on our website](https://thunderbird.net/get-involved). Below are some quick references from that page that you can use if you are looking to contribute to Thunderbird core right away.
+
+#### Mailing Lists
+
+If you want to participate in discussions about Thunderbird development, there are two main mailing lists you want to join.
+
+1. [**TB-Planning**](https://wiki.mozilla.org/Thunderbird/tb-planning)**:** This mailing list is higher level topics like: the future of Thunderbird, potential features, and changes that you would like to see happen. It is also used to discuss a variety of broader issues around community and governance of the project.
+2. [**Maildev**](http://lists.thunderbird.net/mailman/listinfo/maildev_lists.thunderbird.net)**:** A moderated mailing list for discussing engineering plans for Thunderbird. It is a place where you can raise questions and ideas for core Thunderbird development.
+
+#### IRC
+
+If you want to ask questions about how to hack on Thunderbird, the IRC channel you want to join is [\#maildev on irc.mozilla.org](irc://irc.mozilla.org/maildev).
+
+### Report a Bug and Request Features
+
+### [Bugzilla](https://bugzilla.mozilla.org/enter_bug.cgi?product=Thunderbird)
+
+Thunderbird uses bugzilla for reporting and tracking bugs as well as enhancement requests. If you want to become a contributor to Thunderbird, you will need an account on Bugzilla.
+
+### Fixing a Bug and Submitting Patches
+
+All the issues, bugs, work in progress patches, or updates related to Thunderbird, are listed on Bugzilla and are properly organized per **Product**, **Component**, and **Status**. For instance you can see how they are listed by looking at [recent bugs for Thunderbird](https://bugzilla.mozilla.org/buglist.cgi?query_format=advanced&product=Thunderbird&bug_status=UNCONFIRMED&bug_severity=blocker&bug_severity=critical&bug_severity=major&bug_severity=normal&bug_severity=minor&bug_severity=trivial&chfieldfrom=-30d&chfield=%5BBug%20creation%5D&list_id=14706087).
+
+#### Create a Bugzilla account
+
+Creating an account is necessary in order to submit patches, leave comments, and interact with any other aspect of Bugzilla. If you're currently using an `IRC` username in the `#maildev` channel, we recommend saving your profile name with the current format `Firstname Lastname (:username)` in order to be easily searchable and allow the Thunderbird team to offer better support.
+
+#### Find a Bug
+
+Use the [Advanced Search](https://bugzilla.mozilla.org/query.cgi?format=advanced) section to find bugs you want to take care of, and be sure that the bug doesn't currently have any user listed as _Assignee_ and the _Status_ is set to `NEW`. You can see a list of "easy" bugs for beginners [via this query](https://bugzilla.mozilla.org/buglist.cgi?bug_status=NEW&classification=Client%20Software&classification=Developer%20Infrastructure&classification=Components&classification=Server%20Software&classification=Other&f1=status_whiteboard&o1=allwordssubstr&product=Calendar&product=Chat%20Core&product=MailNews%20Core&product=Thunderbird&resolution=---&v1=good%20first%20bug&list_id=14884036). However, we assume you came here to fix your "pet hate" bug, so you already likely have a bug to work with.
+
+#### Search for Code References
+
+Making sense of the **Thunderbird** source code, and knowing where to look, will take some time. The code base is pretty big and if you never worked with `XBL` or `Custom Elements` it can be overwhelming at first. We recommend using our code search engine, [Searchfox](https://searchfox.org/comm-central/source/), to inspect the source code and find snippets and references to help you out while investigating a bug.
+
+#### Mercurial Workflow
+
+Mercurial is pretty flexible in terms of allowing you to write your own code and keep it separate from the main code base. You can use Mercurial Bookmarks or Mercurial Queues for managing your work. We have guides created for [bookmarks](https://developer.thunderbird.net/contributing/fixing-a-bug/using-mercurial-bookmarks) and [queues](https://developer.thunderbird.net/contributing/fixing-a-bug/using-mercurial-queues) on our developer website. While some find Mercurial Queues easier to work with, support for them is being deprecated in various Mozilla tools.
+
+Once you finished taking care of your favorite bug and using Mercurial to commit and export your patch, you can upload it to Bugzilla for review.
+
+#### Upload a Patch
+
+Open your patch file in your code editor and be sure it includes all your code changes, and your name and commit message at the top. You can see an example of a patch for this [README here](https://bug1547325.bmoattachments.org/attachment.cgi?id=9093146).
+
+If everything looks good, you can access the selected bug in Bugzilla and click on the **Attach File** link located above the first comment.
+
+#### Ask for a Review
+
+When uploading a patch to Bugzilla, you can request a review from the user who opened the bug or another developer. Simply select the `?` in the dropdown selector in the _review_ option of the **Flags** section. An input field will appear which will allow you to type the name or username of the user you want to review your patch. You can see an example of [a patch on Bugzilla here](https://bugzilla.mozilla.org/show_bug.cgi?id=1547325#c1).
new file mode 100644
--- /dev/null
+++ b/build/moz.configure/gecko_source.configure
@@ -0,0 +1,286 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+#  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/.
+
+# Attempt to ascertain the Gecko source repository information. This is
+# necessary because MOZ_SOURCE_REPOSITORY and MOZ_SOURCE_CHANGESET both refer
+# to the Thunderbird (comm) repository.
+# We need to have accurate source repository information for MPL compliance.
+
+
+def get_fail_msg(source_name, repo_name, rev_name):
+    return """Unable to determine {} source repository.
+Try setting {} and {}
+environment variables or build from a Mercurial checkout.""".format(
+        source_name, repo_name, rev_name)
+
+
+# Wrap check_cmd_output so that it does not fatally end configure on command
+# failure.
+def hg_cmd_output(*args, **kwargs):
+    def hg_error():
+        return None
+    kwargs['onerror'] = hg_error
+
+    return check_cmd_output(*args, **kwargs)
+
+
+@template
+def read_sourcestamp(repository):
+    """
+    Last resort, look for the revision data in the sourcestamp file.
+    This file only exists in release tar files created in CI.
+    repository must be one of "GECKO" or "COMM".
+    """
+    log.info('Determining %s source information from sourcestamp.txt...'
+             % repository)
+
+    line2read = {'COMM': 1,
+                 'GECKO': 2}[repository]
+
+    @depends(comm_paths)
+    @imports(_from='os.path', _import='exists')
+    @imports(_from='os.path', _import='join')
+    @imports(_from='__builtin__', _import='open')
+    @imports(_from='mozbuild.util', _import='system_encoding')
+    def get_sourcestamp(paths):
+        sourcestamp_file = join(paths.moztopsrcdir, 'sourcestamp.txt')
+        if exists(sourcestamp_file):
+            try:
+                lines = open(sourcestamp_file).readlines()
+            except:
+                pass
+
+            if len(lines) != 3:
+                log.warn('sourcestamp.txt is corrupt!')
+                return
+
+            if lines and lines[line2read].startswith('http'):
+                repo_line = lines[line2read].decode(system_encoding)
+                repo_url = repo_line.split('/rev/')
+                return namespace(repo_url=repo_url[0], repo_rev=repo_url[1])
+
+    return get_sourcestamp
+
+
+@template
+def read_gecko_rev_yml():
+    def get_value(x):
+        return x.split()[1]
+
+    @depends(comm_paths)
+    @imports(_from='os.path', _import='exists')
+    @imports(_from='os.path', _import='join')
+    @imports(_from='__builtin__', _import='open')
+    @imports(_from='mozbuild.util', _import='system_encoding')
+    def wrapped(paths):
+        log.info("Determining GECKO source information from .gecko_rev.yml")
+        rev_file = join(paths.commtopsrcdir, '.gecko_rev.yml')
+        if not exists(rev_file): return
+
+        repo = rev = ref = None
+
+        for line in open(rev_file).readlines():
+            if line.startswith('GECKO_HEAD_REPOSITORY:'):
+                repo = get_value(line).decode(system_encoding)
+            elif line.startswith('GECKO_HEAD_REV:'):
+                rev = get_value(line).decode(system_encoding)
+            elif line.startswith('GECKO_HEAD_REF:'):
+                ref = get_value(line).decode(system_encoding)
+            else:
+                pass
+
+        return namespace(repo=repo, rev=rev, ref=ref)
+
+    return wrapped
+
+
+@depends(application)
+@imports(_from='os', _import="environ")
+@imports(_from='mozbuild.util', _import='system_encoding')
+def comm_repo_from_environ(app):
+    """
+    Read the Thunderbird source repository information from the environment.
+
+    Taskcluster builds set MOZ_SOURCE_REPO and MOZ_SOURCE_CHANGESET pointing
+    to the comm-* repository.
+    """
+    log.info("Determining COMM source information from environment...")
+    comm_repo = environ.get('MOZ_SOURCE_REPO', None)
+    comm_rev = environ.get('MOZ_SOURCE_CHANGESET', None)
+
+    if all([comm_repo, comm_rev]):
+        comm_repo = comm_repo.decode(system_encoding)
+        comm_rev = comm_rev.decode(system_encoding)
+
+        log.info("{}/rev/{}".format(comm_repo, comm_rev))
+        return namespace(comm_repo=comm_repo, comm_rev=comm_rev)
+
+
+# Read sourcestamp.txt and return the Thunderbird source URL (with changeset).
+# Silent fail if the file cannot be read.
+comm_sourcestamp = read_sourcestamp('COMM')
+
+
+@depends(comm_repo_from_environ, comm_paths, hg, comm_sourcestamp)
+@imports(_from='os', _import="environ")
+def comm_repo_heuristics(comm_environ, paths, hg, sourcestamp):
+    """
+    Determine the Thunderbird Mercurial repository and revision from Mercurial
+    or sourcestamp.txt when MOZ_SOURCE_REPO and MOZ_SOURCE_CHANGESET are unset
+    (local developer builds).
+
+    In that case, MOZ_SOURCE_REPO and MOZ_SOURCE_CHANGESET are set
+    by build/variables.py, but will refer to the mozilla- repository,
+    which is incorrect for Thunderbird builds.
+
+    There's no set_config call for MOZ_SOURCE_REPO or MOZ_SOURCE_CHANGESET
+    here as that will be done when old-configure runs later. Here we just
+    set the environment variables the same as Taskcluster would.
+    """
+    if not comm_environ:
+        comm_repo = comm_rev = None
+        if hg:
+            log.info(
+                "Determining COMM source information from "
+                "Mercurial...")
+            comm_rev = hg_cmd_output(hg, '-R', paths.commtopsrcdir,
+                                     'parent', '--template={node}')
+            comm_repo = hg_cmd_output(hg, '-R', paths.commtopsrcdir,
+                                      'path', 'default')
+            if comm_repo:
+                comm_repo = comm_repo.strip()
+                if comm_repo.startswith('ssh://'):
+                    comm_repo = 'https://' + comm_repo[6:]
+                comm_repo = comm_repo.rstrip('/')
+        # TODO: git-cinnabar support?
+
+        if not comm_repo or not comm_rev:
+            try:
+                comm_repo, comm_rev = sourcestamp.repo_url, sourcestamp.repo_rev
+            except:
+                pass
+
+        # If values are found, set MOZ_SOURCE_REPO and MOZ_SOURCE_CHANGESET
+        if comm_repo and comm_rev:
+            environ['MOZ_SOURCE_REPO'] = comm_repo
+            environ['MOZ_SOURCE_CHANGESET'] = comm_rev
+
+        if comm_repo and comm_rev:
+            return namespace(comm_repo=comm_repo, comm_rev=comm_rev)
+
+
+@depends(comm_repo_from_environ, comm_repo_heuristics, 'MOZ_AUTOMATION')
+def comm_source_repo(from_environ, from_config, automation):
+    rv = None
+    if from_environ:
+        rv = from_environ
+    elif from_config:
+        rv = from_config
+    elif automation:
+        die(get_fail_msg("COMM", "MOZ_SOURCE_REPO", "MOZ_SOURCE_CHANGESET"))
+    else:
+        log.info(
+            get_fail_msg("COMM", "MOZ_SOURCE_REPO", "MOZ_SOURCE_CHANGESET"))
+        rv = namespace(comm_repo="unknown", comm_rev="unknown")
+
+    log.info('COMM_SOURCE_REPOSITORY: {}'.format(rv.comm_repo))
+    log.info('COMM_SOURCE_CHANGESET: {}'.format(rv.comm_rev))
+    return rv
+
+
+@depends(application)
+@imports(_from='os', _import="environ")
+@imports(_from='mozbuild.util', _import='system_encoding')
+def gecko_repo_from_environ(app):
+    """
+    Same as above, but this time checking for the mozilla- repository.
+    """
+    log.info("Determining GECKO source information from environment...")
+    gecko_repo = environ.get('GECKO_HEAD_REPOSITORY', None)
+    gecko_rev = environ.get('GECKO_HEAD_REV', None)
+    if all([gecko_repo, gecko_rev]):
+        gecko_repo = gecko_repo.decode(system_encoding)
+        gecko_rev = gecko_rev.decode(system_encoding)
+
+        log.info("{}/rev/{}".format(gecko_repo, gecko_rev))
+        return namespace(gecko_repo=gecko_repo, gecko_rev=gecko_rev)
+
+
+# Read sourcestamp.txt, this time returning the mozilla- data
+gecko_sourcestamp = read_sourcestamp('GECKO')
+# Look in comm/.gecko_rev.yml fpr repository information
+gecko_yml = read_gecko_rev_yml()
+
+
+@depends(gecko_repo_from_environ, comm_paths, hg, gecko_sourcestamp, gecko_yml)
+@imports(_from='os.path', _import='join')
+@imports(_from='os.path', _import='exists')
+def gecko_repo_heuristics(gecko_environ, paths, hg, sourcestamp, gecko_yml):
+    """
+    Look for the source repository and changeset for the mozilla- repository
+    when the Taskcluster environment variables are not set, checking
+    .gecko_rev.yml before falling back to Mercurial and sourcestamp.txt.
+    """
+    if not gecko_environ:
+        gecko_repo = gecko_rev = gecko_ref = None
+
+        try:
+            gecko_repo = gecko_yml.repo
+            gecko_rev = gecko_yml.rev
+            gecko_ref = gecko_yml.ref
+        except:
+            pass
+
+        if gecko_repo:
+            if not gecko_rev and gecko_ref:
+                # gecko_repo is known, but we have a branch ref like
+                # "default" when a revision hash is needed. Try to query
+                # Mercurial first.
+                if hg:
+                    log.info(
+                        "Determining GECKO source information from "
+                        "Mercurial...")
+                    gecko_rev = hg_cmd_output(hg, '-R', paths.moztopsrcdir,
+                                              'parent', '--template={node}')
+                # TODO: git-cinnabar support?
+
+        if not gecko_repo or not gecko_rev:
+            # See if we have a sourcestamo file. Last ditch effort!
+            try:
+                gecko_repo, gecko_rev = sourcestamp.repo_url, \
+                                        sourcestamp.repo_rev
+            except:
+                pass
+
+        # Check one last time to see if both gecko_repo and gecko_rev
+        # are set
+        if gecko_repo and gecko_rev:
+            return namespace(gecko_repo=gecko_repo, gecko_rev=gecko_rev)
+
+
+@depends(gecko_repo_from_environ, gecko_repo_heuristics, 'MOZ_AUTOMATION')
+def gecko_source_repo(from_environ, from_heuristics, automation):
+    rv = None
+    if from_environ:
+        rv = from_environ
+    elif from_heuristics:
+        rv = from_heuristics
+    elif automation:
+        die(get_fail_msg("GECKO", "GECKO_HEAD_REPOSITORY", "GECKO_HEAD_REV"))
+    else:
+        log.info(
+            get_fail_msg("GECKO", "GECKO_HEAD_REPOSITORY", "GECKO_HEAD_REV"))
+        rv = namespace(gecko_repo="unknown", gecko_rev="unknown")
+
+    log.info('GECKO_SOURCE_REPOSITORY: {}'.format(rv.gecko_repo))
+    log.info('GECKO_SOURCE_CHANGESET: {}'.format(rv.gecko_rev))
+    return rv
+
+
+set_config('MOZ_COMM_SOURCE_REPO', comm_source_repo.comm_repo)
+set_config('MOZ_COMM_SOURCE_CHANGESET', comm_source_repo.comm_rev)
+set_config('MOZ_GECKO_SOURCE_REPO', gecko_source_repo.gecko_repo)
+set_config('MOZ_GECKO_SOURCE_CHANGESET', gecko_source_repo.gecko_rev)
--- a/build/mozconfig.sccache
+++ b/build/mozconfig.sccache
@@ -29,19 +29,19 @@ if test -n "$bucket"; then
     *Windows)
         platform=win
 	;;
     *)
         mk_add_options "export AWS_IAM_CREDENTIALS_URL=http://taskcluster/auth/v1/aws/s3/read-write/${bucket}/?format=iam-role-compat"
 	;;
     esac
 
-    export CCACHE="$topsrcdir/sccache/sccache${suffix}"
+    export CCACHE="$MOZ_FETCHES_DIR/sccache/sccache${suffix}"
     export SCCACHE_VERBOSE_STATS=1
-    mk_add_options "MOZBUILD_MANAGE_SCCACHE_DAEMON=${topsrcdir}/sccache/sccache"
+    mk_add_options "MOZBUILD_MANAGE_SCCACHE_DAEMON=$MOZ_FETCHES_DIR/sccache/sccache"
     mk_add_options "UPLOAD_EXTRA_FILES+=sccache.log.gz"
 
     case "$platform" in
     win)
         # sccache supports a special flag to create depfiles.
         #TODO: bug 1318370 - move this all into toolchain.configure
         export _DEPEND_CFLAGS='-deps$(MDDEPDIR)/$(@F).pp'
         # Windows builds have a default wrapper that needs to be overridden
new file mode 100644
--- /dev/null
+++ b/build/source_repos.py
@@ -0,0 +1,88 @@
+#  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/.
+
+from __future__ import print_function, unicode_literals
+
+import sys
+import os
+
+import buildconfig
+
+sourcestamp_tmpl = """{buildid}
+{comm_repo}/rev/{comm_rev}
+{gecko_repo}/rev/{gecko_rev}
+"""
+
+
+def gen_platformini(output, platform_ini):
+    gecko_repo = buildconfig.substs.get('MOZ_GECKO_SOURCE_REPO', '')
+    gecko_rev = buildconfig.substs.get('MOZ_GECKO_SOURCE_CHANGESET', '')
+
+    with open(platform_ini, 'r') as fp:
+        data = fp.readlines()
+
+    for i in range(len(data)):
+        if data[i].startswith('SourceRepository='):
+            data[i] = 'SourceRepository=%s\n' % gecko_repo
+        elif data[i].startswith('SourceStamp='):
+            data[i] = 'SourceStamp=%s\n' % gecko_rev
+
+    with open(platform_ini, 'w') as fp:
+        fp.writelines(data)
+
+    output.write('platform.ini updated.\n')
+
+
+def gen_sourcestamp(output):
+    data = dict(buildid=os.environ.get('MOZ_BUILD_DATE', 'unknown'),
+        gecko_repo=buildconfig.substs.get('MOZ_GECKO_SOURCE_REPO', None),
+        gecko_rev=buildconfig.substs.get('MOZ_GECKO_SOURCE_CHANGESET', None),
+        comm_repo=buildconfig.substs.get('MOZ_COMM_SOURCE_REPO', None),
+        comm_rev=buildconfig.substs.get('MOZ_COMM_SOURCE_CHANGESET', None))
+
+    output.write(sourcestamp_tmpl.format(**data))
+
+
+def source_repo_header(output):
+    """
+    Appends the Gecko source repository information to source-repo.h
+    This information should be set in buildconfig.substs by moz.configure
+    """
+    gecko_repo = buildconfig.substs.get('MOZ_GECKO_SOURCE_REPO', None)
+    gecko_rev = buildconfig.substs.get('MOZ_GECKO_SOURCE_CHANGESET', None)
+    comm_repo = buildconfig.substs.get('MOZ_COMM_SOURCE_REPO', None)
+    comm_rev = buildconfig.substs.get('MOZ_COMM_SOURCE_CHANGESET', None)
+
+    if None in [gecko_repo, gecko_rev, comm_repo, comm_rev]:
+        Exception("Source information not found in buildconfig."
+                  "Try setting GECKO_HEAD_REPOSITORY and GECKO_HEAD_REV"
+                  "as well as MOZ_SOURCE_REPO and MOZ_SOURCE_CHANGESET"
+                  "environment variables and running mach configure again.")
+
+    output.write('#define MOZ_GECKO_SOURCE_STAMP {}\n'.format(gecko_rev))
+    output.write('#define MOZ_COMM_SOURCE_STAMP {}\n'.format(comm_rev))
+    output.write('#define MOZ_SOURCE_STAMP {}\n'.format(comm_rev))
+
+    if buildconfig.substs.get('MOZ_INCLUDE_SOURCE_INFO'):
+        gecko_source_url = '%s/rev/%s' % (gecko_repo, gecko_rev)
+        comm_source_url = '%s/rev/%s' % (comm_repo, comm_rev)
+        output.write('#define MOZ_GECKO_SOURCE_REPO {}\n'.format(gecko_repo))
+        output.write('#define MOZ_GECKO_SOURCE_URL {}\n'.format(gecko_source_url))
+        output.write('#define MOZ_COMM_SOURCE_REPO {}\n'.format(comm_repo))
+        output.write('#define MOZ_COMM_SOURCE_URL {}\n'.format(comm_source_url))
+        output.write('#define MOZ_SOURCE_REPO {}\n'.format(comm_repo))
+        output.write('#define MOZ_SOURCE_URL {}\n'.format(comm_source_url))
+
+
+def main(args):
+    if args:
+        func = globals().get(args[0])
+        if func:
+            return func(sys.stdout, *args[1:])
+
+    return 1
+
+
+if __name__ == '__main__':
+    sys.exit(main(sys.argv[1:]))
--- a/calendar/.eslintrc.js
+++ b/calendar/.eslintrc.js
@@ -1,511 +1,525 @@
 "use strict";
 
 module.exports = {
-    "extends": [
-        "../../toolkit/.eslintrc.js"
-    ],
-    "rules": {
-        // Enforce one true brace style (opening brace on the same line)
-        // Allow single line (for now) because of the vast number of changes needed
-        "brace-style": [2, "1tbs", { allowSingleLine: true }],
+  extends: ["../../toolkit/.eslintrc.js"],
+  rules: {
+    // Enforce newline at the end of file, with no multiple empty lines.
+    "eol-last": 2,
 
-        // Enforce newline at the end of file, with no multiple empty lines.
-        "eol-last": 2,
+    // Disallow using variables outside the blocks they are defined
+    "block-scoped-var": 2,
 
-        // Disallow using variables outside the blocks they are defined
-        "block-scoped-var": 2,
+    // Allow trailing commas for easy list extension.  Having them does not
+    // impair readability, but also not required either.
+    "comma-dangle": 0,
+
+    // Enforce spacing before and after comma
+    "comma-spacing": [2, { before: false, after: true }],
 
-        // Allow trailing commas for easy list extension.  Having them does not
-        // impair readability, but also not required either.
-        "comma-dangle": 0,
+    // Enforce one true comma style.
+    "comma-style": [2, "last"],
 
-        // Enforce spacing before and after comma
-        "comma-spacing": [2, { before: false, after: true }],
+    // We should get better at complexity, but at the moment it is what it is
+    complexity: [2, 90],
 
-        // Enforce one true comma style.
-        "comma-style": [2, "last"],
+    // Enforce curly brace conventions for all control statements.
+    curly: 2,
 
-        // We should get better at complexity, but at the moment it is what it is
-        "complexity": [2, 90],
+    // Require space before/after arrow function's arrow
+    "arrow-spacing": [2, { before: true, after: true }],
 
-        // Enforce curly brace conventions for all control statements.
-        "curly": 2,
+    // Enforces spacing between keys and values in object literal properties.
+    "key-spacing": [2, { beforeColon: false, afterColon: true, mode: "minimum" }],
 
-        // Enforce the spacing around the * in generator functions.
-        "generator-star-spacing": [2, "after"],
-
-        // Require space before/after arrow function's arrow
-        "arrow-spacing": [2, { before: true, after: true }],
+    // Disallow the omission of parentheses when invoking a constructor with no
+    // arguments.
+    "new-parens": 2,
 
-        // Enforces spacing between keys and values in object literal properties.
-        "key-spacing": [2, { beforeColon: false, afterColon: true, mode: "minimum" }],
+    // Disallow use of the Array constructor.
+    "no-array-constructor": 2,
 
-        // Disallow the omission of parentheses when invoking a constructor with no
-        // arguments.
-        "new-parens": 2,
+    // disallow use of the Object constructor
+    "no-new-object": 2,
 
-        // Disallow use of the Array constructor.
-        "no-array-constructor": 2,
+    // Disallow Primitive Wrapper Instances
+    "no-new-wrappers": 2,
 
-        // disallow use of the Object constructor
-        "no-new-object": 2,
+    // Disallow the catch clause parameter name being the same as a variable in
+    // the outer scope, to avoid confusion.
+    "no-catch-shadow": 2,
 
-        // Disallow Primitive Wrapper Instances
-        "no-new-wrappers": 2,
+    // Disallow assignment in conditional expressions.
+    "no-cond-assign": 2,
 
-        // Disallow the catch clause parameter name being the same as a variable in
-        // the outer scope, to avoid confusion.
-        "no-catch-shadow": 2,
+    // Disallow use of debugger.
+    "no-debugger": 2,
+
+    // Disallow deletion of variables (deleting properties is fine).
+    "no-delete-var": 2,
 
-        // Disallow assignment in conditional expressions.
-        "no-cond-assign": 2,
+    // Disallow duplicate arguments in functions.
+    "no-dupe-args": 2,
 
-        // Disallow use of debugger.
-        "no-debugger": 2,
+    // Disallow duplicate keys when creating object literals.
+    "no-dupe-keys": 2,
 
-        // Disallow deletion of variables (deleting properties is fine).
-        "no-delete-var": 2,
+    // Disallow a duplicate case label.
+    "no-duplicate-case": 2,
 
-        // Disallow duplicate arguments in functions.
-        "no-dupe-args": 2,
+    // Disallow the use of empty character classes in regular expressions.
+    "no-empty-character-class": 2,
 
-        // Disallow duplicate keys when creating object literals.
-        "no-dupe-keys": 2,
+    // Disallow assigning to the exception in a catch block.
+    "no-ex-assign": 2,
 
-        // Disallow a duplicate case label.
-        "no-duplicate-case": 2,
+    // Disallow adding to native types
+    "no-extend-native": 2,
 
-        // Disallow the use of empty character classes in regular expressions.
-        "no-empty-character-class": 2,
+    // Disallow double-negation boolean casts in a boolean context.
+    "no-extra-boolean-cast": 2,
 
-        // Disallow assigning to the exception in a catch block.
-        "no-ex-assign": 2,
+    // Disallow unnecessary semicolons.
+    "no-extra-semi": 2,
 
-        // Disallow adding to native types
-        "no-extend-native": 2,
+    // Disallow mixed spaces and tabs for indentation.
+    "no-mixed-spaces-and-tabs": 2,
+
+    // Disallow reassignments of native objects.
+    "no-native-reassign": 2,
 
-        // Disallow double-negation boolean casts in a boolean context.
-        "no-extra-boolean-cast": 2,
+    // Disallow nested ternary expressions, they make the code hard to read.
+    "no-nested-ternary": 2,
 
-        // Disallow unnecessary semicolons.
-        "no-extra-semi": 2,
+    // Disallow use of octal literals.
+    "no-octal": 2,
 
-        // Disallow mixed spaces and tabs for indentation.
-        "no-mixed-spaces-and-tabs": 2,
+    // Disallow comparisons where both sides are exactly the same.
+    "no-self-compare": 2,
 
-        // Disallow reassignments of native objects.
-        "no-native-reassign": 2,
+    // Disallow sparse arrays, eg. let arr = [,,2].
+    // Array destructuring is fine though:
+    // for (let [, breakpointPromise] of aPromises)
+    "no-sparse-arrays": 2,
 
-        // Disallow nested ternary expressions, they make the code hard to read.
-        "no-nested-ternary": 2,
+    // Disallow trailing whitespace at the end of lines.
+    "no-trailing-spaces": 2,
 
-        // Disallow use of octal literals.
-        "no-octal": 2,
+    // Disallow use of the with statement.
+    "no-with": 2,
 
-        // Disallow comparisons where both sides are exactly the same.
-        "no-self-compare": 2,
+    // Disallow comparisons with the value NaN.
+    "use-isnan": 2,
+
+    // Ensure that the results of typeof are compared against a valid string.
+    "valid-typeof": 2,
 
-        // Disallow sparse arrays, eg. let arr = [,,2].
-        // Array destructuring is fine though:
-        // for (let [, breakpointPromise] of aPromises)
-        "no-sparse-arrays": 2,
+    // disallow the use of object properties of the global object (Math and
+    // JSON) as functions
+    "no-obj-calls": 2,
 
-        // Disallow trailing whitespace at the end of lines.
-        "no-trailing-spaces": 2,
+    // disallow use of octal escape sequences in string literals, such as
+    // var foo = "Copyright \251";
+    "no-octal-escape": 2,
 
-        // Disallow use of the with statement.
-        "no-with": 2,
-
-        // Disallow comparisons with the value NaN.
-        "use-isnan": 2,
+    // disallow use of void operator
+    "no-void": 2,
 
-        // Ensure that the results of typeof are compared against a valid string.
-        "valid-typeof": 2,
+    // Disallow Yoda conditions (where literal value comes first).
+    yoda: 2,
 
-        // disallow the use of object properties of the global object (Math and
-        // JSON) as functions
-        "no-obj-calls": 2,
+    // Require a space immediately following the // in a line comment.
+    "spaced-comment": [2, "always"],
 
-        // disallow use of octal escape sequences in string literals, such as
-        // var foo = "Copyright \251";
-        "no-octal-escape": 2,
+    // Require use of the second argument for parseInt().
+    radix: 2,
 
-        // disallow use of void operator
-        "no-void": 2,
+    // Require spaces before/after unary operators (words on by default,
+    // nonwords off by default).
+    "space-unary-ops": [2, { words: true, nonwords: false }],
 
-        // Disallow Yoda conditions (where literal value comes first).
-        "yoda": 2,
+    // Enforce spacing after semicolons.
+    "semi-spacing": [2, { before: false, after: true }],
 
-        // Require a space immediately following the // in a line comment.
-        "spaced-comment": [2, "always"],
+    // Disallow the use of Boolean literals in conditional expressions.
+    "no-unneeded-ternary": 2,
 
-        // Require use of the second argument for parseInt().
-        "radix": 2,
+    // Disallow use of multiple spaces (sometimes used to align const values,
+    // array or object items, etc.). It's hard to maintain and doesn't add that
+    // much benefit.
+    "no-multi-spaces": [2, { ignoreEOLComments: true }],
 
-        // Require spaces before/after unary operators (words on by default,
-        // nonwords off by default).
-        "space-unary-ops": [2, { words: true, nonwords: false }],
+    // Require spaces around operators, except for a|0.
+    // Disabled for now given eslint doesn't support default args yet
+    // "space-infix-ops": [2, { "int32Hint": true }],
+    "space-infix-ops": 0,
 
-        // Enforce spacing after semicolons.
-        "semi-spacing": [2, { before: false, after: true }],
+    // Require a space around all keywords.
+    "keyword-spacing": 2,
 
-        // Disallow the use of Boolean literals in conditional expressions.
-        "no-unneeded-ternary": 2,
+    // Disallow space between function identifier and application.
+    "no-spaced-func": 2,
+
+    // Disallow shadowing of names such as arguments.
+    "no-shadow-restricted-names": 2,
 
-        // Disallow use of multiple spaces (sometimes used to align const values,
-        // array or object items, etc.). It's hard to maintain and doesn't add that
-        // much benefit.
-        "no-multi-spaces": [2, { ignoreEOLComments: true }],
+    // Disallow use of comma operator.
+    "no-sequences": 2,
+
+    // Disallow use of assignment in return statement. It is preferable for a
+    // single line of code to have only one easily predictable effect.
+    "no-return-assign": 2,
 
-        // Require spaces around operators, except for a|0.
-        // Disabled for now given eslint doesn't support default args yet
-        // "space-infix-ops": [2, { "int32Hint": true }],
-        "space-infix-ops": 0,
+    // Require return statements to either always or never specify values
+    "consistent-return": 2,
 
-        // Require a space around all keywords.
-        "keyword-spacing": 2,
+    // Disallow padding within blocks.
+    "padded-blocks": [2, "never"],
 
-        // Disallow space between function identifier and application.
-        "no-spaced-func": 2,
+    // Disallow spaces inside parentheses.
+    "space-in-parens": [2, "never"],
 
-        // Disallow shadowing of names such as arguments.
-        "no-shadow-restricted-names": 2,
+    // Require space after keyword for anonymous functions, but disallow space
+    // after name of named functions.
+    "space-before-function-paren": [2, { anonymous: "never", named: "never" }],
 
-        // Disallow use of comma operator.
-        "no-sequences": 2,
+    // Disallow unreachable statements after a return, throw, continue, or break
+    // statement.
+    "no-unreachable": 2,
 
-        // Disallow use of assignment in return statement. It is preferable for a
-        // single line of code to have only one easily predictable effect.
-        "no-return-assign": 2,
+    // Always require use of semicolons wherever they are valid.
+    semi: [2, "always"],
 
-        // Require return statements to either always or never specify values
-        "consistent-return": 2,
-
-        // Disallow padding within blocks.
-        "padded-blocks": [2, "never"],
-
-        // Disallow spaces inside parentheses.
-        "space-in-parens": [2, "never"],
+    // Disallow empty statements. This will report an error for:
+    // try { something(); } catch (e) {}
+    // but will not report it for:
+    // try { something(); } catch (e) { /* Silencing the error because ...*/ }
+    // which is a valid use case.
+    "no-empty": 2,
 
-        // Require space after keyword for anonymous functions, but disallow space
-        // after name of named functions.
-        "space-before-function-paren": [2, { anonymous: "never", named: "never" }],
+    // Disallow declaring the same variable more than once (we use let anyway).
+    "no-redeclare": 2,
 
-        // Disallow unreachable statements after a return, throw, continue, or break
-        // statement.
-        "no-unreachable": 2,
+    // Warn about declaration of variables already declared in the outer scope.
+    // This isn't an error because it sometimes is useful to use the same name
+    // in a small helper function rather than having to come up with another
+    // random name.  Still, making this a warning can help people avoid being
+    // confused.
+    "no-shadow": 2,
 
-        // Always require use of semicolons wherever they are valid.
-        "semi": [2, "always"],
+    // We use var-only-at-top-level instead of no-var as we allow top level
+    // vars.
+    "no-var": 0,
+    "mozilla/var-only-at-top-level": 1,
 
-        // Disallow empty statements. This will report an error for:
-        // try { something(); } catch (e) {}
-        // but will not report it for:
-        // try { something(); } catch (e) { /* Silencing the error because ...*/ }
-        // which is a valid use case.
-        "no-empty": 2,
+    // Disallow global and local variables that aren't used, but allow unused function arguments.
+    "no-unused-vars": [2, { vars: "all", args: "none", varsIgnorePattern: "EXPORTED_SYMBOLS" }],
 
-        // Disallow declaring the same variable more than once (we use let anyway).
-        "no-redeclare": 2,
+    "mozilla/mark-test-function-used": 1,
+
+    // Require padding inside curly braces
+    "object-curly-spacing": [2, "always"],
 
-        // Warn about declaration of variables already declared in the outer scope.
-        // This isn't an error because it sometimes is useful to use the same name
-        // in a small helper function rather than having to come up with another
-        // random name.  Still, making this a warning can help people avoid being
-        // confused.
-        "no-shadow": 2,
+    // Disallow spaces inside of brackets
+    "array-bracket-spacing": [2, "never"],
 
-        // We use var-only-at-top-level instead of no-var as we allow top level
-        // vars.
-        "no-var": 0,
-        "mozilla/var-only-at-top-level": 1,
+    // Disallow control characters in regular expressions
+    "no-control-regex": 2,
+
+    // Disallow invalid regular expression strings in RegExp constructors
+    "no-invalid-regexp": 2,
 
-        // Disallow global and local variables that aren't used, but allow unused function arguments.
-        "no-unused-vars": [2, { vars: "all", args: "none", varsIgnorePattern: "EXPORTED_SYMBOLS" }],
+    // Disallow multiple spaces in regular expression literals
+    "no-regex-spaces": 2,
 
-        "mozilla/mark-test-function-used": 1,
+    // Disallow irregular whitespace
+    "no-irregular-whitespace": 2,
 
-        // Require padding inside curly braces
-        "object-curly-spacing": [2, "always"],
+    // Disallow negating the left operand in `in` expressions
+    "no-negated-in-lhs": 2,
 
-        // Disallow spaces inside of brackets
-        "array-bracket-spacing": [2, "never"],
+    // Allow constant expressions in conditions
+    // With 2.11.0 we can enable this with checkLoops: false
+    "no-constant-condition": [2, { checkLoops: false }],
 
-        // Disallow control characters in regular expressions
-        "no-control-regex": 2,
+    // Disallow Regexs That Look Like Division
+    "no-div-regex": 2,
 
-        // Disallow invalid regular expression strings in RegExp constructors
-        "no-invalid-regexp": 2,
+    // Disallow Iterator (using __iterator__)
+    "no-iterator": 2,
 
-        // Disallow multiple spaces in regular expression literals
-        "no-regex-spaces": 2,
+    // Enforce consistent linebreak style
+    "linebreak-style": [2, "unix"],
 
-        // Disallow irregular whitespace
-        "no-irregular-whitespace": 2,
+    // Enforces return statements in callbacks of array's methods
+    "array-callback-return": 2,
 
-        // Disallow negating the left operand in `in` expressions
-        "no-negated-in-lhs": 2,
+    // Verify super() calls in constructors
+    "constructor-super": 2,
 
-        // Allow constant expressions in conditions
-        // With 2.11.0 we can enable this with checkLoops: false
-        "no-constant-condition": [2, { checkLoops: false }],
+    // Disallow modifying variables of class declarations
+    "no-class-assign": 2,
 
-        // Disallow Regexs That Look Like Division
-        "no-div-regex": 2,
+    // Disallow modifying variables that are declared using const
+    "no-const-assign": 2,
 
-        // Disallow Iterator (using __iterator__)
-        "no-iterator": 2,
+    // Disallow duplicate name in class members
+    "no-dupe-class-members": 2,
 
-        // Enforce consistent linebreak style
-        "linebreak-style": [2, "unix"],
+    // Disallow use of this/super before calling super() in constructors
+    "no-this-before-super": 2,
 
-        // Enforces return statements in callbacks of array's methods
-        "array-callback-return": 2,
+    // Disallow duplicate imports
+    "no-duplicate-imports": 2,
 
-        // Verify super() calls in constructors
-        "constructor-super": 2,
+    // Disallow empty destructuring patterns
+    "no-empty-pattern": 2,
 
-        // Disallow modifying variables of class declarations
-        "no-class-assign": 2,
+    // Disallow Labeled Statements
+    "no-labels": 2,
 
-        // Disallow modifying variables that are declared using const
-        "no-const-assign": 2,
+    // Disallow Multiline Strings
+    "no-multi-str": 2,
 
-        // Disallow duplicate name in class members
-        "no-dupe-class-members": 2,
+    // Disallow Symbol Constructor
+    "no-new-symbol": 2,
 
-        // Disallow use of this/super before calling super() in constructors
-        "no-this-before-super": 2,
+    // Disallow Initializing to undefined
+    "no-undef-init": 2,
 
-        // Disallow duplicate imports
-        "no-duplicate-imports": 2,
+    // Disallow control flow statements in finally blocks
+    "no-unsafe-finally": 2,
 
-        // Disallow empty destructuring patterns
-        "no-empty-pattern": 2,
+    // Disallow Unused Labels
+    "no-unused-labels": 2,
 
-        // Disallow Labeled Statements
-        "no-labels": 2,
+    // Disallow unnecessary computed property keys on objects
+    "no-useless-computed-key": 2,
 
-        // Disallow Multiline Strings
-        "no-multi-str": 2,
+    // Disallow unnecessary constructor
+    "no-useless-constructor": 2,
 
-        // Disallow Symbol Constructor
-        "no-new-symbol": 2,
+    // Disallow renaming import, export, and destructured assignments to the
+    // same name
+    "no-useless-rename": 2,
 
-        // Disallow Initializing to undefined
-        "no-undef-init": 2,
+    // Enforce spacing between rest and spread operators and their expressions
+    "rest-spread-spacing": [2, "never"],
 
-        // Disallow control flow statements in finally blocks
-        "no-unsafe-finally": 2,
+    // Disallow usage of spacing in template string expressions
+    "template-curly-spacing": [2, "never"],
 
-        // Disallow Unused Labels
-        "no-unused-labels": 2,
+    // Disallow the Unicode Byte Order Mark
+    "unicode-bom": [2, "never"],
 
-        // Disallow unnecessary computed property keys on objects
-        "no-useless-computed-key": 2,
+    // Enforce spacing around the * in yield* expressions
+    "yield-star-spacing": [2, "after"],
+
+    // Disallow Implied eval
+    "no-implied-eval": 2,
 
-        // Disallow unnecessary constructor
-        "no-useless-constructor": 2,
+    // Disallow unnecessary function binding
+    "no-extra-bind": 2,
 
-        // Disallow renaming import, export, and destructured assignments to the
-        // same name
-        "no-useless-rename": 2,
+    // Disallow new For Side Effects
+    "no-new": 2,
 
-        // Enforce spacing between rest and spread operators and their expressions
-        "rest-spread-spacing": [2, "never"],
+    // Disallow Self Assignment
+    "no-self-assign": 2,
 
-        // Disallow usage of spacing in template string expressions
-        "template-curly-spacing": [2, "never"],
+    // Disallow confusing multiline expressions
+    "no-unexpected-multiline": 2,
 
-        // Disallow the Unicode Byte Order Mark
-        "unicode-bom": [2, "never"],
+    // Require IIFEs to be Wrapped
+    "wrap-iife": [2, "inside"],
 
-        // Enforce spacing around the * in yield* expressions
-        "yield-star-spacing": [2, "after"],
+    // Disallow Unused Expressions
+    "no-unused-expressions": 2,
 
-        // Disallow Implied eval
-        "no-implied-eval": 2,
+    // Disallow function or var declarations in nested blocks
+    "no-inner-declarations": 2,
 
-        // Disallow unnecessary function binding
-        "no-extra-bind": 2,
+    // Enforce newline before and after dot
+    "dot-location": [2, "property"],
 
-        // Disallow new For Side Effects
-        "no-new": 2,
+    // Disallow Use of caller/callee
+    "no-caller": 2,
 
-        // Disallow Self Assignment
-        "no-self-assign": 2,
+    // Disallow Case Statement Fallthrough
+    "no-fallthrough": 2,
 
-        // Disallow confusing multiline expressions
-        "no-unexpected-multiline": 2,
+    // Disallow Floating Decimals
+    "no-floating-decimal": 2,
 
-        // Require IIFEs to be Wrapped
-        "wrap-iife": [2, "inside"],
+    // Require Space Before Blocks
+    "space-before-blocks": 2,
 
-        // Disallow Unused Expressions
-        "no-unused-expressions": 2,
+    // Operators always before the line break
+    "operator-linebreak": [2, "after", { overrides: { ":": "before", "?": "ignore" } }],
 
-        // Disallow function or var declarations in nested blocks
-        "no-inner-declarations": 2,
+    // Restricts the use of parentheses to only where they are necessary
+    // Disabled for now since this also removes parens around assignments, e.g. let foo = bar == baz
+    // "no-extra-parens": [2, "all", { "conditionalAssign": false, "returnAssign": false, "nestedBinaryExpressions": false }],
 
-        // Enforce newline before and after dot
-        "dot-location": [2, "property"],
+    // Double quotes should be used.
+    quotes: [2, "double", { avoidEscape: true }],
 
-        // Disallow Use of caller/callee
-        "no-caller": 2,
+    // Disallow if as the only statement in an else block.
+    "no-lonely-if": 2,
 
-        // Disallow Case Statement Fallthrough
-        "no-fallthrough": 2,
+    // Not more than two empty lines with in the file, and no extra lines at
+    // beginning or end of file.
+    "no-multiple-empty-lines": [2, { max: 2, maxEOF: 0, maxBOF: 0 }],
 
-        // Disallow Floating Decimals
-        "no-floating-decimal": 2,
+    // Make sure all setters have a corresponding getter
+    "accessor-pairs": 2,
 
-        // Require Space Before Blocks
-        "space-before-blocks": 2,
+    // Enforce spaces inside of single line blocks
+    "block-spacing": [2, "always"],
 
-        // Operators always before the line break
-        "operator-linebreak": [2, "after", { overrides: { ":": "before", "?": "ignore" } }],
+    // Disallow spaces inside of computed properties
+    "computed-property-spacing": [2, "never"],
 
-        // Restricts the use of parentheses to only where they are necessary
-        // Disabled for now since this also removes parens around assignments, e.g. let foo = bar == baz
-        // "no-extra-parens": [2, "all", { "conditionalAssign": false, "returnAssign": false, "nestedBinaryExpressions": false }],
+    // Require consistent this (using |self|)
+    "consistent-this": [2, "self"],
 
-        // Double quotes should be used.
-        "quotes": [2, "double", { avoidEscape: true }],
+    // Disallow unnecessary .call() and .apply()
+    "no-useless-call": 2,
 
-        // Disallow if as the only statement in an else block.
-        "no-lonely-if": 2,
+    // Require dot notation when accessing properties
+    "dot-notation": 2,
 
-        // Not more than two empty lines with in the file, and no extra lines at
-        // beginning or end of file.
-        "no-multiple-empty-lines": [2, { max: 2, maxEOF: 0, maxBOF: 0 }],
+    // Enforce placing object properties on separate lines
+    "object-property-newline": [2, { allowMultiplePropertiesPerLine: true }],
 
-        // Make sure all setters have a corresponding getter
-        "accessor-pairs": 2,
-
-        // Enforce spaces inside of single line blocks
-        "block-spacing": [2, "always"],
+    // Do Not Require Object Literal Shorthand Syntax
+    // (Override the parent eslintrc setting for this.)
+    "object-shorthand": "off",
 
-        // Disallow spaces inside of computed properties
-        "computed-property-spacing": [2, "never"],
+    // Disallow whitespace before properties
+    "no-whitespace-before-property": 2,
 
-        // Require consistent this (using |self|)
-        "consistent-this": [2, "self"],
-
-        // Disallow unnecessary .call() and .apply()
-        "no-useless-call": 2,
+    // Disallow unnecessary escape usage
+    "no-useless-escape": 2,
 
-        // Require dot notation when accessing properties
-        "dot-notation": 2,
-
-        // Disallow named function expressions
-        "func-names": [2, "never"],
-
-        // Enforce placing object properties on separate lines
-        "object-property-newline": [2, { allowMultiplePropertiesPerLine: true }],
-
-        // Enforce consistent line breaks inside braces
-        "object-curly-newline": [2, { multiline: true }],
-
-        // Do Not Require Object Literal Shorthand Syntax
-        // (Override the parent eslintrc setting for this.)
-        "object-shorthand": "off",
+    // Disallow mixes of different operators, but allow simple math operations.
+    "no-mixed-operators": [
+      2,
+      {
+        groups: [
+          /* ["+", "-", "*", "/", "%", "**"], */
+          ["&", "|", "^", "~", "<<", ">>", ">>>"],
+          ["==", "!=", "===", "!==", ">", ">=", "<", "<="],
+          ["&&", "||"],
+          ["in", "instanceof"],
+        ],
+      },
+    ],
 
-        // Disallow whitespace before properties
-        "no-whitespace-before-property": 2,
+    // Disallow unnecessary concatenation of strings
+    "no-useless-concat": 2,
+
+    // Disallow unmodified conditions of loops
+    "no-unmodified-loop-condition": 2,
 
-        // Disallow unnecessary escape usage
-        "no-useless-escape": 2,
+    // Suggest using arrow functions as callbacks
+    "prefer-arrow-callback": [2, { allowNamedFunctions: true }],
+
+    // Suggest using the spread operator instead of .apply()
+    "prefer-spread": 2,
 
-        // Disallow mixes of different operators, but allow simple math operations.
-        "no-mixed-operators": [2, {
-            groups: [
-                /* ["+", "-", "*", "/", "%", "**"], */
-                ["&", "|", "^", "~", "<<", ">>", ">>>"],
-                ["==", "!=", "===", "!==", ">", ">=", "<", "<="],
-                ["&&", "||"],
-                ["in", "instanceof"]
-            ]
-        }],
+    // Disallow negated conditions
+    "no-negated-condition": 2,
+
+    // Enforce a maximum number of statements allowed per line
+    "max-statements-per-line": [2, { max: 2 }],
 
-        // Disallow unnecessary concatenation of strings
-        "no-useless-concat": 2,
-
-        // Disallow unmodified conditions of loops
-        "no-unmodified-loop-condition": 2,
+    // Disallow arrow functions where they could be confused with comparisons
+    "no-confusing-arrow": 2,
 
-        // Suggest using arrow functions as callbacks
-        "prefer-arrow-callback": [2, { allowNamedFunctions: true }],
-
-        // Suggest using the spread operator instead of .apply()
-        "prefer-spread": 2,
-
-        // Quoting style for property names
-        "quote-props": [2, "consistent-as-needed", { keywords: true }],
+    // Disallow Unnecessary Nested Blocks
+    "no-lone-blocks": 2,
 
-        // Disallow negated conditions
-        "no-negated-condition": 2,
-
-        // Enforce a maximum number of statements allowed per line
-        "max-statements-per-line": [2, { max: 2 }],
-
-        // Disallow arrow functions where they could be confused with comparisons
-        "no-confusing-arrow": 2,
-
-        // Disallow Unnecessary Nested Blocks
-        "no-lone-blocks": 2,
-
-        // Enforce minimum identifier length
-        "id-length": [2, {
-            min: 3,
-            exceptions: [
-                /* sorting */ "a", "b",
-                /* exceptions */ "e", "ex",
-                /* loop indices */ "i", "j", "k", "n",
-                /* coordinates */ "x", "y",
-                /* regexes */ "re",
-                /* known words */ "rc", "rv", "id", "OS", "os", "db", "is",
-                /* mail/calendar words */ "to", "cc",
-                /* Components */ "Ci", "Cc", "Cu", "Cr",
-            ]
-        }],
-
-        // Disallow lexical declarations in case/default clauses
-        "no-case-declarations": 2,
-
-        // Enforce consistent indentation (4-space)
-        "indent-legacy": [2, 4, { SwitchCase: 1, }],
+    // Enforce minimum identifier length
+    "id-length": [
+      2,
+      {
+        min: 3,
+        exceptions: [
+          /* sorting */
+          "a",
+          "b",
+          /* exceptions */
+          "e",
+          "ex",
+          /* loop indices */
+          "i",
+          "j",
+          "k",
+          "n",
+          /* coordinates */
+          "x",
+          "y",
+          /* regexes */
+          "re",
+          /* known words */
+          "rc",
+          "rv",
+          "id",
+          "OS",
+          "os",
+          "db",
+          "is",
+          /* mail/calendar words */
+          "to",
+          "cc",
+          /* Components */
+          "Ci",
+          "Cc",
+          "Cu",
+          "Cr",
+        ],
+      },
+    ],
 
-        // The following rules will not be enabled currently, but are kept here for
-        // easier updates in the future.
-        "no-else-return": 0,
-    },
-    "overrides": [{
-        files: [
-            "base/modules/utils/calAuthUtils.jsm",
-            "base/modules/utils/calEmailUtils.jsm",
-            "base/modules/utils/calIteratorUtils.jsm",
-            "base/modules/utils/calItipUtils.jsm",
-            "base/modules/utils/calL10NUtils.jsm",
-            "base/modules/utils/calProviderUtils.jsm",
-            "base/modules/utils/calUnifinderUtils.jsm",
-        ],
-        rules: {
-            "require-jsdoc": [2, { require: { ClassDeclaration: true } }],
+    // Disallow lexical declarations in case/default clauses
+    "no-case-declarations": 2,
+
+    // The following rules will not be enabled currently, but are kept here for
+    // easier updates in the future.
+    "no-else-return": 0,
+  },
+  overrides: [
+    {
+      files: [
+        "base/modules/utils/calAuthUtils.jsm",
+        "base/modules/utils/calEmailUtils.jsm",
+        "base/modules/utils/calIteratorUtils.jsm",
+        "base/modules/utils/calItipUtils.jsm",
+        "base/modules/utils/calL10NUtils.jsm",
+        "base/modules/utils/calProviderUtils.jsm",
+        "base/modules/utils/calUnifinderUtils.jsm",
+      ],
+      rules: {
+        "require-jsdoc": [2, { require: { ClassDeclaration: true } }],
 
-            "valid-jsdoc": [2, {
-                prefer: { returns: "return" },
-                preferType: {
-                    "boolean": "Boolean",
-                    "string": "String",
-                    "number": "Number",
-                    "object": "Object",
-                    "function": "Function",
-                    "map": "Map",
-                    "set": "Set",
-                    "date": "Date",
-                },
-                requireReturn: false
-            }],
-        }
-    }]
+        "valid-jsdoc": [
+          2,
+          {
+            prefer: { returns: "return" },
+            preferType: {
+              boolean: "Boolean",
+              string: "String",
+              number: "Number",
+              object: "Object",
+              function: "Function",
+              map: "Map",
+              set: "Set",
+              date: "Date",
+            },
+            requireReturn: false,
+          },
+        ],
+      },
+    },
+  ],
 };
new file mode 100644
--- /dev/null
+++ b/calendar/.prettierrc
@@ -0,0 +1,5 @@
+{
+  "printWidth": 100,
+  "tabWidth": 2,
+  "trailingComma": "es5"
+}
--- a/calendar/base/backend/calBackendLoader.js
+++ b/calendar/base/backend/calBackendLoader.js
@@ -1,76 +1,79 @@
 /* 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/. */
 
 var { XPCOMUtils } = ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
 var { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
 
 function calBackendLoader() {
-    this.wrappedJSObject = this;
-    try {
-        this.loadBackend();
-    } catch (e) {
-        dump(`### Error loading backend:${e.filename || e.fileName}:${e.lineNumber}: ${e}\n`);
-    }
+  this.wrappedJSObject = this;
+  try {
+    this.loadBackend();
+  } catch (e) {
+    dump(`### Error loading backend:${e.filename || e.fileName}:${e.lineNumber}: ${e}\n`);
+  }
 }
 
 calBackendLoader.prototype = {
-    classID: Components.ID("{0314c271-7168-40fa-802e-83c8c46a557e}"),
-    QueryInterface: ChromeUtils.generateQI([Ci.nsIObserver]),
+  classID: Components.ID("{0314c271-7168-40fa-802e-83c8c46a557e}"),
+  QueryInterface: ChromeUtils.generateQI([Ci.nsIObserver]),
 
-    loaded: false,
+  loaded: false,
+
+  observe: function() {
+    // Nothing to do here, just need the entry so this is instantiated
+  },
 
-    observe: function() {
-        // Nothing to do here, just need the entry so this is instantiated
-    },
+  loadBackend: function() {
+    if (this.loaded) {
+      return;
+    }
 
-    loadBackend: function() {
-        if (this.loaded) {
-            return;
-        }
+    if (Services.prefs.getBoolPref("calendar.icaljs", false)) {
+      let contracts = {
+        "@mozilla.org/calendar/datetime;1": "{36783242-ec94-4d8a-9248-d2679edd55b9}",
+        "@mozilla.org/calendar/ics-service;1": "{c61cb903-4408-41b3-bc22-da0b27efdfe1}",
+        "@mozilla.org/calendar/period;1": "{394a281f-7299-45f7-8b1f-cce21258972f}",
+        "@mozilla.org/calendar/recurrence-rule;1": "{df19281a-5389-4146-b941-798cb93a7f0d}",
+        "@mozilla.org/calendar/duration;1": "{7436f480-c6fc-4085-9655-330b1ee22288}",
+      };
 
-        if (Services.prefs.getBoolPref("calendar.icaljs", false)) {
-            let contracts = {
-                "@mozilla.org/calendar/datetime;1": "{36783242-ec94-4d8a-9248-d2679edd55b9}",
-                "@mozilla.org/calendar/ics-service;1": "{c61cb903-4408-41b3-bc22-da0b27efdfe1}",
-                "@mozilla.org/calendar/period;1": "{394a281f-7299-45f7-8b1f-cce21258972f}",
-                "@mozilla.org/calendar/recurrence-rule;1": "{df19281a-5389-4146-b941-798cb93a7f0d}",
-                "@mozilla.org/calendar/duration;1": "{7436f480-c6fc-4085-9655-330b1ee22288}",
-            };
-
-            // Load ical.js backend
-            let scope = {};
-            Services.scriptloader.loadSubScript("resource://calendar/components/calICALJSComponents.js", scope);
+      // Load ical.js backend
+      let scope = {};
+      Services.scriptloader.loadSubScript(
+        "resource://calendar/components/calICALJSComponents.js",
+        scope
+      );
 
-            // Register the icaljs components. We used to unregisterFactory, but this caused all
-            // sorts of problems. Just registering over it seems to work quite fine.
-            let registrar = Components.manager.QueryInterface(Ci.nsIComponentRegistrar);
-            for (let [contractID, classID] of Object.entries(contracts)) {
-                let newClassID = Components.ID(classID);
-                let newFactory = lazyFactoryFor(scope, newClassID);
-                registrar.registerFactory(newClassID, "", contractID, newFactory);
-            }
+      // Register the icaljs components. We used to unregisterFactory, but this caused all
+      // sorts of problems. Just registering over it seems to work quite fine.
+      let registrar = Components.manager.QueryInterface(Ci.nsIComponentRegistrar);
+      for (let [contractID, classID] of Object.entries(contracts)) {
+        let newClassID = Components.ID(classID);
+        let newFactory = lazyFactoryFor(scope, newClassID);
+        registrar.registerFactory(newClassID, "", contractID, newFactory);
+      }
 
-            dump("[calBackendLoader] Using Lightning's icaljs backend\n");
-        } else {
-            dump("[calBackendLoader] Using Thunderbird's builtin libical backend\n");
-        }
+      dump("[calBackendLoader] Using Lightning's icaljs backend\n");
+    } else {
+      dump("[calBackendLoader] Using Thunderbird's builtin libical backend\n");
+    }
 
-        this.loaded = true;
-    }
+    this.loaded = true;
+  },
 };
 
 function lazyFactoryFor(backendScope, classID) {
-    return {
-        createInstance: function(aOuter, aIID) {
-            let realFactory = backendScope.NSGetFactory(classID);
-            return realFactory.createInstance(aOuter, aIID);
-        },
-        lockFactory: function(lock) {
-            let realFactory = backendScope.NSGetFactory(classID);
-            return realFactory.lockFactory(lock);
-        }
-    };
+  return {
+    createInstance: function(aOuter, aIID) {
+      let realFactory = backendScope.NSGetFactory(classID);
+      return realFactory.createInstance(aOuter, aIID);
+    },
+    lockFactory: function(lock) {
+      let realFactory = backendScope.NSGetFactory(classID);
+      return realFactory.lockFactory(lock);
+    },
+  };
 }
 
 this.NSGetFactory = XPCOMUtils.generateNSGetFactory([calBackendLoader]);
--- a/calendar/base/backend/icaljs/calDateTime.js
+++ b/calendar/base/backend/icaljs/calDateTime.js
@@ -4,125 +4,192 @@
 
 /* import-globals-from calICALJSComponents.js */
 
 var { ICAL, unwrap, unwrapSetter } = ChromeUtils.import("resource://calendar/modules/ical.js");
 
 var UNIX_TIME_TO_PRTIME = 1000000;
 
 function calDateTime(innerObject) {
-    this.wrappedJSObject = this;
-    this.innerObject = innerObject || ICAL.Time.epochTime.clone();
+  this.wrappedJSObject = this;
+  this.innerObject = innerObject || ICAL.Time.epochTime.clone();
 }
 
 calDateTime.prototype = {
-    QueryInterface: ChromeUtils.generateQI([Ci.calIDateTime]),
-    classID: Components.ID("{36783242-ec94-4d8a-9248-d2679edd55b9}"),
+  QueryInterface: ChromeUtils.generateQI([Ci.calIDateTime]),
+  classID: Components.ID("{36783242-ec94-4d8a-9248-d2679edd55b9}"),
 
-    isMutable: true,
-    makeImmutable: function() { this.isMutable = false; },
-    clone: function() { return new calDateTime(this.innerObject.clone()); },
+  isMutable: true,
+  makeImmutable: function() {
+    this.isMutable = false;
+  },
+  clone: function() {
+    return new calDateTime(this.innerObject.clone());
+  },
 
-    isValid: true,
-    innerObject: null,
+  isValid: true,
+  innerObject: null,
+
+  get nativeTime() {
+    return this.innerObject.toUnixTime() * UNIX_TIME_TO_PRTIME;
+  },
+  set nativeTime(val) {
+    this.innerObject.fromUnixTime(val / UNIX_TIME_TO_PRTIME);
+  },
 
-    get nativeTime() { return this.innerObject.toUnixTime() * UNIX_TIME_TO_PRTIME; },
-    set nativeTime(val) { this.innerObject.fromUnixTime(val / UNIX_TIME_TO_PRTIME); },
-
-    get year() { return this.innerObject.year; },
-    set year(val) { this.innerObject.year = val; },
+  get year() {
+    return this.innerObject.year;
+  },
+  set year(val) {
+    this.innerObject.year = val;
+  },
 
-    get month() { return this.innerObject.month - 1; },
-    set month(val) { this.innerObject.month = val + 1; },
+  get month() {
+    return this.innerObject.month - 1;
+  },
+  set month(val) {
+    this.innerObject.month = val + 1;
+  },
 
-    get day() { return this.innerObject.day; },
-    set day(val) { this.innerObject.day = val; },
-
-    get hour() { return this.innerObject.hour; },
-    set hour(val) { this.innerObject.hour = val; },
+  get day() {
+    return this.innerObject.day;
+  },
+  set day(val) {
+    this.innerObject.day = val;
+  },
 
-    get minute() { return this.innerObject.minute; },
-    set minute(val) { this.innerObject.minute = val; },
-
-    get second() { return this.innerObject.second; },
-    set second(val) { this.innerObject.second = val; },
+  get hour() {
+    return this.innerObject.hour;
+  },
+  set hour(val) {
+    this.innerObject.hour = val;
+  },
 
-    get timezone() { return new calICALJSTimezone(this.innerObject.zone); },
-    set timezone(rawval) {
-        unwrapSetter(ICAL.Timezone, rawval, function(val) {
-            this.innerObject.zone = val;
-            return val;
-        }, this);
-    },
+  get minute() {
+    return this.innerObject.minute;
+  },
+  set minute(val) {
+    this.innerObject.minute = val;
+  },
+
+  get second() {
+    return this.innerObject.second;
+  },
+  set second(val) {
+    this.innerObject.second = val;
+  },
 
-    resetTo: function(year, month, day, hour, minute, second, timezone) {
-        this.innerObject.fromData({
-            year: year,
-            month: month + 1,
-            day: day,
-            hour: hour,
-            minute: minute,
-            second: second,
-        });
-        this.timezone = timezone;
-    },
+  get timezone() {
+    return new calICALJSTimezone(this.innerObject.zone);
+  },
+  set timezone(rawval) {
+    unwrapSetter(
+      ICAL.Timezone,
+      rawval,
+      function(val) {
+        this.innerObject.zone = val;
+        return val;
+      },
+      this
+    );
+  },
 
-    reset: function() { this.innerObject.reset(); },
+  resetTo: function(year, month, day, hour, minute, second, timezone) {
+    this.innerObject.fromData({
+      year: year,
+      month: month + 1,
+      day: day,
+      hour: hour,
+      minute: minute,
+      second: second,
+    });
+    this.timezone = timezone;
+  },
 
-    get timezoneOffset() { return this.innerObject.utcOffset(); },
-    get isDate() { return this.innerObject.isDate; },
-    set isDate(val) { this.innerObject.isDate = val; },
+  reset: function() {
+    this.innerObject.reset();
+  },
 
-    get weekday() { return this.innerObject.dayOfWeek() - 1; },
-    get yearday() { return this.innerObject.dayOfYear(); },
-
-    toString: function() { return this.innerObject.toString(); },
+  get timezoneOffset() {
+    return this.innerObject.utcOffset();
+  },
+  get isDate() {
+    return this.innerObject.isDate;
+  },
+  set isDate(val) {
+    this.innerObject.isDate = val;
+  },
 
-    getInTimezone: unwrap(ICAL.Timezone, function(val) {
-        return new calDateTime(this.innerObject.convertToZone(val));
-    }),
+  get weekday() {
+    return this.innerObject.dayOfWeek() - 1;
+  },
+  get yearday() {
+    return this.innerObject.dayOfYear();
+  },
 
-    addDuration: unwrap(ICAL.Duration, function(val) {
-        this.innerObject.addDuration(val);
-    }),
+  toString: function() {
+    return this.innerObject.toString();
+  },
 
-    subtractDate: unwrap(ICAL.Time, function(val) {
-        return new calDuration(this.innerObject.subtractDateTz(val));
-    }),
+  getInTimezone: unwrap(ICAL.Timezone, function(val) {
+    return new calDateTime(this.innerObject.convertToZone(val));
+  }),
+
+  addDuration: unwrap(ICAL.Duration, function(val) {
+    this.innerObject.addDuration(val);
+  }),
 
-    compare: unwrap(ICAL.Time, function(val) {
-        let a = this.innerObject;
-        let b = val;
+  subtractDate: unwrap(ICAL.Time, function(val) {
+    return new calDuration(this.innerObject.subtractDateTz(val));
+  }),
+
+  compare: unwrap(ICAL.Time, function(val) {
+    let a = this.innerObject;
+    let b = val;
 
-        // If either this or aOther is floating, both objects are treated
-        // as floating for the comparison.
-        if (a.zone == ICAL.Timezone.localTimezone || b.zone == ICAL.Timezone.localTimezone) {
-            a = a.convertToZone(ICAL.Timezone.localTimezone);
-            b = b.convertToZone(ICAL.Timezone.localTimezone);
-        }
+    // If either this or aOther is floating, both objects are treated
+    // as floating for the comparison.
+    if (a.zone == ICAL.Timezone.localTimezone || b.zone == ICAL.Timezone.localTimezone) {
+      a = a.convertToZone(ICAL.Timezone.localTimezone);
+      b = b.convertToZone(ICAL.Timezone.localTimezone);
+    }
 
-        if (a.isDate || b.isDate) {
-            // Lightning expects 20120101 and 20120101T010101 to be equal
-            return a.compareDateOnlyTz(b, a.zone);
-        } else {
-            // If both are dates or date-times, then just do the normal compare
-            return a.compare(b);
-        }
-    }),
+    if (a.isDate || b.isDate) {
+      // Lightning expects 20120101 and 20120101T010101 to be equal
+      return a.compareDateOnlyTz(b, a.zone);
+    } else {
+      // If both are dates or date-times, then just do the normal compare
+      return a.compare(b);
+    }
+  }),
 
-    get startOfWeek() { return new calDateTime(this.innerObject.startOfWeek()); },
-    get endOfWeek() { return new calDateTime(this.innerObject.endOfWeek()); },
-    get startOfMonth() { return new calDateTime(this.innerObject.startOfMonth()); },
-    get endOfMonth() { return new calDateTime(this.innerObject.endOfMonth()); },
-    get startOfYear() { return new calDateTime(this.innerObject.startOfYear()); },
-    get endOfYear() { return new calDateTime(this.innerObject.endOfYear()); },
+  get startOfWeek() {
+    return new calDateTime(this.innerObject.startOfWeek());
+  },
+  get endOfWeek() {
+    return new calDateTime(this.innerObject.endOfWeek());
+  },
+  get startOfMonth() {
+    return new calDateTime(this.innerObject.startOfMonth());
+  },
+  get endOfMonth() {
+    return new calDateTime(this.innerObject.endOfMonth());
+  },
+  get startOfYear() {
+    return new calDateTime(this.innerObject.startOfYear());
+  },
+  get endOfYear() {
+    return new calDateTime(this.innerObject.endOfYear());
+  },
 
-    get icalString() { return this.innerObject.toICALString(); },
-    set icalString(val) {
-        let jcalString;
-        if (val.length > 10) {
-            jcalString = ICAL.design.icalendar.value["date-time"].fromICAL(val);
-        } else {
-            jcalString = ICAL.design.icalendar.value.date.fromICAL(val);
-        }
-        this.innerObject = ICAL.Time.fromString(jcalString);
+  get icalString() {
+    return this.innerObject.toICALString();
+  },
+  set icalString(val) {
+    let jcalString;
+    if (val.length > 10) {
+      jcalString = ICAL.design.icalendar.value["date-time"].fromICAL(val);
+    } else {
+      jcalString = ICAL.design.icalendar.value.date.fromICAL(val);
     }
+    this.innerObject = ICAL.Time.fromString(jcalString);
+  },
 };
--- a/calendar/base/backend/icaljs/calDuration.js
+++ b/calendar/base/backend/icaljs/calDuration.js
@@ -1,58 +1,104 @@
 /* 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/. */
 
 var { ICAL, unwrap } = ChromeUtils.import("resource://calendar/modules/ical.js");
 
 function calDuration(innerObject) {
-    this.innerObject = innerObject || new ICAL.Duration();
-    this.wrappedJSObject = this;
+  this.innerObject = innerObject || new ICAL.Duration();
+  this.wrappedJSObject = this;
 }
 
 calDuration.prototype = {
-    QueryInterface: ChromeUtils.generateQI([Ci.calIDuration]),
-    classID: Components.ID("{7436f480-c6fc-4085-9655-330b1ee22288}"),
+  QueryInterface: ChromeUtils.generateQI([Ci.calIDuration]),
+  classID: Components.ID("{7436f480-c6fc-4085-9655-330b1ee22288}"),
 
-    get icalDuration() { return this.innerObject; },
-    set icalDuration(val) { this.innerObject = val; },
+  get icalDuration() {
+    return this.innerObject;
+  },
+  set icalDuration(val) {
+    this.innerObject = val;
+  },
 
-    isMutable: true,
-    makeImmutable: function() { this.isMutable = false; },
-    clone: function() { return new calDuration(this.innerObject.clone()); },
+  isMutable: true,
+  makeImmutable: function() {
+    this.isMutable = false;
+  },
+  clone: function() {
+    return new calDuration(this.innerObject.clone());
+  },
 
-    get isNegative() { return this.innerObject.isNegative; },
-    set isNegative(val) { this.innerObject.isNegative = val; },
+  get isNegative() {
+    return this.innerObject.isNegative;
+  },
+  set isNegative(val) {
+    this.innerObject.isNegative = val;
+  },
 
-    get weeks() { return this.innerObject.weeks; },
-    set weeks(val) { this.innerObject.weeks = val; },
+  get weeks() {
+    return this.innerObject.weeks;
+  },
+  set weeks(val) {
+    this.innerObject.weeks = val;
+  },
 
-    get days() { return this.innerObject.days; },
-    set days(val) { this.innerObject.days = val; },
+  get days() {
+    return this.innerObject.days;
+  },
+  set days(val) {
+    this.innerObject.days = val;
+  },
 
-    get hours() { return this.innerObject.hours; },
-    set hours(val) { this.innerObject.hours = val; },
+  get hours() {
+    return this.innerObject.hours;
+  },
+  set hours(val) {
+    this.innerObject.hours = val;
+  },
 
-    get minutes() { return this.innerObject.minutes; },
-    set minutes(val) { this.innerObject.minutes = val; },
+  get minutes() {
+    return this.innerObject.minutes;
+  },
+  set minutes(val) {
+    this.innerObject.minutes = val;
+  },
 
-    get seconds() { return this.innerObject.seconds; },
-    set seconds(val) { this.innerObject.seconds = val; },
+  get seconds() {
+    return this.innerObject.seconds;
+  },
+  set seconds(val) {
+    this.innerObject.seconds = val;
+  },
 
-    get inSeconds() { return this.innerObject.toSeconds(); },
-    set inSeconds(val) { this.innerObject.fromSeconds(val); },
+  get inSeconds() {
+    return this.innerObject.toSeconds();
+  },
+  set inSeconds(val) {
+    this.innerObject.fromSeconds(val);
+  },
 
-    addDuration: unwrap(ICAL.Duration, function(val) {
-        this.innerObject.fromSeconds(this.innerObject.toSeconds() + val.toSeconds());
-    }),
+  addDuration: unwrap(ICAL.Duration, function(val) {
+    this.innerObject.fromSeconds(this.innerObject.toSeconds() + val.toSeconds());
+  }),
 
-    compare: unwrap(ICAL.Duration, function(val) {
-        return this.innerObject.compare(val);
-    }),
+  compare: unwrap(ICAL.Duration, function(val) {
+    return this.innerObject.compare(val);
+  }),
 
-    reset: function() { this.innerObject.reset(); },
-    normalize: function() { this.innerObject.normalize(); },
-    toString: function() { return this.innerObject.toString(); },
+  reset: function() {
+    this.innerObject.reset();
+  },
+  normalize: function() {
+    this.innerObject.normalize();
+  },
+  toString: function() {
+    return this.innerObject.toString();
+  },
 
-    get icalString() { return this.innerObject.toString(); },
-    set icalString(val) { this.innerObject = ICAL.Duration.fromString(val); }
+  get icalString() {
+    return this.innerObject.toString();
+  },
+  set icalString(val) {
+    this.innerObject = ICAL.Duration.fromString(val);
+  },
 };
--- a/calendar/base/backend/icaljs/calICALJSComponents.js
+++ b/calendar/base/backend/icaljs/calICALJSComponents.js
@@ -7,30 +7,35 @@
 /* import-globals-from calDuration.js */
 /* import-globals-from calICSService.js */
 /* import-globals-from calPeriod.js */
 /* import-globals-from calRecurrenceRule.js */
 
 var { XPCOMUtils } = ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
 var { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
 
-this.NSGetFactory = (cid) => {
-    let scriptLoadOrder = [
-        "resource://calendar/calendar-js/calTimezone.js",
-        "resource://calendar/calendar-js/calDateTime.js",
-        "resource://calendar/calendar-js/calDuration.js",
-        "resource://calendar/calendar-js/calICSService.js",
-        "resource://calendar/calendar-js/calPeriod.js",
-        "resource://calendar/calendar-js/calRecurrenceRule.js",
-    ];
+this.NSGetFactory = cid => {
+  let scriptLoadOrder = [
+    "resource://calendar/calendar-js/calTimezone.js",
+    "resource://calendar/calendar-js/calDateTime.js",
+    "resource://calendar/calendar-js/calDuration.js",
+    "resource://calendar/calendar-js/calICSService.js",
+    "resource://calendar/calendar-js/calPeriod.js",
+    "resource://calendar/calendar-js/calRecurrenceRule.js",
+  ];
+
+  for (let script of scriptLoadOrder) {
+    Services.scriptloader.loadSubScript(script, this);
+  }
 
-    for (let script of scriptLoadOrder) {
-        Services.scriptloader.loadSubScript(script, this);
-    }
+  let components = [
+    calDateTime,
+    calDuration,
+    calIcalComponent,
+    calIcalProperty,
+    calICSService,
+    calPeriod,
+    calRecurrenceRule,
+  ];
 
-    let components = [
-        calDateTime, calDuration, calIcalComponent, calIcalProperty, calICSService, calPeriod,
-        calRecurrenceRule
-    ];
-
-    this.NSGetFactory = XPCOMUtils.generateNSGetFactory(components);
-    return this.NSGetFactory(cid);
+  this.NSGetFactory = XPCOMUtils.generateNSGetFactory(components);
+  return this.NSGetFactory(cid);
 };
--- a/calendar/base/backend/icaljs/calICSService-worker.js
+++ b/calendar/base/backend/icaljs/calICSService-worker.js
@@ -11,16 +11,16 @@
 
 var NS_OK = 0;
 var NS_ERROR_FAILURE = 2147500037;
 
 // eslint-disable-next-line no-unused-vars
 importScripts("resource://calendar/modules/ical.js");
 
 onmessage = function(event) {
-    try {
-        let comp = ICAL.parse(event.data);
-        postMessage({ rc: NS_OK, data: comp });
-    } catch (e) {
-        postMessage({ rc: NS_ERROR_FAILURE, data: "Exception occurred: " + e });
-    }
-    close();
+  try {
+    let comp = ICAL.parse(event.data);
+    postMessage({ rc: NS_OK, data: comp });
+  } catch (e) {
+    postMessage({ rc: NS_ERROR_FAILURE, data: "Exception occurred: " + e });
+  }
+  close();
 };
--- a/calendar/base/backend/icaljs/calICSService.js
+++ b/calendar/base/backend/icaljs/calICSService.js
@@ -1,497 +1,617 @@
 /* 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/. */
 
 /* import-globals-from calICALJSComponents.js */
 
-var { ICAL, unwrapSetter, unwrapSingle, wrapGetter } = ChromeUtils.import("resource://calendar/modules/ical.js");
+var { ICAL, unwrapSetter, unwrapSingle, wrapGetter } = ChromeUtils.import(
+  "resource://calendar/modules/ical.js"
+);
 var { cal } = ChromeUtils.import("resource://calendar/modules/calUtils.jsm");
 
 function calIcalProperty(innerObject) {
-    this.innerObject = innerObject || new ICAL.Property();
-    this.wrappedJSObject = this;
+  this.innerObject = innerObject || new ICAL.Property();
+  this.wrappedJSObject = this;
 }
 
 calIcalProperty.prototype = {
-    QueryInterface: ChromeUtils.generateQI([Ci.calIIcalProperty]),
-    classID: Components.ID("{423ac3f0-f612-48b3-953f-47f7f8fd705b}"),
+  QueryInterface: ChromeUtils.generateQI([Ci.calIIcalProperty]),
+  classID: Components.ID("{423ac3f0-f612-48b3-953f-47f7f8fd705b}"),
 
-    get icalString() { return this.innerObject.toICALString() + ICAL.newLineChar; },
-    get icalProperty() { return this.innerObject; },
-    set icalProperty(val) { this.innerObject = val; },
-
-    get parent() { return this.innerObject.parent; },
-    toString: function() { return this.innerObject.toICAL(); },
+  get icalString() {
+    return this.innerObject.toICALString() + ICAL.newLineChar;
+  },
+  get icalProperty() {
+    return this.innerObject;
+  },
+  set icalProperty(val) {
+    this.innerObject = val;
+  },
 
-    get value() {
-        // Unescaped value for properties of TEXT, escaped otherwise.
-        if (this.innerObject.type == "text") {
-            return this.innerObject.getValues().join(",");
-        }
-        return this.valueAsIcalString;
-    },
-    set value(val) {
-        // Unescaped value for properties of TEXT, escaped otherwise.
-        if (this.innerObject.type == "text") {
-            this.innerObject.setValue(val);
-            return val;
-        }
-        this.valueAsIcalString = val;
-        return val;
-    },
+  get parent() {
+    return this.innerObject.parent;
+  },
+  toString: function() {
+    return this.innerObject.toICAL();
+  },
 
-    get valueAsIcalString() {
-        let type = this.innerObject.type;
-        return this.innerObject.getValues().map(val => {
-            if (type == "text") {
-                return ICAL.stringify.value(val, type, ICAL.design.icalendar);
-            } else if (typeof val == "number" || typeof val == "string") {
-                return val;
-            } else if ("toICALString" in val) {
-                return val.toICALString();
-            } else {
-                return val.toString();
-            }
-        }).join(",");
-    },
-    set valueAsIcalString(val) {
-        let mockLine = this.propertyName + ":" + val;
-        let prop = ICAL.Property.fromString(mockLine, ICAL.design.icalendar);
+  get value() {
+    // Unescaped value for properties of TEXT, escaped otherwise.
+    if (this.innerObject.type == "text") {
+      return this.innerObject.getValues().join(",");
+    }
+    return this.valueAsIcalString;
+  },
+  set value(val) {
+    // Unescaped value for properties of TEXT, escaped otherwise.
+    if (this.innerObject.type == "text") {
+      this.innerObject.setValue(val);
+      return val;
+    }
+    this.valueAsIcalString = val;
+    return val;
+  },
 
-        if (this.innerObject.isMultiValue) {
-            this.innerObject.setValues(prop.getValues());
+  get valueAsIcalString() {
+    let type = this.innerObject.type;
+    return this.innerObject
+      .getValues()
+      .map(val => {
+        if (type == "text") {
+          return ICAL.stringify.value(val, type, ICAL.design.icalendar);
+        } else if (typeof val == "number" || typeof val == "string") {
+          return val;
+        } else if ("toICALString" in val) {
+          return val.toICALString();
         } else {
-            this.innerObject.setValue(prop.getFirstValue());
+          return val.toString();
         }
-        return val;
-    },
+      })
+      .join(",");
+  },
+  set valueAsIcalString(val) {
+    let mockLine = this.propertyName + ":" + val;
+    let prop = ICAL.Property.fromString(mockLine, ICAL.design.icalendar);
+
+    if (this.innerObject.isMultiValue) {
+      this.innerObject.setValues(prop.getValues());
+    } else {
+      this.innerObject.setValue(prop.getFirstValue());
+    }
+    return val;
+  },
 
-    get valueAsDatetime() {
-        let val = this.innerObject.getFirstValue();
-        let isIcalTime = val && (typeof val == "object") &&
-                         ("icalclass" in val) && val.icalclass == "icaltime";
-        return (isIcalTime ? new calDateTime(val) : null);
-    },
-    set valueAsDatetime(rawval) {
-        unwrapSetter(ICAL.Time, rawval, function(val) {
-            if (val && val.zone &&
-                val.zone != ICAL.Timezone.utcTimezone &&
-                val.zone != ICAL.Timezone.localTimezone) {
-                this.innerObject.setParameter("TZID", val.zone.tzid);
-                if (this.parent) {
-                    let tzref = wrapGetter(calICALJSTimezone, val.zone);
-                    this.parent.addTimezoneReference(tzref);
-                }
-            } else {
-                this.innerObject.removeParameter("TZID");
-            }
-            this.innerObject.setValue(val);
-        }, this);
-    },
+  get valueAsDatetime() {
+    let val = this.innerObject.getFirstValue();
+    let isIcalTime =
+      val && typeof val == "object" && "icalclass" in val && val.icalclass == "icaltime";
+    return isIcalTime ? new calDateTime(val) : null;
+  },
+  set valueAsDatetime(rawval) {
+    unwrapSetter(
+      ICAL.Time,
+      rawval,
+      function(val) {
+        if (
+          val &&
+          val.zone &&
+          val.zone != ICAL.Timezone.utcTimezone &&
+          val.zone != ICAL.Timezone.localTimezone
+        ) {
+          this.innerObject.setParameter("TZID", val.zone.tzid);
+          if (this.parent) {
+            let tzref = wrapGetter(calICALJSTimezone, val.zone);
+            this.parent.addTimezoneReference(tzref);
+          }
+        } else {
+          this.innerObject.removeParameter("TZID");
+        }
+        this.innerObject.setValue(val);
+      },
+      this
+    );
+  },
 
-    get propertyName() { return this.innerObject.name.toUpperCase(); },
-
-    getParameter: function(name) {
-        // Unfortunately getting the "VALUE" parameter won't work, since in
-        // jCal it has been translated to the value type id.
-        if (name == "VALUE") {
-            let defaultType = this.innerObject.getDefaultType();
-            if (this.innerObject.type != defaultType) {
-                // Default type doesn't match object type, so we have a VALUE
-                // parameter
-                return this.innerObject.type.toUpperCase();
-            }
-        }
+  get propertyName() {
+    return this.innerObject.name.toUpperCase();
+  },
 
-        return this.innerObject.getParameter(name.toLowerCase());
-    },
-    setParameter: function(name, value) {
-        // Similar problems for setting the value parameter. Lightning code
-        // expects setting the value parameter to just change the value type
-        // and attempt to use the previous value as the new one. To do this in
-        // ICAL.js we need to save the value, reset the type and then try to
-        // set the value again.
-        if (name == "VALUE") {
-            let oldValues;
-            let type = this.innerObject.type;
-            let designSet = this.innerObject._designSet;
+  getParameter: function(name) {
+    // Unfortunately getting the "VALUE" parameter won't work, since in
+    // jCal it has been translated to the value type id.
+    if (name == "VALUE") {
+      let defaultType = this.innerObject.getDefaultType();
+      if (this.innerObject.type != defaultType) {
+        // Default type doesn't match object type, so we have a VALUE
+        // parameter
+        return this.innerObject.type.toUpperCase();
+      }
+    }
 
-            let wasMultiValue = this.innerObject.isMultiValue;
-            if (wasMultiValue) {
-                oldValues = this.innerObject.getValues();
-            } else {
-                let oldValue = this.innerObject.getFirstValue();
-                oldValues = oldValue ? [oldValue] : [];
-            }
+    return this.innerObject.getParameter(name.toLowerCase());
+  },
+  setParameter: function(name, value) {
+    // Similar problems for setting the value parameter. Lightning code
+    // expects setting the value parameter to just change the value type
+    // and attempt to use the previous value as the new one. To do this in
+    // ICAL.js we need to save the value, reset the type and then try to
+    // set the value again.
+    if (name == "VALUE") {
+      let oldValues;
+      let type = this.innerObject.type;
+      let designSet = this.innerObject._designSet;
 
-            this.innerObject.resetType(value.toLowerCase());
-            try {
-                oldValues = oldValues.map(oldValue => {
-                    let strvalue = ICAL.stringify.value(oldValue.toString(), type, designSet);
-                    return ICAL.parse._parseValue(strvalue, value, designSet);
-                });
-            } catch (e) {
-                // If there was an error reparsing the value, then just keep it
-                // empty.
-                oldValues = null;
-            }
+      let wasMultiValue = this.innerObject.isMultiValue;
+      if (wasMultiValue) {
+        oldValues = this.innerObject.getValues();
+      } else {
+        let oldValue = this.innerObject.getFirstValue();
+        oldValues = oldValue ? [oldValue] : [];
+      }
 
-            if (oldValues && oldValues.length) {
-                if (wasMultiValue && this.innerObject.isMultiValue) {
-                    this.innerObject.setValues(oldValues);
-                } else {
-                    this.innerObject.setValue(oldValues.join(","));
-                }
-            }
+      this.innerObject.resetType(value.toLowerCase());
+      try {
+        oldValues = oldValues.map(oldValue => {
+          let strvalue = ICAL.stringify.value(oldValue.toString(), type, designSet);
+          return ICAL.parse._parseValue(strvalue, value, designSet);
+        });
+      } catch (e) {
+        // If there was an error reparsing the value, then just keep it
+        // empty.
+        oldValues = null;
+      }
+
+      if (oldValues && oldValues.length) {
+        if (wasMultiValue && this.innerObject.isMultiValue) {
+          this.innerObject.setValues(oldValues);
         } else {
-            this.innerObject.setParameter(name.toLowerCase(), value);
+          this.innerObject.setValue(oldValues.join(","));
         }
-    },
-    removeParameter: function(name) {
-        // Again, VALUE needs special handling. Removing the value parameter is
-        // kind of like resetting it to the default type. So find out the
-        // default type and then set the value parameter to it.
-        if (name == "VALUE") {
-            let propname = this.innerObject.name.toLowerCase();
-            if (propname in ICAL.design.icalendar.property) {
-                let details = ICAL.design.icalendar.property[propname];
-                if ("defaultType" in details) {
-                    this.setParameter("VALUE", details.defaultType);
-                }
-            }
-        } else {
-            this.innerObject.removeParameter(name.toLowerCase());
+      }
+    } else {
+      this.innerObject.setParameter(name.toLowerCase(), value);
+    }
+  },
+  removeParameter: function(name) {
+    // Again, VALUE needs special handling. Removing the value parameter is
+    // kind of like resetting it to the default type. So find out the
+    // default type and then set the value parameter to it.
+    if (name == "VALUE") {
+      let propname = this.innerObject.name.toLowerCase();
+      if (propname in ICAL.design.icalendar.property) {
+        let details = ICAL.design.icalendar.property[propname];
+        if ("defaultType" in details) {
+          this.setParameter("VALUE", details.defaultType);
         }
-    },
+      }
+    } else {
+      this.innerObject.removeParameter(name.toLowerCase());
+    }
+  },
 
-    clearXParameters: function() {
-        cal.WARN("calIICSService::clearXParameters is no longer implemented, " +
-                 "please use removeParameter");
-    },
+  clearXParameters: function() {
+    cal.WARN(
+      "calIICSService::clearXParameters is no longer implemented, please use removeParameter"
+    );
+  },
 
-    paramIterator: null,
-    getFirstParameterName: function() {
-        let innerObject = this.innerObject;
-        this.paramIterator = (function* () {
-            let defaultType = innerObject.getDefaultType();
-            if (defaultType != innerObject.type) {
-                yield "VALUE";
-            }
+  paramIterator: null,
+  getFirstParameterName: function() {
+    let innerObject = this.innerObject;
+    this.paramIterator = (function*() {
+      let defaultType = innerObject.getDefaultType();
+      if (defaultType != innerObject.type) {
+        yield "VALUE";
+      }
 
-            let paramNames = Object.keys(innerObject.jCal[1] || {});
-            for (let name of paramNames) {
-                yield name.toUpperCase();
-            }
-        })();
-        return this.getNextParameterName();
-    },
+      let paramNames = Object.keys(innerObject.jCal[1] || {});
+      for (let name of paramNames) {
+        yield name.toUpperCase();
+      }
+    })();
+    return this.getNextParameterName();
+  },
 
-    getNextParameterName: function() {
-        if (this.paramIterator) {
-            let next = this.paramIterator.next();
-            if (next.done) {
-                this.paramIterator = null;
-            }
+  getNextParameterName: function() {
+    if (this.paramIterator) {
+      let next = this.paramIterator.next();
+      if (next.done) {
+        this.paramIterator = null;
+      }
 
-            return next.value;
-        } else {
-            return this.getFirstParameterName();
-        }
+      return next.value;
+    } else {
+      return this.getFirstParameterName();
     }
+  },
 };
 
 function calIcalComponent(innerObject) {
-    this.innerObject = innerObject || new ICAL.Component();
-    this.wrappedJSObject = this;
-    this.mReferencedZones = {};
+  this.innerObject = innerObject || new ICAL.Component();
+  this.wrappedJSObject = this;
+  this.mReferencedZones = {};
 }
 
 calIcalComponent.prototype = {
-    QueryInterface: ChromeUtils.generateQI([Ci.calIIcalComponent]),
-    classID: Components.ID("{51ac96fd-1279-4439-a85b-6947b37f4cea}"),
+  QueryInterface: ChromeUtils.generateQI([Ci.calIIcalComponent]),
+  classID: Components.ID("{51ac96fd-1279-4439-a85b-6947b37f4cea}"),
 
-    clone: function() { return new calIcalComponent(new ICAL.Component(this.innerObject.toJSON())); },
+  clone: function() {
+    return new calIcalComponent(new ICAL.Component(this.innerObject.toJSON()));
+  },
 
-    get parent() { return wrapGetter(calIcalComponent, this.innerObject.parent); },
+  get parent() {
+    return wrapGetter(calIcalComponent, this.innerObject.parent);
+  },
 
-    get icalTimezone() { return this.innerObject.name == "vtimezone" ? this.innerObject : null; },
-    get icalComponent() { return this.innerObject; },
-    set icalComponent(val) { this.innerObject = val; },
+  get icalTimezone() {
+    return this.innerObject.name == "vtimezone" ? this.innerObject : null;
+  },
+  get icalComponent() {
+    return this.innerObject;
+  },
+  set icalComponent(val) {
+    this.innerObject = val;
+  },
 
-    componentIterator: null,
-    getFirstSubcomponent: function(kind) {
-        if (kind == "ANY") {
-            kind = null;
-        } else if (kind) {
-            kind = kind.toLowerCase();
+  componentIterator: null,
+  getFirstSubcomponent: function(kind) {
+    if (kind == "ANY") {
+      kind = null;
+    } else if (kind) {
+      kind = kind.toLowerCase();
+    }
+    let innerObject = this.innerObject;
+    this.componentIterator = (function*() {
+      let comps = innerObject.getAllSubcomponents(kind);
+      if (comps) {
+        for (let comp of comps) {
+          yield new calIcalComponent(comp);
         }
-        let innerObject = this.innerObject;
-        this.componentIterator = (function* () {
-            let comps = innerObject.getAllSubcomponents(kind);
-            if (comps) {
-                for (let comp of comps) {
-                    yield new calIcalComponent(comp);
-                }
-            }
-        })();
-        return this.getNextSubcomponent(kind);
-    },
-    getNextSubcomponent: function(kind) {
-        if (this.componentIterator) {
-            let next = this.componentIterator.next();
-            if (next.done) {
-                this.componentIterator = null;
-            }
+      }
+    })();
+    return this.getNextSubcomponent(kind);
+  },
+  getNextSubcomponent: function(kind) {
+    if (this.componentIterator) {
+      let next = this.componentIterator.next();
+      if (next.done) {
+        this.componentIterator = null;
+      }
+
+      return next.value;
+    } else {
+      return this.getFirstSubcomponent(kind);
+    }
+  },
+
+  get componentType() {
+    return this.innerObject.name.toUpperCase();
+  },
 
-            return next.value;
-        } else {
-            return this.getFirstSubcomponent(kind);
-        }
-    },
-
-    get componentType() { return this.innerObject.name.toUpperCase(); },
+  get uid() {
+    return this.innerObject.getFirstPropertyValue("uid");
+  },
+  set uid(val) {
+    this.innerObject.updatePropertyWithValue("uid", val);
+  },
 
-    get uid() { return this.innerObject.getFirstPropertyValue("uid"); },
-    set uid(val) { this.innerObject.updatePropertyWithValue("uid", val); },
-
-    get prodid() { return this.innerObject.getFirstPropertyValue("prodid"); },
-    set prodid(val) { this.innerObject.updatePropertyWithValue("prodid", val); },
+  get prodid() {
+    return this.innerObject.getFirstPropertyValue("prodid");
+  },
+  set prodid(val) {
+    this.innerObject.updatePropertyWithValue("prodid", val);
+  },
 
-    get version() { return this.innerObject.getFirstPropertyValue("version"); },
-    set version(val) { this.innerObject.updatePropertyWithValue("version", val); },
-
-    get method() { return this.innerObject.getFirstPropertyValue("method"); },
-    set method(val) { this.innerObject.updatePropertyWithValue("method", val); },
+  get version() {
+    return this.innerObject.getFirstPropertyValue("version");
+  },
+  set version(val) {
+    this.innerObject.updatePropertyWithValue("version", val);
+  },
 
-    get status() { return this.innerObject.getFirstPropertyValue("status"); },
-    set status(val) { this.innerObject.updatePropertyWithValue("status", val); },
-
-    get summary() { return this.innerObject.getFirstPropertyValue("summary"); },
-    set summary(val) { this.innerObject.updatePropertyWithValue("summary", val); },
+  get method() {
+    return this.innerObject.getFirstPropertyValue("method");
+  },
+  set method(val) {
+    this.innerObject.updatePropertyWithValue("method", val);
+  },
 
-    get description() { return this.innerObject.getFirstPropertyValue("description"); },
-    set description(val) { this.innerObject.updatePropertyWithValue("description", val); },
-
-    get location() { return this.innerObject.getFirstPropertyValue("location"); },
-    set location(val) { this.innerObject.updatePropertyWithValue("location", val); },
+  get status() {
+    return this.innerObject.getFirstPropertyValue("status");
+  },
+  set status(val) {
+    this.innerObject.updatePropertyWithValue("status", val);
+  },
 
-    get categories() { return this.innerObject.getFirstPropertyValue("categories"); },
-    set categories(val) { this.innerObject.updatePropertyWithValue("categories", val); },
-
-    get URL() { return this.innerObject.getFirstPropertyValue("url"); },
-    set URL(val) { this.innerObject.updatePropertyWithValue("url", val); },
+  get summary() {
+    return this.innerObject.getFirstPropertyValue("summary");
+  },
+  set summary(val) {
+    this.innerObject.updatePropertyWithValue("summary", val);
+  },
 
-    get priority() {
-        // If there is no value for this integer property, then we must return
-        // the designated INVALID_VALUE.
-        const INVALID_VALUE = Ci.calIIcalComponent.INVALID_VALUE;
-        let prop = this.innerObject.getFirstProperty("priority");
-        let val = prop ? prop.getFirstValue() : null;
-        return (val === null ? INVALID_VALUE : val);
-    },
-    set priority(val) { this.innerObject.updatePropertyWithValue("priority", val); },
+  get description() {
+    return this.innerObject.getFirstPropertyValue("description");
+  },
+  set description(val) {
+    this.innerObject.updatePropertyWithValue("description", val);
+  },
+
+  get location() {
+    return this.innerObject.getFirstPropertyValue("location");
+  },
+  set location(val) {
+    this.innerObject.updatePropertyWithValue("location", val);
+  },
 
-    _setTimeAttr: function(propName, val) {
-        let prop = this.innerObject.updatePropertyWithValue(propName, val);
-        if (val && val.zone &&
-            val.zone != ICAL.Timezone.utcTimezone &&
-            val.zone != ICAL.Timezone.localTimezone) {
-            prop.setParameter("TZID", val.zone.tzid);
-            this.addTimezoneReference(wrapGetter(calICALJSTimezone, val.zone));
-        } else {
-            prop.removeParameter("TZID");
-        }
-    },
+  get categories() {
+    return this.innerObject.getFirstPropertyValue("categories");
+  },
+  set categories(val) {
+    this.innerObject.updatePropertyWithValue("categories", val);
+  },
+
+  get URL() {
+    return this.innerObject.getFirstPropertyValue("url");
+  },
+  set URL(val) {
+    this.innerObject.updatePropertyWithValue("url", val);
+  },
 
-    get startTime() { return wrapGetter(calDateTime, this.innerObject.getFirstPropertyValue("dtstart")); },
-    set startTime(val) { unwrapSetter(ICAL.Time, val, this._setTimeAttr.bind(this, "dtstart"), this); },
-
-    get endTime() { return wrapGetter(calDateTime, this.innerObject.getFirstPropertyValue("dtend")); },
-    set endTime(val) { unwrapSetter(ICAL.Time, val, this._setTimeAttr.bind(this, "dtend"), this); },
-
-    get duration() { return wrapGetter(calDuration, this.innerObject.getFirstPropertyValue("duration")); },
+  get priority() {
+    // If there is no value for this integer property, then we must return
+    // the designated INVALID_VALUE.
+    const INVALID_VALUE = Ci.calIIcalComponent.INVALID_VALUE;
+    let prop = this.innerObject.getFirstProperty("priority");
+    let val = prop ? prop.getFirstValue() : null;
+    return val === null ? INVALID_VALUE : val;
+  },
+  set priority(val) {
+    this.innerObject.updatePropertyWithValue("priority", val);
+  },
 
-    get dueTime() { return wrapGetter(calDateTime, this.innerObject.getFirstPropertyValue("due")); },
-    set dueTime(val) { unwrapSetter(ICAL.Time, val, this._setTimeAttr.bind(this, "due"), this); },
+  _setTimeAttr: function(propName, val) {
+    let prop = this.innerObject.updatePropertyWithValue(propName, val);
+    if (
+      val &&
+      val.zone &&
+      val.zone != ICAL.Timezone.utcTimezone &&
+      val.zone != ICAL.Timezone.localTimezone
+    ) {
+      prop.setParameter("TZID", val.zone.tzid);
+      this.addTimezoneReference(wrapGetter(calICALJSTimezone, val.zone));
+    } else {
+      prop.removeParameter("TZID");
+    }
+  },
 
-    get stampTime() { return wrapGetter(calDateTime, this.innerObject.getFirstPropertyValue("dtstamp")); },
-    set stampTime(val) { unwrapSetter(ICAL.Time, val, this._setTimeAttr.bind(this, "dtstamp"), this); },
-
-    get createdTime() { return wrapGetter(calDateTime, this.innerObject.getFirstPropertyValue("created")); },
-    set createdTime(val) { unwrapSetter(ICAL.Time, val, this._setTimeAttr.bind(this, "created"), this); },
+  get startTime() {
+    return wrapGetter(calDateTime, this.innerObject.getFirstPropertyValue("dtstart"));
+  },
+  set startTime(val) {
+    unwrapSetter(ICAL.Time, val, this._setTimeAttr.bind(this, "dtstart"), this);
+  },
 
-    get completedTime() { return wrapGetter(calDateTime, this.innerObject.getFirstPropertyValue("completed")); },
-    set completedTime(val) { unwrapSetter(ICAL.Time, val, this._setTimeAttr.bind(this, "completed"), this); },
+  get endTime() {
+    return wrapGetter(calDateTime, this.innerObject.getFirstPropertyValue("dtend"));
+  },
+  set endTime(val) {
+    unwrapSetter(ICAL.Time, val, this._setTimeAttr.bind(this, "dtend"), this);
+  },
 
-    get lastModified() { return wrapGetter(calDateTime, this.innerObject.getFirstPropertyValue("last-modified")); },
-    set lastModified(val) { unwrapSetter(ICAL.Time, val, this._setTimeAttr.bind(this, "last-modified"), this); },
-
-    get recurrenceId() { return wrapGetter(calDateTime, this.innerObject.getFirstPropertyValue("recurrence-id")); },
-    set recurrenceId(val) { unwrapSetter(ICAL.Time, val, this._setTimeAttr.bind(this, "recurrence-id"), this); },
+  get duration() {
+    return wrapGetter(calDuration, this.innerObject.getFirstPropertyValue("duration"));
+  },
 
-    serializeToICS: function() { return this.innerObject.toString() + ICAL.newLineChar; },
-    toString: function() { return this.innerObject.toString(); },
+  get dueTime() {
+    return wrapGetter(calDateTime, this.innerObject.getFirstPropertyValue("due"));
+  },
+  set dueTime(val) {
+    unwrapSetter(ICAL.Time, val, this._setTimeAttr.bind(this, "due"), this);
+  },
 
-    addSubcomponent: function(comp) {
-        comp.getReferencedTimezones({}).forEach(this.addTimezoneReference, this);
-        let jscomp = unwrapSingle(ICAL.Component, comp);
-        this.innerObject.addSubcomponent(jscomp);
-    },
+  get stampTime() {
+    return wrapGetter(calDateTime, this.innerObject.getFirstPropertyValue("dtstamp"));
+  },
+  set stampTime(val) {
+    unwrapSetter(ICAL.Time, val, this._setTimeAttr.bind(this, "dtstamp"), this);
+  },
+
+  get createdTime() {
+    return wrapGetter(calDateTime, this.innerObject.getFirstPropertyValue("created"));
+  },
+  set createdTime(val) {
+    unwrapSetter(ICAL.Time, val, this._setTimeAttr.bind(this, "created"), this);
+  },
 
-    propertyIterator: null,
-    getFirstProperty: function(kind) {
-        if (kind == "ANY") {
-            kind = null;
-        } else if (kind) {
-            kind = kind.toLowerCase();
-        }
-        let innerObject = this.innerObject;
-        this.propertyIterator = (function* () {
-            let props = innerObject.getAllProperties(kind);
-            if (!props) {
-                return;
-            }
-            for (let prop of props) {
-                let hell = prop.getValues();
-                if (hell.length > 1) {
-                    // Uh oh, multiple property values. Our code expects each as one
-                    // property. I hate API incompatibility!
-                    for (let devil of hell) {
-                        let thisprop = new ICAL.Property(prop.toJSON(),
-                                                         prop.parent);
-                        thisprop.removeAllValues();
-                        thisprop.setValue(devil);
-                        yield new calIcalProperty(thisprop);
-                    }
-                } else {
-                    yield new calIcalProperty(prop);
-                }
-            }
-        })();
+  get completedTime() {
+    return wrapGetter(calDateTime, this.innerObject.getFirstPropertyValue("completed"));
+  },
+  set completedTime(val) {
+    unwrapSetter(ICAL.Time, val, this._setTimeAttr.bind(this, "completed"), this);
+  },
+
+  get lastModified() {
+    return wrapGetter(calDateTime, this.innerObject.getFirstPropertyValue("last-modified"));
+  },
+  set lastModified(val) {
+    unwrapSetter(ICAL.Time, val, this._setTimeAttr.bind(this, "last-modified"), this);
+  },
 
-        return this.getNextProperty(kind);
-    },
+  get recurrenceId() {
+    return wrapGetter(calDateTime, this.innerObject.getFirstPropertyValue("recurrence-id"));
+  },
+  set recurrenceId(val) {
+    unwrapSetter(ICAL.Time, val, this._setTimeAttr.bind(this, "recurrence-id"), this);
+  },
+
+  serializeToICS: function() {
+    return this.innerObject.toString() + ICAL.newLineChar;
+  },
+  toString: function() {
+    return this.innerObject.toString();
+  },
+
+  addSubcomponent: function(comp) {
+    comp.getReferencedTimezones({}).forEach(this.addTimezoneReference, this);
+    let jscomp = unwrapSingle(ICAL.Component, comp);
+    this.innerObject.addSubcomponent(jscomp);
+  },
 
-    getNextProperty: function(kind) {
-        if (this.propertyIterator) {
-            let next = this.propertyIterator.next();
-            if (next.done) {
-                this.propertyIterator = null;
-            }
-
-            return next.value;
+  propertyIterator: null,
+  getFirstProperty: function(kind) {
+    if (kind == "ANY") {
+      kind = null;
+    } else if (kind) {
+      kind = kind.toLowerCase();
+    }
+    let innerObject = this.innerObject;
+    this.propertyIterator = (function*() {
+      let props = innerObject.getAllProperties(kind);
+      if (!props) {
+        return;
+      }
+      for (let prop of props) {
+        let hell = prop.getValues();
+        if (hell.length > 1) {
+          // Uh oh, multiple property values. Our code expects each as one
+          // property. I hate API incompatibility!
+          for (let devil of hell) {
+            let thisprop = new ICAL.Property(prop.toJSON(), prop.parent);
+            thisprop.removeAllValues();
+            thisprop.setValue(devil);
+            yield new calIcalProperty(thisprop);
+          }
         } else {
-            return this.getFirstProperty(kind);
-        }
-    },
-
-    _getNextParentVCalendar: function() {
-        let vcalendar = this; // eslint-disable-line consistent-this
-        while (vcalendar && vcalendar.componentType != "VCALENDAR") {
-            vcalendar = vcalendar.parent;
-        }
-        return vcalendar || this;
-    },
-
-    addProperty: function(prop) {
-        try {
-            let datetime = prop.valueAsDatetime;
-            if (datetime && datetime.timezone) {
-                this._getNextParentVCalendar().addTimezoneReference(datetime.timezone);
-            }
-        } catch (e) {
-            // If there is an issue adding the timezone reference, don't make
-            // that break adding the property.
+          yield new calIcalProperty(prop);
         }
+      }
+    })();
 
-        let jsprop = unwrapSingle(ICAL.Property, prop);
-        this.innerObject.addProperty(jsprop);
-    },
+    return this.getNextProperty(kind);
+  },
+
+  getNextProperty: function(kind) {
+    if (this.propertyIterator) {
+      let next = this.propertyIterator.next();
+      if (next.done) {
+        this.propertyIterator = null;
+      }
 
-    addTimezoneReference: function(timezone) {
-        if (timezone) {
-            if (!(timezone.tzid in this.mReferencedZones) &&
-                this.componentType == "VCALENDAR") {
-                let comp = timezone.icalComponent;
-                if (comp) {
-                    this.addSubcomponent(comp);
-                }
-            }
+      return next.value;
+    } else {
+      return this.getFirstProperty(kind);
+    }
+  },
+
+  _getNextParentVCalendar: function() {
+    let vcalendar = this; // eslint-disable-line consistent-this
+    while (vcalendar && vcalendar.componentType != "VCALENDAR") {
+      vcalendar = vcalendar.parent;
+    }
+    return vcalendar || this;
+  },
 
-            this.mReferencedZones[timezone.tzid] = timezone;
-        }
-    },
+  addProperty: function(prop) {
+    try {
+      let datetime = prop.valueAsDatetime;
+      if (datetime && datetime.timezone) {
+        this._getNextParentVCalendar().addTimezoneReference(datetime.timezone);
+      }
+    } catch (e) {
+      // If there is an issue adding the timezone reference, don't make
+      // that break adding the property.
+    }
+
+    let jsprop = unwrapSingle(ICAL.Property, prop);
+    this.innerObject.addProperty(jsprop);
+  },
 
-    getReferencedTimezones: function(aCount) {
-        let vals = Object.keys(this.mReferencedZones).map(timezone => this.mReferencedZones[timezone]);
-        aCount.value = vals.length;
-        return vals;
-    },
+  addTimezoneReference: function(timezone) {
+    if (timezone) {
+      if (!(timezone.tzid in this.mReferencedZones) && this.componentType == "VCALENDAR") {
+        let comp = timezone.icalComponent;
+        if (comp) {
+          this.addSubcomponent(comp);
+        }
+      }
+
+      this.mReferencedZones[timezone.tzid] = timezone;
+    }
+  },
 
-    serializeToICSStream: function() {
-        let unicodeConverter = Cc["@mozilla.org/intl/scriptableunicodeconverter"]
-                                 .createInstance(Ci.nsIScriptableUnicodeConverter);
-        unicodeConverter.charset = "UTF-8";
-        return unicodeConverter.convertToInputStream(this.innerObject.toString());
-    }
+  getReferencedTimezones: function(aCount) {
+    let vals = Object.keys(this.mReferencedZones).map(timezone => this.mReferencedZones[timezone]);
+    aCount.value = vals.length;
+    return vals;
+  },
+
+  serializeToICSStream: function() {
+    let unicodeConverter = Cc["@mozilla.org/intl/scriptableunicodeconverter"].createInstance(
+      Ci.nsIScriptableUnicodeConverter
+    );
+    unicodeConverter.charset = "UTF-8";
+    return unicodeConverter.convertToInputStream(this.innerObject.toString());
+  },
 };
 
 function calICSService() {
-    this.wrappedJSObject = this;
+  this.wrappedJSObject = this;
 }
 
 calICSService.prototype = {
-    QueryInterface: ChromeUtils.generateQI([Ci.calIICSService]),
-    classID: Components.ID("{c61cb903-4408-41b3-bc22-da0b27efdfe1}"),
+  QueryInterface: ChromeUtils.generateQI([Ci.calIICSService]),
+  classID: Components.ID("{c61cb903-4408-41b3-bc22-da0b27efdfe1}"),
 
-    parseICS: function(serialized, tzProvider) {
-        // TODO ical.js doesn't support tz providers, but this is usually null
-        // or our timezone service anyway.
-        let comp = ICAL.parse(serialized);
-        return new calIcalComponent(new ICAL.Component(comp));
-    },
+  parseICS: function(serialized, tzProvider) {
+    // TODO ical.js doesn't support tz providers, but this is usually null
+    // or our timezone service anyway.
+    let comp = ICAL.parse(serialized);
+    return new calIcalComponent(new ICAL.Component(comp));
+  },
 
-    parseICSAsync: function(serialized, tzProvider, listener) {
-        // There are way too many error checking messages here, but I had so
-        // much pain with this method that I don't want it to break again.
+  parseICSAsync: function(serialized, tzProvider, listener) {
+    // There are way too many error checking messages here, but I had so
+    // much pain with this method that I don't want it to break again.
+    try {
+      let worker = new ChromeWorker("resource://calendar/calendar-js/calICSService-worker.js");
+      worker.onmessage = function(event) {
+        let rc = Cr.NS_ERROR_FAILURE;
+        let icalComp = null;
         try {
-            let worker = new ChromeWorker("resource://calendar/calendar-js/calICSService-worker.js");
-            worker.onmessage = function(event) {
-                let rc = Cr.NS_ERROR_FAILURE;
-                let icalComp = null;
-                try {
-                    rc = event.data.rc;
-                    icalComp = new calIcalComponent(new ICAL.Component(event.data.data));
-                    if (!Components.isSuccessCode(rc)) {
-                        cal.ERROR("[calICSService] Error in parser worker: " + event.data);
-                    }
-                } catch (e) {
-                    cal.ERROR("[calICSService] Exception parsing item: " + e);
-                }
+          rc = event.data.rc;
+          icalComp = new calIcalComponent(new ICAL.Component(event.data.data));
+          if (!Components.isSuccessCode(rc)) {
+            cal.ERROR("[calICSService] Error in parser worker: " + event.data);
+          }
+        } catch (e) {
+          cal.ERROR("[calICSService] Exception parsing item: " + e);
+        }
 
-                listener.onParsingComplete(rc, icalComp);
-            };
-            worker.onerror = function(event) {
-                cal.ERROR("[calICSService] Error in parser worker: " + event.message);
-                listener.onParsingComplete(Cr.NS_ERROR_FAILURE, null);
-            };
-            worker.postMessage(serialized);
-        } catch (e) {
-            // If an error occurs above, the calling code will hang. Catch the exception just in case
-            cal.ERROR("[calICSService] Error starting parsing worker: " + e);
-            listener.onParsingComplete(Cr.NS_ERROR_FAILURE, null);
-        }
-    },
+        listener.onParsingComplete(rc, icalComp);
+      };
+      worker.onerror = function(event) {
+        cal.ERROR("[calICSService] Error in parser worker: " + event.message);
+        listener.onParsingComplete(Cr.NS_ERROR_FAILURE, null);
+      };
+      worker.postMessage(serialized);
+    } catch (e) {
+      // If an error occurs above, the calling code will hang. Catch the exception just in case
+      cal.ERROR("[calICSService] Error starting parsing worker: " + e);
+      listener.onParsingComplete(Cr.NS_ERROR_FAILURE, null);
+    }
+  },
 
-    createIcalComponent: function(kind) {
-        return new calIcalComponent(new ICAL.Component(kind.toLowerCase()));
-    },
+  createIcalComponent: function(kind) {
+    return new calIcalComponent(new ICAL.Component(kind.toLowerCase()));
+  },
 
-    createIcalProperty: function(kind) {
-        return new calIcalProperty(new ICAL.Property(kind.toLowerCase()));
-    },
+  createIcalProperty: function(kind) {
+    return new calIcalProperty(new ICAL.Property(kind.toLowerCase()));
+  },
 
-    createIcalPropertyFromString: function(str) {
-        return new calIcalProperty(ICAL.Property.fromString(str.trim(), ICAL.design.icalendar));
-    }
+  createIcalPropertyFromString: function(str) {
+    return new calIcalProperty(ICAL.Property.fromString(str.trim(), ICAL.design.icalendar));
+  },
 };
--- a/calendar/base/backend/icaljs/calPeriod.js
+++ b/calendar/base/backend/icaljs/calPeriod.js
@@ -2,53 +2,81 @@
  * 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/. */
 
 /* import-globals-from calICALJSComponents.js */
 
 var { ICAL, unwrapSetter, wrapGetter } = ChromeUtils.import("resource://calendar/modules/ical.js");
 
 function calPeriod(innerObject) {
-    this.innerObject = innerObject || new ICAL.Period({});
-    this.wrappedJSObject = this;
+  this.innerObject = innerObject || new ICAL.Period({});
+  this.wrappedJSObject = this;
 }
 
 calPeriod.prototype = {
-    QueryInterface: ChromeUtils.generateQI([Ci.calIPeriod]),
-    classID: Components.ID("{394a281f-7299-45f7-8b1f-cce21258972f}"),
+  QueryInterface: ChromeUtils.generateQI([Ci.calIPeriod]),
+  classID: Components.ID("{394a281f-7299-45f7-8b1f-cce21258972f}"),
+
+  isMutable: true,
+  innerObject: null,
 
-    isMutable: true,
-    innerObject: null,
-
-    get icalPeriod() { return this.innerObject; },
-    set icalPeriod(val) { this.innerObject = val; },
+  get icalPeriod() {
+    return this.innerObject;
+  },
+  set icalPeriod(val) {
+    this.innerObject = val;
+  },
 
-    makeImmutable: function() { this.isMutable = false; },
-    clone: function() { return new calPeriod(this.innerObject.clone()); },
+  makeImmutable: function() {
+    this.isMutable = false;
+  },
+  clone: function() {
+    return new calPeriod(this.innerObject.clone());
+  },
 
-    get start() { return wrapGetter(calDateTime, this.innerObject.start); },
-    set start(rawval) {
-        unwrapSetter(ICAL.Time, rawval, function(val) {
-            this.innerObject.start = val;
-        }, this);
-    },
+  get start() {
+    return wrapGetter(calDateTime, this.innerObject.start);
+  },
+  set start(rawval) {
+    unwrapSetter(
+      ICAL.Time,
+      rawval,
+      function(val) {
+        this.innerObject.start = val;
+      },
+      this
+    );
+  },
 
-    get end() { return wrapGetter(calDateTime, this.innerObject.getEnd()); },
-    set end(rawval) {
-        unwrapSetter(ICAL.Time, rawval, function(val) {
-            if (this.innerObject.duration) {
-                this.innerObject.duration = null;
-            }
-            this.innerObject.end = val;
-        }, this);
-    },
+  get end() {
+    return wrapGetter(calDateTime, this.innerObject.getEnd());
+  },
+  set end(rawval) {
+    unwrapSetter(
+      ICAL.Time,
+      rawval,
+      function(val) {
+        if (this.innerObject.duration) {
+          this.innerObject.duration = null;
+        }
+        this.innerObject.end = val;
+      },
+      this
+    );
+  },
 
-    get duration() { return wrapGetter(calDuration, this.innerObject.getDuration()); },
+  get duration() {
+    return wrapGetter(calDuration, this.innerObject.getDuration());
+  },
 
-    get icalString() { return this.innerObject.toICALString(); },
-    set icalString(val) {
-        let dates = ICAL.parse._parseValue(val, "period", ICAL.design.icalendar);
-        this.innerObject = ICAL.Period.fromString(dates.join("/"));
-        return val;
-    },
+  get icalString() {
+    return this.innerObject.toICALString();
+  },
+  set icalString(val) {
+    let dates = ICAL.parse._parseValue(val, "period", ICAL.design.icalendar);
+    this.innerObject = ICAL.Period.fromString(dates.join("/"));
+    return val;
+  },
 
-    toString: function() { return this.innerObject.toString(); }
+  toString: function() {
+    return this.innerObject.toString();
+  },
 };
--- a/calendar/base/backend/icaljs/calRecurrenceRule.js
+++ b/calendar/base/backend/icaljs/calRecurrenceRule.js
@@ -1,198 +1,235 @@
 /* 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/. */
 
 /* import-globals-from calICALJSComponents.js */
 
-var { ICAL, unwrapSetter, unwrapSingle, wrapGetter } = ChromeUtils.import("resource://calendar/modules/ical.js");
+var { ICAL, unwrapSetter, unwrapSingle, wrapGetter } = ChromeUtils.import(
+  "resource://calendar/modules/ical.js"
+);
 var { cal } = ChromeUtils.import("resource://calendar/modules/calUtils.jsm");
 
 function calRecurrenceRule(innerObject) {
-    this.innerObject = innerObject || new ICAL.Recur();
-    this.wrappedJSObject = this;
+  this.innerObject = innerObject || new ICAL.Recur();
+  this.wrappedJSObject = this;
 }
 
-var calRecurrenceRuleInterfaces = [
-    Ci.calIRecurrenceRule,
-    Ci.calIRecurrenceItem
-];
+var calRecurrenceRuleInterfaces = [Ci.calIRecurrenceRule, Ci.calIRecurrenceItem];
 var calRecurrenceRuleClassID = Components.ID("{df19281a-5389-4146-b941-798cb93a7f0d}");
 calRecurrenceRule.prototype = {
-    QueryInterface: cal.generateQI(calRecurrenceRuleInterfaces),
+  QueryInterface: cal.generateQI(calRecurrenceRuleInterfaces),
+  classID: calRecurrenceRuleClassID,
+  classInfo: cal.generateCI({
+    contractID: "@mozilla.org/calendar/recurrence-rule;1",
+    classDescription: "Calendar Recurrence Rule",
     classID: calRecurrenceRuleClassID,
-    classInfo: cal.generateCI({
-        contractID: "@mozilla.org/calendar/recurrence-rule;1",
-        classDescription: "Calendar Recurrence Rule",
-        classID: calRecurrenceRuleClassID,
-        interfaces: calRecurrenceRuleInterfaces
-    }),
+    interfaces: calRecurrenceRuleInterfaces,
+  }),
+
+  innerObject: null,
 
-    innerObject: null,
+  isMutable: true,
+  makeImmutable: function() {
+    this.isMutable = false;
+  },
+  clone: function() {
+    return new calRecurrenceRule(new ICAL.Recur(this.innerObject));
+  },
 
-    isMutable: true,
-    makeImmutable: function() { this.isMutable = false; },
-    clone: function() { return new calRecurrenceRule(new ICAL.Recur(this.innerObject)); },
+  isNegative: false, // We don't support EXRULE anymore
+  get isFinite() {
+    return this.innerObject.isFinite();
+  },
 
-    isNegative: false, // We don't support EXRULE anymore
-    get isFinite() { return this.innerObject.isFinite(); },
+  getNextOccurrence: function(aStartTime, aRecId) {
+    aStartTime = unwrapSingle(ICAL.Time, aStartTime);
+    aRecId = unwrapSingle(ICAL.Time, aRecId);
+    return wrapGetter(calDateTime, this.innerObject.getNextOccurrence(aStartTime, aRecId));
+  },
+
+  getOccurrences: function(aStartTime, aRangeStart, aRangeEnd, aMaxCount, aCount) {
+    aStartTime = unwrapSingle(ICAL.Time, aStartTime);
+    aRangeStart = unwrapSingle(ICAL.Time, aRangeStart);
+    aRangeEnd = unwrapSingle(ICAL.Time, aRangeEnd);
 
-    getNextOccurrence: function(aStartTime, aRecId) {
-        aStartTime = unwrapSingle(ICAL.Time, aStartTime);
-        aRecId = unwrapSingle(ICAL.Time, aRecId);
-        return wrapGetter(calDateTime, this.innerObject.getNextOccurrence(aStartTime, aRecId));
-    },
+    if (!aMaxCount && !aRangeEnd && this.count == 0 && this.until == null) {
+      throw Cr.NS_ERROR_INVALID_ARG;
+    }
+
+    let occurrences = [];
+    let rangeStart = aRangeStart.clone();
+    rangeStart.isDate = false;
+
+    let dtend = null;
+
+    if (aRangeEnd) {
+      dtend = aRangeEnd.clone();
+      dtend.isDate = false;
 
-    getOccurrences: function(aStartTime, aRangeStart, aRangeEnd, aMaxCount, aCount) {
-        aStartTime = unwrapSingle(ICAL.Time, aStartTime);
-        aRangeStart = unwrapSingle(ICAL.Time, aRangeStart);
-        aRangeEnd = unwrapSingle(ICAL.Time, aRangeEnd);
+      // If the start of the recurrence is past the end, we have no dates
+      if (aStartTime.compare(dtend) >= 0) {
+        aCount.value = 0;
+        return [];
+      }
+    }
+
+    let iter = this.innerObject.iterator(aStartTime);
+
+    for (let next = iter.next(); next; next = iter.next()) {
+      let dtNext = next.clone();
+      dtNext.isDate = false;
 
-        if (!aMaxCount && !aRangeEnd && this.count == 0 && this.until == null) {
-            throw Cr.NS_ERROR_INVALID_ARG;
-        }
+      if (dtNext.compare(rangeStart) < 0) {
+        continue;
+      }
 
-        let occurrences = [];
-        let rangeStart = aRangeStart.clone();
-        rangeStart.isDate = false;
+      if (dtend && dtNext.compare(dtend) >= 0) {
+        break;
+      }
+
+      next = next.clone();
+
+      if (aStartTime.zone) {
+        next.zone = aStartTime.zone;
+      }
 
-        let dtend = null;
+      occurrences.push(new calDateTime(next));
 
-        if (aRangeEnd) {
-            dtend = aRangeEnd.clone();
-            dtend.isDate = false;
+      if (aMaxCount && aMaxCount >= occurrences.length) {
+        break;
+      }
+    }
+
+    aCount.value = occurrences.length;
+    return occurrences;
+  },
 
-            // If the start of the recurrence is past the end, we have no dates
-            if (aStartTime.compare(dtend) >= 0) {
-                aCount.value = 0;
-                return [];
-            }
-        }
+  get icalString() {
+    return "RRULE:" + this.innerObject.toString() + ICAL.newLineChar;
+  },
+  set icalString(val) {
+    this.innerObject = ICAL.Recur.fromString(val.replace(/^RRULE:/i, ""));
+  },
 
-        let iter = this.innerObject.iterator(aStartTime);
-
-        for (let next = iter.next(); next; next = iter.next()) {
-            let dtNext = next.clone();
-            dtNext.isDate = false;
+  get icalProperty() {
+    let prop = new ICAL.Property("rrule");
+    prop.setValue(this.innerObject);
+    return new calIcalProperty(prop);
+  },
+  set icalProperty(rawval) {
+    unwrapSetter(
+      ICAL.Property,
+      rawval,
+      function(val) {
+        this.innerObject = val.getFirstValue();
+      },
+      this
+    );
+  },
 
-            if (dtNext.compare(rangeStart) < 0) {
-                continue;
-            }
+  get type() {
+    return this.innerObject.freq;
+  },
+  set type(val) {
+    this.innerObject.freq = val;
+  },
 
-            if (dtend && dtNext.compare(dtend) >= 0) {
-                break;
-            }
-
-            next = next.clone();
+  get interval() {
+    return this.innerObject.interval;
+  },
+  set interval(val) {
+    this.innerObject.interval = val;
+  },
 
-            if (aStartTime.zone) {
-                next.zone = aStartTime.zone;
-            }
+  get count() {
+    if (!this.isByCount) {
+      throw Cr.NS_ERROR_FAILURE;
+    }
+    return this.innerObject.count || -1;
+  },
+  set count(val) {
+    this.innerObject.count = val && val > 0 ? val : null;
+  },
 
-            occurrences.push(new calDateTime(next));
-
-            if (aMaxCount && aMaxCount >= occurrences.length) {
-                break;
-            }
+  get untilDate() {
+    if (this.innerObject.until) {
+      return new calDateTime(this.innerObject.until);
+    } else {
+      return null;
+    }
+  },
+  set untilDate(rawval) {
+    unwrapSetter(
+      ICAL.Time,
+      rawval,
+      function(val) {
+        if (
+          val.timezone != ICAL.Timezone.utcTimezone &&
+          val.timezone != ICAL.Timezone.localTimezone
+        ) {
+          val = val.convertToZone(ICAL.Timezone.utcTimezone);
         }
 
-        aCount.value = occurrences.length;
-        return occurrences;
-    },
-
-    get icalString() { return "RRULE:" + this.innerObject.toString() + ICAL.newLineChar; },
-    set icalString(val) { this.innerObject = ICAL.Recur.fromString(val.replace(/^RRULE:/i, "")); },
-
-    get icalProperty() {
-        let prop = new ICAL.Property("rrule");
-        prop.setValue(this.innerObject);
-        return new calIcalProperty(prop);
-    },
-    set icalProperty(rawval) {
-        unwrapSetter(ICAL.Property, rawval, function(val) {
-            this.innerObject = val.getFirstValue();
-        }, this);
-    },
-
-    get type() { return this.innerObject.freq; },
-    set type(val) { this.innerObject.freq = val; },
-
-    get interval() { return this.innerObject.interval; },
-    set interval(val) { this.innerObject.interval = val; },
+        this.innerObject.until = val;
+      },
+      this
+    );
+  },
 
-    get count() {
-        if (!this.isByCount) {
-            throw Cr.NS_ERROR_FAILURE;
-        }
-        return this.innerObject.count || -1;
-    },
-    set count(val) { this.innerObject.count = (val && val > 0 ? val : null); },
+  get isByCount() {
+    return this.innerObject.isByCount();
+  },
 
-    get untilDate() {
-        if (this.innerObject.until) {
-            return new calDateTime(this.innerObject.until);
-        } else {
-            return null;
-        }
-    },
-    set untilDate(rawval) {
-        unwrapSetter(ICAL.Time, rawval, function(val) {
-            if (val.timezone != ICAL.Timezone.utcTimezone &&
-                val.timezone != ICAL.Timezone.localTimezone) {
-                val = val.convertToZone(ICAL.Timezone.utcTimezone);
-            }
-
-            this.innerObject.until = val;
-        }, this);
-    },
+  get weekStart() {
+    return this.innerObject.wkst - 1;
+  },
+  set weekStart(val) {
+    this.innerObject.wkst = val + 1;
+  },
 
-    get isByCount() { return this.innerObject.isByCount(); },
-
-    get weekStart() { return this.innerObject.wkst - 1; },
-    set weekStart(val) { this.innerObject.wkst = val + 1; },
-
-    getComponent: function(aType, aCount) {
-        let values = this.innerObject.getComponent(aType);
-        if (aType == "BYDAY") {
-            // BYDAY values are alphanumeric: SU, MO, TU, etc..
-            for (let i = 0; i < values.length; i++) {
-                let match = /^([+-])?(5[0-3]|[1-4][0-9]|[1-9])?(SU|MO|TU|WE|TH|FR|SA)$/.exec(values[i]);
-                if (!match) {
-                    cal.ERROR("Malformed BYDAY rule\n" + cal.STACK(10));
-                    return [];
-                }
-                values[i] = ICAL.Recur.icalDayToNumericDay(match[3]);
-                if (match[2]) {
-                    // match[2] is the week number for this value.
-                    values[i] += 8 * match[2];
-                }
-                if (match[1] == "-") {
-                    // Week numbers are counted back from the end of the period.
-                    values[i] *= -1;
-                }
-            }
+  getComponent: function(aType, aCount) {
+    let values = this.innerObject.getComponent(aType);
+    if (aType == "BYDAY") {
+      // BYDAY values are alphanumeric: SU, MO, TU, etc..
+      for (let i = 0; i < values.length; i++) {
+        let match = /^([+-])?(5[0-3]|[1-4][0-9]|[1-9])?(SU|MO|TU|WE|TH|FR|SA)$/.exec(values[i]);
+        if (!match) {
+          cal.ERROR("Malformed BYDAY rule\n" + cal.STACK(10));
+          return [];
+        }
+        values[i] = ICAL.Recur.icalDayToNumericDay(match[3]);
+        if (match[2]) {
+          // match[2] is the week number for this value.
+          values[i] += 8 * match[2];
+        }
+        if (match[1] == "-") {
+          // Week numbers are counted back from the end of the period.
+          values[i] *= -1;
         }
+      }
+    }
 
-        if (aCount) {
-            aCount.value = values.length;
-        }
-        return values;
-    },
+    if (aCount) {
+      aCount.value = values.length;
+    }
+    return values;
+  },
 
-    setComponent: function(aType, aCount, aValues) {
-        let values = aValues;
-        if (aType == "BYDAY") {
-            // BYDAY values are alphanumeric: SU, MO, TU, etc..
-            for (let i = 0; i < values.length; i++) {
-                let absValue = Math.abs(values[i]);
-                if (absValue > 7) {
-                    let ordinal = Math.trunc(values[i] / 8);
-                    let day = ICAL.Recur.numericDayToIcalDay(absValue % 8);
-                    values[i] = ordinal + day;
-                } else {
-                    values[i] = ICAL.Recur.numericDayToIcalDay(values[i]);
-                }
-            }
+  setComponent: function(aType, aCount, aValues) {
+    let values = aValues;
+    if (aType == "BYDAY") {
+      // BYDAY values are alphanumeric: SU, MO, TU, etc..
+      for (let i = 0; i < values.length; i++) {
+        let absValue = Math.abs(values[i]);
+        if (absValue > 7) {
+          let ordinal = Math.trunc(values[i] / 8);
+          let day = ICAL.Recur.numericDayToIcalDay(absValue % 8);
+          values[i] = ordinal + day;
+        } else {
+          values[i] = ICAL.Recur.numericDayToIcalDay(values[i]);
         }
-        this.innerObject.setComponent(aType, values);
+      }
     }
+    this.innerObject.setComponent(aType, values);
+  },
 };
--- a/calendar/base/content/agenda-listbox-utils.js
+++ b/calendar/base/content/agenda-listbox-utils.js
@@ -8,1117 +8,1120 @@
 /* import-globals-from calendar-ui-utils.js */
 /* import-globals-from calendar-views-utils.js */
 
 var { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
 
 var { cal } = ChromeUtils.import("resource://calendar/modules/calUtils.jsm");
 
 function Synthetic(aHeader, aDuration, aMultiday) {
-    this.open = aHeader.getAttribute("checked") == "true";
-    this.duration = aDuration;
-    this.multiday = aMultiday;
+  this.open = aHeader.getAttribute("checked") == "true";
+  this.duration = aDuration;
+  this.multiday = aMultiday;
 }
 
 var agendaListbox = {
-    agendaListboxControl: null,
-    mPendingRefreshJobs: null,
-    kDefaultTimezone: null,
-    showsToday: false,
-    soonDays: 5
+  agendaListboxControl: null,
+  mPendingRefreshJobs: null,
+  kDefaultTimezone: null,
+  showsToday: false,
+  soonDays: 5,
 };
 
 /**
  * Initialize the agenda listbox, used on window load.
  */
 agendaListbox.init = function() {
-    this.agendaListboxControl = document.getElementById("agenda-listbox");
-    this.agendaListboxControl.removeAttribute("suppressonselect");
-    let showTodayHeader = document.getElementById("today-header");
-    let showTomorrowHeader = document.getElementById("tomorrow-header");
-    let showSoonHeader = document.getElementById("nextweek-header");
+  this.agendaListboxControl = document.getElementById("agenda-listbox");
+  this.agendaListboxControl.removeAttribute("suppressonselect");
+  let showTodayHeader = document.getElementById("today-header");
+  let showTomorrowHeader = document.getElementById("tomorrow-header");
+  let showSoonHeader = document.getElementById("nextweek-header");
 
-    this.today = new Synthetic(showTodayHeader, 1, false);
-    this.addPeriodListItem(this.today, "today-header");
-    this.tomorrow = new Synthetic(showTomorrowHeader, 1, false);
-    this.soonDays = getSoondaysPreference();
-    this.soon = new Synthetic(showSoonHeader, this.soonDays, true);
-    this.periods = [this.today, this.tomorrow, this.soon];
-    this.mPendingRefreshJobs = new Map();
+  this.today = new Synthetic(showTodayHeader, 1, false);
+  this.addPeriodListItem(this.today, "today-header");
+  this.tomorrow = new Synthetic(showTomorrowHeader, 1, false);
+  this.soonDays = getSoondaysPreference();
+  this.soon = new Synthetic(showSoonHeader, this.soonDays, true);
+  this.periods = [this.today, this.tomorrow, this.soon];
+  this.mPendingRefreshJobs = new Map();
 
-    for (let header of [showTodayHeader, showTomorrowHeader, showSoonHeader]) {
-        header.getCheckbox().addEventListener("CheckboxStateChange", this.onCheckboxChange, true);
-    }
+  for (let header of [showTodayHeader, showTomorrowHeader, showSoonHeader]) {
+    header.getCheckbox().addEventListener("CheckboxStateChange", this.onCheckboxChange, true);
+  }
 
-    // At this point, we're ready and waiting for refreshPeriodDates to be called by TodayPane.
+  // At this point, we're ready and waiting for refreshPeriodDates to be called by TodayPane.
 
-    let prefObserver = {
-        observe: function(aSubject, aTopic, aPrefName) {
-            switch (aPrefName) {
-                case "calendar.agendaListbox.soondays":
-                    agendaListbox.soonDays = getSoondaysPreference();
-                    agendaListbox.updateSoonSection();
-                    break;
-            }
-        }
-    };
-    Services.prefs.addObserver("calendar.agendaListbox", prefObserver);
+  let prefObserver = {
+    observe: function(aSubject, aTopic, aPrefName) {
+      switch (aPrefName) {
+        case "calendar.agendaListbox.soondays":
+          agendaListbox.soonDays = getSoondaysPreference();
+          agendaListbox.updateSoonSection();
+          break;
+      }
+    },
+  };
+  Services.prefs.addObserver("calendar.agendaListbox", prefObserver);
 
-    // Make sure the agenda listbox is unloaded
-    window.addEventListener("unload", () => {
-        Services.prefs.removeObserver("calendar.agendaListbox", prefObserver);
-        this.uninit();
-    });
+  // Make sure the agenda listbox is unloaded
+  window.addEventListener("unload", () => {
+    Services.prefs.removeObserver("calendar.agendaListbox", prefObserver);
+    this.uninit();
+  });
 };
 
 /**
  * Clean up the agenda listbox, used on window unload.
  */
 agendaListbox.uninit = function() {
-    if (this.calendar) {
-        this.calendar.removeObserver(this.calendarObserver);
-    }
+  if (this.calendar) {
+    this.calendar.removeObserver(this.calendarObserver);
+  }
 
-    for (let period of this.periods) {
-        if (period.listItem) {
-            period.listItem.getCheckbox()
-                  .removeEventListener("CheckboxStateChange",
-                                       this.onCheckboxChange,
-                                       true);
-        }
+  for (let period of this.periods) {
+    if (period.listItem) {
+      period.listItem
+        .getCheckbox()
+        .removeEventListener("CheckboxStateChange", this.onCheckboxChange, true);
     }
+  }
 };
 
 /**
  * Adds a period item to the listbox. This is a section of the today pane like
  * "Today", "Tomorrow", and is usually a <agenda-header-richlist-item> tag. A
  * copy of the template node is made and added to the agenda listbox.
  *
  * @param aPeriod       The period item to add.
  * @param aItemId       The id of an <agenda-header-richlist-item> to add to.
  */
 agendaListbox.addPeriodListItem = function(aPeriod, aItemId) {
-    aPeriod.listItem = document.getElementById(aItemId);
-    aPeriod.listItem.hidden = false;
-    aPeriod.listItem.getCheckbox().checked = aPeriod.open;
+  aPeriod.listItem = document.getElementById(aItemId);
+  aPeriod.listItem.hidden = false;
+  aPeriod.listItem.getCheckbox().checked = aPeriod.open;
 };
 
 /**
  * Remove a period item from the agenda listbox.
  * @see agendaListbox::addPeriodListItem
  */
 agendaListbox.removePeriodListItem = function(aPeriod) {
+  if (aPeriod.listItem) {
+    aPeriod.listItem
+      .getCheckbox()
+      .removeEventListener("CheckboxStateChange", this.onCheckboxChange, true);
     if (aPeriod.listItem) {
-        aPeriod.listItem.getCheckbox().removeEventListener("CheckboxStateChange", this.onCheckboxChange, true);
-        if (aPeriod.listItem) {
-            aPeriod.listItem.hidden = true;
-            aPeriod.listItem = null;
-        }
+      aPeriod.listItem.hidden = true;
+      aPeriod.listItem = null;
     }
+  }
 };
 
 /**
  * Handler function called when changing the checkbox state on period items.
  *
  * @param event     The DOM event that triggered the checkbox state change.
  */
 agendaListbox.onCheckboxChange = function(event) {
-    let periodCheckbox = event.target;
-    let lopen = (periodCheckbox.getAttribute("checked") == "true");
-    let listItem = cal.view.getParentNodeOrThis(periodCheckbox, "richlistitem");
-    let period = listItem.getItem();
-    if (!period) {
-        return;
-    }
+  let periodCheckbox = event.target;
+  let lopen = periodCheckbox.getAttribute("checked") == "true";
+  let listItem = cal.view.getParentNodeOrThis(periodCheckbox, "richlistitem");
+  let period = listItem.getItem();
+  if (!period) {
+    return;
+  }
 
-    period.open = lopen;
-    // as the agenda-checkboxes are only transient we have to set the "checked"
-    // attribute at their hidden origins to make that attribute persistent.
-    document.getElementById(listItem.id).setAttribute("checked",
-                            periodCheckbox.getAttribute("checked"));
-    if (lopen) {
-        agendaListbox.refreshCalendarQuery(period.start, period.end);
-    } else {
-        listItem = listItem.nextSibling;
-        let leaveloop;
-        do {
-            leaveloop = (listItem == null);
-            if (!leaveloop) {
-                let nextItemSibling = listItem.nextSibling;
-                leaveloop = !agendaListbox.isEventListItem(listItem);
-                if (!leaveloop) {
-                    listItem.remove();
-                    listItem = nextItemSibling;
-                }
-            }
-        } while (!leaveloop);
-    }
-    calendarController.onSelectionChanged({ detail: [] });
+  period.open = lopen;
+  // as the agenda-checkboxes are only transient we have to set the "checked"
+  // attribute at their hidden origins to make that attribute persistent.
+  document
+    .getElementById(listItem.id)
+    .setAttribute("checked", periodCheckbox.getAttribute("checked"));
+  if (lopen) {
+    agendaListbox.refreshCalendarQuery(period.start, period.end);
+  } else {
+    listItem = listItem.nextSibling;
+    let leaveloop;
+    do {
+      leaveloop = listItem == null;
+      if (!leaveloop) {
+        let nextItemSibling = listItem.nextSibling;
+        leaveloop = !agendaListbox.isEventListItem(listItem);
+        if (!leaveloop) {
+          listItem.remove();
+          listItem = nextItemSibling;
+        }
+      }
+    } while (!leaveloop);
+  }
+  calendarController.onSelectionChanged({ detail: [] });
 };
 
 /**
  * Handler function called when an agenda listbox item is selected
  *
  * @param aListItem     The agenda-base-richlist-item that was selected.
  */
 agendaListbox.onSelect = function(aListItem) {
-    let listbox = document.getElementById("agenda-listbox");
-    let item = aListItem || listbox.selectedItem;
-    if (aListItem) {
-        listbox.selectedItem = item;
-    }
-    calendarController.onSelectionChanged({ detail: agendaListbox.getSelectedItems() });
+  let listbox = document.getElementById("agenda-listbox");
+  let item = aListItem || listbox.selectedItem;
+  if (aListItem) {
+    listbox.selectedItem = item;
+  }
+  calendarController.onSelectionChanged({ detail: agendaListbox.getSelectedItems() });
 };
 
 /**
  * Handler function called when the agenda listbox becomes focused
  */
 agendaListbox.onFocus = function() {
-    calendarController.onSelectionChanged({ detail: agendaListbox.getSelectedItems() });
+  calendarController.onSelectionChanged({ detail: agendaListbox.getSelectedItems() });
 };
 
 /**
  * Handler function called when the agenda listbox loses focus.
  */
 agendaListbox.onBlur = function() {
-    calendarController.onSelectionChanged({ detail: [] });
+  calendarController.onSelectionChanged({ detail: [] });
 };
 
-
 /**
  * Handler function called when a key was pressed on the agenda listbox
  */
 agendaListbox.onKeyPress = function(aEvent) {
-    let listItem = aEvent.target;
-    if (listItem.localName == "richlistbox") {
-        listItem = listItem.selectedItem;
-    }
-    switch (aEvent.key) {
-        case "Enter":
-            document.getElementById("agenda_edit_event_command").doCommand();
-            break;
-        case "Delete":
-            document.getElementById("agenda_delete_event_command").doCommand();
-            aEvent.stopPropagation();
-            aEvent.preventDefault();
-            break;
-        case "ArrowLeft":
-            if (!this.isEventListItem(listItem)) {
-                listItem.getCheckbox().checked = false;
-            }
-            break;
-        case "ArrowRight":
-            if (!this.isEventListItem(listItem)) {
-                listItem.getCheckbox().checked = true;
-            }
-            break;
-    }
+  let listItem = aEvent.target;
+  if (listItem.localName == "richlistbox") {
+    listItem = listItem.selectedItem;
+  }
+  switch (aEvent.key) {
+    case "Enter":
+      document.getElementById("agenda_edit_event_command").doCommand();
+      break;
+    case "Delete":
+      document.getElementById("agenda_delete_event_command").doCommand();
+      aEvent.stopPropagation();
+      aEvent.preventDefault();
+      break;
+    case "ArrowLeft":
+      if (!this.isEventListItem(listItem)) {
+        listItem.getCheckbox().checked = false;
+      }
+      break;
+    case "ArrowRight":
+      if (!this.isEventListItem(listItem)) {
+        listItem.getCheckbox().checked = true;
+      }
+      break;
+  }
 };
 
 /**
  * Calls the event dialog to edit the currently selected item
  */
 agendaListbox.editSelectedItem = function() {
-    let listItem = document.getElementById("agenda-listbox").selectedItem;
-    if (listItem) {
-        modifyEventWithDialog(listItem.occurrence, null, true);
-    }
+  let listItem = document.getElementById("agenda-listbox").selectedItem;
+  if (listItem) {
+    modifyEventWithDialog(listItem.occurrence, null, true);
+  }
 };
 
 /**
  * Finds the appropriate period for the given item, i.e finds "Tomorrow" if the
  * item occurs tomorrow.
  *
  * @param aItem     The item to find the period for.
  */
 agendaListbox.findPeriodsForItem = function(aItem) {
-    let retPeriods = [];
-    for (let i = 0; i < this.periods.length; i++) {
-        if (this.periods[i].open) {
-            if (cal.item.checkIfInRange(aItem, this.periods[i].start, this.periods[i].end)) {
-                retPeriods.push(this.periods[i]);
-            }
-        }
+  let retPeriods = [];
+  for (let i = 0; i < this.periods.length; i++) {
+    if (this.periods[i].open) {
+      if (cal.item.checkIfInRange(aItem, this.periods[i].start, this.periods[i].end)) {
+        retPeriods.push(this.periods[i]);
+      }
     }
-    return retPeriods;
+  }
+  return retPeriods;
 };
 
 /**
  * Gets the start of the earliest period shown in the agenda listbox
  */
 agendaListbox.getStart = function() {
-    let retStart = null;
-    for (let i = 0; i < this.periods.length; i++) {
-        if (this.periods[i].open) {
-            retStart = this.periods[i].start;
-            break;
-        }
+  let retStart = null;
+  for (let i = 0; i < this.periods.length; i++) {
+    if (this.periods[i].open) {
+      retStart = this.periods[i].start;
+      break;
     }
-    return retStart;
+  }
+  return retStart;
 };
 
 /**
  * Gets the end of the latest period shown in the agenda listbox
  */
 agendaListbox.getEnd = function() {
-    let retEnd = null;
-    for (let i = this.periods.length - 1; i >= 0; i--) {
-        if (this.periods[i].open) {
-            retEnd = this.periods[i].end;
-            break;
-        }
+  let retEnd = null;
+  for (let i = this.periods.length - 1; i >= 0; i--) {
+    if (this.periods[i].open) {
+      retEnd = this.periods[i].end;
+      break;
     }
-    return retEnd;
+  }
+  return retEnd;
 };
 
 /**
  * Adds an item to an agenda period before another existing item.
  *
  * @param aNewItem      The calIItemBase to add.
  * @param aAgendaItem   The existing item to insert before.
  * @param aPeriod       The period to add the item to.
  * @param visible       If true, the item should be visible.
  * @return              The newly created XUL element.
  */
 agendaListbox.addItemBefore = function(aNewItem, aAgendaItem, aPeriod, visible) {
-    let newelement = null;
-    if (aNewItem.startDate.isDate) {
-        newelement = document.createXULElement("richlistitem", { is: "agenda-allday-richlist-item" });
-    } else {
-        newelement = document.createXULElement("richlistitem", { is: "agenda-richlist-item" });
-    }
-    // set the item at the richlistItem. When the duration of the period
-    // is bigger than 1 (day) the starttime of the item has to include
-    // information about the day of the item
-    if (aAgendaItem == null) {
-        this.agendaListboxControl.appendChild(newelement);
-    } else {
-        this.agendaListboxControl.insertBefore(newelement, aAgendaItem);
-    }
-    newelement.setOccurrence(aNewItem, aPeriod);
-    newelement.removeAttribute("selected");
-    return newelement;
+  let newelement = null;
+  if (aNewItem.startDate.isDate) {
+    newelement = document.createXULElement("richlistitem", { is: "agenda-allday-richlist-item" });
+  } else {
+    newelement = document.createXULElement("richlistitem", { is: "agenda-richlist-item" });
+  }
+  // set the item at the richlistItem. When the duration of the period
+  // is bigger than 1 (day) the starttime of the item has to include
+  // information about the day of the item
+  if (aAgendaItem == null) {
+    this.agendaListboxControl.appendChild(newelement);
+  } else {
+    this.agendaListboxControl.insertBefore(newelement, aAgendaItem);
+  }
+  newelement.setOccurrence(aNewItem, aPeriod);
+  newelement.removeAttribute("selected");
+  return newelement;
 };
 
 /**
  * Adds an item to the agenda listbox. This function finds the correct period
  * for the item and inserts it correctly so the period stays sorted.
  *
  * @param aItem         The calIItemBase to add.
  * @return              The newly created XUL element.
  */
 agendaListbox.addItem = function(aItem) {
-    if (!cal.item.isEvent(aItem)) {
-        return null;
-    }
-    aItem.QueryInterface(Ci.calIEvent);
-    let periods = this.findPeriodsForItem(aItem);
-    if (periods.length == 0) {
-        return null;
-    }
-    let newlistItem = null;
-    for (let i = 0; i < periods.length; i++) {
-        let period = periods[i];
-        let complistItem = period.listItem;
-        let visible = complistItem.getCheckbox().checked;
-        if (aItem.startDate.isDate && period.duration == 1 && aItem.duration.days == 1) {
-            if (this.getListItems(aItem, period).length == 0) {
-                this.addItemBefore(aItem, period.listItem.nextSibling, period, visible);
+  if (!cal.item.isEvent(aItem)) {
+    return null;
+  }
+  aItem.QueryInterface(Ci.calIEvent);
+  let periods = this.findPeriodsForItem(aItem);
+  if (periods.length == 0) {
+    return null;
+  }
+  let newlistItem = null;
+  for (let i = 0; i < periods.length; i++) {
+    let period = periods[i];
+    let complistItem = period.listItem;
+    let visible = complistItem.getCheckbox().checked;
+    if (aItem.startDate.isDate && period.duration == 1 && aItem.duration.days == 1) {
+      if (this.getListItems(aItem, period).length == 0) {
+        this.addItemBefore(aItem, period.listItem.nextSibling, period, visible);
+      }
+    } else {
+      do {
+        complistItem = complistItem.nextSibling;
+        if (this.isEventListItem(complistItem)) {
+          let compitem = complistItem.occurrence;
+          if (this.isSameEvent(aItem, compitem)) {
+            // The same event occurs on several calendars but we only
+            // display the first one.
+            // TODO: find a way to display this special circumstance
+            break;
+          } else if (this.isBefore(aItem, compitem, period)) {
+            if (this.isSameEvent(aItem, compitem)) {
+              newlistItem = this.addItemBefore(aItem, complistItem, period, visible);
+              break;
+            } else {
+              newlistItem = this.addItemBefore(aItem, complistItem, period, visible);
+              break;
             }
+          }
         } else {
-            do {
-                complistItem = complistItem.nextSibling;
-                if (this.isEventListItem(complistItem)) {
-                    let compitem = complistItem.occurrence;
-                    if (this.isSameEvent(aItem, compitem)) {
-                        // The same event occurs on several calendars but we only
-                        // display the first one.
-                        // TODO: find a way to display this special circumstance
-                        break;
-                    } else if (this.isBefore(aItem, compitem, period)) {
-                        if (this.isSameEvent(aItem, compitem)) {
-                            newlistItem = this.addItemBefore(aItem, complistItem, period, visible);
-                            break;
-                        } else {
-                            newlistItem = this.addItemBefore(aItem, complistItem, period, visible);
-                            break;
-                        }
-                    }
-                } else {
-                    newlistItem = this.addItemBefore(aItem, complistItem, period, visible);
-                    break;
-                }
-            } while (complistItem);
+          newlistItem = this.addItemBefore(aItem, complistItem, period, visible);
+          break;
         }
+      } while (complistItem);
     }
-    return newlistItem;
+  }
+  return newlistItem;
 };
 
 /**
  * Checks if the given item happens before the comparison item.
  *
  * @param aItem         The item to compare.
  * @param aCompItem     The item to compare with.
  * @param aPeriod       The period where the items are inserted.
  * @return              True, if the aItem happens before aCompItem.
  */
 agendaListbox.isBefore = function(aItem, aCompItem, aPeriod) {
-    let itemDate = this.comparisonDate(aItem, aPeriod);
-    let compItemDate = this.comparisonDate(aCompItem, aPeriod);
-    let itemDateEndDate = itemDate.clone();
-    itemDateEndDate.day++;
+  let itemDate = this.comparisonDate(aItem, aPeriod);
+  let compItemDate = this.comparisonDate(aCompItem, aPeriod);
+  let itemDateEndDate = itemDate.clone();
+  itemDateEndDate.day++;
 
-    if (compItemDate.day == itemDate.day) {
-        // In the same day the order is:
-        // - all-day events (single day);
-        // - all-day events spanning multiple days: start, end, intermediate;
-        // - events and events spanning multiple days: start, end, (sorted by
-        //   time) and intermediate.
-        if (itemDate.isDate && aItem.duration.days == 1) {
-            // all-day events with duration one day
-            return true;
-        } else if (itemDate.isDate) {
-            if (aItem.startDate.compare(itemDate) == 0) {
-                // starting day of an all-day events spannig multiple days
-                return !compItemDate.isDate || aCompItem.duration.days != 1;
-            } else if (aItem.endDate.compare(itemDateEndDate) == 0) {
-                // ending day of an all-day events spannig multiple days
-                return !compItemDate.isDate ||
-                       (aCompItem.duration.days != 1 &&
-                        aCompItem.startDate.compare(compItemDate) != 0);
-            } else {
-                // intermediate day of an all-day events spannig multiple days
-                return !compItemDate.isDate;
-            }
-        } else if (aCompItem.startDate.isDate) {
-            return false;
-        }
+  if (compItemDate.day == itemDate.day) {
+    // In the same day the order is:
+    // - all-day events (single day);
+    // - all-day events spanning multiple days: start, end, intermediate;
+    // - events and events spanning multiple days: start, end, (sorted by
+    //   time) and intermediate.
+    if (itemDate.isDate && aItem.duration.days == 1) {
+      // all-day events with duration one day
+      return true;
+    } else if (itemDate.isDate) {
+      if (aItem.startDate.compare(itemDate) == 0) {
+        // starting day of an all-day events spannig multiple days
+        return !compItemDate.isDate || aCompItem.duration.days != 1;
+      } else if (aItem.endDate.compare(itemDateEndDate) == 0) {
+        // ending day of an all-day events spannig multiple days
+        return (
+          !compItemDate.isDate ||
+          (aCompItem.duration.days != 1 && aCompItem.startDate.compare(compItemDate) != 0)
+        );
+      } else {
+        // intermediate day of an all-day events spannig multiple days
+        return !compItemDate.isDate;
+      }
+    } else if (aCompItem.startDate.isDate) {
+      return false;
     }
-    // Non all-day event sorted by date-time. When equal, sorted by start
-    // date-time then by end date-time.
-    let comp = itemDate.compare(compItemDate);
+  }
+  // Non all-day event sorted by date-time. When equal, sorted by start
+  // date-time then by end date-time.
+  let comp = itemDate.compare(compItemDate);
+  if (comp == 0) {
+    comp = aItem.startDate.compare(aCompItem.startDate);
     if (comp == 0) {
-        comp = aItem.startDate.compare(aCompItem.startDate);
-        if (comp == 0) {
-            comp = aItem.endDate.compare(aCompItem.endDate);
-        }
+      comp = aItem.endDate.compare(aCompItem.endDate);
     }
-    return (comp <= 0);
+  }
+  return comp <= 0;
 };
 
 /**
  * Returns the start or end date of an item according to which of them
  * must be displayed in a given period of the agenda
  *
  * @param aItem         The item to compare.
  * @param aPeriod       The period where the item is inserted.
  * @return              The start or end date of the item showed in the agenda.
  */
 agendaListbox.comparisonDate = function(aItem, aPeriod) {
-    let periodStartDate = aPeriod.start.clone();
-    periodStartDate.isDate = true;
-    let periodEndDate = aPeriod.end.clone();
-    periodEndDate.day--;
-    let startDate = aItem.startDate.clone();
-    startDate.isDate = true;
-    let endDate = aItem.endDate.clone();
+  let periodStartDate = aPeriod.start.clone();
+  periodStartDate.isDate = true;
+  let periodEndDate = aPeriod.end.clone();
+  periodEndDate.day--;
+  let startDate = aItem.startDate.clone();
+  startDate.isDate = true;
+  let endDate = aItem.endDate.clone();
 
-    let endDateToReturn = aItem.endDate.clone();
-    if (aItem.startDate.isDate && aPeriod.duration == 1) {
-        endDateToReturn = periodEndDate.clone();
-    } else if (endDate.isDate) {
-        endDateToReturn.day--;
-    } else if (endDate.hour == 0 && endDate.minute == 0) {
-        // End at midnight -> end date in the day where midnight occurs
-        endDateToReturn.day--;
-        endDateToReturn.hour = 23;
-        endDateToReturn.minute = 59;
-        endDateToReturn.second = 59;
-    }
-    endDate.isDate = true;
-    if (startDate.compare(endDate) != 0 &&
-         startDate.compare(periodStartDate) < 0) {
-        // returns a end date when the item is a multiday event AND
-        // it starts before the given period
-        return endDateToReturn;
-    }
-    return aItem.startDate.clone();
+  let endDateToReturn = aItem.endDate.clone();
+  if (aItem.startDate.isDate && aPeriod.duration == 1) {
+    endDateToReturn = periodEndDate.clone();
+  } else if (endDate.isDate) {
+    endDateToReturn.day--;
+  } else if (endDate.hour == 0 && endDate.minute == 0) {
+    // End at midnight -> end date in the day where midnight occurs
+    endDateToReturn.day--;
+    endDateToReturn.hour = 23;
+    endDateToReturn.minute = 59;
+    endDateToReturn.second = 59;
+  }
+  endDate.isDate = true;
+  if (startDate.compare(endDate) != 0 && startDate.compare(periodStartDate) < 0) {
+    // returns a end date when the item is a multiday event AND
+    // it starts before the given period
+    return endDateToReturn;
+  }
+  return aItem.startDate.clone();
 };
 
 /**
  * Gets the listitems for a given item, possibly in a given period.
  *
  * @param aItem         The item to get the list items for.
  * @param aPeriod       (optional) the period to search in.
  * @return              An array of list items for the given item.
  */
 agendaListbox.getListItems = function(aItem, aPeriod) {
-    let retlistItems = [];
-    let periods = [aPeriod];
-    if (!aPeriod) {
-        periods = this.findPeriodsForItem(aItem);
+  let retlistItems = [];
+  let periods = [aPeriod];
+  if (!aPeriod) {
+    periods = this.findPeriodsForItem(aItem);
+  }
+  if (periods.length > 0) {
+    for (let i = 0; i < periods.length; i++) {
+      let period = periods[i];
+      let complistItem = period.listItem;
+      let leaveloop;
+      do {
+        complistItem = complistItem.nextSibling;
+        leaveloop = !this.isEventListItem(complistItem);
+        if (!leaveloop) {
+          if (this.isSameEvent(aItem, complistItem.occurrence)) {
+            retlistItems.push(complistItem);
+            break;
+          }
+        }
+      } while (!leaveloop);
     }
-    if (periods.length > 0) {
-        for (let i = 0; i < periods.length; i++) {
-            let period = periods[i];
-            let complistItem = period.listItem;
-            let leaveloop;
-            do {
-                complistItem = complistItem.nextSibling;
-                leaveloop = !this.isEventListItem(complistItem);
-                if (!leaveloop) {
-                    if (this.isSameEvent(aItem, complistItem.occurrence)) {
-                        retlistItems.push(complistItem);
-                        break;
-                    }
-                }
-            } while (!leaveloop);
-        }
-    }
-    return retlistItems;
+  }
+  return retlistItems;
 };
 
 /**
  * Removes the given item from the agenda listbox
  *
  * @param aItem             The item to remove.
  * @param aMoveSelection    If true, the selection will be moved to the next
  *                            sibling that is not an period item.
  * @return                  Returns true if the removed item was selected.
  */
 agendaListbox.deleteItem = function(aItem, aMoveSelection) {
-    let isSelected = false;
-    let listItems = this.getListItems(aItem);
-    if (listItems.length > 0) {
-        for (let i = listItems.length - 1; i >= 0; i--) {
-            let listItem = listItems[i];
-            let isSelected2 = listItem.selected;
-            if (isSelected2 && !isSelected) {
-                isSelected = true;
-                if (aMoveSelection) {
-                    this.moveSelection();
-                }
-            }
-            listItem.remove();
+  let isSelected = false;
+  let listItems = this.getListItems(aItem);
+  if (listItems.length > 0) {
+    for (let i = listItems.length - 1; i >= 0; i--) {
+      let listItem = listItems[i];
+      let isSelected2 = listItem.selected;
+      if (isSelected2 && !isSelected) {
+        isSelected = true;
+        if (aMoveSelection) {
+          this.moveSelection();
         }
+      }
+      listItem.remove();
     }
-    return isSelected;
+  }
+  return isSelected;
 };
 
 /**
  * Remove all items belonging to the specified calendar.
  *
  * @param aCalendar         The item to compare.
  */
 agendaListbox.deleteItemsFromCalendar = function(aCalendar) {
-    let childNodes = Array.from(this.agendaListboxControl.childNodes);
-    for (let childNode of childNodes) {
-        if (childNode && childNode.occurrence &&
-            childNode.occurrence.calendar.id == aCalendar.id) {
-            childNode.remove();
-        }
+  let childNodes = Array.from(this.agendaListboxControl.childNodes);
+  for (let childNode of childNodes) {
+    if (childNode && childNode.occurrence && childNode.occurrence.calendar.id == aCalendar.id) {
+      childNode.remove();
     }
+  }
 };
 
 /**
  * Compares two items to see if they have the same id and their start date
  * matches
  *
  * @param aItem         The item to compare.
  * @param aCompItem     The item to compare with.
  * @return              True, if the items match with the above noted criteria.
  */
 agendaListbox.isSameEvent = function(aItem, aCompItem) {
-    return aItem.id == aCompItem.id &&
-           aItem[cal.dtz.startDateProp(aItem)].compare(aCompItem[cal.dtz.startDateProp(aCompItem)]) == 0;
+  return (
+    aItem.id == aCompItem.id &&
+    aItem[cal.dtz.startDateProp(aItem)].compare(aCompItem[cal.dtz.startDateProp(aCompItem)]) == 0
+  );
 };
 
 /**
  * Checks if the currently selected node in the listbox is an Event item (not a
  * period item).
  *
  * @return              True, if the node is not a period item.
  */
 agendaListbox.isEventSelected = function() {
-    let listItem = this.agendaListboxControl.selectedItem;
-    if (listItem) {
-        return this.isEventListItem(listItem);
-    }
-    return false;
+  let listItem = this.agendaListboxControl.selectedItem;
+  if (listItem) {
+    return this.isEventListItem(listItem);
+  }
+  return false;
 };
 
 /**
  * Delete the selected item from its calendar (if it is an event item)
  *
  * @param aDoNotConfirm     If true, the user will not be prompted.
  */
 agendaListbox.deleteSelectedItem = function(aDoNotConfirm) {
-    let listItem = this.agendaListboxControl.selectedItem;
-    if (this.isEventListItem(listItem)) {
-        let selectedItems = [listItem.occurrence];
-        calendarViewController.deleteOccurrences(selectedItems.length,
-                                                 selectedItems,
-                                                 false,
-                                                 aDoNotConfirm);
-    }
+  let listItem = this.agendaListboxControl.selectedItem;
+  if (this.isEventListItem(listItem)) {
+    let selectedItems = [listItem.occurrence];
+    calendarViewController.deleteOccurrences(
+      selectedItems.length,
+      selectedItems,
+      false,
+      aDoNotConfirm
+    );
+  }
 };
 
 /**
  * If a Period item is targeted by the passed DOM event, opens the event dialog
  * with the period's start date prefilled.
  *
  * @param aEvent            The DOM event that targets the period.
  */
 agendaListbox.createNewEvent = function(aEvent) {
-    if (!this.isEventListItem(aEvent.target)) {
-        // Create new event for the date currently displayed in the agenda. Setting
-        // isDate = true automatically makes the start time be the next full hour.
-        let eventStart = agendaListbox.today.start.clone();
-        eventStart.isDate = true;
-        if (calendarController.isCommandEnabled("calendar_new_event_command")) {
-            createEventWithDialog(getSelectedCalendar(), eventStart);
-        }
+  if (!this.isEventListItem(aEvent.explicitOriginalTarget)) {
+    // Create new event for the date currently displayed in the agenda. Setting
+    // isDate = true automatically makes the start time be the next full hour.
+    let eventStart = agendaListbox.today.start.clone();
+    eventStart.isDate = true;
+    if (calendarController.isCommandEnabled("calendar_new_event_command")) {
+      createEventWithDialog(getSelectedCalendar(), eventStart);
     }
+  }
 };
 
 /**
  * Sets up the context menu for the agenda listbox
  *
  * @param popup         The <menupopup> element to set up.
  */
 agendaListbox.setupContextMenu = function(popup) {
-    let listItem = this.agendaListboxControl.selectedItem;
-    let enabled = this.isEventListItem(listItem);
-    let menuitems = popup.childNodes;
-    for (let i = 0; i < menuitems.length; i++) {
-        setBooleanAttribute(menuitems[i], "disabled", !enabled);
-    }
+  let listItem = this.agendaListboxControl.selectedItem;
+  let enabled = this.isEventListItem(listItem);
+  let menuitems = popup.childNodes;
+  for (let i = 0; i < menuitems.length; i++) {
+    setBooleanAttribute(menuitems[i], "disabled", !enabled);
+  }
 
-    let menu = document.getElementById("calendar-today-pane-menu-attendance-menu");
-    setupAttendanceMenu(menu, agendaListbox.getSelectedItems({}));
+  let menu = document.getElementById("calendar-today-pane-menu-attendance-menu");
+  setupAttendanceMenu(menu, agendaListbox.getSelectedItems({}));
 };
 
-
 /**
  * Refreshes the agenda listbox. If aStart or aEnd is not passed, the agenda
  * listbox's limiting dates will be used.
  *
  * @param aStart        (optional) The start date for the item query.
  * @param aEnd          (optional) The end date for the item query.
  * @param aCalendar     (optional) If specified, the single calendar from
  *                                   which the refresh will occur.
  */
 agendaListbox.refreshCalendarQuery = function(aStart, aEnd, aCalendar) {
-    let refreshJob = {
-        QueryInterface: ChromeUtils.generateQI([Ci.calIOperationListener]),
-        agendaListbox: this,
-        calendar: null,
-        calId: null,
-        operation: null,
-        cancelled: false,
+  let refreshJob = {
+    QueryInterface: ChromeUtils.generateQI([Ci.calIOperationListener]),
+    agendaListbox: this,
+    calendar: null,
+    calId: null,
+    operation: null,
+    cancelled: false,
 
-        onOperationComplete: function(aOpCalendar, aStatus, aOperationType, aId, aDateTime) {
-            if (this.agendaListbox.mPendingRefreshJobs.has(this.calId)) {
-                this.agendaListbox.mPendingRefreshJobs.delete(this.calId);
-            }
+    onOperationComplete: function(aOpCalendar, aStatus, aOperationType, aId, aDateTime) {
+      if (this.agendaListbox.mPendingRefreshJobs.has(this.calId)) {
+        this.agendaListbox.mPendingRefreshJobs.delete(this.calId);
+      }
 
-            if (!this.cancelled) {
-                setCurrentEvent();
-            }
-        },
+      if (!this.cancelled) {
+        setCurrentEvent();
+      }
+    },
 
-        onGetResult: function(aOpCalendar, aStatus, aItemType, aDetail, aCount, aItems) {
-            if (this.cancelled || !Components.isSuccessCode(aStatus)) {
-                return;
-            }
-            for (let item of aItems) {
-                this.agendaListbox.addItem(item);
-            }
-        },
+    onGetResult: function(aOpCalendar, aStatus, aItemType, aDetail, aCount, aItems) {
+      if (this.cancelled || !Components.isSuccessCode(aStatus)) {
+        return;
+      }
+      for (let item of aItems) {
+        this.agendaListbox.addItem(item);
+      }
+    },
 
-        cancel: function() {
-            this.cancelled = true;
-            let operation = cal.wrapInstance(this.operation, Ci.calIOperation);
-            if (operation && operation.isPending) {
-                operation.cancel();
-                this.operation = null;
-            }
-        },
+    cancel: function() {
+      this.cancelled = true;
+      let operation = cal.wrapInstance(this.operation, Ci.calIOperation);
+      if (operation && operation.isPending) {
+        operation.cancel();
+        this.operation = null;
+      }
+    },
 
-        execute: function() {
-            if (!(aStart || aEnd || aCalendar)) {
-                this.agendaListbox.removeListItems();
-            }
+    execute: function() {
+      if (!(aStart || aEnd || aCalendar)) {
+        this.agendaListbox.removeListItems();
+      }
 
-            if (!aCalendar) {
-                aCalendar = this.agendaListbox.calendar;
-            }
-            if (!aStart) {
-                aStart = this.agendaListbox.getStart();
-            }
-            if (!aEnd) {
-                aEnd = this.agendaListbox.getEnd();
-            }
-            if (!(aStart || aEnd || aCalendar)) {
-                return;
-            }
+      if (!aCalendar) {
+        aCalendar = this.agendaListbox.calendar;
+      }
+      if (!aStart) {
+        aStart = this.agendaListbox.getStart();
+      }
+      if (!aEnd) {
+        aEnd = this.agendaListbox.getEnd();
+      }
+      if (!(aStart || aEnd || aCalendar)) {
+        return;
+      }
 
-            if (aCalendar.type == "composite") {
-                // we're refreshing from the composite calendar, so we can cancel
-                // all other pending refresh jobs.
-                this.calId = "composite";
-                for (let job of this.agendaListbox.mPendingRefreshJobs.values()) {
-                    job.cancel();
-                }
-                this.agendaListbox.mPendingRefreshJobs.clear();
-            } else {
-                this.calId = aCalendar.id;
-                if (this.agendaListbox.mPendingRefreshJobs.has(this.calId)) {
-                    this.agendaListbox.mPendingRefreshJobs.get(this.calId).cancel();
-                    this.agendaListbox.mPendingRefreshJobs.delete(this.calId);
-                }
-            }
-            this.calendar = aCalendar;
+      if (aCalendar.type == "composite") {
+        // we're refreshing from the composite calendar, so we can cancel
+        // all other pending refresh jobs.
+        this.calId = "composite";
+        for (let job of this.agendaListbox.mPendingRefreshJobs.values()) {
+          job.cancel();
+        }
+        this.agendaListbox.mPendingRefreshJobs.clear();
+      } else {
+        this.calId = aCalendar.id;
+        if (this.agendaListbox.mPendingRefreshJobs.has(this.calId)) {
+          this.agendaListbox.mPendingRefreshJobs.get(this.calId).cancel();
+          this.agendaListbox.mPendingRefreshJobs.delete(this.calId);
+        }
+      }
+      this.calendar = aCalendar;
 
-            let filter = this.calendar.ITEM_FILTER_CLASS_OCCURRENCES |
-                         this.calendar.ITEM_FILTER_TYPE_EVENT;
-            let operation = this.calendar.getItems(filter, 0, aStart, aEnd, this);
-            operation = cal.wrapInstance(operation, Ci.calIOperation);
-            if (operation && operation.isPending) {
-                this.operation = operation;
-                this.agendaListbox.mPendingRefreshJobs.set(this.calId, this);
-            }
-        }
-    };
+      let filter =
+        this.calendar.ITEM_FILTER_CLASS_OCCURRENCES | this.calendar.ITEM_FILTER_TYPE_EVENT;
+      let operation = this.calendar.getItems(filter, 0, aStart, aEnd, this);
+      operation = cal.wrapInstance(operation, Ci.calIOperation);
+      if (operation && operation.isPending) {
+        this.operation = operation;
+        this.agendaListbox.mPendingRefreshJobs.set(this.calId, this);
+      }
+    },
+  };
 
-    this.setupCalendar();
-    refreshJob.execute();
+  this.setupCalendar();
+  refreshJob.execute();
 };
 
 /**
  * Sets up the calendar for the agenda listbox.
  */
 agendaListbox.setupCalendar = function() {
-    if (this.calendar == null) {
-        this.calendar = cal.view.getCompositeCalendar(window);
-        this.calendar.addObserver(this.calendarObserver);
-    }
+  if (this.calendar == null) {
+    this.calendar = cal.view.getCompositeCalendar(window);
+    this.calendar.addObserver(this.calendarObserver);
+  }
 };
 
 /**
  * Refreshes the period dates, especially when a period is showing "today".
  * Usually called at midnight to update the agenda pane. Also retrieves the
  * items from the calendar.
  *
  * @see #refreshCalendarQuery
  * @param newDate       The first date to show if the agenda pane doesn't show
  *                        today.
  */
 agendaListbox.refreshPeriodDates = function(newDate) {
-    this.kDefaultTimezone = cal.dtz.defaultTimezone;
-    // Today: now until midnight of tonight
-    let oldshowstoday = this.showstoday;
-    this.showstoday = this.showsToday(newDate);
-    if ((this.showstoday) && (!oldshowstoday)) {
-        this.addPeriodListItem(this.tomorrow, "tomorrow-header");
-        this.addPeriodListItem(this.soon, "nextweek-header");
-    } else if (!this.showstoday) {
-        this.removePeriodListItem(this.tomorrow);
-        this.removePeriodListItem(this.soon);
+  this.kDefaultTimezone = cal.dtz.defaultTimezone;
+  // Today: now until midnight of tonight
+  let oldshowstoday = this.showstoday;
+  this.showstoday = this.showsToday(newDate);
+  if (this.showstoday && !oldshowstoday) {
+    this.addPeriodListItem(this.tomorrow, "tomorrow-header");
+    this.addPeriodListItem(this.soon, "nextweek-header");
+  } else if (!this.showstoday) {
+    this.removePeriodListItem(this.tomorrow);
+    this.removePeriodListItem(this.soon);
+  }
+  newDate.isDate = true;
+  for (let i = 0; i < this.periods.length; i++) {
+    let curPeriod = this.periods[i];
+    newDate.hour = newDate.minute = newDate.second = 0;
+    if (i == 0 && this.showstoday) {
+      curPeriod.start = cal.dtz.now();
+    } else {
+      curPeriod.start = newDate.clone();
     }
-    newDate.isDate = true;
-    for (let i = 0; i < this.periods.length; i++) {
-        let curPeriod = this.periods[i];
-        newDate.hour = newDate.minute = newDate.second = 0;
-        if (i == 0 && this.showstoday) {
-            curPeriod.start = cal.dtz.now();
-        } else {
-            curPeriod.start = newDate.clone();
-        }
-        newDate.day += curPeriod.duration;
-        curPeriod.end = newDate.clone();
-        curPeriod.listItem.setItem(curPeriod, this.showstoday);
-    }
-    this.refreshCalendarQuery();
+    newDate.day += curPeriod.duration;
+    curPeriod.end = newDate.clone();
+    curPeriod.listItem.setItem(curPeriod, this.showstoday);
+  }
+  this.refreshCalendarQuery();
 };
 
 /**
  * Checks if the agenda listbox is showing "today". Without arguments, this
  * function assumes the today attribute of the agenda listbox.
  *
  * @param aStartDate    (optional) The day to check if its "today".
  * @return              Returns true if today is shown.
  */
 agendaListbox.showsToday = function(aStartDate) {
-    let lstart = aStartDate;
-    if (!lstart) {
-        lstart = this.today.start;
-    }
-    let lshowsToday = cal.dtz.sameDay(cal.dtz.now(), lstart);
-    if (lshowsToday) {
-        this.periods = [this.today, this.tomorrow, this.soon];
-    } else {
-        this.periods = [this.today];
-    }
-    return lshowsToday;
+  let lstart = aStartDate;
+  if (!lstart) {
+    lstart = this.today.start;
+  }
+  let lshowsToday = cal.dtz.sameDay(cal.dtz.now(), lstart);
+  if (lshowsToday) {
+    this.periods = [this.today, this.tomorrow, this.soon];
+  } else {
+    this.periods = [this.today];
+  }
+  return lshowsToday;
 };
 
 /**
  * Moves the selection. Moves down unless the next item is a period item, in
  * which case the selection moves up.
  */
 agendaListbox.moveSelection = function() {
-    if (this.isEventListItem(this.agendaListboxControl.selectedItem.nextSibling)) {
-        this.agendaListboxControl.moveByOffset(-1);
-    } else {
-        this.agendaListboxControl.moveByOffset(1);
-    }
+  if (this.isEventListItem(this.agendaListboxControl.selectedItem.nextSibling)) {
+    this.agendaListboxControl.moveByOffset(-1);
+  } else {
+    this.agendaListboxControl.moveByOffset(1);
+  }
 };
 
 /**
  * Gets an array of selected items. If a period node is selected, it is not
  * included.
  *
  * @return      An array with all selected items.
  */
 agendaListbox.getSelectedItems = function() {
-    let items = [];
-    if (this.isEventListItem(this.agendaListboxControl.selectedItem)) {
-        // If at some point we support selecting multiple items, this array can
-        // be expanded.
-        items = [this.agendaListboxControl.selectedItem.occurrence];
-    }
-    return items;
+  let items = [];
+  if (this.isEventListItem(this.agendaListboxControl.selectedItem)) {
+    // If at some point we support selecting multiple items, this array can
+    // be expanded.
+    items = [this.agendaListboxControl.selectedItem.occurrence];
+  }
+  return items;
 };
 
 /**
  * Checks if the passed node in the listbox is an Event item (not a
  * period item).
  *
  * @param aListItem     The node to check for.
  * @return              True, if the node is not a period item.
  */
 agendaListbox.isEventListItem = function(aListItem) {
-    let isListItem = (aListItem != null);
-    if (isListItem) {
-        let localName = aListItem.getAttribute("is");
-        isListItem = (localName == "agenda-richlist-item" ||
-                      localName == "agenda-allday-richlist-item");
-    }
-    return isListItem;
+  let isListItem = aListItem != null;
+  if (isListItem) {
+    let localName = aListItem.getAttribute("is");
+    isListItem = localName == "agenda-richlist-item" || localName == "agenda-allday-richlist-item";
+  }
+  return isListItem;
 };
 
 /**
  * Removes all Event items, keeping the period items intact.
  */
 agendaListbox.removeListItems = function() {
-    let listItem = this.agendaListboxControl.lastChild;
-    if (listItem) {
-        let leaveloop = false;
-        do {
-            let newlistItem = null;
-            if (listItem) {
-                newlistItem = listItem.previousSibling;
-            } else {
-                leaveloop = true;
-            }
-            if (this.isEventListItem(listItem)) {
-                if (listItem == this.agendaListboxControl.firstChild) {
-                    leaveloop = true;
-                } else {
-                    listItem.remove();
-                }
-            }
-            listItem = newlistItem;
-        } while (!leaveloop);
-    }
+  let listItem = this.agendaListboxControl.lastChild;
+  if (listItem) {
+    let leaveloop = false;
+    do {
+      let newlistItem = null;
+      if (listItem) {
+        newlistItem = listItem.previousSibling;
+      } else {
+        leaveloop = true;
+      }
+      if (this.isEventListItem(listItem)) {
+        if (listItem == this.agendaListboxControl.firstChild) {
+          leaveloop = true;
+        } else {
+          listItem.remove();
+        }
+      }
+      listItem = newlistItem;
+    } while (!leaveloop);
+  }
 };
 
 /**
  * Gets the list item node by its associated event's hashId.
  *
  * @return The XUL node if successful, otherwise null.
  */
 agendaListbox.getListItemByHashId = function(ahashId) {
-    let listItem = this.agendaListboxControl.firstChild;
-    let leaveloop = false;
-    do {
-        if (this.isEventListItem(listItem)) {
-            if (listItem.occurrence.hashId == ahashId) {
-                return listItem;
-            }
-        }
-        listItem = listItem.nextSibling;
-        leaveloop = (listItem == null);
-    } while (!leaveloop);
-    return null;
+  let listItem = this.agendaListboxControl.firstChild;
+  let leaveloop = false;
+  do {
+    if (this.isEventListItem(listItem)) {
+      if (listItem.occurrence.hashId == ahashId) {
+        return listItem;
+      }
+    }
+    listItem = listItem.nextSibling;
+    leaveloop = listItem == null;
+  } while (!leaveloop);
+  return null;
 };
 
 /**
  * The operation listener used for calendar queries.
  * Implements calIOperationListener.
  */
 agendaListbox.calendarOpListener = { agendaListbox: agendaListbox };
 
 /**
  * Calendar and composite observer, used to keep agenda listbox up to date.
  * @see calIObserver
  * @see calICompositeObserver
  */
 agendaListbox.calendarObserver = { agendaListbox: agendaListbox };
 
 agendaListbox.calendarObserver.QueryInterface = cal.generateQI([
-    Ci.calIObserver,
-    Ci.calICompositeObserver
+  Ci.calIObserver,
+  Ci.calICompositeObserver,
 ]);
 
 // calIObserver:
 agendaListbox.calendarObserver.onStartBatch = function() {
+  this.needsRefresh = true;
 };
 
-agendaListbox.calendarObserver.onEndBatch = function() {
-};
+agendaListbox.calendarObserver.onEndBatch = function() {};
 
 agendaListbox.calendarObserver.onLoad = function() {
-    this.agendaListbox.refreshCalendarQuery();
+  this.needsRefresh = false;
+  this.agendaListbox.refreshCalendarQuery();
 };
 
 agendaListbox.calendarObserver.onAddItem = function(item) {
-    if (!cal.item.isEvent(item)) {
-        return;
-    }
-    // get all sub items if it is a recurring item
-    let occs = this.getOccurrencesBetween(item);
-    occs.forEach(this.agendaListbox.addItem, this.agendaListbox);
-    setCurrentEvent();
+  if (this.needsRefresh || !cal.item.isEvent(item)) {
+    return;
+  }
+  // get all sub items if it is a recurring item
+  let occs = this.getOccurrencesBetween(item);
+  occs.forEach(this.agendaListbox.addItem, this.agendaListbox);
+  setCurrentEvent();
 };
 
 agendaListbox.calendarObserver.getOccurrencesBetween = function(aItem) {
-    let occs = [];
-    let start = this.agendaListbox.getStart();
-    let end = this.agendaListbox.getEnd();
-    if (start && end) {
-        occs = aItem.getOccurrencesBetween(start, end, {});
-    }
-    return occs;
+  let occs = [];
+  let start = this.agendaListbox.getStart();
+  let end = this.agendaListbox.getEnd();
+  if (start && end) {
+    occs = aItem.getOccurrencesBetween(start, end, {});
+  }
+  return occs;
 };
 
 agendaListbox.calendarObserver.onDeleteItem = function(item, rebuildFlag) {
-    this.onLocalDeleteItem(item, true);
+  this.onLocalDeleteItem(item, true);
 };
 
 agendaListbox.calendarObserver.onLocalDeleteItem = function(item, moveSelection) {
-    if (!cal.item.isEvent(item)) {
-        return false;
+  if (!cal.item.isEvent(item)) {
+    return false;
+  }
+  let selectedItemHashId = -1;
+  // get all sub items if it is a recurring item
+  let occs = this.getOccurrencesBetween(item);
+  for (let i = 0; i < occs.length; i++) {
+    let isSelected = this.agendaListbox.deleteItem(occs[i], moveSelection);
+    if (isSelected) {
+      selectedItemHashId = occs[i].hashId;
     }
-    let selectedItemHashId = -1;
-    // get all sub items if it is a recurring item
-    let occs = this.getOccurrencesBetween(item);
-    for (let i = 0; i < occs.length; i++) {
-        let isSelected = this.agendaListbox.deleteItem(occs[i], moveSelection);
-        if (isSelected) {
-            selectedItemHashId = occs[i].hashId;
-        }
-    }
-    return selectedItemHashId;
+  }
+  return selectedItemHashId;
 };
 
 agendaListbox.calendarObserver.onModifyItem = function(newItem, oldItem) {
-    let selectedItemHashId = this.onLocalDeleteItem(oldItem, false);
-    if (!cal.item.isEvent(newItem)) {
-        return;
+  let selectedItemHashId = this.onLocalDeleteItem(oldItem, false);
+  if (!cal.item.isEvent(newItem)) {
+    return;
+  }
+  this.onAddItem(newItem);
+  if (selectedItemHashId != -1) {
+    let listItem = agendaListbox.getListItemByHashId(selectedItemHashId);
+    if (listItem) {
+      agendaListbox.agendaListboxControl.clearSelection();
+      agendaListbox.agendaListboxControl.ensureElementIsVisible(listItem);
+      agendaListbox.agendaListboxControl.selectedItem = listItem;
     }
-    this.onAddItem(newItem);
-    if (selectedItemHashId != -1) {
-        let listItem = agendaListbox.getListItemByHashId(selectedItemHashId);
-        if (listItem) {
-            agendaListbox.agendaListboxControl.clearSelection();
-            agendaListbox.agendaListboxControl.ensureElementIsVisible(listItem);
-            agendaListbox.agendaListboxControl.selectedItem = listItem;
-        }
-    }
-    setCurrentEvent();
+  }
+  setCurrentEvent();
 };
 
 agendaListbox.calendarObserver.onError = function(_cal, errno, msg) {};
 
 agendaListbox.calendarObserver.onPropertyChanged = function(aCalendar, aName, aValue, aOldValue) {
-    switch (aName) {
-        case "disabled":
-            this.agendaListbox.refreshCalendarQuery();
-            break;
-        case "color":
-            for (let node = agendaListbox.agendaListboxControl.firstChild;
-                 node;
-                 node = node.nextSibling) {
-                // Change color on all nodes that don't do so themselves, which
-                // is currently only he agenda-richlist-item
-                if (node.localName != "agenda-richlist-item") {
-                    continue;
-                }
-                node.refreshColor();
-            }
-            break;
-    }
+  switch (aName) {
+    case "disabled":
+      this.agendaListbox.refreshCalendarQuery();
+      break;
+    case "color":
+      for (
+        let node = agendaListbox.agendaListboxControl.firstChild;
+        node;
+        node = node.nextSibling
+      ) {
+        // Change color on all nodes that don't do so themselves, which
+        // is currently only he agenda-richlist-item
+        if (node.localName != "agenda-richlist-item") {
+          continue;
+        }
+        node.refreshColor();
+      }
+      break;
+  }
 };
 
 agendaListbox.calendarObserver.onPropertyDeleting = function(aCalendar, aName) {
-    this.onPropertyChanged(aCalendar, aName, null, null);
+  this.onPropertyChanged(aCalendar, aName, null, null);
 };
 
-
 agendaListbox.calendarObserver.onCalendarRemoved = function(aCalendar) {
-    if (!aCalendar.getProperty("disabled")) {
-        this.agendaListbox.deleteItemsFromCalendar(aCalendar);
-    }
+  if (!aCalendar.getProperty("disabled")) {
+    this.agendaListbox.deleteItemsFromCalendar(aCalendar);
+  }
 };
 
 agendaListbox.calendarObserver.onCalendarAdded = function(aCalendar) {
-    if (!aCalendar.getProperty("disabled")) {
-        this.agendaListbox.refreshCalendarQuery(null, null, aCalendar);
-    }
+  if (!aCalendar.getProperty("disabled")) {
+    this.agendaListbox.refreshCalendarQuery(null, null, aCalendar);
+  }
 };
 
-agendaListbox.calendarObserver.onDefaultCalendarChanged = function(aCalendar) {
-};
+agendaListbox.calendarObserver.onDefaultCalendarChanged = function(aCalendar) {};
 
 /**
  * Updates the "Upcoming" section of today pane when preference soondays changes
  **/
 agendaListbox.updateSoonSection = function() {
-    this.soon.duration = this.soonDays;
-    this.soon.open = true;
-    let soonHeader = document.getElementById("nextweek-header");
-    if (soonHeader) {
-        soonHeader.setItem(this.soon, true);
-        agendaListbox.refreshPeriodDates(cal.dtz.now());
-    }
+  this.soon.duration = this.soonDays;
+  this.soon.open = true;
+  let soonHeader = document.getElementById("nextweek-header");
+  if (soonHeader) {
+    soonHeader.setItem(this.soon, true);
+    agendaListbox.refreshPeriodDates(cal.dtz.now());
+  }
 };
 
 /**
  * Updates the event considered "current". This goes through all "today" items
  * and sets the "current" attribute on all list items that are currently
  * occurring.
  *
  * @see scheduleNextCurrentEventUpdate
  */
 function setCurrentEvent() {
-    if (!agendaListbox.showsToday() || !agendaListbox.today.open) {
-        return;
-    }
+  if (!agendaListbox.showsToday() || !agendaListbox.today.open) {
+    return;
+  }
 
-    let msScheduleTime = -1;
-    let complistItem = agendaListbox.tomorrow.listItem.previousSibling;
-    let removelist = [];
-    let anow = cal.dtz.now();
-    let msuntillend = 0;
-    let msuntillstart = 0;
-    let leaveloop;
-    do {
-        leaveloop = !agendaListbox.isEventListItem(complistItem);
-        if (!leaveloop) {
-            msuntillstart = complistItem.occurrence.startDate
-                                        .getInTimezone(agendaListbox.kDefaultTimezone)
-                                        .subtractDate(anow).inSeconds;
-            if (msuntillstart <= 0) {
-                msuntillend = complistItem.occurrence.endDate
-                                          .getInTimezone(agendaListbox.kDefaultTimezone)
-                                          .subtractDate(anow).inSeconds;
-                if (msuntillend > 0) {
-                    complistItem.setAttribute("current", "true");
-                    if (msuntillend < msScheduleTime || msScheduleTime == -1) {
-                        msScheduleTime = msuntillend;
-                    }
-                } else {
-                    removelist.push(complistItem);
-                }
-            } else {
-                complistItem.removeAttribute("current");
-            }
-            if (msScheduleTime == -1 || msuntillstart < msScheduleTime) {
-                if (msuntillstart > 0) {
-                    msScheduleTime = msuntillstart;
-                }
-            }
+  let msScheduleTime = -1;
+  let complistItem = agendaListbox.tomorrow.listItem.previousSibling;
+  let removelist = [];
+  let anow = cal.dtz.now();
+  let msuntillend = 0;
+  let msuntillstart = 0;
+  let leaveloop;
+  do {
+    leaveloop = !agendaListbox.isEventListItem(complistItem);
+    if (!leaveloop) {
+      msuntillstart = complistItem.occurrence.startDate
+        .getInTimezone(agendaListbox.kDefaultTimezone)
+        .subtractDate(anow).inSeconds;
+      if (msuntillstart <= 0) {
+        msuntillend = complistItem.occurrence.endDate
+          .getInTimezone(agendaListbox.kDefaultTimezone)
+          .subtractDate(anow).inSeconds;
+        if (msuntillend > 0) {
+          complistItem.setAttribute("current", "true");
+          if (msuntillend < msScheduleTime || msScheduleTime == -1) {
+            msScheduleTime = msuntillend;
+          }
+        } else {
+          removelist.push(complistItem);
         }
-        if (!leaveloop) {
-            complistItem = complistItem.previousSibling;
+      } else {
+        complistItem.removeAttribute("current");
+      }
+      if (msScheduleTime == -1 || msuntillstart < msScheduleTime) {
+        if (msuntillstart > 0) {
+          msScheduleTime = msuntillstart;
         }
-    } while (!leaveloop);
-
-    if (msScheduleTime > -1) {
-        scheduleNextCurrentEventUpdate(setCurrentEvent, msScheduleTime * 1000);
+      }
+    }
+    if (!leaveloop) {
+      complistItem = complistItem.previousSibling;
     }
+  } while (!leaveloop);
 
-    if (removelist) {
-        if (removelist.length > 0) {
-            for (let i = 0; i < removelist.length; i++) {
-                removelist[i].remove();
-            }
-        }
+  if (msScheduleTime > -1) {
+    scheduleNextCurrentEventUpdate(setCurrentEvent, msScheduleTime * 1000);
+  }
+
+  if (removelist) {
+    if (removelist.length > 0) {
+      for (let i = 0; i < removelist.length; i++) {
+        removelist[i].remove();
+      }
     }
+  }
 }
 
 var gEventTimer;
 
 /**
  * Creates a timer that will fire after the next event is current.
  *  Pass in a function as aRefreshCallback that should be called at that time.
  *
  * @param aRefreshCallback      The function to call when the next event is
  *                                current.
  * @param aMsUntil              The number of milliseconds until the next event
  *                                is current.
  */
 function scheduleNextCurrentEventUpdate(aRefreshCallback, aMsUntil) {
-    // Is an nsITimer/callback extreme overkill here? Yes, but it's necessary to
-    // workaround bug 291386.  If we don't, we stand a decent chance of getting
-    // stuck in an infinite loop.
-    let udCallback = {
-        notify: function(timer) {
-            aRefreshCallback();
-        }
-    };
+  // Is an nsITimer/callback extreme overkill here? Yes, but it's necessary to
+  // workaround bug 291386.  If we don't, we stand a decent chance of getting
+  // stuck in an infinite loop.
+  let udCallback = {
+    notify: function(timer) {
+      aRefreshCallback();
+    },
+  };
 
-    if (gEventTimer) {
-        gEventTimer.cancel();
-    } else {
-        // Observer for wake after sleep/hibernate/standby to create new timers and refresh UI
-        let wakeObserver = {
-            observe: function(aSubject, aTopic, aData) {
-                if (aTopic == "wake_notification") {
-                    aRefreshCallback();
-                }
-            }
-        };
-        // Add observer
-        Services.obs.addObserver(wakeObserver, "wake_notification");
+  if (gEventTimer) {
+    gEventTimer.cancel();
+  } else {
+    // Observer for wake after sleep/hibernate/standby to create new timers and refresh UI
+    let wakeObserver = {
+      observe: function(aSubject, aTopic, aData) {
+        if (aTopic == "wake_notification") {
+          aRefreshCallback();
+        }
+      },
+    };
+    // Add observer
+    Services.obs.addObserver(wakeObserver, "wake_notification");
 
-        // Remove observer on unload
-        window.addEventListener("unload", () => {
-            Services.obs.removeObserver(wakeObserver, "wake_notification");
-        });
+    // Remove observer on unload
+    window.addEventListener("unload", () => {
+      Services.obs.removeObserver(wakeObserver, "wake_notification");
+    });
 
-        gEventTimer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
-    }
-    gEventTimer.initWithCallback(udCallback, aMsUntil, gEventTimer.TYPE_ONE_SHOT);
+    gEventTimer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
+  }
+  gEventTimer.initWithCallback(udCallback, aMsUntil, gEventTimer.TYPE_ONE_SHOT);
 }
 
 /**
  * Gets a right value for calendar.agendaListbox.soondays preference, avoid
  * erroneous values edited in the lightning.js preference file
  **/
 function getSoondaysPreference() {
-    let prefName = "calendar.agendaListbox.soondays";
-    let soonpref = Services.prefs.getIntPref(prefName, 5);
+  let prefName = "calendar.agendaListbox.soondays";
+  let soonpref = Services.prefs.getIntPref(prefName, 5);
 
-    if (soonpref > 0 && soonpref <= 28) {
-        if (soonpref % 7 != 0) {
-            let intSoonpref = Math.floor(soonpref / 7) * 7;
-            soonpref = (intSoonpref == 0 ? soonpref : intSoonpref);
-            Services.prefs.setIntPref(prefName, soonpref);
-        }
-    } else {
-        soonpref = soonpref > 28 ? 28 : 1;
-        Services.prefs.setIntPref(prefName, soonpref);
+  if (soonpref > 0 && soonpref <= 28) {
+    if (soonpref % 7 != 0) {
+      let intSoonpref = Math.floor(soonpref / 7) * 7;
+      soonpref = intSoonpref == 0 ? soonpref : intSoonpref;
+      Services.prefs.setIntPref(prefName, soonpref);
     }
-    return soonpref;
+  } else {
+    soonpref = soonpref > 28 ? 28 : 1;
+    Services.prefs.setIntPref(prefName, soonpref);
+  }
+  return soonpref;
 }
--- a/calendar/base/content/agenda-listbox.js
+++ b/calendar/base/content/agenda-listbox.js
@@ -1,328 +1,355 @@
 /* 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";
 
 /* global MozXULElement, MozElements, unitPluralForm, agendaListbox,
-   invokeEventDragSession, setBooleanAttribute, hideElement, onMouseOverItem */
+   invokeEventDragSession, setBooleanAttribute, onMouseOverItem */
 {
-    var { cal } = ChromeUtils.import("resource://calendar/modules/calUtils.jsm");
-    /**
-     * The MozAgendaHeaderRichlistItem widget is typically used to display the
-     * Today, Tomorrow, and Upcoming headers of the Today Pane listing.
-     *
-     * @extends {MozElements.MozRichlistitem}
-     */
-    class MozAgendaHeaderRichlistItem extends MozElements.MozRichlistitem {
-        static get inheritedAttributes() {
-            return { ".agenda-checkbox": "selected,label,hidden,disabled" };
+  var { cal } = ChromeUtils.import("resource://calendar/modules/calUtils.jsm");
+  /**
+   * The MozAgendaHeaderRichlistItem widget is typically used to display the
+   * Today, Tomorrow, and Upcoming headers of the Today Pane listing.
+   *
+   * @extends {MozElements.MozRichlistitem}
+   */
+  class MozAgendaHeaderRichlistItem extends MozElements.MozRichlistitem {
+    static get inheritedAttributes() {
+      return { ".agenda-checkbox": "selected,label,hidden,disabled" };
+    }
+
+    connectedCallback() {
+      if (this.delayConnectedCallback() || this.hasChildNodes()) {
+        return;
+      }
+      this.kCheckbox = document.createXULElement("checkbox");
+      this.kCheckbox.classList.add("agenda-checkbox", "treenode-checkbox");
+      this.appendChild(this.kCheckbox);
+
+      this.initializeAttributeInheritance();
+    }
+
+    getItem() {
+      return this.mItem;
+    }
+
+    setItem(synthetic, showsToday) {
+      this.mItem = synthetic;
+      let duration = synthetic.duration;
+      if (showsToday) {
+        this.kCheckbox.label = this.getAttribute("title");
+        if (this.id == "nextweek-header") {
+          if (duration > 7) {
+            this.kCheckbox.label += " (" + unitPluralForm(duration / 7, "weeks") + ")";
+          } else {
+            this.kCheckbox.label += " (" + unitPluralForm(duration, "days") + ")";
+          }
         }
+      } else if (synthetic.duration == 1) {
+        this.kCheckbox.label = cal.getDateFormatter().formatDate(synthetic.start);
+      } else {
+        this.kCheckbox.label = cal
+          .getDateFormatter()
+          .formatInterval(synthetic.start, synthetic.end);
+      }
+    }
+    getCheckbox() {
+      return this.kCheckbox;
+    }
+  }
 
-        connectedCallback() {
-            if (this.delayConnectedCallback() || this.hasChildNodes()) {
-                return;
-            }
-            this.kCheckbox = document.createXULElement("checkbox");
-            this.kCheckbox.classList.add("agenda-checkbox", "treenode-checkbox");
-            this.appendChild(this.kCheckbox);
+  MozXULElement.implementCustomInterface(MozAgendaHeaderRichlistItem, [
+    Ci.nsIDOMXULSelectControlItemElement,
+  ]);
 
-            this.initializeAttributeInheritance();
-        }
+  customElements.define("agenda-header-richlist-item", MozAgendaHeaderRichlistItem, {
+    extends: "richlistitem",
+  });
 
-        getItem() {
-            return this.mItem;
+  /**
+   * The MozAgendaAlldayRichlistItem widget displays the information about
+   * all day event: i.e. event start time, icon and calendar-month-day-box-item.
+   * It is typically shown under the the agenda-header-richlist-item dropdown.
+   *
+   * @extends {MozElements.MozRichlistitem}
+   */
+  class MozAgendaAlldayRichlistItem extends MozElements.MozRichlistitem {
+    static get inheritedAttributes() {
+      return {
+        ".agenda-allday-container-box": "selected,disabled",
+        ".agenda-event-start": "selected",
+      };
+    }
+    connectedCallback() {
+      if (this.delayConnectedCallback() || this.hasChildNodes()) {
+        return;
+      }
+      this.setAttribute("is", "agenda-allday-richlist-item");
+      this.addEventListener("click", event => {
+        if (event.detail == 1) {
+          agendaListbox.onSelect(this);
+        } else if (event.button == 0) {
+          // We only care about button 0 doubleclick events
+          document.getElementById("agenda_edit_event_command").doCommand();
+          event.stopPropagation();
+          event.preventDefault();
         }
+      });
 
-        setItem(synthetic, showsToday) {
-            this.mItem = synthetic;
-            let duration = synthetic.duration;
-            if (showsToday) {
-                this.kCheckbox.label = this.getAttribute("title");
-                if (this.id == "nextweek-header") {
-                    if (duration > 7) {
-                        this.kCheckbox.label += " (" + unitPluralForm(duration / 7, "weeks") + ")";
-                    } else {
-                        this.kCheckbox.label += " (" + unitPluralForm(duration, "days") + ")";
-                    }
-                }
-            } else if (synthetic.duration == 1) {
-                this.kCheckbox.label = cal.getDateFormatter().formatDate(synthetic.start);
-            } else {
-                this.kCheckbox.label = cal.getDateFormatter().formatInterval(synthetic.start, synthetic.end);
-            }
-        }
-        getCheckbox() {
-            return this.kCheckbox;
-        }
+      this.addEventListener("mouseover", event => {
+        event.stopPropagation();
+        onMouseOverItem(event);
+      });
+
+      this.addEventListener(
+        "dragstart",
+        event => {
+          invokeEventDragSession(this.mAllDayItem.occurrence.clone(), this);
+          event.stopPropagation();
+          event.preventDefault();
+        },
+        true
+      );
+
+      // Prevent double clicks from opening a dialog to create a new event.
+      this.addEventListener("dblclick", event => {
+        event.stopPropagation();
+      });
+
+      this.appendChild(
+        MozXULElement.parseXULToFragment(`
+          <hbox class="agenda-allday-container-box" flex="1">
+            <vbox pack="center" flex="1">
+              <label class="agenda-event-start" crop="end" hidden="true"></label>
+              <hbox flex="1" align="start">
+                <image class="agenda-multiDayEvent-image"></image>
+                <calendar-month-day-box-item flex="1" flat="true"></calendar-month-day-box-item>
+              </hbox>
+            </vbox>
+          </hbox>
+        `)
+      );
+      this.mAllDayItem = null;
+      this.mOccurrence = null;
+      this.initializeAttributeInheritance();
     }
 
-    MozXULElement.implementCustomInterface(MozAgendaHeaderRichlistItem, [Ci.nsIDOMXULSelectControlItemElement]);
-
-    customElements.define("agenda-header-richlist-item", MozAgendaHeaderRichlistItem, { "extends": "richlistitem" });
-
-
-    /**
-     * The MozAgendaAlldayRichlistItem widget displays the information about
-     * all day event: i.e. event start time, icon and calendar-month-day-box-item.
-     * It is typically shown under the the agenda-header-richlist-item dropdown.
-     *
-     * @extends {MozElements.MozRichlistitem}
-     */
-    class MozAgendaAlldayRichlistItem extends MozElements.MozRichlistitem {
-        static get inheritedAttributes() {
-            return {
-                ".agenda-allday-container-box": "selected,disabled",
-                ".agenda-event-start": "selected"
-            };
-        }
-        connectedCallback() {
-            if (this.delayConnectedCallback() || this.hasChildNodes()) {
-                return;
-            }
-            this.setAttribute("is", "agenda-allday-richlist-item");
-            this.addEventListener("click", (event) => {
-                if (event.detail == 1) {
-                    agendaListbox.onSelect(this);
-                } else if (event.button == 0) {
-                    // We only care about button 0 doubleclick events
-                    document.getElementById("agenda_edit_event_command").doCommand();
-                    event.stopPropagation();
-                    event.preventDefault();
-                }
-            });
-
-            this.addEventListener("mouseover", (event) => {
-                event.stopPropagation();
-                onMouseOverItem(event);
-            });
-
-            this.addEventListener("dragstart", (event) => {
-                invokeEventDragSession(this.mAllDayItem.occurrence.clone(), this);
-                event.stopPropagation();
-                event.preventDefault();
-            }, true);
-
-
-            // Prevent double clicks from opening a dialog to create a new event.
-            this.addEventListener("dblclick", (event) => {
-                event.stopPropagation();
-            });
+    setOccurrence(aOccurrence, aPeriod) {
+      this.mOccurrence = aOccurrence;
+      this.mAllDayItem = this.querySelector("calendar-month-day-box-item");
+      this.mAllDayItem.occurrence = aOccurrence;
+      let dateFormatter = cal.getDateFormatter();
+      let periodStartDate = aPeriod.start.clone();
+      periodStartDate.isDate = true;
+      let periodEndDate = aPeriod.end;
+      let startDate = this.mOccurrence[cal.dtz.startDateProp(this.mOccurrence)].getInTimezone(
+        cal.dtz.defaultTimezone
+      );
+      let endDate = this.mOccurrence[cal.dtz.endDateProp(this.mOccurrence)].getInTimezone(
+        cal.dtz.defaultTimezone
+      );
+      let endPreviousDay = endDate.clone();
+      endPreviousDay.day--;
+      // Show items's date for long periods but also for "Upcoming"
+      // period with one day duration.
+      let showDate = aPeriod.multiday || aPeriod.duration > 1;
+      let date = "";
+      let iconType = "";
+      let allDayDateLabel = this.querySelector(".agenda-event-start");
+      setBooleanAttribute(allDayDateLabel, "hidden", !showDate);
+      if (startDate.compare(endPreviousDay) == 0) {
+        // All day event one day duration.
+        date = dateFormatter.formatDate(startDate);
+      } else if (startDate.compare(periodStartDate) >= 0 && startDate.compare(periodEndDate) <= 0) {
+        // All day event spanning multiple days.
+        iconType = "start";
+        date = dateFormatter.formatDate(startDate);
+      } else if (endDate.compare(periodStartDate) >= 0 && endDate.compare(periodEndDate) <= 0) {
+        iconType = "end";
+        date = dateFormatter.formatDate(endPreviousDay);
+      } else {
+        iconType = "continue";
+        allDayDateLabel.setAttribute("hidden", "true");
+      }
+      let multiDayImage = this.querySelector(".agenda-multiDayEvent-image");
+      multiDayImage.setAttribute("type", iconType);
+      // class wrap causes allday items to wrap its text in today-pane
+      let eventBoxContainer = this.mAllDayItem.querySelector(".calendar-event-box-container");
+      eventBoxContainer.classList.add("wrap");
+      let eventDetailBox = this.mAllDayItem.querySelector("event-detail-box");
+      if (eventDetailBox) {
+        eventDetailBox.classList.add("wrap");
+      }
+      allDayDateLabel.value = date;
+    }
+    get occurrence() {
+      return this.mOccurrence;
+    }
+  }
 
-            this.appendChild(MozXULElement.parseXULToFragment(`
-                <hbox class="agenda-allday-container-box" flex="1">
-                    <vbox pack="center" flex="1">
-                        <label class="agenda-event-start" crop="end" hidden="true"></label>
-                        <hbox flex="1" align="start">
-                            <image class="agenda-multiDayEvent-image"></image>
-                            <calendar-month-day-box-item flex="1" flat="true"></calendar-month-day-box-item>
-                        </hbox>
-                    </vbox>
-                </hbox>
-            `));
-            this.mAllDayItem = null;
-            this.mOccurrence = null;
-            this.initializeAttributeInheritance();
-        }
+  MozXULElement.implementCustomInterface(MozAgendaAlldayRichlistItem, [
+    Ci.nsIDOMXULSelectControlItemElement,
+  ]);
+
+  customElements.define("agenda-allday-richlist-item", MozAgendaAlldayRichlistItem, {
+    extends: "richlistitem",
+  });
 
-        setOccurrence(aOccurrence, aPeriod) {
-            this.mOccurrence = aOccurrence;
-            this.mAllDayItem = this.querySelector("calendar-month-day-box-item");
-            this.mAllDayItem.occurrence = aOccurrence;
-            let dateFormatter = cal.getDateFormatter();
-            let periodStartDate = aPeriod.start.clone();
-            periodStartDate.isDate = true;
-            let periodEndDate = aPeriod.end;
-            let startDate = this.mOccurrence[cal.dtz.startDateProp(this.mOccurrence)].getInTimezone(cal.dtz.defaultTimezone);
-            let endDate = this.mOccurrence[cal.dtz.endDateProp(this.mOccurrence)].getInTimezone(cal.dtz.defaultTimezone);
-            let endPreviousDay = endDate.clone();
-            endPreviousDay.day--;
-            // Show items's date for long periods but also for "Upcoming"
-            // period with one day duration.
-            let showDate = aPeriod.multiday || aPeriod.duration > 1;
-            let date = "";
-            let iconType = "";
-            let allDayDateLabel = this.querySelector(".agenda-event-start");
-            setBooleanAttribute(allDayDateLabel, "hidden", !showDate);
-            if (startDate.compare(endPreviousDay) == 0) {
-                // All day event one day duration.
-                date = dateFormatter.formatDate(startDate);
-            } else if (startDate.compare(periodStartDate) >= 0 &&
-                startDate.compare(periodEndDate) <= 0) {
-                // All day event spanning multiple days.
-                iconType = "start";
-                date = dateFormatter.formatDate(startDate);
-            } else if (endDate.compare(periodStartDate) >= 0 &&
-                endDate.compare(periodEndDate) <= 0) {
-                iconType = "end";
-                date = dateFormatter.formatDate(endPreviousDay);
-            } else {
-                iconType = "continue";
-                hideElement(allDayDateLabel);
-            }
-            let multiDayImage = this.querySelector(".agenda-multiDayEvent-image");
-            multiDayImage.setAttribute("type", iconType);
-            // class wrap causes allday items to wrap its text in today-pane
-            let addWrap = document.getAnonymousElementByAttribute(this.mAllDayItem, "anonid", "eventbox");
-            addWrap.classList.add("wrap");
-            addWrap = document.getAnonymousElementByAttribute(this.mAllDayItem, "anonid", "event-detail-box");
-            addWrap.classList.add("wrap");
-            allDayDateLabel.value = date;
-        }
-        get occurrence() {
-            return this.mOccurrence;
-        }
+  /**
+   * The MozAgendaRichlistItem widget displays the information about
+   * event: i.e. event start time, icon and name. It is shown under
+   * agenda-header-richlist-item dropdown as a richlistitem.
+   *
+   * @extends {MozElements.MozRichlistitem}
+   */
+  class MozAgendaRichlistItem extends MozElements.MozRichlistitem {
+    static get inheritedAttributes() {
+      return {
+        ".agenda-container-box": "selected,disabled,current",
+        ".agenda-event-start": "selected",
+        ".agenda-event-title": "selected",
+      };
     }
 
-    MozXULElement.implementCustomInterface(
-        MozAgendaAlldayRichlistItem, [Ci.nsIDOMXULSelectControlItemElement]
-    );
-
-    customElements.define("agenda-allday-richlist-item", MozAgendaAlldayRichlistItem,
-        { "extends": "richlistitem" });
+    connectedCallback() {
+      if (this.delayConnectedCallback() || this.hasChildNodes()) {
+        return;
+      }
+      this.setAttribute("is", "agenda-richlist-item");
+      this.addEventListener(
+        "click",
+        event => {
+          if (event.detail == 1) {
+            agendaListbox.onSelect(this);
+          } else if (event.button == 0) {
+            // We only care about button 0 doubleclick events
+            document.getElementById("agenda_edit_event_command").doCommand();
+            event.stopPropagation();
+            event.preventDefault();
+          }
+        },
+        true
+      );
 
-    /**
-     * The MozAgendaRichlistItem widget displays the information about
-     * event: i.e. event start time, icon and name. It is shown under
-     * agenda-header-richlist-item dropdown as a richlistitem.
-     *
-     * @extends {MozElements.MozRichlistitem}
-     */
-    class MozAgendaRichlistItem extends MozElements.MozRichlistitem {
-        static get inheritedAttributes() {
-            return {
-                ".agenda-container-box": "selected,disabled,current",
-                ".agenda-event-start": "selected",
-                ".agenda-event-title": "selected"
-            };
-        }
+      this.addEventListener("mouseover", event => {
+        event.stopPropagation();
+        onMouseOverItem(event);
+      });
+
+      this.addEventListener("dragstart", event => {
+        invokeEventDragSession(this.mOccurrence.clone(), this);
+      });
+      // Prevent double clicks from opening a dialog to create a new event.
+      this.addEventListener("dblclick", event => {
+        event.stopPropagation();
+      });
 
-        connectedCallback() {
-            if (this.delayConnectedCallback() || this.hasChildNodes()) {
-                return;
-            }
-            this.setAttribute("is", "agenda-richlist-item");
-            this.addEventListener("click", (event) => {
-                if (event.detail == 1) {
-                    agendaListbox.onSelect(this);
-                } else if (event.button == 0) {
-                    // We only care about button 0 doubleclick events
-                    document.getElementById("agenda_edit_event_command").doCommand();
-                    event.stopPropagation();
-                    event.preventDefault();
-                }
-            }, true);
-
-            this.addEventListener("mouseover", (event) => {
-                event.stopPropagation();
-                onMouseOverItem(event);
-            });
-
-            this.addEventListener("dragstart", (event) => {
-                invokeEventDragSession(this.mOccurrence.clone(), this);
-            });
-            // Prevent double clicks from opening a dialog to create a new event.
-            this.addEventListener("dblclick", (event) => {
-                event.stopPropagation();
-            });
-
-            this.appendChild(MozXULElement.parseXULToFragment(`
-                <hbox class="agenda-container-box" flex="1">
-                    <hbox>
-                        <vbox>
-                            <image class="agenda-calendar-image"></image>
-                            <spacer flex="1"></spacer>
-                        </vbox>
-                    </hbox>
-                    <vbox flex="1" class="agenda-description">
-                        <hbox align="start">
-                            <image class="agenda-multiDayEvent-image"></image>
-                            <label class="agenda-event-start" crop="end" flex="1"></label>
-                        </hbox>
-                        <label class="agenda-event-title" crop="end"></label>
-                    </vbox>
-                </hbox>
-            `));
-            this.mOccurrence = null;
-            this.initializeAttributeInheritance();
+      this.appendChild(
+        MozXULElement.parseXULToFragment(`
+          <hbox class="agenda-container-box" flex="1">
+            <hbox>
+              <vbox>
+                <image class="agenda-calendar-image"></image>
+                <spacer flex="1"></spacer>
+              </vbox>
+            </hbox>
+            <vbox flex="1" class="agenda-description">
+              <hbox align="start">
+                <image class="agenda-multiDayEvent-image"></image>
+                <label class="agenda-event-start" crop="end" flex="1"></label>
+              </hbox>
+              <label class="agenda-event-title" crop="end"></label>
+            </vbox>
+          </hbox>
+        `)
+      );
+      this.mOccurrence = null;
+      this.initializeAttributeInheritance();
+    }
+    setOccurrence(aItem, aPeriod) {
+      this.mOccurrence = aItem;
+      this.setAttribute("status", aItem.status);
+      let dateFormatter = Cc["@mozilla.org/calendar/datetime-formatter;1"].getService(
+        Ci.calIDateTimeFormatter
+      );
+      let periodStartDate = aPeriod.start.clone();
+      periodStartDate.isDate = true;
+      let periodEndDate = aPeriod.end.clone();
+      periodEndDate.day--;
+      let start = this.mOccurrence[cal.dtz.startDateProp(this.mOccurrence)].getInTimezone(
+        cal.dtz.defaultTimezone
+      );
+      let end = this.mOccurrence[cal.dtz.endDateProp(this.mOccurrence)].getInTimezone(
+        cal.dtz.defaultTimezone
+      );
+      let startDate = start.clone();
+      startDate.isDate = true;
+      let endDate = end.clone();
+      endDate.isDate = true;
+      let endAtMidnight = end.hour == 0 && end.minute == 0;
+      if (endAtMidnight) {
+        endDate.day--;
+      }
+      // Show items's date for long periods but also for "Upcoming"
+      // period with one day duration.
+      let longFormat = aPeriod.multiday || aPeriod.duration > 1;
+      let duration = "";
+      let iconType = "";
+      if (startDate.compare(endDate) == 0) {
+        // event that starts and ends in the same day, midnight included
+        duration = longFormat
+          ? dateFormatter.formatDateTime(start)
+          : dateFormatter.formatTime(start);
+      } else if (startDate.compare(periodStartDate) >= 0 && startDate.compare(periodEndDate) <= 0) {
+        // event spanning multiple days, start date within period
+        iconType = "start";
+        duration = longFormat
+          ? dateFormatter.formatDateTime(start)
+          : dateFormatter.formatTime(start);
+      } else if (endDate.compare(periodStartDate) >= 0 && endDate.compare(periodEndDate) <= 0) {
+        // event spanning multiple days, end date within period
+        iconType = "end";
+        if (endAtMidnight) {
+          duration = dateFormatter.formatDate(endDate) + " ";
+          duration = longFormat
+            ? duration + cal.l10n.getDateFmtString("midnight")
+            : cal.l10n.getDateFmtString("midnight");
+        } else {
+          duration = longFormat ? dateFormatter.formatDateTime(end) : dateFormatter.formatTime(end);
         }
-        setOccurrence(aItem, aPeriod) {
-            this.mOccurrence = aItem;
-            this.setAttribute("status", aItem.status);
-            let dateFormatter = Cc["@mozilla.org/calendar/datetime-formatter;1"].getService(Ci.calIDateTimeFormatter);
-            let periodStartDate = aPeriod.start.clone();
-            periodStartDate.isDate = true;
-            let periodEndDate = aPeriod.end.clone();
-            periodEndDate.day--;
-            let start = this.mOccurrence[cal.dtz.startDateProp(this.mOccurrence)].getInTimezone(cal.dtz.defaultTimezone);
-            let end = this.mOccurrence[cal.dtz.endDateProp(this.mOccurrence)].getInTimezone(cal.dtz.defaultTimezone);
-            let startDate = start.clone();
-            startDate.isDate = true;
-            let endDate = end.clone();
-            endDate.isDate = true;
-            let endAtMidnight = (end.hour == 0 && end.minute == 0);
-            if (endAtMidnight) {
-                endDate.day--;
-            }
-            // Show items's date for long periods but also for "Upcoming"
-            // period with one day duration.
-            let longFormat = aPeriod.multiday || aPeriod.duration > 1;
-            let duration = "";
-            let iconType = "";
-            if (startDate.compare(endDate) == 0) {
-                // event that starts and ends in the same day, midnight included
-                duration = longFormat ? dateFormatter.formatDateTime(start)
-                    : dateFormatter.formatTime(start);
-            } else if (startDate.compare(periodStartDate) >= 0 &&
-                startDate.compare(periodEndDate) <= 0) {
-                // event spanning multiple days, start date within period
-                iconType = "start";
-                duration = longFormat ? dateFormatter.formatDateTime(start)
-                    : dateFormatter.formatTime(start);
-            } else if (endDate.compare(periodStartDate) >= 0 &&
-                endDate.compare(periodEndDate) <= 0) {
-                // event spanning multiple days, end date within period
-                iconType = "end";
-                if (endAtMidnight) {
-                    duration = dateFormatter.formatDate(endDate) + " ";
-                    duration = longFormat ? duration + cal.l10n.getDateFmtString("midnight")
-                        : cal.l10n.getDateFmtString("midnight");
-                } else {
-                    duration = longFormat ? dateFormatter.formatDateTime(end)
-                        : dateFormatter.formatTime(end);
-                }
-            } else {
-                iconType = "continue";
-            }
-            let multiDayImage = this.querySelector(".agenda-multiDayEvent-image");
-            multiDayImage.setAttribute("type", iconType);
-            let durationbox = this.querySelector(".agenda-event-start");
-            durationbox.textContent = duration;
+      } else {
+        iconType = "continue";
+      }
+      let multiDayImage = this.querySelector(".agenda-multiDayEvent-image");
+      multiDayImage.setAttribute("type", iconType);
+      let durationbox = this.querySelector(".agenda-event-start");
+      durationbox.textContent = duration;
 
-
-            // show items with time only (today & tomorrow) as one line.
-            if (longFormat) {
-                let titlebox = this.querySelector(".agenda-event-title");
-                titlebox.textContent = aItem.title;
-            } else {
-                durationbox.textContent += " " + aItem.title;
-            }
-            this.refreshColor();
-        }
-
-        refreshColor() {
-            let imagebox = this.querySelector(".agenda-calendar-image");
-            let cssSafeId = cal.view.formatStringForCSSRule(this.mOccurrence.calendar.id);
-            imagebox.style.backgroundColor = `var(--calendar-${cssSafeId}-backcolor)`;
-        }
-
-        get occurrence() {
-            return this.mOccurrence;
-        }
+      // show items with time only (today & tomorrow) as one line.
+      if (longFormat) {
+        let titlebox = this.querySelector(".agenda-event-title");
+        titlebox.textContent = aItem.title;
+      } else {
+        durationbox.textContent += " " + aItem.title;
+      }
+      this.refreshColor();
     }
 
-
-    MozXULElement.implementCustomInterface(MozAgendaRichlistItem, [Ci.nsIDOMXULSelectControlItemElement]);
+    refreshColor() {
+      let imagebox = this.querySelector(".agenda-calendar-image");
+      let cssSafeId = cal.view.formatStringForCSSRule(this.mOccurrence.calendar.id);
+      imagebox.style.backgroundColor = `var(--calendar-${cssSafeId}-backcolor)`;
+    }
 
-    customElements.define("agenda-richlist-item", MozAgendaRichlistItem, { "extends": "richlistitem" });
+    get occurrence() {
+      return this.mOccurrence;
+    }
+  }
+
+  MozXULElement.implementCustomInterface(MozAgendaRichlistItem, [
+    Ci.nsIDOMXULSelectControlItemElement,
+  ]);
+
+  customElements.define("agenda-richlist-item", MozAgendaRichlistItem, { extends: "richlistitem" });
 }
--- a/calendar/base/content/calendar-base-view.js
+++ b/calendar/base/content/calendar-base-view.js
@@ -3,951 +3,977 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 /* globals cal currentView MozElements MozXULElement Services toggleOrientation */
 
 "use strict";
 
 // Wrap in a block to prevent leaking to window scope.
 {
+  const { Log4Moz } = ChromeUtils.import("resource:///modules/gloda/log4moz.js");
+
+  /**
+   * Calendar observer for calendar view elements. Used in CalendarBaseView class.
+   *
+   * @implements {calIObserver}
+   * @implements {calICompositeObserver}
+   * @implements {calIAlarmServiceObserver}
+   */
+  class CalendarViewObserver {
     /**
-     * Calendar observer for calendar view elements. Used in CalendarBaseView class.
+     * Constructor for CalendarViewObserver.
      *
-     * @implements {calIObserver}
-     * @implements {calICompositeObserver}
-     * @implements {calIAlarmServiceObserver}
+     * @param {CalendarBaseView} calendarView    A calendar view.
      */
-    class CalendarViewObserver {
-        /**
-         * Constructor for CalendarViewObserver.
-         *
-         * @param {CalendarBaseView} calendarView    A calendar view.
-         */
-        constructor(calendarView) {
-            this.QueryInterface = cal.generateQI([
-                Ci.calIObserver,
-                Ci.calIAlarmServiceObserver,
-                Ci.calICompositeObserver
-            ]);
+    constructor(calendarView) {
+      this.QueryInterface = cal.generateQI([
+        Ci.calIObserver,
+        Ci.calIAlarmServiceObserver,
+        Ci.calICompositeObserver,
+      ]);
+
+      this.calView = calendarView.calICalendarView;
+    }
+
+    // calIObserver
+
+    onStartBatch() {}
+    onEndBatch() {}
+
+    onLoad() {
+      this.calView.refresh();
+    }
+
+    onAddItem(item) {
+      if (cal.item.isToDo(item)) {
+        if (
+          (!item.entryDate && !item.dueDate) ||
+          !this.calView.mTasksInView ||
+          (item.isCompleted && !this.calView.mShowCompleted)
+        ) {
+          return;
+        }
+      }
+
+      const occs = item.getOccurrencesBetween(
+        this.calView.startDate,
+        this.calView.queryEndDate,
+        {}
+      );
+      for (const occ of occs) {
+        if (cal.item.isToDo(occ)) {
+          this.calView.doAddItem(occ.QueryInterface(Ci.calITodo));
+        } else {
+          this.calView.doAddItem(occ.QueryInterface(Ci.calIEvent));
+        }
+      }
+    }
+
+    onModifyItem(newItem, oldItem) {
+      if (cal.item.isToDo(newItem) && cal.item.isToDo(oldItem) && !this.calView.mTasksInView) {
+        return;
+      }
+      if (!cal.item.isToDo(oldItem) || oldItem.entryDate || oldItem.dueDate) {
+        let occs = oldItem.getOccurrencesBetween(
+          this.calView.startDate,
+          this.calView.queryEndDate,
+          {}
+        );
+        for (const occ of occs) {
+          if (cal.item.isToDo(occ)) {
+            this.calView.doDeleteItem(occ.QueryInterface(Ci.calITodo));
+          } else {
+            this.calView.doDeleteItem(occ.QueryInterface(Ci.calIEvent));
+          }
+        }
+      }
+      if (cal.item.isToDo(newItem)) {
+        if ((!newItem.entryDate && !newItem.dueDate) || !this.calView.mTasksInView) {
+          return;
+        }
+        if (newItem.isCompleted && !this.calView.mShowCompleted) {
+          return;
+        }
+      }
 
-            this.calView = calendarView.calICalendarView;
+      let occs = newItem.getOccurrencesBetween(
+        this.calView.startDate,
+        this.calView.queryEndDate,
+        {}
+      );
+      for (const occ of occs) {
+        if (cal.item.isToDo(occ)) {
+          this.calView.doAddItem(occ.QueryInterface(Ci.calITodo));
+        } else {
+          this.calView.doAddItem(occ.QueryInterface(Ci.calIEvent));
         }
+      }
+    }
 
-        // calIObserver
+    onDeleteItem(item) {
+      if (cal.item.isToDo(item)) {
+        if (!this.calView.mTasksInView) {
+          return;
+        }
+        if (!item.entryDate && !item.dueDate) {
+          return;
+        }
+        if (item.isCompleted && !this.calView.mShowCompleted) {
+          return;
+        }
+      }
 
-        onStartBatch() {}
-        onEndBatch() {}
+      const occs = item.getOccurrencesBetween(
+        this.calView.startDate,
+        this.calView.queryEndDate,
+        {}
+      );
+      for (const occ of occs) {
+        if (cal.item.isToDo(occ)) {
+          this.calView.doDeleteItem(occ.QueryInterface(Ci.calITodo));
+        } else {
+          this.calView.doDeleteItem(occ.QueryInterface(Ci.calIEvent));
+        }
+      }
+    }
+
+    onError(calendar, errNo, message) {}
 
-        onLoad() {
-            this.calView.refresh();
-        }
+    onPropertyChanged(calendar, name, value, oldValue) {
+      switch (name) {
+        case "suppressAlarms":
+          if (
+            !Services.prefs.getBoolPref("calendar.alarms.indicator.show", true) ||
+            calendar.getProperty("capabilities.alarms.popup.supported") === false
+          ) {
+            break;
+          }
+        // Else fall through.
+        case "readOnly":
+        case "disabled":
+          // XXXvv We can be smarter about how we handle this stuff.
+          this.calView.refresh();
+          break;
+      }
+    }
+
+    onPropertyDeleting(calendar, name) {
+      // Values are not important here yet.
+      this.onPropertyChanged(calendar, name, null, null);
+    }
 
-        onAddItem(item) {
-            if (cal.item.isToDo(item)) {
-                if ((!item.entryDate && !item.dueDate) ||
-                    !this.calView.mTasksInView ||
-                    (item.isCompleted && !this.calView.mShowCompleted)) {
-                    return;
-                }
-            }
+    // End calIObserver
+    // calIAlarmServiceObserver
+
+    onAlarm(alarmItem) {
+      this.calView.flashAlarm(alarmItem, false);
+    }
+
+    onRemoveAlarmsByItem(item) {
+      // Stop the flashing for the item.
+      this.calView.flashAlarm(item, true);
+    }
+
+    onRemoveAlarmsByCalendar(calendar) {
+      // Stop the flashing for all items of this calendar.
+      for (const key in this.calView.mFlashingEvents) {
+        const item = this.calView.mFlashingEvents[key];
+        if (item.calendar.id == calendar.id) {
+          this.calView.flashAlarm(item, true);
+        }
+      }
+    }
+
+    onAlarmsLoaded(calendar) {}
 
-            const occs = item.getOccurrencesBetween(this.calView.startDate,
-                this.calView.queryEndDate, {});
-            for (const occ of occs) {
-                if (cal.item.isToDo(occ)) {
-                    this.calView.doAddItem(occ.QueryInterface(Ci.calITodo));
-                } else {
-                    this.calView.doAddItem(occ.QueryInterface(Ci.calIEvent));
-                }
-            }
+    // End calIAlarmServiceObserver
+    // calICompositeObserver
+    // XXXvv We can be smarter about how we handle this stuff.
+
+    onCalendarAdded(calendar) {
+      if (!calendar.getProperty("disabled")) {
+        this.calView.addItemsFromCalendar(calendar);
+      }
+    }
+
+    onCalendarRemoved(calendar) {
+      if (!calendar.getProperty("disabled")) {
+        this.calView.deleteItemsFromCalendar(calendar);
+      }
+    }
+
+    onDefaultCalendarChanged(newDefaultCalendar) {
+      // We don't care, for now.
+    }
+
+    // End calICompositeObserver
+  }
+
+  /**
+   * Class for a refresh job object that is used in CalendarBaseView.addItemsFromCalendar.
+   */
+  class CalendarViewRefreshJob {
+    /**
+     * Constructor for CalendarViewRefreshJob.
+     *
+     * @param {CalendarBaseView} calendarView                   A calendar view.
+     * @param {calICalendar|calICompositeCalendar} calendar     A calendar object.
+     */
+    constructor(calendarView, calendar) {
+      this.QueryInterface = ChromeUtils.generateQI([Ci.calIOperationListener]);
+      this.calView = calendarView;
+      this.calendar = calendar;
+      this.calId = null;
+      this.operation = null;
+      this.cancelled = false;
+    }
+
+    onOperationComplete(opCalendar, status, operationType, id, dateTime) {
+      this.calView.mLog.info("Refresh complete of calendar " + this.calId);
+      if (this.calView.mPendingRefreshJobs.has(this.calId)) {
+        this.calView.mPendingRefreshJobs.delete(this.calId);
+      }
+
+      if (!this.cancelled) {
+        this.calView.fireEvent("viewloaded", operationType);
+      }
+    }
+
+    onGetResult(opCalendar, status, itemType, detail, count, items) {
+      if (this.cancelled || !Components.isSuccessCode(status)) {
+        return;
+      }
+
+      for (const item of items) {
+        if (!cal.item.isToDo(item) || item.entryDate || item.dueDate) {
+          this.calView.doAddItem(item);
         }
+      }
+    }
 
-        onModifyItem(newItem, oldItem) {
-            if (cal.item.isToDo(newItem) && cal.item.isToDo(oldItem) &&
-                !this.calView.mTasksInView) {
-                return;
+    cancel() {
+      this.calView.mLog.info("Refresh cancelled for calendar " + this.calId);
+      this.cancelled = true;
+      const operation = cal.wrapInstance(this.operation, Ci.calIOperation);
+      if (operation && operation.isPending) {
+        operation.cancel();
+        this.operation = null;
+      }
+    }
+
+    execute() {
+      if (!this.calView.startDate || !this.calView.endDate || !this.calendar) {
+        return;
+      }
+
+      if (this.calendar.type == "composite") {
+        // We're refreshing from the composite calendar, so we can cancel
+        // all other pending refresh jobs.
+        this.calView.mLog.info("Refreshing composite calendar, cancelling all pending refreshes");
+        this.calId = "composite";
+        for (const job of this.calView.mPendingRefreshJobs.values()) {
+          job.cancel();
+        }
+        this.calView.mPendingRefreshJobs.clear();
+        this.calView.relayout();
+      } else {
+        this.calId = this.calendar.id;
+        if (this.calView.mPendingRefreshJobs.has(this.calId)) {
+          this.calView.mPendingRefreshJobs.get(this.calId).cancel();
+          this.calView.mPendingRefreshJobs.delete(this.calId);
+        }
+      }
+
+      // Start our items query. For a disjoint date range we get all the items,
+      // and just filter out the ones we don't care about in addItem.
+      let filter = this.calendar.ITEM_FILTER_CLASS_OCCURRENCES;
+      if (this.calView.mShowCompleted) {
+        filter |= this.calendar.ITEM_FILTER_COMPLETED_ALL;
+      } else {
+        filter |= this.calendar.ITEM_FILTER_COMPLETED_NO;
+      }
+
+      if (this.calView.mTasksInView) {
+        filter |= this.calendar.ITEM_FILTER_TYPE_ALL;
+      } else {
+        filter |= this.calendar.ITEM_FILTER_TYPE_EVENT;
+      }
+
+      let operation = this.calendar.getItems(
+        filter,
+        0,
+        this.calView.startDate,
+        this.calView.queryEndDate,
+        this
+      );
+
+      operation = cal.wrapInstance(operation, Ci.calIOperation);
+      if (operation && operation.isPending) {
+        this.operation = operation;
+        this.calView.mPendingRefreshJobs.set(this.calId, this);
+      }
+    }
+  }
+
+  /**
+   * Abstract base class for calendar view elements (day, week, multiweek, month).
+   *
+   * @implements {calICalendarView}
+   * @abstract
+   */
+  class CalendarBaseView extends MozXULElement {
+    connectedCallback() {
+      if (this.delayConnectedCallback() || this.hasConnected) {
+        return;
+      }
+      this.hasConnected = true;
+
+      this.calICalendarView = this.getCustomInterfaceCallback(Ci.calICalendarView);
+
+      this.addEventListener("move", event => {
+        this.moveView(event.detail);
+      });
+
+      this.addEventListener("keypress", event => {
+        switch (event.key) {
+          case "PageUp":
+            this.moveView(-1);
+            break;
+          case "PageDown":
+            this.moveView(1);
+            break;
+        }
+      });
+
+      this.addEventListener("wheel", event => {
+        const pixelThreshold = 150;
+
+        if (event.shiftKey && Services.prefs.getBoolPref("calendar.view.mousescroll", true)) {
+          let deltaView = 0;
+          if (event.deltaMode == event.DOM_DELTA_LINE) {
+            if (event.deltaY != 0) {
+              deltaView = event.deltaY < 0 ? -1 : 1;
             }
-            if (!cal.item.isToDo(oldItem) || oldItem.entryDate || oldItem.dueDate) {
-                let occs = oldItem.getOccurrencesBetween(this.calView.startDate,
-                    this.calView.queryEndDate, {});
-                for (const occ of occs) {
-                    if (cal.item.isToDo(occ)) {
-                        this.calView.doDeleteItem(occ.QueryInterface(Ci.calITodo));
-                    } else {
-                        this.calView.doDeleteItem(occ.QueryInterface(Ci.calIEvent));
-                    }
-                }
+          } else if (event.deltaMode == event.DOM_DELTA_PIXEL) {
+            this.mPixelScrollDelta += event.deltaY;
+            if (this.mPixelScrollDelta > pixelThreshold) {
+              deltaView = 1;
+              this.mPixelScrollDelta = 0;
+            } else if (this.mPixelScrollDelta < -pixelThreshold) {
+              deltaView = -1;
+              this.mPixelScrollDelta = 0;
             }
-            if (cal.item.isToDo(newItem)) {
-                if ((!newItem.entryDate && !newItem.dueDate) || !this.calView.mTasksInView) {
-                    return;
-                }
-                if (newItem.isCompleted && !this.calView.mShowCompleted) {
-                    return;
-                }
-            }
+          }
 
-            let occs = newItem.getOccurrencesBetween(this.calView.startDate,
-                this.calView.queryEndDate, {});
-            for (const occ of occs) {
-                if (cal.item.isToDo(occ)) {
-                    this.calView.doAddItem(occ.QueryInterface(Ci.calITodo));
-                } else {
-                    this.calView.doAddItem(occ.QueryInterface(Ci.calIEvent));
-                }
-            }
+          if (deltaView != 0) {
+            this.moveView(deltaView);
+          }
         }
 
-        onDeleteItem(item) {
-            if (cal.item.isToDo(item)) {
-                if (!this.calView.mTasksInView) {
-                    return;
-                }
-                if (!item.entryDate && !item.dueDate) {
-                    return;
-                }
-                if (item.isCompleted && !this.calView.mShowCompleted) {
-                    return;
-                }
-            }
+        event.preventDefault();
+      });
 
-            const occs = item.getOccurrencesBetween(this.calView.startDate,
-                this.calView.queryEndDate, {});
-            for (const occ of occs) {
-                if (cal.item.isToDo(occ)) {
-                    this.calView.doDeleteItem(occ.QueryInterface(Ci.calITodo));
-                } else {
-                    this.calView.doDeleteItem(occ.QueryInterface(Ci.calIEvent));
-                }
-            }
+      this.addEventListener("MozRotateGesture", event => {
+        // Threshold for the minimum and maximum angle we should accept
+        // rotation for. 90 degrees minimum is most logical, but 45 degrees
+        // allows you to rotate with one hand.
+        const MIN_ROTATE_ANGLE = 45;
+        const MAX_ROTATE_ANGLE = 180;
+
+        const absval = Math.abs(event.delta);
+        if (this.supportsRotation && absval >= MIN_ROTATE_ANGLE && absval < MAX_ROTATE_ANGLE) {
+          toggleOrientation();
+          event.preventDefault();
         }
+      });
 
-        onError(calendar, errNo, message) {}
+      this.addEventListener("MozMagnifyGestureStart", event => {
+        this.mMagnifyAmount = 0;
+      });
+
+      this.addEventListener("MozMagnifyGestureUpdate", event => {
+        // Threshold as to how much magnification causes the zoom to happen.
+        const THRESHOLD = 30;
+
+        if (this.supportsZoom) {
+          this.mMagnifyAmount += event.delta;
 
-        onPropertyChanged(calendar, name, value, oldValue) {
-            switch (name) {
-                case "suppressAlarms":
-                    if (!Services.prefs.getBoolPref("calendar.alarms.indicator.show", true) ||
-                        calendar.getProperty("capabilities.alarms.popup.supported") === false) {
-                        break;
-                    }
-                // Else fall through.
-                case "readOnly":
-                case "disabled":
-                    // XXXvv We can be smarter about how we handle this stuff.
-                    this.calView.refresh();
-                    break;
-            }
+          if (this.mMagnifyAmount > THRESHOLD) {
+            this.zoomOut();
+            this.mMagnifyAmount = 0;
+          } else if (this.mMagnifyAmount < -THRESHOLD) {
+            this.zoomIn();
+            this.mMagnifyAmount = 0;
+          }
+          event.preventDefault();
         }
+      });
 
-        onPropertyDeleting(calendar, name) {
-            // Values are not important here yet.
-            this.onPropertyChanged(calendar, name, null, null);
+      this.addEventListener("MozSwipeGesture", event => {
+        if (
+          (event.direction == SimpleGestureEvent.DIRECTION_UP && !this.rotated) ||
+          (event.direction == SimpleGestureEvent.DIRECTION_LEFT && this.rotated)
+        ) {
+          this.moveView(-1);
+        } else if (
+          (event.direction == SimpleGestureEvent.DIRECTION_DOWN && !this.rotated) ||
+          (event.direction == SimpleGestureEvent.DIRECTION_RIGHT && this.rotated)
+        ) {
+          this.moveView(1);
         }
+      });
 
-        // End calIObserver
-        // calIAlarmServiceObserver
+      this.mWeekStartOffset = 0;
+
+      this.mRangeStartDate = null;
+      this.mRangeEndDate = null;
+
+      this.mWorkdaysOnly = false;
+      this.mPendingRefreshJobs = null;
+
+      this.mCalendar = null;
+      this.mController = null;
 
-        onAlarm(alarmItem) {
-            this.calView.flashAlarm(alarmItem, false);
-        }
+      this.mStartDate = null;
+      this.mEndDate = null;
+
+      this.mTasksInView = false;
+      this.mShowCompleted = false;
+
+      this.mDisplayDaysOff = true;
+      this.mDaysOffArray = [0, 6];
+
+      this.mTimezone = null;
+      this.mFlashingEvents = {};
+
+      this.mSelectedItems = [];
+      this.mLongWeekdayTotalPixels = -1;
 
-        onRemoveAlarmsByItem(item) {
-            // Stop the flashing for the item.
-            this.calView.flashAlarm(item, true);
-        }
+      this.mDropShadowsLength = null;
+
+      this.mShadowOffset = null;
+      this.mDropShadows = null;
+
+      this.mMagnifyAmount = 0;
+      this.mPixelScrollDelta = 0;
+
+      this.mViewStart = null;
+      this.mViewEnd = null;
+
+      this.mToggleStatus = 0;
+      this.mLog = null;
 
-        onRemoveAlarmsByCalendar(calendar) {
-            // Stop the flashing for all items of this calendar.
-            for (const key in this.calView.mFlashingEvents) {
-                const item = this.calView.mFlashingEvents[key];
-                if (item.calendar.id == calendar.id) {
-                    this.calView.flashAlarm(item, true);
-                }
-            }
-        }
+      this.mToggleStatusFlag = {
+        WorkdaysOnly: 1,
+        TasksInView: 2,
+        ShowCompleted: 4,
+      };
+
+      this.mTimezoneObserver = {
+        observe: () => {
+          this.timezone = cal.dtz.defaultTimezone;
+          this.refreshView();
+
+          if (this.updateTimeIndicatorPosition) {
+            this.updateTimeIndicatorPosition(true);
+          }
+        },
+      };
 
-        onAlarmsLoaded(calendar) {}
+      this.mPrefObserver = {
+        calView: this.calICalendarView,
 
-        // End calIAlarmServiceObserver
-        // calICompositeObserver
-        // XXXvv We can be smarter about how we handle this stuff.
+        observe(subj, topic, pref) {
+          this.calView.handlePreference(subj, topic, pref);
+        },
+      };
+
+      this.mObserver = new CalendarViewObserver(this);
+
+      const isChecked = id => document.getElementById(id).getAttribute("checked") == "true";
 
-        onCalendarAdded(calendar) {
-            if (!calendar.getProperty("disabled")) {
-                this.calView.addItemsFromCalendar(calendar);
-            }
-        }
+      this.workdaysOnly = isChecked("calendar_toggle_workdays_only_command");
+      this.tasksInView = isChecked("calendar_toggle_tasks_in_view_command");
+      this.rotated = isChecked("calendar_toggle_orientation_command");
+      this.showCompleted = isChecked("calendar_toggle_show_completed_in_view_command");
+
+      this.mTimezone = cal.dtz.defaultTimezone;
+      const alarmService = Cc["@mozilla.org/calendar/alarm-service;1"].getService(
+        Ci.calIAlarmService
+      );
+
+      alarmService.addObserver(this.mObserver);
+
+      this.setAttribute("type", this.type);
 
-        onCalendarRemoved(calendar) {
-            if (!calendar.getProperty("disabled")) {
-                this.calView.deleteItemsFromCalendar(calendar);
-            }
-        }
+      this.addEventListener(
+        "viewresize",
+        event => {
+          this.onResize(this);
+        },
+        true
+      );
+
+      // Add a preference observer to monitor changes.
+      Services.prefs.addObserver("calendar.", this.mPrefObserver);
+      Services.obs.addObserver(this.mTimezoneObserver, "defaultTimezoneChanged");
+
+      this.weekStartOffset = Services.prefs.getIntPref("calendar.week.start", 0);
+      this.updateDaysOffPrefs();
+      this.mPendingRefreshJobs = new Map();
 
-        onDefaultCalendarChanged(newDefaultCalendar) {
-            // We don't care, for now.
-        }
+      this.mLog = Log4Moz.getConfiguredLogger("calBaseView");
 
-        // End calICompositeObserver
+      // Remove observers on window unload.
+      window.addEventListener(
+        "unload",
+        () => {
+          if (this.mCalendar) {
+            this.mCalendar.removeObserver(this.mObserver);
+          }
+
+          alarmService.removeObserver(this.mObserver);
+
+          Services.prefs.removeObserver("calendar.", this.mPrefObserver);
+          Services.obs.removeObserver(this.mTimezoneObserver, "defaultTimezoneChanged");
+        },
+        { once: true }
+      );
     }
 
     /**
-     * Class for a refresh job object that is used in CalendarBaseView.addItemsFromCalendar.
+     * Handle resizing by adjusting the view to the new size.
+     *
+     * @param {calICalendarView} [calViewElem] - A calendar view element.
      */
-    class CalendarViewRefreshJob {
-        /**
-         * Constructor for CalendarViewRefreshJob.
-         *
-         * @param {CalendarBaseView} calendarView                   A calendar view.
-         * @param {calICalendar|calICompositeCalendar} calendar     A calendar object.
-         */
-        constructor(calendarView, calendar) {
-            this.QueryInterface = ChromeUtils.generateQI([Ci.calIOperationListener]);
-            this.calView = calendarView;
-            this.calendar = calendar;
-            this.calId = null;
-            this.operation = null;
-            this.cancelled = false;
-        }
+    onResize(calView) {
+      // Child classes should provide the implementation.
+      throw new Error(this.constructor.name + ".onResize not implemented");
+    }
 
-        onOperationComplete(opCalendar, status, operationType, id, dateTime) {
-            this.calView.mLog.info("Refresh complete of calendar " + this.calId);
-            if (this.calView.mPendingRefreshJobs.has(this.calId)) {
-                this.calView.mPendingRefreshJobs.delete(this.calId);
-            }
+    get type() {
+      const typelist = this.id.split("-");
+      return typelist[0];
+    }
+
+    get labeldaybox() {
+      return this.querySelector(".labeldaybox");
+    }
+
+    set rotated(rotated) {
+      return (this.orient = rotated ? "horizontal" : "vertical");
+    }
 
-            if (!this.cancelled) {
-                this.calView.fireEvent("viewloaded", operationType);
-            }
-        }
+    get rotated() {
+      return this.orient == "horizontal";
+    }
 
-        onGetResult(opCalendar, status, itemType, detail, count, items) {
-            if (this.cancelled || !Components.isSuccessCode(status)) {
-                return;
-            }
+    get supportsRotation() {
+      return false;
+    }
+
+    set displayDaysOff(displayDaysOff) {
+      return (this.mDisplayDaysOff = displayDaysOff);
+    }
 
-            for (const item of items) {
-                if (!cal.item.isToDo(item) || item.entryDate || item.dueDate) {
-                    this.calView.doAddItem(item);
-                }
-            }
-        }
+    get displayDaysOff() {
+      return this.mDisplayDaysOff;
+    }
+
+    set controller(controller) {
+      return (this.mController = controller);
+    }
 
-        cancel() {
-            this.calView.mLog.info("Refresh cancelled for calendar " + this.calId);
-            this.cancelled = true;
-            const operation = cal.wrapInstance(this.operation, Ci.calIOperation);
-            if (operation && operation.isPending) {
-                operation.cancel();
-                this.operation = null;
-            }
-        }
+    get controller() {
+      return this.mController;
+    }
+
+    set daysOffArray(daysOffArray) {
+      return (this.mDaysOffArray = daysOffArray);
+    }
 
-        execute() {
-            if (!this.calView.startDate || !this.calView.endDate || !this.calendar) {
-                return;
-            }
+    get daysOffArray() {
+      return this.mDaysOffArray;
+    }
+
+    set tasksInView(tasksInView) {
+      return (this.mTasksInView = tasksInView);
+    }
+
+    get tasksInView() {
+      return this.mTasksInView;
+    }
 
-            if (this.calendar.type == "composite") {
-                // We're refreshing from the composite calendar, so we can cancel
-                // all other pending refresh jobs.
-                this.calView.mLog.info("Refreshing composite calendar, cancelling all pending refreshes");
-                this.calId = "composite";
-                for (const job of this.calView.mPendingRefreshJobs.values()) {
-                    job.cancel();
-                }
-                this.calView.mPendingRefreshJobs.clear();
-                this.calView.relayout();
-            } else {
-                this.calId = this.calendar.id;
-                if (this.calView.mPendingRefreshJobs.has(this.calId)) {
-                    this.calView.mPendingRefreshJobs.get(this.calId).cancel();
-                    this.calView.mPendingRefreshJobs.delete(this.calId);
-                }
-            }
+    set showCompleted(showCompleted) {
+      return (this.mShowCompleted = showCompleted);
+    }
+
+    get showCompleted() {
+      return this.mShowCompleted;
+    }
+
+    set timezone(timezone) {
+      return (this.mTimezone = timezone);
+    }
 
-            // Start our items query. For a disjoint date range we get all the items,
-            // and just filter out the ones we don't care about in addItem.
-            let filter = this.calendar.ITEM_FILTER_CLASS_OCCURRENCES;
-            if (this.calView.mShowCompleted) {
-                filter |= this.calendar.ITEM_FILTER_COMPLETED_ALL;
-            } else {
-                filter |= this.calendar.ITEM_FILTER_COMPLETED_NO;
-            }
+    get timezone() {
+      return this.mTimezone;
+    }
+
+    set workdaysOnly(workdaysOnly) {
+      return (this.mWorkdaysOnly = workdaysOnly);
+    }
+
+    get workdaysOnly() {
+      return this.mWorkdaysOnly;
+    }
 
-            if (this.calView.mTasksInView) {
-                filter |= this.calendar.ITEM_FILTER_TYPE_ALL;
-            } else {
-                filter |= this.calendar.ITEM_FILTER_TYPE_EVENT;
-            }
+    get supportsWorkdaysOnly() {
+      return true;
+    }
 
-            let operation = this.calendar.getItems(filter,
-                0,
-                this.calView.startDate,
-                this.calView.queryEndDate,
-                this);
+    get supportsZoom() {
+      return false;
+    }
 
-            operation = cal.wrapInstance(operation, Ci.calIOperation);
-            if (operation && operation.isPending) {
-                this.operation = operation;
-                this.calView.mPendingRefreshJobs.set(this.calId, this);
-            }
-        }
+    get selectionObserver() {
+      return this.mSelectionObserver;
+    }
+
+    get startDay() {
+      return this.startDate;
     }
 
+    get endDay() {
+      return this.endDate;
+    }
+
+    get supportDisjointDates() {
+      return false;
+    }
+
+    get hasDisjointDates() {
+      return false;
+    }
+
+    set rangeStartDate(startDate) {
+      return (this.mRangeStartDate = startDate);
+    }
+
+    get rangeStartDate() {
+      return this.mRangeStartDate;
+    }
+
+    set rangeEndDate(endDate) {
+      return (this.mRangeEndDate = endDate);
+    }
+
+    get rangeEndDate() {
+      return this.mRangeEndDate;
+    }
+
+    get observerID() {
+      return "base-view-observer";
+    }
+
+    set weekStartOffset(offset) {
+      this.mWeekStartOffset = offset;
+      return offset;
+    }
+
+    get weekStartOffset() {
+      return this.mWeekStartOffset;
+    }
+
+    set displayCalendar(calendar) {
+      if (this.mCalendar) {
+        this.mCalendar.removeObserver(this.mObserver);
+      }
+      this.mCalendar = calendar;
+      this.mCalendar.addObserver(this.mObserver);
+      this.refresh();
+      return calendar;
+    }
+
+    get displayCalendar() {
+      return this.mCalendar;
+    }
+
+    get initialized() {
+      let retval;
+
+      // Some views throw when accessing an uninitialized startDay.
+      try {
+        retval = this.displayCalendar && this.startDay && this.endDay;
+      } catch (ex) {
+        return false;
+      }
+      return retval;
+    }
+
+    // The end date that should be used for getItems and similar queries.
+    get queryEndDate() {
+      if (!this.endDate) {
+        return null;
+      }
+      const end = this.endDate.clone();
+      end.day += 1;
+      end.isDate = true;
+      return end;
+    }
+
+    /**
+     * Guarantee that the labels are clipped when an overflow occurs, to
+     * prevent horizontal scrollbars from appearing briefly.
+     *
+     * @param {boolean} forceShortName  Whether to force the use of a short name.
+     */
+    adjustWeekdayLength(forceShortName) {
+      const labelDayBoxKids = this.labeldaybox.childNodes;
+      let useShortNames = false;
+
+      if (!labelDayBoxKids || !labelDayBoxKids[0] || forceShortName === true) {
+        useShortNames = true;
+      } else {
+        const clientWidth = this.querySelector(".mainbox").clientWidth;
+        const timespacer = this.querySelector(".headertimespacer");
+
+        const width = timespacer ? clientWidth - timespacer.clientWidth : clientWidth;
+
+        if (this.longWeekdayTotalPixels > 0.95 * width) {
+          useShortNames = true;
+        }
+      }
+
+      for (const kid of labelDayBoxKids) {
+        kid.shortWeekNames = useShortNames;
+      }
+    }
 
     /**
-     * Abstract base class for calendar view elements (day, week, multiweek, month).
+     * The width in pixels of the widest weekday label.
      *
-     * @implements {calICalendarView}
-     * @abstract
+     * @return {number}  A number of pixels.
      */
-    class CalendarBaseView extends MozXULElement {
-        connectedCallback() {
-            if (this.delayConnectedCallback() || this.hasConnected) {
-                return;
-            }
-            this.hasConnected = true;
-
-            this.calICalendarView = this.getCustomInterfaceCallback(Ci.calICalendarView);
-
-            this.addEventListener("move", (event) => {
-                this.moveView(event.detail);
-            });
-
-            this.addEventListener("keypress", (event) => {
-                switch (event.key) {
-                    case "PageUp":
-                        this.moveView(-1);
-                        break;
-                    case "PageDown":
-                        this.moveView(1);
-                        break;
-                }
-            });
-
-            this.addEventListener("wheel", (event) => {
-                const pixelThreshold = 150;
-
-                if (event.shiftKey &&
-                    Services.prefs.getBoolPref("calendar.view.mousescroll", true)) {
-                    let deltaView = 0;
-                    if (event.deltaMode == event.DOM_DELTA_LINE) {
-                        if (event.deltaY != 0) {
-                            deltaView = event.deltaY < 0 ? -1 : 1;
-                        }
-                    } else if (event.deltaMode == event.DOM_DELTA_PIXEL) {
-                        this.mPixelScrollDelta += event.deltaY;
-                        if (this.mPixelScrollDelta > pixelThreshold) {
-                            deltaView = 1;
-                            this.mPixelScrollDelta = 0;
-                        } else if (this.mPixelScrollDelta < -pixelThreshold) {
-                            deltaView = -1;
-                            this.mPixelScrollDelta = 0;
-                        }
-                    }
-
-                    if (deltaView != 0) {
-                        this.moveView(deltaView);
-                    }
-                }
-
-                event.preventDefault();
-            });
-
-            this.addEventListener("MozRotateGesture", (event) => {
-                // Threshold for the minimum and maximum angle we should accept
-                // rotation for. 90 degrees minimum is most logical, but 45 degrees
-                // allows you to rotate with one hand.
-                const MIN_ROTATE_ANGLE = 45;
-                const MAX_ROTATE_ANGLE = 180;
-
-                const absval = Math.abs(event.delta);
-                if (this.supportsRotation &&
-                    absval >= MIN_ROTATE_ANGLE &&
-                    absval < MAX_ROTATE_ANGLE) {
-                    toggleOrientation();
-                    event.preventDefault();
-                }
-            });
-
-            this.addEventListener("MozMagnifyGestureStart", (event) => {
-                this.mMagnifyAmount = 0;
-            });
-
-            this.addEventListener("MozMagnifyGestureUpdate", (event) => {
-                // Threshold as to how much magnification causes the zoom to happen.
-                const THRESHOLD = 30;
-
-                if (this.supportsZoom) {
-                    this.mMagnifyAmount += event.delta;
-
-                    if (this.mMagnifyAmount > THRESHOLD) {
-                        this.zoomOut();
-                        this.mMagnifyAmount = 0;
-                    } else if (this.mMagnifyAmount < -THRESHOLD) {
-                        this.zoomIn();
-                        this.mMagnifyAmount = 0;
-                    }
-                    event.preventDefault();
-                }
-            });
-
-            this.addEventListener("MozSwipeGesture", (event) => {
-                if ((event.direction == SimpleGestureEvent.DIRECTION_UP && !this.rotated) ||
-                    (event.direction == SimpleGestureEvent.DIRECTION_LEFT && this.rotated)) {
-                    this.moveView(-1);
-                } else if ((event.direction == SimpleGestureEvent.DIRECTION_DOWN && !this.rotated) ||
-                    (event.direction == SimpleGestureEvent.DIRECTION_RIGHT && this.rotated)) {
-                    this.moveView(1);
-                }
-            });
-
-            this.mWeekStartOffset = 0;
-
-            this.mRangeStartDate = null;
-            this.mRangeEndDate = null;
-
-            this.mWorkdaysOnly = false;
-            this.mPendingRefreshJobs = null;
-
-            this.mCalendar = null;
-            this.mController = null;
-
-            this.mStartDate = null;
-            this.mEndDate = null;
-
-            this.mTasksInView = false;
-            this.mShowCompleted = false;
-
-            this.mDisplayDaysOff = true;
-            this.mDaysOffArray = [0, 6];
-
-            this.mTimezone = null;
-            this.mFlashingEvents = null;
-
-            this.mSelectedItems = [];
-            this.mLongWeekdayTotalPixels = -1;
-
-            this.mResizeHandler = null;
-            this.mDropShadowsLength = null;
-
-            this.mShadowOffset = null;
-            this.mDropShadows = null;
-
-            this.mMagnifyAmount = 0;
-            this.mPixelScrollDelta = 0;
-
-            this.mViewStart = null;
-            this.mViewEnd = null;
-
-            this.mToggleStatus = 0;
-            this.mLog = null;
-
-            this.mToggleStatusFlag = {
-                WorkdaysOnly: 1,
-                TasksInView: 2,
-                ShowCompleted: 4,
-            };
-
-            this.mTimezoneObserver = {
-                observe: () => {
-                    this.timezone = cal.dtz.defaultTimezone;
-                    this.refreshView();
+    get longWeekdayTotalPixels() {
+      if (this.mLongWeekdayTotalPixels <= 0) {
+        let maxDayWidth = 0;
 
-                    if (this.updateTimeIndicatorPosition) {
-                        this.updateTimeIndicatorPosition(true);
-                    }
-                }
-            };
-
-            this.mPrefObserver = {
-                calView: this.calICalendarView,
-
-                observe(subj, topic, pref) {
-                    this.calView.handlePreference(subj, topic, pref);
-                }
-            };
-
-            this.mObserver = new CalendarViewObserver(this);
-
-            const isChecked = id => document.getElementById(id).getAttribute("checked") == "true";
-
-            this.workdaysOnly = isChecked("calendar_toggle_workdays_only_command");
-            this.tasksInView = isChecked("calendar_toggle_tasks_in_view_command");
-            this.rotated = isChecked("calendar_toggle_orientation_command");
-            this.showCompleted = isChecked("calendar_toggle_show_completed_in_view_command");
-
-            this.mTimezone = cal.dtz.defaultTimezone;
-            const alarmService = Cc["@mozilla.org/calendar/alarm-service;1"]
-                .getService(Ci.calIAlarmService);
-
-            alarmService.addObserver(this.mObserver);
-
-            this.setAttribute("type", this.type);
-            this.mResizeHandler = () => {
-                this.onResize(this);
-            };
-            document.getElementById("calendarviewBroadcaster").addEventListener(
-                this.getAttribute("type") + "viewresized",
-                this.mResizeHandler, true
-            );
-
-            // Add a preference observer to monitor changes.
-            Services.prefs.addObserver("calendar.", this.mPrefObserver);
-            Services.obs.addObserver(this.mTimezoneObserver, "defaultTimezoneChanged");
-
-            this.weekStartOffset = Services.prefs.getIntPref("calendar.week.start", 0);
-            this.updateDaysOffPrefs();
-            this.mPendingRefreshJobs = new Map();
-
-            const { Log4Moz } = ChromeUtils.import("resource:///modules/gloda/log4moz.js");
-            this.mLog = Log4Moz.getConfiguredLogger("calBaseView");
-            this.mFlashingEvents = {};
-
-            // Remove observers and listeners on window unload.
-            window.addEventListener("unload", () => {
-                if (this.mCalendar) {
-                    this.mCalendar.removeObserver(this.mObserver);
-                }
-
-                alarmService.removeObserver(this.mObserver);
-
-                document.getElementById("calendarviewBroadcaster").removeEventListener(
-                    this.getAttribute("type") + "viewresized",
-                    this.mResizeHandler,
-                    true);
-
-                Services.prefs.removeObserver("calendar.", this.mPrefObserver);
-                Services.obs.removeObserver(this.mTimezoneObserver, "defaultTimezoneChanged");
-            }, { once: true });
+        for (const label of this.labeldaybox.childNodes) {
+          if (label.localName == "calendar-day-label") {
+            label.shortWeekNames = false;
+            const curPixelLength = label.getLongWeekdayPixels();
+            maxDayWidth = Math.max(maxDayWidth, curPixelLength);
+          }
         }
-
-        get type() {
-            const typelist = this.id.split("-");
-            return typelist[0];
+        if (maxDayWidth > 0) {
+          this.mLongWeekdayTotalPixels = maxDayWidth * this.labeldaybox.childNodes.length + 10;
         }
-
-        get labeldaybox() {
-            return this.querySelector(".labeldaybox");
-        }
-
-        set rotated(rotated) {
-            return (this.orient = (rotated ? "horizontal" : "vertical"));
-        }
+      }
+      return this.mLongWeekdayTotalPixels;
+    }
 
-        get rotated() {
-            return (this.orient == "horizontal");
-        }
-
-        get supportsRotation() {
-            return false;
-        }
-
-        set displayDaysOff(displayDaysOff) {
-            return (this.mDisplayDaysOff = displayDaysOff);
-        }
-
-        get displayDaysOff() {
-            return this.mDisplayDaysOff;
-        }
-
-        set controller(controller) {
-            return (this.mController = controller);
-        }
-
-        get controller() {
-            return this.mController;
-        }
-
-        set daysOffArray(daysOffArray) {
-            return (this.mDaysOffArray = daysOffArray);
-        }
-
-        get daysOffArray() {
-            return this.mDaysOffArray;
-        }
-
-        set tasksInView(tasksInView) {
-            return (this.mTasksInView = tasksInView);
-        }
-
-        get tasksInView() {
-            return this.mTasksInView;
-        }
+    /**
+     * Return a date object representing the current day.
+     *
+     * @return {calIDateTime}    A date object.
+     */
+    today() {
+      const date = cal.dtz.jsDateToDateTime(new Date()).getInTimezone(this.mTimezone);
+      date.isDate = true;
+      return date;
+    }
 
-        set showCompleted(showCompleted) {
-            return (this.mShowCompleted = showCompleted);
-        }
-
-        get showCompleted() {
-            return this.mShowCompleted;
-        }
-
-        set timezone(timezone) {
-            return (this.mTimezone = timezone);
-        }
-
-        get timezone() {
-            return this.mTimezone;
-        }
-
-        set workdaysOnly(workdaysOnly) {
-            return (this.mWorkdaysOnly = workdaysOnly);
-        }
-
-        get workdaysOnly() {
-            return this.mWorkdaysOnly;
-        }
-
-        get supportsWorkdaysOnly() {
-            return true;
-        }
-
-        get supportsZoom() {
-            return false;
-        }
-
-        get selectionObserver() {
-            return this.mSelectionObserver;
-        }
-
-        get startDay() {
-            return this.startDate;
-        }
-
-        get endDay() {
-            return this.endDate;
-        }
+    /**
+     * Return whether this view is currently active and visible in the UI.
+     *
+     * @return {boolean}
+     */
+    isVisible() {
+      return this.nodeName == currentView().nodeName;
+    }
 
-        get supportDisjointDates() {
-            return false;
-        }
-
-        get hasDisjointDates() {
-            return false;
-        }
-
-        set rangeStartDate(startDate) {
-            return (this.mRangeStartDate = startDate);
-        }
-
-        get rangeStartDate() {
-            return this.mRangeStartDate;
-        }
-
-        set rangeEndDate(endDate) {
-            return (this.mRangeEndDate = endDate);
-        }
-
-        get rangeEndDate() {
-            return this.mRangeEndDate;
-        }
-
-        get observerID() {
-            return "base-view-observer";
-        }
-
-        set weekStartOffset(offset) {
-            this.mWeekStartOffset = offset;
-            return offset;
-        }
-
-        get weekStartOffset() {
-            return this.mWeekStartOffset;
-        }
-
-        set displayCalendar(calendar) {
-            if (this.mCalendar) {
-                this.mCalendar.removeObserver(this.mObserver);
-            }
-            this.mCalendar = calendar;
-            this.mCalendar.addObserver(this.mObserver);
-            this.refresh();
-            return calendar;
-        }
-
-        get displayCalendar() {
-            return this.mCalendar;
-        }
-
-        get initialized() {
-            let retval;
-
-            // Some views throw when accessing an uninitialized startDay.
-            try {
-                retval = this.displayCalendar && this.startDay && this.endDay;
-            } catch (ex) {
-                return false;
-            }
-            return retval;
-        }
-
-        // The end date that should be used for getItems and similar queries.
-        get queryEndDate() {
-            if (!this.endDate) {
-                return null;
-            }
-            const end = this.endDate.clone();
-            end.day += 1;
-            end.isDate = true;
-            return end;
-        }
+    /**
+     * Refresh the view if it is active and visible, or if refresh is forced.
+     *
+     * @param {boolean} [force]    Whether to force a refresh.
+     */
+    refresh(force) {
+      if (this.isVisible() || force) {
+        this.addItemsFromCalendar(this.mCalendar);
+      }
+    }
 
-        /**
-         * Guarantee that the labels are clipped when an overflow occurs, to
-         * prevent horizontal scrollbars from appearing briefly.
-         *
-         * @param {boolean} forceShortName  Whether to force the use of a short name.
-         */
-        adjustWeekdayLength(forceShortName) {
-            const labelDayBoxKids = this.labeldaybox.childNodes;
-            let useShortNames = false;
-
-            if (!labelDayBoxKids || !labelDayBoxKids[0] || forceShortName === true) {
-                useShortNames = true;
-            } else {
-                const clientWidth = this.querySelector(".mainbox").clientWidth;
-                const timespacer = this.querySelector(".headertimespacer");
-
-                const width = timespacer
-                    ? clientWidth - timespacer.clientWidth
-                    : clientWidth;
-
-                if (this.longWeekdayTotalPixels > 0.95 * width) {
-                    useShortNames = true;
-                }
-            }
-
-            for (const kid of labelDayBoxKids) {
-                kid.shortWeekNames = useShortNames;
-            }
-        }
-
-        /**
-         * The width in pixels of the widest weekday label.
-         *
-         * @return {number}  A number of pixels.
-         */
-        get longWeekdayTotalPixels() {
-            if (this.mLongWeekdayTotalPixels <= 0) {
-                let maxDayWidth = 0;
-
-                for (const label of this.labeldaybox.childNodes) {
-                    if (label.localName == "calendar-day-label") {
-                        label.shortWeekNames = false;
-                        const curPixelLength = label.getLongWeekdayPixels();
-                        maxDayWidth = Math.max(maxDayWidth, curPixelLength);
-                    }
-                }
-                if (maxDayWidth > 0) {
-                    this.mLongWeekdayTotalPixels = (maxDayWidth * this.labeldaybox.childNodes.length) + 10;
-                }
-            }
-            return this.mLongWeekdayTotalPixels;
-        }
-
-        /**
-         * Return a date object representing the current day.
-         *
-         * @return {calIDateTime}    A date object.
-         */
-        today() {
-            const date = cal.dtz.jsDateToDateTime(new Date()).getInTimezone(this.mTimezone);
-            date.isDate = true;
-            return date;
-        }
-
-        /**
-         * Return whether this view is currently active and visible in the UI.
-         *
-         * @return {boolean}
-         */
-        isVisible() {
-            return this.nodeName == currentView().nodeName;
-        }
-
-        /**
-         * Refresh the view if it is active and visible, or if refresh is forced.
-         *
-         * @param {boolean} [force]    Whether to force a refresh.
-         */
-        refresh(force) {
-            if (this.isVisible() || force) {
-                this.addItemsFromCalendar(this.mCalendar);
-            }
-        }
+    /**
+     * Force the view to refresh, even if it is not visible.
+     * This method is needed because when only a preference is toggled, the start
+     * and end date of the views are unchanged, therefore the inactive/invisible views
+     * may remain the same when switching to them.
+     */
+    forceRefresh() {
+      this.refresh(true);
+    }
 
-        /**
-         * Force the view to refresh, even if it is not visible.
-         * This method is needed because when only a preference is toggled, the start
-         * and end date of the views are unchanged, therefore the inactive/invisible views
-         * may remain the same when switching to them.
-         */
-        forceRefresh() {
-            this.refresh(true);
-        }
-
-        /**
-         * Add items from a calendar to the view. Also used for refreshing the view.
-         *
-         * @param {calICalendar|calICompositeCalendar} calendar    A calendar object.
-         */
-        addItemsFromCalendar(calendar) {
-            const refreshJob = new CalendarViewRefreshJob(this, calendar);
-            refreshJob.execute();
-        }
-
-        /**
-         * Delete items from a calendar. Must be implemented in subclasses.
-         *
-         * @param {calICalendar|calICompositeCalendar} calendar    A calendar object.
-         */
-        deleteItemsFromCalendar(calendar) {
-            throw Cr.NS_ERROR_NOT_IMPLEMENTED;
-        }
-
-        /**
-         * Create and fire an event.
-         *
-         * @param {string} eventName      Name of the event.
-         * @param {Object} eventDetail    The details to add to the event.
-         */
-        fireEvent(eventName, eventDetail) {
-            this.dispatchEvent(new CustomEvent(eventName,
-                { bubbles: true, cancelable: false, detail: eventDetail }));
-        }
-
-        /**
-         * A preference handler typically called by a preferences observer when a preference
-         * changes. Handles common preferences while other preferences are handled in subclasses.
-         *
-         * @param {Object} subject       A subject, a prefs object.
-         * @param {string} topic         A topic.
-         * @param {string} preference    A preference that has changed.
-         */
-        handleCommonPreference(subject, topic, preference) {
-            // Refresh view if categories seem to have changed.
-            if (preference.startsWith("calendar.category.color")) {
-                this.refreshView();
-                return;
-            }
-            switch (preference) {
-                case "calendar.week.d0sundaysoff":
-                case "calendar.week.d1mondaysoff":
-                case "calendar.week.d2tuesdaysoff":
-                case "calendar.week.d3wednesdaysoff":
-                case "calendar.week.d4thursdaysoff":
-                case "calendar.week.d5fridaysoff":
-                case "calendar.week.d6saturdaysoff":
-                    this.updateDaysOffPrefs();
-                    break;
-                case "calendar.alarms.indicator.show":
-                    // Break here to ensure the view is refreshed.
-                    break;
-                case "calendar.week.start":
-                    this.weekStartOffset = subject.getIntPref(preference);
-                    break;
-                case "calendar.date.format":
-                case "calendar.view.showLocation":
-                    this.refreshView();
-                    break;
-                default:
-                    return;
-            }
-            this.refreshView();
-        }
+    /**
+     * Add items from a calendar to the view. Also used for refreshing the view.
+     *
+     * @param {calICalendar|calICompositeCalendar} calendar    A calendar object.
+     */
+    addItemsFromCalendar(calendar) {
+      const refreshJob = new CalendarViewRefreshJob(this, calendar);
+      refreshJob.execute();
+    }
 
-        /**
-         * Check preferences and update which days are days off.
-         */
-        updateDaysOffPrefs() {
-            const prefix = "calendar.week.";
-            const daysOffPrefs = [
-                [0, "d0sundaysoff", "true"],
-                [1, "d1mondaysoff", "false"],
-                [2, "d2tuesdaysoff", "false"],
-                [3, "d3wednesdaysoff", "false"],
-                [4, "d4thursdaysoff", "false"],
-                [5, "d5fridaysoff", "false"],
-                [6, "d6saturdaysoff", "true"]
-            ];
-            const filterDaysOff = ([number, name, defaultValue]) =>
-                Services.prefs.getBoolPref(prefix + name, defaultValue);