Created
December 28, 2017 05:37
-
-
Save toddjcrane/2d7ac50853f8f5eefc39d0ee420a9245 to your computer and use it in GitHub Desktop.
This file has been truncated, but you can view the full file.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| /** | |
| * protonmail-web - 3.12.13 - 2017-12-06 14:26:36 | |
| * | |
| * copyright 2017 Proton Technologies AG | |
| * MIT | |
| */ | |
| "use strict"; | |
| function _asyncToGenerator(fn) { | |
| return function() { | |
| var gen = fn.apply(this, arguments); | |
| return new Promise(function(resolve, reject) { | |
| function step(key, arg) { | |
| try { | |
| var info = gen[key](arg), | |
| value = info.value | |
| } catch (error) { | |
| return void reject(error) | |
| } | |
| if (!info.done) return Promise.resolve(value).then(function(value) { | |
| step("next", value) | |
| }, function(err) { | |
| step("throw", err) | |
| }); | |
| resolve(value) | |
| } | |
| return step("next") | |
| }) | |
| } | |
| } | |
| function _asyncToGenerator(fn) { | |
| return function() { | |
| var gen = fn.apply(this, arguments); | |
| return new Promise(function(resolve, reject) { | |
| function step(key, arg) { | |
| try { | |
| var info = gen[key](arg), | |
| value = info.value | |
| } catch (error) { | |
| return void reject(error) | |
| } | |
| if (!info.done) return Promise.resolve(value).then(function(value) { | |
| step("next", value) | |
| }, function(err) { | |
| step("throw", err) | |
| }); | |
| resolve(value) | |
| } | |
| return step("next") | |
| }) | |
| } | |
| } | |
| function _defineProperty(obj, key, value) { | |
| return key in obj ? Object.defineProperty(obj, key, { | |
| value: value, | |
| enumerable: !0, | |
| configurable: !0, | |
| writable: !0 | |
| }) : obj[key] = value, obj | |
| } | |
| function _asyncToGenerator(fn) { | |
| return function() { | |
| var gen = fn.apply(this, arguments); | |
| return new Promise(function(resolve, reject) { | |
| function step(key, arg) { | |
| try { | |
| var info = gen[key](arg), | |
| value = info.value | |
| } catch (error) { | |
| return void reject(error) | |
| } | |
| if (!info.done) return Promise.resolve(value).then(function(value) { | |
| step("next", value) | |
| }, function(err) { | |
| step("throw", err) | |
| }); | |
| resolve(value) | |
| } | |
| return step("next") | |
| }) | |
| } | |
| } | |
| function _toConsumableArray(arr) { | |
| if (Array.isArray(arr)) { | |
| for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) arr2[i] = arr[i]; | |
| return arr2 | |
| } | |
| return Array.from(arr) | |
| } | |
| function _toConsumableArray(arr) { | |
| if (Array.isArray(arr)) { | |
| for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) arr2[i] = arr[i]; | |
| return arr2 | |
| } | |
| return Array.from(arr) | |
| } | |
| function _asyncToGenerator(fn) { | |
| return function() { | |
| var gen = fn.apply(this, arguments); | |
| return new Promise(function(resolve, reject) { | |
| function step(key, arg) { | |
| try { | |
| var info = gen[key](arg), | |
| value = info.value | |
| } catch (error) { | |
| return void reject(error) | |
| } | |
| if (!info.done) return Promise.resolve(value).then(function(value) { | |
| step("next", value) | |
| }, function(err) { | |
| step("throw", err) | |
| }); | |
| resolve(value) | |
| } | |
| return step("next") | |
| }) | |
| } | |
| } | |
| function _defineProperty(obj, key, value) { | |
| return key in obj ? Object.defineProperty(obj, key, { | |
| value: value, | |
| enumerable: !0, | |
| configurable: !0, | |
| writable: !0 | |
| }) : obj[key] = value, obj | |
| } | |
| function _defineProperty(obj, key, value) { | |
| return key in obj ? Object.defineProperty(obj, key, { | |
| value: value, | |
| enumerable: !0, | |
| configurable: !0, | |
| writable: !0 | |
| }) : obj[key] = value, obj | |
| } | |
| function _toConsumableArray(arr) { | |
| if (Array.isArray(arr)) { | |
| for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) arr2[i] = arr[i]; | |
| return arr2 | |
| } | |
| return Array.from(arr) | |
| } | |
| function _toConsumableArray(arr) { | |
| if (Array.isArray(arr)) { | |
| for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) arr2[i] = arr[i]; | |
| return arr2 | |
| } | |
| return Array.from(arr) | |
| } | |
| function _defineProperty(obj, key, value) { | |
| return key in obj ? Object.defineProperty(obj, key, { | |
| value: value, | |
| enumerable: !0, | |
| configurable: !0, | |
| writable: !0 | |
| }) : obj[key] = value, obj | |
| } | |
| function generateDirective(attrName) { | |
| function assert(condition, missing, found) { | |
| if (!condition) throw new Error("You should add a " + missing + " attribute whenever you add a " + found + " attribute.") | |
| } | |
| var normAttrName = function(attributeName) { | |
| function camelCase(name) { | |
| return name.replace(SPECIAL_CHARS_REGEXP, function(_, separator, letter, offset) { | |
| return offset ? letter.toUpperCase() : letter | |
| }).replace(MOZ_HACK_REGEXP, "Moz$1") | |
| } | |
| var SPECIAL_CHARS_REGEXP = /([:\-_]+(.))/g, | |
| MOZ_HACK_REGEXP = /^moz([A-Z])/, | |
| PREFIX_REGEXP = /^(x[:\-_]|data[:\-_])/i; | |
| return function(name) { | |
| return camelCase(name.replace(PREFIX_REGEXP, "")) | |
| }(attributeName) | |
| }(attrName); | |
| return ["gettextCatalog", "$parse", "$animate", "$compile", function(gettextCatalog, $parse, $animate, $compile) { | |
| return { | |
| restrict: "A", | |
| terminal: !0, | |
| priority: 1e3, | |
| compile: function(element, attrs) { | |
| if (!attrs[normAttrName + "Translate"]) throw new Error("Missing " + normAttrName + "-translate attribute!"); | |
| assert(!attrs[normAttrName + "TranslatePlural"] || attrs[normAttrName + "TranslateN"], normAttrName + "translate-n", normAttrName + "translate-plural"), assert(!attrs[normAttrName + "TranslateN"] || attrs[normAttrName + "TranslatePlural"], normAttrName + "translate-plural", normAttrName + "translate-n"); | |
| var msgid = attrs[normAttrName + "Translate"], | |
| translatePlural = attrs[normAttrName + "TranslatePlural"], | |
| translateContext = attrs[normAttrName + "TranslateContext"]; | |
| return { | |
| pre: function(scope, element, attrs) { | |
| function update() { | |
| var translated = void 0; | |
| translatePlural ? (scope = pluralScope || (pluralScope = scope.$new()), scope.$count = countFn(scope), translated = gettextCatalog.getPlural(scope.$count, msgid, translatePlural, {}, translateContext)) : translated = gettextCatalog.getString(msgid, null, translateContext), translated !== attrs[normAttrName] && 8 !== element[0].nodeType && element[0].setAttribute(attrName, translated) | |
| } | |
| var attribute = attrs[normAttrName + "TranslateN"], | |
| countFn = attribute ? angular.noop : $parse(attribute), | |
| pluralScope = null; | |
| attribute && scope.$watch(attribute, update), scope.$on("gettextLanguageChanged", update), update(), element.removeAttr(attrName + "-translate"), $compile(element)(scope) | |
| } | |
| } | |
| } | |
| } | |
| }] | |
| } | |
| function _asyncToGenerator(fn) { | |
| return function() { | |
| var gen = fn.apply(this, arguments); | |
| return new Promise(function(resolve, reject) { | |
| function step(key, arg) { | |
| try { | |
| var info = gen[key](arg), | |
| value = info.value | |
| } catch (error) { | |
| return void reject(error) | |
| } | |
| if (!info.done) return Promise.resolve(value).then(function(value) { | |
| step("next", value) | |
| }, function(err) { | |
| step("throw", err) | |
| }); | |
| resolve(value) | |
| } | |
| return step("next") | |
| }) | |
| } | |
| } | |
| function _asyncToGenerator(fn) { | |
| return function() { | |
| var gen = fn.apply(this, arguments); | |
| return new Promise(function(resolve, reject) { | |
| function step(key, arg) { | |
| try { | |
| var info = gen[key](arg), | |
| value = info.value | |
| } catch (error) { | |
| return void reject(error) | |
| } | |
| if (!info.done) return Promise.resolve(value).then(function(value) { | |
| step("next", value) | |
| }, function(err) { | |
| step("throw", err) | |
| }); | |
| resolve(value) | |
| } | |
| return step("next") | |
| }) | |
| } | |
| } | |
| function _taggedTemplateLiteral(strings, raw) { | |
| return Object.freeze(Object.defineProperties(strings, { | |
| raw: { | |
| value: Object.freeze(raw) | |
| } | |
| })) | |
| } | |
| function _asyncToGenerator(fn) { | |
| return function() { | |
| var gen = fn.apply(this, arguments); | |
| return new Promise(function(resolve, reject) { | |
| function step(key, arg) { | |
| try { | |
| var info = gen[key](arg), | |
| value = info.value | |
| } catch (error) { | |
| return void reject(error) | |
| } | |
| if (!info.done) return Promise.resolve(value).then(function(value) { | |
| step("next", value) | |
| }, function(err) { | |
| step("throw", err) | |
| }); | |
| resolve(value) | |
| } | |
| return step("next") | |
| }) | |
| } | |
| } | |
| function _toArray(arr) { | |
| return Array.isArray(arr) ? arr : Array.from(arr) | |
| } | |
| function _defineProperty(obj, key, value) { | |
| return key in obj ? Object.defineProperty(obj, key, { | |
| value: value, | |
| enumerable: !0, | |
| configurable: !0, | |
| writable: !0 | |
| }) : obj[key] = value, obj | |
| } | |
| function _toConsumableArray(arr) { | |
| if (Array.isArray(arr)) { | |
| for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) arr2[i] = arr[i]; | |
| return arr2 | |
| } | |
| return Array.from(arr) | |
| } | |
| function _asyncToGenerator(fn) { | |
| return function() { | |
| var gen = fn.apply(this, arguments); | |
| return new Promise(function(resolve, reject) { | |
| function step(key, arg) { | |
| try { | |
| var info = gen[key](arg), | |
| value = info.value | |
| } catch (error) { | |
| return void reject(error) | |
| } | |
| if (!info.done) return Promise.resolve(value).then(function(value) { | |
| step("next", value) | |
| }, function(err) { | |
| step("throw", err) | |
| }); | |
| resolve(value) | |
| } | |
| return step("next") | |
| }) | |
| } | |
| } | |
| function _asyncToGenerator(fn) { | |
| return function() { | |
| var gen = fn.apply(this, arguments); | |
| return new Promise(function(resolve, reject) { | |
| function step(key, arg) { | |
| try { | |
| var info = gen[key](arg), | |
| value = info.value | |
| } catch (error) { | |
| return void reject(error) | |
| } | |
| if (!info.done) return Promise.resolve(value).then(function(value) { | |
| step("next", value) | |
| }, function(err) { | |
| step("throw", err) | |
| }); | |
| resolve(value) | |
| } | |
| return step("next") | |
| }) | |
| } | |
| } | |
| function _asyncToGenerator(fn) { | |
| return function() { | |
| var gen = fn.apply(this, arguments); | |
| return new Promise(function(resolve, reject) { | |
| function step(key, arg) { | |
| try { | |
| var info = gen[key](arg), | |
| value = info.value | |
| } catch (error) { | |
| return void reject(error) | |
| } | |
| if (!info.done) return Promise.resolve(value).then(function(value) { | |
| step("next", value) | |
| }, function(err) { | |
| step("throw", err) | |
| }); | |
| resolve(value) | |
| } | |
| return step("next") | |
| }) | |
| } | |
| } | |
| function _asyncToGenerator(fn) { | |
| return function() { | |
| var gen = fn.apply(this, arguments); | |
| return new Promise(function(resolve, reject) { | |
| function step(key, arg) { | |
| try { | |
| var info = gen[key](arg), | |
| value = info.value | |
| } catch (error) { | |
| return void reject(error) | |
| } | |
| if (!info.done) return Promise.resolve(value).then(function(value) { | |
| step("next", value) | |
| }, function(err) { | |
| step("throw", err) | |
| }); | |
| resolve(value) | |
| } | |
| return step("next") | |
| }) | |
| } | |
| } | |
| function _asyncToGenerator(fn) { | |
| return function() { | |
| var gen = fn.apply(this, arguments); | |
| return new Promise(function(resolve, reject) { | |
| function step(key, arg) { | |
| try { | |
| var info = gen[key](arg), | |
| value = info.value | |
| } catch (error) { | |
| return void reject(error) | |
| } | |
| if (!info.done) return Promise.resolve(value).then(function(value) { | |
| step("next", value) | |
| }, function(err) { | |
| step("throw", err) | |
| }); | |
| resolve(value) | |
| } | |
| return step("next") | |
| }) | |
| } | |
| } | |
| function _asyncToGenerator(fn) { | |
| return function() { | |
| var gen = fn.apply(this, arguments); | |
| return new Promise(function(resolve, reject) { | |
| function step(key, arg) { | |
| try { | |
| var info = gen[key](arg), | |
| value = info.value | |
| } catch (error) { | |
| return void reject(error) | |
| } | |
| if (!info.done) return Promise.resolve(value).then(function(value) { | |
| step("next", value) | |
| }, function(err) { | |
| step("throw", err) | |
| }); | |
| resolve(value) | |
| } | |
| return step("next") | |
| }) | |
| } | |
| } | |
| function _toConsumableArray(arr) { | |
| if (Array.isArray(arr)) { | |
| for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) arr2[i] = arr[i]; | |
| return arr2 | |
| } | |
| return Array.from(arr) | |
| } | |
| function _defineProperty(obj, key, value) { | |
| return key in obj ? Object.defineProperty(obj, key, { | |
| value: value, | |
| enumerable: !0, | |
| configurable: !0, | |
| writable: !0 | |
| }) : obj[key] = value, obj | |
| } | |
| function _asyncToGenerator(fn) { | |
| return function() { | |
| var gen = fn.apply(this, arguments); | |
| return new Promise(function(resolve, reject) { | |
| function step(key, arg) { | |
| try { | |
| var info = gen[key](arg), | |
| value = info.value | |
| } catch (error) { | |
| return void reject(error) | |
| } | |
| if (!info.done) return Promise.resolve(value).then(function(value) { | |
| step("next", value) | |
| }, function(err) { | |
| step("throw", err) | |
| }); | |
| resolve(value) | |
| } | |
| return step("next") | |
| }) | |
| } | |
| } | |
| function _asyncToGenerator(fn) { | |
| return function() { | |
| var gen = fn.apply(this, arguments); | |
| return new Promise(function(resolve, reject) { | |
| function step(key, arg) { | |
| try { | |
| var info = gen[key](arg), | |
| value = info.value | |
| } catch (error) { | |
| return void reject(error) | |
| } | |
| if (!info.done) return Promise.resolve(value).then(function(value) { | |
| step("next", value) | |
| }, function(err) { | |
| step("throw", err) | |
| }); | |
| resolve(value) | |
| } | |
| return step("next") | |
| }) | |
| } | |
| } | |
| function _toConsumableArray(arr) { | |
| if (Array.isArray(arr)) { | |
| for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) arr2[i] = arr[i]; | |
| return arr2 | |
| } | |
| return Array.from(arr) | |
| } | |
| function _asyncToGenerator(fn) { | |
| return function() { | |
| var gen = fn.apply(this, arguments); | |
| return new Promise(function(resolve, reject) { | |
| function step(key, arg) { | |
| try { | |
| var info = gen[key](arg), | |
| value = info.value | |
| } catch (error) { | |
| return void reject(error) | |
| } | |
| if (!info.done) return Promise.resolve(value).then(function(value) { | |
| step("next", value) | |
| }, function(err) { | |
| step("throw", err) | |
| }); | |
| resolve(value) | |
| } | |
| return step("next") | |
| }) | |
| } | |
| } | |
| function _defineProperty(obj, key, value) { | |
| return key in obj ? Object.defineProperty(obj, key, { | |
| value: value, | |
| enumerable: !0, | |
| configurable: !0, | |
| writable: !0 | |
| }) : obj[key] = value, obj | |
| } | |
| function _defineProperty(obj, key, value) { | |
| return key in obj ? Object.defineProperty(obj, key, { | |
| value: value, | |
| enumerable: !0, | |
| configurable: !0, | |
| writable: !0 | |
| }) : obj[key] = value, obj | |
| } | |
| function _defineProperty(obj, key, value) { | |
| return key in obj ? Object.defineProperty(obj, key, { | |
| value: value, | |
| enumerable: !0, | |
| configurable: !0, | |
| writable: !0 | |
| }) : obj[key] = value, obj | |
| } | |
| function _toConsumableArray(arr) { | |
| if (Array.isArray(arr)) { | |
| for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) arr2[i] = arr[i]; | |
| return arr2 | |
| } | |
| return Array.from(arr) | |
| } | |
| function _defineProperty(obj, key, value) { | |
| return key in obj ? Object.defineProperty(obj, key, { | |
| value: value, | |
| enumerable: !0, | |
| configurable: !0, | |
| writable: !0 | |
| }) : obj[key] = value, obj | |
| } | |
| function _asyncToGenerator(fn) { | |
| return function() { | |
| var gen = fn.apply(this, arguments); | |
| return new Promise(function(resolve, reject) { | |
| function step(key, arg) { | |
| try { | |
| var info = gen[key](arg), | |
| value = info.value | |
| } catch (error) { | |
| return void reject(error) | |
| } | |
| if (!info.done) return Promise.resolve(value).then(function(value) { | |
| step("next", value) | |
| }, function(err) { | |
| step("throw", err) | |
| }); | |
| resolve(value) | |
| } | |
| return step("next") | |
| }) | |
| } | |
| } | |
| function _asyncToGenerator(fn) { | |
| return function() { | |
| var gen = fn.apply(this, arguments); | |
| return new Promise(function(resolve, reject) { | |
| function step(key, arg) { | |
| try { | |
| var info = gen[key](arg), | |
| value = info.value | |
| } catch (error) { | |
| return void reject(error) | |
| } | |
| if (!info.done) return Promise.resolve(value).then(function(value) { | |
| step("next", value) | |
| }, function(err) { | |
| step("throw", err) | |
| }); | |
| resolve(value) | |
| } | |
| return step("next") | |
| }) | |
| } | |
| } | |
| function _defineProperty(obj, key, value) { | |
| return key in obj ? Object.defineProperty(obj, key, { | |
| value: value, | |
| enumerable: !0, | |
| configurable: !0, | |
| writable: !0 | |
| }) : obj[key] = value, obj | |
| } | |
| function _taggedTemplateLiteral(strings, raw) { | |
| return Object.freeze(Object.defineProperties(strings, { | |
| raw: { | |
| value: Object.freeze(raw) | |
| } | |
| })) | |
| } | |
| function _toArray(arr) { | |
| return Array.isArray(arr) ? arr : Array.from(arr) | |
| } | |
| function _toArray(arr) { | |
| return Array.isArray(arr) ? arr : Array.from(arr) | |
| } | |
| function _defineProperty(obj, key, value) { | |
| return key in obj ? Object.defineProperty(obj, key, { | |
| value: value, | |
| enumerable: !0, | |
| configurable: !0, | |
| writable: !0 | |
| }) : obj[key] = value, obj | |
| } | |
| function _toConsumableArray(arr) { | |
| if (Array.isArray(arr)) { | |
| for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) arr2[i] = arr[i]; | |
| return arr2 | |
| } | |
| return Array.from(arr) | |
| } | |
| function _defineProperty(obj, key, value) { | |
| return key in obj ? Object.defineProperty(obj, key, { | |
| value: value, | |
| enumerable: !0, | |
| configurable: !0, | |
| writable: !0 | |
| }) : obj[key] = value, obj | |
| } | |
| function _asyncToGenerator(fn) { | |
| return function() { | |
| var gen = fn.apply(this, arguments); | |
| return new Promise(function(resolve, reject) { | |
| function step(key, arg) { | |
| try { | |
| var info = gen[key](arg), | |
| value = info.value | |
| } catch (error) { | |
| return void reject(error) | |
| } | |
| if (!info.done) return Promise.resolve(value).then(function(value) { | |
| step("next", value) | |
| }, function(err) { | |
| step("throw", err) | |
| }); | |
| resolve(value) | |
| } | |
| return step("next") | |
| }) | |
| } | |
| } | |
| function _asyncToGenerator(fn) { | |
| return function() { | |
| var gen = fn.apply(this, arguments); | |
| return new Promise(function(resolve, reject) { | |
| function step(key, arg) { | |
| try { | |
| var info = gen[key](arg), | |
| value = info.value | |
| } catch (error) { | |
| return void reject(error) | |
| } | |
| if (!info.done) return Promise.resolve(value).then(function(value) { | |
| step("next", value) | |
| }, function(err) { | |
| step("throw", err) | |
| }); | |
| resolve(value) | |
| } | |
| return step("next") | |
| }) | |
| } | |
| } | |
| function _defineProperty(obj, key, value) { | |
| return key in obj ? Object.defineProperty(obj, key, { | |
| value: value, | |
| enumerable: !0, | |
| configurable: !0, | |
| writable: !0 | |
| }) : obj[key] = value, obj | |
| } | |
| function _classCallCheck(instance, Constructor) { | |
| if (!(instance instanceof Constructor)) throw new TypeError("Cannot call a class as a function") | |
| } | |
| function _asyncToGenerator(fn) { | |
| return function() { | |
| var gen = fn.apply(this, arguments); | |
| return new Promise(function(resolve, reject) { | |
| function step(key, arg) { | |
| try { | |
| var info = gen[key](arg), | |
| value = info.value | |
| } catch (error) { | |
| return void reject(error) | |
| } | |
| if (!info.done) return Promise.resolve(value).then(function(value) { | |
| step("next", value) | |
| }, function(err) { | |
| step("throw", err) | |
| }); | |
| resolve(value) | |
| } | |
| return step("next") | |
| }) | |
| } | |
| } | |
| function _asyncToGenerator(fn) { | |
| return function() { | |
| var gen = fn.apply(this, arguments); | |
| return new Promise(function(resolve, reject) { | |
| function step(key, arg) { | |
| try { | |
| var info = gen[key](arg), | |
| value = info.value | |
| } catch (error) { | |
| return void reject(error) | |
| } | |
| if (!info.done) return Promise.resolve(value).then(function(value) { | |
| step("next", value) | |
| }, function(err) { | |
| step("throw", err) | |
| }); | |
| resolve(value) | |
| } | |
| return step("next") | |
| }) | |
| } | |
| } | |
| function _asyncToGenerator(fn) { | |
| return function() { | |
| var gen = fn.apply(this, arguments); | |
| return new Promise(function(resolve, reject) { | |
| function step(key, arg) { | |
| try { | |
| var info = gen[key](arg), | |
| value = info.value | |
| } catch (error) { | |
| return void reject(error) | |
| } | |
| if (!info.done) return Promise.resolve(value).then(function(value) { | |
| step("next", value) | |
| }, function(err) { | |
| step("throw", err) | |
| }); | |
| resolve(value) | |
| } | |
| return step("next") | |
| }) | |
| } | |
| } | |
| function _toConsumableArray(arr) { | |
| if (Array.isArray(arr)) { | |
| for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) arr2[i] = arr[i]; | |
| return arr2 | |
| } | |
| return Array.from(arr) | |
| } | |
| function _defineProperty(obj, key, value) { | |
| return key in obj ? Object.defineProperty(obj, key, { | |
| value: value, | |
| enumerable: !0, | |
| configurable: !0, | |
| writable: !0 | |
| }) : obj[key] = value, obj | |
| } | |
| function _asyncToGenerator(fn) { | |
| return function() { | |
| var gen = fn.apply(this, arguments); | |
| return new Promise(function(resolve, reject) { | |
| function step(key, arg) { | |
| try { | |
| var info = gen[key](arg), | |
| value = info.value | |
| } catch (error) { | |
| return void reject(error) | |
| } | |
| if (!info.done) return Promise.resolve(value).then(function(value) { | |
| step("next", value) | |
| }, function(err) { | |
| step("throw", err) | |
| }); | |
| resolve(value) | |
| } | |
| return step("next") | |
| }) | |
| } | |
| } | |
| function _asyncToGenerator(fn) { | |
| return function() { | |
| var gen = fn.apply(this, arguments); | |
| return new Promise(function(resolve, reject) { | |
| function step(key, arg) { | |
| try { | |
| var info = gen[key](arg), | |
| value = info.value | |
| } catch (error) { | |
| return void reject(error) | |
| } | |
| if (!info.done) return Promise.resolve(value).then(function(value) { | |
| step("next", value) | |
| }, function(err) { | |
| step("throw", err) | |
| }); | |
| resolve(value) | |
| } | |
| return step("next") | |
| }) | |
| } | |
| } | |
| function _toConsumableArray(arr) { | |
| if (Array.isArray(arr)) { | |
| for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) arr2[i] = arr[i]; | |
| return arr2 | |
| } | |
| return Array.from(arr) | |
| } | |
| function _asyncToGenerator(fn) { | |
| return function() { | |
| var gen = fn.apply(this, arguments); | |
| return new Promise(function(resolve, reject) { | |
| function step(key, arg) { | |
| try { | |
| var info = gen[key](arg), | |
| value = info.value | |
| } catch (error) { | |
| return void reject(error) | |
| } | |
| if (!info.done) return Promise.resolve(value).then(function(value) { | |
| step("next", value) | |
| }, function(err) { | |
| step("throw", err) | |
| }); | |
| resolve(value) | |
| } | |
| return step("next") | |
| }) | |
| } | |
| } | |
| function _defineProperty(obj, key, value) { | |
| return key in obj ? Object.defineProperty(obj, key, { | |
| value: value, | |
| enumerable: !0, | |
| configurable: !0, | |
| writable: !0 | |
| }) : obj[key] = value, obj | |
| } | |
| function _toConsumableArray(arr) { | |
| if (Array.isArray(arr)) { | |
| for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) arr2[i] = arr[i]; | |
| return arr2 | |
| } | |
| return Array.from(arr) | |
| } | |
| function _defineProperty(obj, key, value) { | |
| return key in obj ? Object.defineProperty(obj, key, { | |
| value: value, | |
| enumerable: !0, | |
| configurable: !0, | |
| writable: !0 | |
| }) : obj[key] = value, obj | |
| } | |
| function _asyncToGenerator(fn) { | |
| return function() { | |
| var gen = fn.apply(this, arguments); | |
| return new Promise(function(resolve, reject) { | |
| function step(key, arg) { | |
| try { | |
| var info = gen[key](arg), | |
| value = info.value | |
| } catch (error) { | |
| return void reject(error) | |
| } | |
| if (!info.done) return Promise.resolve(value).then(function(value) { | |
| step("next", value) | |
| }, function(err) { | |
| step("throw", err) | |
| }); | |
| resolve(value) | |
| } | |
| return step("next") | |
| }) | |
| } | |
| } | |
| function _asyncToGenerator(fn) { | |
| return function() { | |
| var gen = fn.apply(this, arguments); | |
| return new Promise(function(resolve, reject) { | |
| function step(key, arg) { | |
| try { | |
| var info = gen[key](arg), | |
| value = info.value | |
| } catch (error) { | |
| return void reject(error) | |
| } | |
| if (!info.done) return Promise.resolve(value).then(function(value) { | |
| step("next", value) | |
| }, function(err) { | |
| step("throw", err) | |
| }); | |
| resolve(value) | |
| } | |
| return step("next") | |
| }) | |
| } | |
| } | |
| function _asyncToGenerator(fn) { | |
| return function() { | |
| var gen = fn.apply(this, arguments); | |
| return new Promise(function(resolve, reject) { | |
| function step(key, arg) { | |
| try { | |
| var info = gen[key](arg), | |
| value = info.value | |
| } catch (error) { | |
| return void reject(error) | |
| } | |
| if (!info.done) return Promise.resolve(value).then(function(value) { | |
| step("next", value) | |
| }, function(err) { | |
| step("throw", err) | |
| }); | |
| resolve(value) | |
| } | |
| return step("next") | |
| }) | |
| } | |
| } | |
| function _asyncToGenerator(fn) { | |
| return function() { | |
| var gen = fn.apply(this, arguments); | |
| return new Promise(function(resolve, reject) { | |
| function step(key, arg) { | |
| try { | |
| var info = gen[key](arg), | |
| value = info.value | |
| } catch (error) { | |
| return void reject(error) | |
| } | |
| if (!info.done) return Promise.resolve(value).then(function(value) { | |
| step("next", value) | |
| }, function(err) { | |
| step("throw", err) | |
| }); | |
| resolve(value) | |
| } | |
| return step("next") | |
| }) | |
| } | |
| } | |
| function _asyncToGenerator(fn) { | |
| return function() { | |
| var gen = fn.apply(this, arguments); | |
| return new Promise(function(resolve, reject) { | |
| function step(key, arg) { | |
| try { | |
| var info = gen[key](arg), | |
| value = info.value | |
| } catch (error) { | |
| return void reject(error) | |
| } | |
| if (!info.done) return Promise.resolve(value).then(function(value) { | |
| step("next", value) | |
| }, function(err) { | |
| step("throw", err) | |
| }); | |
| resolve(value) | |
| } | |
| return step("next") | |
| }) | |
| } | |
| } | |
| function _asyncToGenerator(fn) { | |
| return function() { | |
| var gen = fn.apply(this, arguments); | |
| return new Promise(function(resolve, reject) { | |
| function step(key, arg) { | |
| try { | |
| var info = gen[key](arg), | |
| value = info.value | |
| } catch (error) { | |
| return void reject(error) | |
| } | |
| if (!info.done) return Promise.resolve(value).then(function(value) { | |
| step("next", value) | |
| }, function(err) { | |
| step("throw", err) | |
| }); | |
| resolve(value) | |
| } | |
| return step("next") | |
| }) | |
| } | |
| } | |
| function _defineProperty(obj, key, value) { | |
| return key in obj ? Object.defineProperty(obj, key, { | |
| value: value, | |
| enumerable: !0, | |
| configurable: !0, | |
| writable: !0 | |
| }) : obj[key] = value, obj | |
| } | |
| angular.module("proton.address", []), | |
| angular.module("proton.analytics", []).run(function(analytics, eventListener) { | |
| analytics.init(), eventListener.init() | |
| }), | |
| angular.module("proton.attachments", ["proton.authentication", "proton.utils"]), | |
| angular.module("proton.authentication", ["proton.constants", "proton.utils", "proton.settings", "proton.keys"]).run(function($rootScope, authentication) { | |
| authentication.detectAuthenticationState(), $rootScope.isLoggedIn = authentication.isLoggedIn(), $rootScope.isLocked = authentication.isLocked(), $rootScope.isSecure = authentication.isSecured() | |
| }), | |
| angular.module("proton.autoresponder", []), | |
| angular.module("proton.blackFriday", []).run(function(blackFridayModel) { | |
| return blackFridayModel.init() | |
| }), | |
| angular.module("proton.bridge", []), | |
| angular.module("proton.browserSupport", []).run(function(browserFixes) { | |
| return browserFixes.init() | |
| }), | |
| angular.module("proton.bugReport", []).run(function(bugReportModel) { | |
| return bugReportModel.init() | |
| }), | |
| angular.module("proton.commons", []), | |
| angular.module("proton.composer", ["proton.constants"]), | |
| angular.module("proton.contact", ["vs-repeat"]).run(function(contactEditor, contactMerger) { | |
| contactEditor.init(), contactMerger.init() | |
| }).config(function($stateProvider) { | |
| $stateProvider.state("secured.contacts", { | |
| url: "/contacts?sort&page&keyword", | |
| params: { | |
| page: { | |
| value: null, | |
| squash: !0 | |
| }, | |
| keyword: { | |
| value: null, | |
| squash: !0 | |
| }, | |
| sort: { | |
| value: null, | |
| squash: !0 | |
| } | |
| }, | |
| resolve: { | |
| delinquent: function(user, isDelinquent) { | |
| return isDelinquent() | |
| } | |
| }, | |
| views: { | |
| "content@secured": { | |
| template: "<contact-view></contact-view>" | |
| } | |
| }, | |
| onEnter: function(AppModel) { | |
| AppModel.set("contactSidebar", !0) | |
| }, | |
| onExit: function(AppModel) { | |
| AppModel.set("contactSidebar", !1) | |
| } | |
| }).state("secured.contacts.details", { | |
| url: "/:id", | |
| params: { | |
| id: null | |
| }, | |
| views: { | |
| "[email protected]": { | |
| template: '<div class="contactsDetails-body"><contact-details ng-if="contact" data-contact="contact"></contact-details><loader-tag></loader-tag></div>', | |
| controller: function($scope, $stateParams, contactCache) { | |
| contactCache.find($stateParams.id).then(function(data) { | |
| return $scope.$applyAsync(function() { | |
| $scope.contact = data | |
| }) | |
| }) | |
| } | |
| } | |
| } | |
| }) | |
| }), | |
| angular.module("proton.conversation", []).config(function($httpProvider) { | |
| $httpProvider.interceptors.push("conversationsInterceptor") | |
| }), | |
| angular.module("proton.core", ["proton.constants", "proton.utils"]).run(function(paginationModel, cachePages) { | |
| paginationModel.init(), cachePages.init() | |
| }), | |
| angular.module("proton.dashboard", []), | |
| angular.module("proton.dnd", []).run(function(actionDnd) { | |
| return actionDnd.init() | |
| }), | |
| angular.module("proton.domains", []), | |
| angular.module("proton.elements", ["proton.constants"]), | |
| angular.module("proton.filter", ["proton.constants", "proton.utils"]).run(function(sieveLint) { | |
| return sieveLint.init() | |
| }), | |
| angular.module("proton.formUtils", ["ngIntlTelInput"]), | |
| angular.module("proton.keys", ["proton.elements"]), | |
| angular.module("proton.labels", []), | |
| angular.module("proton.members", []), | |
| angular.module("proton.message", ["ngSanitize"]).run(function(unsubscribeModel) { | |
| return unsubscribeModel.init() | |
| }), | |
| angular.module("proton.organization", []), | |
| angular.module("proton.outside", ["proton.routes", "proton.constants", "proton.utils"]).run(function(attachmentModelOutside) { | |
| return attachmentModelOutside.load() | |
| }), | |
| angular.module("proton.payment", []).config(function($httpProvider) { | |
| $httpProvider.interceptors.push("paymentsInterceptor") | |
| }), | |
| angular.module("proton.search", []).run(function(wildcardModel) { | |
| return wildcardModel.init() | |
| }), | |
| angular.module("proton.settings", []), | |
| angular.module("proton.sidebar", []), | |
| angular.module("proton.squire", []), | |
| angular.module("proton.ui", ["ui.indeterminate"]).run(function(backState) { | |
| return backState.init() | |
| }), | |
| angular.module("proton.user", []), | |
| angular.module("proton.utils", ["proton.constants"]).run(function(resurrecter) { | |
| return resurrecter.init() | |
| }), | |
| angular.module("proton.vpn", []), | |
| angular.module("proton.wizard", []), | |
| angular.module("proton.address").directive("addressBtnActions", function(addressModel, gettextCatalog) { | |
| var I18N = { | |
| makeDefault: gettextCatalog.getString("Make default", null, "Action"), | |
| editSignature: gettextCatalog.getString("Edit signature", null, "Action"), | |
| disable: gettextCatalog.getString("Disable", null, "Action"), | |
| enable: gettextCatalog.getString("Enable", null, "Action"), | |
| remove: gettextCatalog.getString("Delete", null, "Action"), | |
| generate: gettextCatalog.getString("Generate missing keys", null, "Action"), | |
| add: gettextCatalog.getString("Add address", null, "Action") | |
| }; | |
| return { | |
| replace: !0, | |
| scope: { | |
| model: "=?", | |
| model2: "=?" | |
| }, | |
| template: '<button type="button" class="addressBtnActions-container">' + I18N.editSignature + "</button>", | |
| link: function(scope, el, _ref) { | |
| var _ref$action = _ref.action, | |
| action = void 0 === _ref$action ? "editSignature" : _ref$action; | |
| "editSignature" !== action && el.text(I18N[action]); | |
| var onClick = function() { | |
| return addressModel[action](scope.model, scope.model2) | |
| }; | |
| el.on("click", onClick), scope.$on("$destroy", function() { | |
| el.off("click", onClick) | |
| }) | |
| } | |
| } | |
| }), | |
| angular.module("proton.address").directive("addressKeysView", function($rootScope, downloadFile, authentication, gettextCatalog, tools, notification, Key, keyPasswordModal, pmcw, networkActivityTracker, eventManager) { | |
| var I18N = { | |
| ERROR: gettextCatalog.getString("Error reactivating key. Please try again", null, "Error"), | |
| SUCCESS: gettextCatalog.getString("Key reactivated", null, "Info") | |
| }, | |
| reactivateProcess = function() { | |
| var _ref = _asyncToGenerator(regeneratorRuntime.mark(function _callee(decryptedKey, key) { | |
| var PrivateKey, _ref2, _ref2$data, data; | |
| return regeneratorRuntime.wrap(function(_context) { | |
| for (;;) switch (_context.prev = _context.next) { | |
| case 0: | |
| return _context.prev = 0, _context.next = 3, pmcw.encryptPrivateKey(decryptedKey, authentication.getPassword()); | |
| case 3: | |
| return PrivateKey = _context.sent, _context.next = 6, Key.reactivate(key.ID, { | |
| PrivateKey: PrivateKey | |
| }); | |
| case 6: | |
| if (_ref2 = _context.sent, _ref2$data = _ref2.data, data = void 0 === _ref2$data ? {} : _ref2$data, 1e3 === data.Code) { | |
| _context.next = 11; | |
| break | |
| } | |
| throw new Error(data.Error || I18N.ERROR); | |
| case 11: | |
| return key.decrypted = !0, notification.success(I18N.SUCCESS), _context.abrupt("return", eventManager.call()); | |
| case 16: | |
| throw _context.prev = 16, _context.t0 = _context.catch(0), new Error(I18N.ERROR); | |
| case 19: | |
| case "end": | |
| return _context.stop() | |
| } | |
| }, _callee, void 0, [ | |
| [0, 16] | |
| ]) | |
| })); | |
| return function(_x, _x2) { | |
| return _ref.apply(this, arguments) | |
| } | |
| }(), | |
| reactivate = function() { | |
| var _ref3 = _asyncToGenerator(regeneratorRuntime.mark(function _callee2(key) { | |
| var _ref4, _ref4$data, data, _ref5, salt; | |
| return regeneratorRuntime.wrap(function(_context2) { | |
| for (;;) switch (_context2.prev = _context2.next) { | |
| case 0: | |
| return _context2.prev = 0, _context2.next = 3, Key.salts(); | |
| case 3: | |
| _ref4 = _context2.sent, _ref4$data = _ref4.data, data = void 0 === _ref4$data ? {} : _ref4$data, _ref5 = _.findWhere(data.KeySalts, { | |
| ID: key.ID | |
| }) || {}, salt = _ref5.KeySalt, keyPasswordModal.activate({ | |
| params: { | |
| salt: salt, | |
| privateKey: key.PrivateKey, | |
| submit: function(decryptedKey) { | |
| keyPasswordModal.deactivate(), networkActivityTracker.track(reactivateProcess(decryptedKey, key)) | |
| }, | |
| cancel: function() { | |
| keyPasswordModal.deactivate() | |
| } | |
| } | |
| }), _context2.next = 12; | |
| break; | |
| case 10: | |
| _context2.prev = 10, _context2.t0 = _context2.catch(0); | |
| case 12: | |
| case "end": | |
| return _context2.stop() | |
| } | |
| }, _callee2, void 0, [ | |
| [0, 10] | |
| ]) | |
| })); | |
| return function(_x3) { | |
| return _ref3.apply(this, arguments) | |
| } | |
| }(); | |
| return { | |
| replace: !0, | |
| restrict: "E", | |
| templateUrl: "templates/address/addressKeysView.tpl.html", | |
| link: function(scope) { | |
| function populateKeys() { | |
| authentication.user.Addresses.forEach(function(_ref6) { | |
| var _ref6$Keys = _ref6.Keys, | |
| Keys = void 0 === _ref6$Keys ? [] : _ref6$Keys, | |
| _ref6$ID = _ref6.ID, | |
| ID = void 0 === _ref6$ID ? "" : _ref6$ID, | |
| _ref6$Email = _ref6.Email, | |
| Email = void 0 === _ref6$Email ? "" : _ref6$Email, | |
| Order = _ref6.Order; | |
| if (Keys.length) { | |
| var _Keys$ = Keys[0], | |
| fingerprint = _Keys$.fingerprint, | |
| created = _Keys$.created, | |
| bitSize = _Keys$.bitSize, | |
| PublicKey = _Keys$.PublicKey, | |
| index = _.findIndex(scope.addresses, { | |
| addressID: ID | |
| }), | |
| address = { | |
| order: Order, | |
| addressID: ID, | |
| email: Email, | |
| fingerprint: fingerprint, | |
| created: created, | |
| bitSize: bitSize, | |
| publicKey: PublicKey, | |
| keys: Keys | |
| }; | |
| index > -1 ? angular.extend(scope.addresses[index], address) : scope.addresses.push(address) | |
| } | |
| }) | |
| } | |
| var unsubscribe = $rootScope.$on("updateUser", function() { | |
| populateKeys() | |
| }); | |
| scope.isSubUser = authentication.user.subuser, scope.addresses = [], scope.download = function(key, email, type) { | |
| var blob = new Blob([key], { | |
| type: "data:text/plain;charset=utf-8;" | |
| }); | |
| downloadFile(blob, type + "key." + email + ".asc") | |
| }, scope.reactivate = reactivate, scope.$on("$destroy", function() { | |
| unsubscribe() | |
| }), populateKeys() | |
| } | |
| } | |
| }); | |
| var _slicedToArray = function() { | |
| function sliceIterator(arr, i) { | |
| var _arr = [], | |
| _n = !0, | |
| _d = !1, | |
| _e = void 0; | |
| try { | |
| for (var _s, _i = arr[Symbol.iterator](); !(_n = (_s = _i.next()).done) && (_arr.push(_s.value), !i || _arr.length !== i); _n = !0); | |
| } catch (err) { | |
| _d = !0, _e = err | |
| } finally { | |
| try { | |
| !_n && _i.return && _i.return() | |
| } finally { | |
| if (_d) throw _e | |
| } | |
| } | |
| return _arr | |
| } | |
| return function(arr, i) { | |
| if (Array.isArray(arr)) return arr; | |
| if (Symbol.iterator in Object(arr)) return sliceIterator(arr, i); | |
| throw new TypeError("Invalid attempt to destructure non-iterable instance") | |
| } | |
| }(); | |
| angular.module("proton.address").factory("addressModel", function($state, gettextCatalog, networkActivityTracker, notification, organizationModel, organizationKeysModel, pmDomainModel, domainModel, memberModel, addressModal, membersValidator, memberModal, eventManager, confirmModal, signatureModal, Address, authentication, addressWithoutKeysManager, CONSTANTS, $rootScope) { | |
| function generate(address) { | |
| var member = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : memberModel.getSelf(); | |
| if (canAdd(member, !1)) return addressWithoutKeysManager.manageOne(address, member).then(function(_ref6) { | |
| var _ref7 = _slicedToArray(_ref6, 1), | |
| _ref7$ = _ref7[0], | |
| adr = void 0 === _ref7$ ? {} : _ref7$, | |
| index = _.findIndex(authentication.user.Addresses, function(_ref8) { | |
| return _ref8.ID === adr.ID | |
| }); | |
| adr.Receive = +(1 === adr.Status), -1 !== index && authentication.user.Addresses.splice(index, 1, adr), $rootScope.$emit("addressModel", { | |
| type: "generateKey.success", | |
| data: { | |
| address: address | |
| } | |
| }) | |
| }).catch(_.noop) | |
| } | |
| var I18N = { | |
| ERROR_DO_UPGRADE: gettextCatalog.getString("You have used all addresses in your plan. Please upgrade your plan to add a new address", null, "Error"), | |
| ERROR_MUST_BE_ADMIN: gettextCatalog.getString("Administrator privileges must be activated", null, "Error"), | |
| SUCCESS_DISABLED: gettextCatalog.getString("Address disabled", null, "Info"), | |
| SUCCESS_ENABLE: gettextCatalog.getString("Address enabled", null, "Info"), | |
| SUCCESS_REMOVE: gettextCatalog.getString("Address deleted", null, "Info"), | |
| SUCCESS_EDIT: gettextCatalog.getString("Address updated", null, "Info"), | |
| SUCCESS_ORDER: gettextCatalog.getString("Order saved", null, "Info"), | |
| DISABLE_MODAL: { | |
| title: gettextCatalog.getString("Disable address", null, "Title"), | |
| message: gettextCatalog.getString("Are you sure you want to disable this address?", null, "Info") | |
| }, | |
| DELETE_MODAL: { | |
| title: gettextCatalog.getString("Delete address", null, "Title"), | |
| message: gettextCatalog.getString("Are you sure you want to delete this address?", null, "Info") | |
| }, | |
| EDIT_MODAL: { | |
| title: gettextCatalog.getString("Name / Signature", null, "Title") | |
| }, | |
| FREE_ADD_ERROR: gettextCatalog.getString('Please <a href="/dashboard">upgrade</a> to a paid account to use this feature', null, "Error") | |
| }, | |
| canAdd = function() { | |
| var member = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {}, | |
| redirect = !(arguments.length > 1 && void 0 !== arguments[1]) || arguments[1], | |
| _ref = organizationModel.get() || {}, | |
| MaxAddresses = _ref.MaxAddresses, | |
| UsedAddresses = _ref.UsedAddresses, | |
| HasKeys = _ref.HasKeys; | |
| return MaxAddresses - UsedAddresses < 1 ? (notification.error(I18N.ERROR_DO_UPGRADE), !1) : !(1 === HasKeys && organizationKeysModel.get("keyStatus") > 0 && !member.Private) || (notification.error(I18N.ERROR_MUST_BE_ADMIN), redirect && $state.go("secured.members"), !1) | |
| }, | |
| formatDomains = function(domain, member) { | |
| var config = { | |
| pmDomains: [], | |
| domains: [domain], | |
| members: [member] | |
| }; | |
| return 0 === member.Type && (config.pmDomains = pmDomainModel.get().map(function(domain) { | |
| return { | |
| DomainName: domain | |
| } | |
| })), !domain.ID && (config.domains = config.pmDomains.concat(domainModel.query())), !member.ID && (config.members = memberModel.getAll()), config | |
| }, | |
| add = function() { | |
| var domain = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {}, | |
| member = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : {}; | |
| if (authentication.user.Role === CONSTANTS.FREE_USER_ROLE) return notification.error(I18N.FREE_ADD_ERROR); | |
| var _formatDomains = formatDomains(domain, member), | |
| domains = _formatDomains.domains, | |
| members = _formatDomains.members; | |
| if (!domains || 0 === domains.length) return $state.go("secured.domains"); | |
| if (canAdd(member)) { | |
| var organizationKey = organizationKeysModel.get("organizationKey"); | |
| addressModal.activate({ | |
| params: { | |
| domains: domains, | |
| members: members, | |
| organizationKey: organizationKey, | |
| cancel: addressModal.deactivate, | |
| addMember: function() { | |
| membersValidator.canAdd(organizationKeysModel.get("keyStatus")) && (addressModal.deactivate(), memberModal.activate({ | |
| params: { | |
| organization: organizationModel.get(), | |
| organizationKey: organizationKey, | |
| domains: domains, | |
| submit: memberModal.deactivate, | |
| cancel: memberModal.deactivate | |
| } | |
| })) | |
| }, | |
| submit: function(address, member) { | |
| if (addressModal.deactivate(), !member.Private) return generate(address, member).then(eventManager.call); | |
| eventManager.call() | |
| } | |
| } | |
| }) | |
| } | |
| }, | |
| disable = function(_ref2) { | |
| var ID = _ref2.ID; | |
| confirmModal.activate({ | |
| params: { | |
| title: I18N.DISABLE_MODAL.title, | |
| message: I18N.DISABLE_MODAL.message, | |
| cancel: confirmModal.deactivate, | |
| confirm: function() { | |
| var promise = Address.disable(ID).then(eventManager.call).then(function() { | |
| notification.success(I18N.SUCCESS_DISABLED), confirmModal.deactivate() | |
| }); | |
| networkActivityTracker.track(promise) | |
| } | |
| } | |
| }) | |
| }, | |
| enable = function(_ref3) { | |
| var ID = _ref3.ID, | |
| promise = Address.enable(ID).then(function() { | |
| return eventManager.call() | |
| }).then(function() { | |
| return notification.success(I18N.SUCCESS_ENABLE) | |
| }); | |
| networkActivityTracker.track(promise) | |
| }, | |
| disableFirst = function() { | |
| var _ref4 = _asyncToGenerator(regeneratorRuntime.mark(function _callee(_ref5) { | |
| var ID = _ref5.ID, | |
| Status = _ref5.Status; | |
| return regeneratorRuntime.wrap(function(_context) { | |
| for (;;) switch (_context.prev = _context.next) { | |
| case 0: | |
| if (0 !== Status) { | |
| _context.next = 2; | |
| break | |
| } | |
| return _context.abrupt("return"); | |
| case 2: | |
| return _context.next = 4, Address.disable(ID); | |
| case 4: | |
| notification.success(I18N.SUCCESS_DISABLED); | |
| case 5: | |
| case "end": | |
| return _context.stop() | |
| } | |
| }, _callee, void 0) | |
| })); | |
| return function(_x5) { | |
| return _ref4.apply(this, arguments) | |
| } | |
| }(), | |
| remove = function(address) { | |
| confirmModal.activate({ | |
| params: { | |
| title: I18N.DELETE_MODAL.title, | |
| message: I18N.DELETE_MODAL.message, | |
| confirm: function() { | |
| var promise = disableFirst(address).then(function() { | |
| return Promise.all([eventManager.call(), Address.remove(address.ID)]) | |
| }).then(function() { | |
| notification.success(I18N.SUCCESS_REMOVE), confirmModal.deactivate() | |
| }).then(eventManager.call).catch(function(e) { | |
| throw confirmModal.deactivate(), e | |
| }); | |
| networkActivityTracker.track(promise) | |
| }, | |
| cancel: function() { | |
| confirmModal.deactivate() | |
| } | |
| } | |
| }) | |
| }, | |
| editSignature = function(address) { | |
| signatureModal.activate({ | |
| params: { | |
| address: address, | |
| title: I18N.EDIT_MODAL.title, | |
| cancel: signatureModal.deactivate, | |
| confirm: function(address) { | |
| !1 === address.custom && (address.DisplayName = null, address.Signature = null); | |
| var promise = Address.edit(address.ID, { | |
| DisplayName: address.DisplayName, | |
| Signature: address.Signature | |
| }).then(function() { | |
| eventManager.call(), notification.success(I18N.SUCCESS_EDIT), signatureModal.deactivate() | |
| }); | |
| networkActivityTracker.track(promise) | |
| } | |
| } | |
| }) | |
| }, | |
| saveOrder = function(Order) { | |
| var promise = Address.order({ | |
| Order: Order | |
| }).then(eventManager.call).then(function() { | |
| return notification.success(I18N.SUCCESS_ORDER) | |
| }); | |
| networkActivityTracker.track(promise) | |
| }, | |
| getActive = function() { | |
| var active = _.where(authentication.user.Addresses, { | |
| Status: 1, | |
| Receive: 1 | |
| }); | |
| return { | |
| active: active, | |
| disabled: _.difference(authentication.user.Addresses, active) | |
| } | |
| }; | |
| return { | |
| add: add, | |
| disable: disable, | |
| enable: enable, | |
| remove: remove, | |
| makeDefault: function(address) { | |
| var _getActive = getActive(), | |
| active = _getActive.active, | |
| disabled = _getActive.disabled, | |
| addresses = [].concat(active, disabled), | |
| index = _.findIndex(addresses, { | |
| ID: address.ID | |
| }); | |
| addresses.splice(index, 1), addresses.unshift(address); | |
| var order = _.pluck(addresses, "Order"); | |
| saveOrder(order) | |
| }, | |
| editSignature: editSignature, | |
| saveOrder: saveOrder, | |
| generate: generate, | |
| getActive: getActive | |
| } | |
| }); | |
| var _slicedToArray = function() { | |
| function sliceIterator(arr, i) { | |
| var _arr = [], | |
| _n = !0, | |
| _d = !1, | |
| _e = void 0; | |
| try { | |
| for (var _s, _i = arr[Symbol.iterator](); !(_n = (_s = _i.next()).done) && (_arr.push(_s.value), !i || _arr.length !== i); _n = !0); | |
| } catch (err) { | |
| _d = !0, _e = err | |
| } finally { | |
| try { | |
| !_n && _i.return && _i.return() | |
| } finally { | |
| if (_d) throw _e | |
| } | |
| } | |
| return _arr | |
| } | |
| return function(arr, i) { | |
| if (Array.isArray(arr)) return arr; | |
| if (Symbol.iterator in Object(arr)) return sliceIterator(arr, i); | |
| throw new TypeError("Invalid attempt to destructure non-iterable instance") | |
| } | |
| }(); | |
| angular.module("proton.address").factory("addressWithoutKeys", function(memberModel, authentication, AppModel) { | |
| var isDirtyAddress = function(_ref) { | |
| var Keys = _ref.Keys, | |
| Status = _ref.Status; | |
| return !Keys.length && 1 === Status | |
| }, | |
| filterDirty = function(user) { | |
| var list = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : []; | |
| return _.filter(list, function(adr) { | |
| return isDirtyAddress(adr) && 1 === user.Private | |
| }) | |
| }, | |
| fromUser = function() { | |
| var user = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : authentication.user; | |
| return filterDirty(user, user.Addresses) | |
| }, | |
| getListAddresses = function(_ref2, user) { | |
| var _ref3 = _slicedToArray(_ref2, 1), | |
| member = _ref3[0]; | |
| if (!member.Private) return member.Addresses; | |
| var mapAddresses = user.Addresses.reduce(function(acc, _ref4) { | |
| return acc[_ref4.ID] = !0, acc | |
| }, {}); | |
| return user.Addresses.concat(member.Addresses.filter(function(_ref5) { | |
| var ID = _ref5.ID; | |
| return !mapAddresses[ID] | |
| })) | |
| }; | |
| return { | |
| get: function() { | |
| var user = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {}, | |
| memberList = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : memberModel.getAll(), | |
| isEvent = arguments[2]; | |
| if (1 === memberList.length && !isEvent) { | |
| var addresses = getListAddresses(memberList, user); | |
| return { | |
| addresses: filterDirty(user, addresses) | |
| } | |
| } | |
| return { | |
| addresses: filterDirty(user, user.Addresses) | |
| } | |
| }, | |
| fromUser: fromUser, | |
| allDirty: function() { | |
| var _ref6 = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : authentication.user, | |
| _ref6$Addresses = _ref6.Addresses, | |
| Addresses = void 0 === _ref6$Addresses ? [] : _ref6$Addresses; | |
| if (!1 === AppModel.get("allDirtyAddresses")) return !1; | |
| var test = Addresses.filter(function(_ref7) { | |
| return _ref7.Status | |
| }).every(isDirtyAddress); | |
| return AppModel.set("allDirtyAddresses", test), test | |
| } | |
| } | |
| }), | |
| angular.module("proton.address").factory("addressModal", function(pmModal, $rootScope, $state, networkActivityTracker, notification, Address, gettextCatalog, organizationModel, CONSTANTS) { | |
| var I18N = { | |
| ERROR_DECRYPT_ORG_KEY: gettextCatalog.getString("Cannot decrypt organization key", null, "Error"), | |
| SUCCESS_ADD: gettextCatalog.getString("Address added", null, "Info") | |
| }; | |
| return pmModal({ | |
| controllerAs: "ctrl", | |
| templateUrl: "templates/modals/addAddress.tpl.html", | |
| controller: function(params) { | |
| var _this = this, | |
| _params$domains = params.domains, | |
| domains = void 0 === _params$domains ? [] : _params$domains, | |
| _params$organizationK = params.organizationKey, | |
| organizationKey = void 0 === _params$organizationK ? null : _params$organizationK, | |
| _params$members = params.members, | |
| members = void 0 === _params$members ? [] : _params$members, | |
| organization = organizationModel.get(); | |
| this.domain = domains[0], this.domains = domains, this.address = "", this.size = CONSTANTS.ENCRYPTION_DEFAULT, this.members = members, this.member = members[0], this.showAddMember = 1 === organization.HasKeys && $state.is("secured.domains"), this.addMember = params.addMember, this.cancel = params.cancel, this.open = function(name) { | |
| return $rootScope.$broadcast(name, params.domain) | |
| }, this.submit = function() { | |
| if (0 === _this.member.Private && !organizationKey) return notification.error(I18N.ERROR_DECRYPT_ORG_KEY); | |
| var promise = Address.create({ | |
| Local: _this.address, | |
| Domain: _this.domain.DomainName, | |
| MemberID: _this.member.ID | |
| }).then(function() { | |
| var data = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {}; | |
| notification.success(I18N.SUCCESS_ADD), params.submit(data.Address, _this.member) | |
| }); | |
| networkActivityTracker.track(promise) | |
| } | |
| } | |
| }) | |
| }), | |
| angular.module("proton.address").factory("addressesModal", function(pmModal, CONSTANTS, addressModal, memberModal, $rootScope, organizationModel) { | |
| return pmModal({ | |
| controllerAs: "ctrl", | |
| templateUrl: "templates/modals/domain/address.tpl.html", | |
| controller: function(params) { | |
| var domain = params.domain, | |
| members = params.members, | |
| step = params.step, | |
| addressParams = params.addressParams, | |
| memberParams = params.memberParams, | |
| _params$showMember = params.showMember, | |
| showMember = void 0 === _params$showMember || _params$showMember, | |
| organization = organizationModel.get(); | |
| this.keyPhase = CONSTANTS.KEY_PHASE, this.domain = domain, this.step = step, this.showMember = showMember && 1 === organization.HasKeys && this.keyPhase > 3, this.open = function(name) { | |
| $rootScope.$broadcast(name, params.domain) | |
| }, this.getMember = function(id) { | |
| var index = _.findIndex(members, { | |
| ID: id | |
| }); | |
| return -1 !== index ? members[index] : {} | |
| }, this.addAddress = function() { | |
| params.cancel(), addressModal.activate(addressParams) | |
| }, this.addMember = function() { | |
| params.cancel(), memberModal.activate(memberParams) | |
| }, this.next = function() { | |
| params.next() | |
| }, this.close = function() { | |
| params.cancel() | |
| } | |
| } | |
| }) | |
| }), angular.module("proton.address").factory("addressWithoutKeysManager", function(addressWithoutKeys, authentication, generateModal, $injector) { | |
| var openModal = function() { | |
| var _ref = _asyncToGenerator(regeneratorRuntime.mark(function _callee(_ref2) { | |
| var organizationModel, organizationKeysModel, addresses = _ref2.addresses, | |
| password = _ref2.password, | |
| _ref2$memberMap = _ref2.memberMap, | |
| memberMap = void 0 === _ref2$memberMap ? {} : _ref2$memberMap; | |
| return regeneratorRuntime.wrap(function(_context) { | |
| for (;;) switch (_context.prev = _context.next) { | |
| case 0: | |
| return organizationModel = $injector.get("organizationModel"), organizationKeysModel = $injector.get("organizationKeysModel"), _context.next = 4, organizationKeysModel.manage(organizationModel.get()); | |
| case 4: | |
| if (!addresses.length || generateModal.active()) { | |
| _context.next = 6; | |
| break | |
| } | |
| return _context.abrupt("return", new Promise(function(resolve, reject) { | |
| generateModal.activate({ | |
| params: { | |
| memberMap: memberMap, | |
| password: password, | |
| addresses: addresses, | |
| organizationKey: organizationKeysModel.get("organizationKey"), | |
| onSuccess: function() { | |
| $injector.get("eventManager").call(), resolve(addresses), generateModal.deactivate() | |
| }, | |
| close: function() { | |
| reject(new Error("generateModal:close")), generateModal.deactivate() | |
| } | |
| } | |
| }) | |
| })); | |
| case 6: | |
| organizationKeysModel.clear(); | |
| case 7: | |
| case "end": | |
| return _context.stop() | |
| } | |
| }, _callee, void 0) | |
| })); | |
| return function(_x) { | |
| return _ref.apply(this, arguments) | |
| } | |
| }(); | |
| return { | |
| manage: function() { | |
| var user = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : authentication.user, | |
| memberList = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : [], | |
| isEvent = arguments[2], | |
| _addressWithoutKeys$g = addressWithoutKeys.get(user, memberList, isEvent), | |
| addresses = _addressWithoutKeys$g.addresses, | |
| memberMap = _addressWithoutKeys$g.memberMap, | |
| password = authentication.getPassword(); | |
| return openModal({ | |
| addresses: addresses, | |
| memberMap: memberMap, | |
| password: password | |
| }) | |
| }, | |
| manageOne: function(address) { | |
| var member = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : {}, | |
| password = arguments.length > 2 && void 0 !== arguments[2] ? arguments[2] : authentication.getPassword(), | |
| addresses = [address], | |
| memberMap = _defineProperty({}, address.ID, member); | |
| return openModal(member.Private ? { | |
| addresses: addresses, | |
| password: password | |
| } : { | |
| addresses: addresses, | |
| memberMap: memberMap, | |
| password: password | |
| }) | |
| } | |
| } | |
| }), angular.module("proton.analytics").factory("analytics", function(CONFIG, CONSTANTS, aboutClient) { | |
| function getTrackerAsync() { | |
| return state.tracker ? Promise.resolve(state.tracker) : new Promise(function(resolve) { | |
| loadQueue.push(resolve) | |
| }) | |
| } | |
| function trackPage(_ref) { | |
| var url = _ref.url, | |
| referrer = _ref.referrer, | |
| title = _ref.title; | |
| getTrackerAsync().then(function(tracker) { | |
| tracker.setDocumentTitle(title), tracker.setReferrerUrl(referrer), tracker.setCustomUrl(url), tracker.trackPageView() | |
| }) | |
| } | |
| function trackGoals(goals) { | |
| getTrackerAsync().then(function(tracker) { | |
| tracker.trackGoal(goals) | |
| }) | |
| } | |
| var _CONFIG$statsConfig = CONFIG.statsConfig, | |
| isEnabled = _CONFIG$statsConfig.isEnabled, | |
| _CONFIG$statsConfig$c = _CONFIG$statsConfig.cookieDomain, | |
| cookieDomain = void 0 === _CONFIG$statsConfig$c ? "" : _CONFIG$statsConfig$c, | |
| _CONFIG$statsConfig$d = _CONFIG$statsConfig.domains, | |
| domains = void 0 === _CONFIG$statsConfig$d ? [] : _CONFIG$statsConfig$d, | |
| _CONFIG$statsConfig$s = _CONFIG$statsConfig.statsHost, | |
| statsHost = void 0 === _CONFIG$statsConfig$s ? "" : _CONFIG$statsConfig$s, | |
| _CONFIG$statsConfig$s2 = _CONFIG$statsConfig.siteId, | |
| siteId = void 0 === _CONFIG$statsConfig$s2 ? -1 : _CONFIG$statsConfig$s2, | |
| _CONFIG$statsConfig$a = _CONFIG$statsConfig.abSiteId, | |
| abSiteId = void 0 === _CONFIG$statsConfig$a ? -1 : _CONFIG$statsConfig$a; | |
| if (!isEnabled || aboutClient.doNotTrack()) return { | |
| init: angular.noop, | |
| trackGoals: angular.noop, | |
| trackPage: angular.noop | |
| }; | |
| var loadQueue = [], | |
| state = {}; | |
| window.piwikAsyncInit = function() { | |
| state.tracker = window.Piwik.getTracker("//" + statsHost + "/" + CONSTANTS.TRACKER_ROUTE, siteId), state.tracker.setCookieDomain(cookieDomain), state.tracker.setDomains(domains), state.tracker.enableCrossDomainLinking(), state.tracker.setCustomVariable(1, "siteFrontEndId", abSiteId, "visit"), state.tracker.setCustomVariable(1, "enablePMRequestCombiner", "yes", "page"), loadQueue.forEach(function(resolve) { | |
| return resolve(state.tracker) | |
| }) | |
| }; | |
| var piwikScript = document.createElement("script"); | |
| return piwikScript.type = "text/javascript", piwikScript.async = !0, piwikScript.defer = !0, piwikScript.src = "https://" + statsHost + "/" + CONSTANTS.PIWIK_SCRIPT, document.head.appendChild(piwikScript), { | |
| init: angular.noop, | |
| trackGoals: trackGoals, | |
| trackPage: trackPage | |
| } | |
| }), angular.module("proton.analytics").factory("eventListener", function(CONSTANTS, CONFIG, $rootScope, analytics, pageTitlesModel) { | |
| function generateTitle(state) { | |
| return document.domain + "/" + pageTitlesModel.find(state, !1) | |
| } | |
| var TRACKED_STATES = ["signup", "secured.dashboard", "login", "secured.inbox"], | |
| state = { | |
| lastLocation: document.referrer | |
| }; | |
| return $rootScope.$on("$stateChangeSuccess", function(event, toState) { | |
| var referrer = state.lastLocation; | |
| if (state.lastLocation = location.href, TRACKED_STATES.includes(toState.name)) { | |
| var title = generateTitle(toState), | |
| page = { | |
| title: title, | |
| referrer: referrer, | |
| url: location.href | |
| }; | |
| analytics.trackPage(page) | |
| } | |
| }), $rootScope.$on("signup", function(event, _ref) { | |
| var type = _ref.type, | |
| data = _ref.data; | |
| if ("user.subscription.finished" === type) { | |
| var plan = data.plan || { | |
| Name: "free" | |
| }, | |
| goals = [CONSTANTS.METRIC_GOALS.SIGNUP_ALL]; | |
| "free" === plan.Name ? goals.push(CONSTANTS.METRIC_GOALS.SIGNUP_FREE) : goals.push(CONSTANTS.METRIC_GOALS.SIGNUP_PAID), "plus" === plan.Name && goals.push(CONSTANTS.METRIC_GOALS.SIGNUP_PLUS), "visionary" === plan.Name && goals.push(CONSTANTS.METRIC_GOALS.SIGNUP_VISIONARY), analytics.trackGoals(goals) | |
| } | |
| }), { | |
| init: angular.noop | |
| } | |
| }), | |
| angular.module("proton", ["gettext", "as.sortable", "cgNotify", "ngCookies", "ngIcal", "ngMessages", "ngSanitize", "ngScrollbars", "pikaday", "ui.router", "ui.codemirror", "proton.constants", "proton.core", "proton.outside", "proton.utils", "proton.user", "templates-app", "proton.routes", "proton.composer", "proton.commons", "proton.bugReport", "proton.browserSupport", "proton.config", "proton.analytics", "proton.search", "proton.ui", "proton.dnd", "proton.sidebar", "proton.attachments", "proton.authentication", "proton.elements", "proton.members", "proton.bridge", "proton.labels", "proton.autoresponder", "proton.filter", "proton.domains", "proton.address", "proton.message", "proton.conversation", "proton.organization", "proton.squire", "proton.wizard", "proton.contact", "proton.blackFriday", "proton.settings", "proton.dashboard", "proton.vpn", "proton.payment", "proton.formUtils"]).config(function(urlProvider, CONFIG, notificationProvider) { | |
| urlProvider.setBaseUrl(CONFIG.apiUrl), notificationProvider.template("templates/notifications/base.tpl.html") | |
| }).run(function($rootScope, $state, logoutManager, authentication, networkActivityTracker, CONSTANTS, tools) { | |
| FastClick.attach(document.body), window.addEventListener("resize", _.debounce(tools.mobileResponsive, 50)), window.addEventListener("orientationchange", tools.mobileResponsive), tools.mobileResponsive(), $rootScope.showWelcome = !0, window.svg4everybody(), moment.relativeTimeThreshold("s", 59), moment.relativeTimeThreshold("m", 59), moment.relativeTimeThreshold("h", 23), $rootScope.networkActivity = networkActivityTracker | |
| }).config(function($httpProvider, CONFIG) { | |
| $httpProvider.interceptors.push("authHttpResponseInterceptor"), $httpProvider.interceptors.push("formatResponseInterceptor"), $httpProvider.defaults.headers.common["x-pm-appversion"] = "Web_" + CONFIG.app_version, $httpProvider.defaults.headers.common["x-pm-apiversion"] = CONFIG.api_version, $httpProvider.defaults.headers.common.Accept = "application/vnd.protonmail.v1+json", $httpProvider.defaults.withCredentials = !0, angular.isUndefined($httpProvider.defaults.headers.get) && ($httpProvider.defaults.headers.get = {}), $httpProvider.defaults.headers.get["Cache-Control"] = "no-cache", $httpProvider.defaults.headers.get.Pragma = "no-cache" | |
| }).run(function($rootScope, $location, $state, authentication, $log, networkActivityTracker, AppModel) { | |
| $rootScope.$on("$stateChangeStart", function(event, toState) { | |
| networkActivityTracker.clear(); | |
| var isLogin = "login" === toState.name, | |
| isSub = "login.sub" === toState.name, | |
| isUpgrade = "upgrade" === toState.name, | |
| isSupport = toState.name.includes("support"), | |
| isAccount = "account" === toState.name, | |
| isSignup = "signup" === toState.name || "pre-invite" === toState.name, | |
| isUnlock = "login.unlock" === toState.name, | |
| isOutside = toState.name.includes("eo"), | |
| isReset = toState.name.includes("reset"), | |
| isPrinter = "printer" === toState.name, | |
| isPgp = "pgp" === toState.name; | |
| return isUnlock && $rootScope.isLoggedIn ? void $log.debug("appjs:(isUnlock && $rootScope.isLoggedIn)") : $rootScope.isLoggedIn && !$rootScope.isLocked && isUnlock ? ($log.debug("appjs:($rootScope.isLoggedIn && !$rootScope.isLocked && isUnlock)"), event.preventDefault(), void $state.go("secured.inbox")) : isLogin || isSub || isSupport || isAccount || isSignup || isOutside || isUpgrade || isReset || isPrinter || isPgp ? void $log.debug("appjs:(isLogin || isSub || isSupport || isAccount || isSignup || isOutside || isUpgrade || isReset || isPrinter || isPgp)") : void(authentication.isLoggedIn() || (event.preventDefault(), $state.go("login"))) | |
| }), $rootScope.$on("$stateChangeSuccess", function() { | |
| AppModel.set("requestTimeout", !1), $(".tooltip").not(void 0).hide(), $(".navbar-toggle").click(), $("#loading_pm, #pm_slow, #pm_slow2").remove() | |
| }) | |
| }).run(function($rootScope, $state) { | |
| $rootScope.$on("$stateChangeError", function(event, current, previous, rejection) { | |
| for (var _len = arguments.length, arg = Array(_len > 4 ? _len - 4 : 0), _key = 4; _key < _len; _key++) arg[_key - 4] = arguments[_key]; | |
| console.error("stateChangeError", event, current, previous, rejection, arg), $state.go("support.message", { | |
| data: {} | |
| }) | |
| }) | |
| }).run(function(consoleMessage) { | |
| return consoleMessage() | |
| }).config(function($logProvider, $compileProvider, $qProvider, CONFIG) { | |
| var debugInfo = CONFIG.debug || !1; | |
| $logProvider.debugEnabled(debugInfo), $compileProvider.debugInfoEnabled(debugInfo), $qProvider.errorOnUnhandledRejections(debugInfo) | |
| }).config(function(CONFIG, CONSTANTS) { | |
| var localhost = "NODE@ENV".replace("@", "_"), | |
| REGEXP_HOST = /proton(mail|vpn)\.(com|blue|host)$/; | |
| if ("build" !== localhost && !REGEXP_HOST.test(window.location.host)) { | |
| var img = new Image; | |
| img.width = 0, img.height = 0, img.src = CONSTANTS.URL_INFO, document.body.appendChild(img) | |
| } | |
| }), angular.module("proton.attachments").directive("btnDownloadAttachments", function(attachmentDownloader) { | |
| return { | |
| scope: { | |
| model: "=" | |
| }, | |
| replace: !0, | |
| templateUrl: "templates/attachments/btnDownloadAttachments.tpl.html", | |
| link: function(scope, el) { | |
| var reset = function() { | |
| return el[0].classList.remove("btnDownloadAttachments-load") | |
| }, | |
| onClick = function(e) { | |
| if (attachmentDownloader.isNotSupported(e)) return !1; | |
| el[0].classList.add("btnDownloadAttachments-load"), attachmentDownloader.all(scope.model, el[0]).then(reset) | |
| }; | |
| el.on("click", onClick), scope.$on("$destroy", function() { | |
| el.off("click", onClick) | |
| }) | |
| } | |
| } | |
| }), angular.module("proton.attachments").directive("iconAttachment", function(embedded) { | |
| var MAP_CLASSNAME = { | |
| zip: "fa-archive-o", | |
| mp3: "fa-audio-o", | |
| javascript: "fa-code-o", | |
| xls: "fa-excel-o", | |
| mov: "fa-movie-o", | |
| pdf: "fa-pdf-o", | |
| power: "fa-powerpoint-o", | |
| word: "fa-word-o" | |
| }, | |
| getFileIconsType = function(_ref) { | |
| var MIMEType = _ref.MIMEType; | |
| return Object.keys(MAP_CLASSNAME).filter(function(key) { | |
| return MIMEType.includes(key) | |
| }).reduce(function(acc, key) { | |
| return acc.push(MAP_CLASSNAME[key]), acc | |
| }, []) | |
| }, | |
| getAttachmentType = function(attachment) { | |
| if (embedded.isEmbedded(attachment)) return ["fa-picture-o", "embedded"]; | |
| var list = ["fa-file-o"]; | |
| return attachment.MIMEType.includes("image") && list.push("fa-image-o"), list | |
| }; | |
| return { | |
| replace: !0, | |
| template: '<i class="fa"></i>', | |
| link: function(scope, el) { | |
| var classNames = [].concat(getAttachmentType(scope.attachment)).concat(getFileIconsType(scope.attachment)); | |
| _rAF(function() { | |
| var _el$0$classList; | |
| (_el$0$classList = el[0].classList).add.apply(_el$0$classList, _toConsumableArray(classNames)) | |
| }) | |
| } | |
| } | |
| }), angular.module("proton.attachments").directive("listAttachments", function($state, $rootScope, attachmentDownloader, notification, AppModel) { | |
| return { | |
| scope: { | |
| model: "=" | |
| }, | |
| replace: !0, | |
| templateUrl: "templates/directives/attachments/listAttachments.tpl.html", | |
| link: function(scope, el) { | |
| var $list = el[0].querySelector(".listAttachments-list"), | |
| hide = function() { | |
| return !scope.model.Attachments.length && el[0].classList.add("hidden") | |
| }, | |
| show = function() { | |
| return scope.model.Attachments.length && el[0].classList.remove("hidden") | |
| }, | |
| unsubscribe = $rootScope.$on("attachmentAdded", show); | |
| hide(), $state.is("eo.reply") && el[0].classList.add("state-eoReply"); | |
| var onClick = function(e) { | |
| var target = e.target; | |
| if ("A" === target.nodeName) { | |
| var ID = target.getAttribute("data-attachment-id"), | |
| attachment = _.findWhere(scope.model.Attachments, { | |
| ID: ID | |
| }); | |
| if (target.classList.add("listAttachments-item-decrypt"), attachmentDownloader.isNotSupported(e)) return !1; | |
| attachmentDownloader.download(attachment, scope.model, target).then(function() { | |
| target.classList.add("listAttachments-item-download") | |
| }).catch(function(error) { | |
| target.classList.remove("listAttachments-item-decrypt"), AppModel.is("onLine") && notification.error(error) | |
| }) | |
| } | |
| if ("BUTTON" === target.nodeName) { | |
| var _ID = target.getAttribute("data-attachment-id"); | |
| $state.is("eo.reply") && $rootScope.$emit("attachment.upload.outside", { | |
| type: "remove", | |
| data: { | |
| id: target.getAttribute("data-attachment-id"), | |
| message: scope.model | |
| } | |
| }), scope.$applyAsync(function() { | |
| 1 === (_.findWhere(scope.model.Attachments, { | |
| ID: _ID | |
| }).Headers || {}).embedded && scope.model.NumEmbedded--, scope.model.Attachments = scope.model.Attachments.filter(function(att) { | |
| return att.ID !== _ID | |
| }), hide() | |
| }) | |
| } | |
| }; | |
| $list.addEventListener("click", onClick, !1), scope.$on("$destroy", function() { | |
| $list.removeEventListener("click", onClick, !1), unsubscribe() | |
| }) | |
| } | |
| } | |
| }), angular.module("proton.attachments").factory("attachmentFileFormat", function(aboutClient) { | |
| var embedded = ["image/gif", "image/jpeg", "image/png", "image/bmp"], | |
| isSafari = function() { | |
| return aboutClient.isSafari() | |
| }, | |
| isUploadMIMEType = function(type) { | |
| return aboutClient.isIE11() ? "Text" !== type : "text/html" !== type && "text/plain" !== type && "text/uri-list" !== type | |
| }; | |
| return { | |
| isEmbedded: function(key) { | |
| return _.contains(embedded, key) | |
| }, | |
| getEmbedded: function() { | |
| return embedded | |
| }, | |
| isUploadAbleType: function(_ref) { | |
| var dataTransfer = _ref.dataTransfer, | |
| list = [].concat(_toConsumableArray(dataTransfer.types || [])); | |
| return !(aboutClient.isIE11() && !list.length) && (isSafari() ? list.some(function(type) { | |
| return "Files" === type | |
| }) : list.every(isUploadMIMEType)) | |
| } | |
| } | |
| }); | |
| var _slicedToArray = function() { | |
| function sliceIterator(arr, i) { | |
| var _arr = [], | |
| _n = !0, | |
| _d = !1, | |
| _e = void 0; | |
| try { | |
| for (var _s, _i = arr[Symbol.iterator](); !(_n = (_s = _i.next()).done) && (_arr.push(_s.value), !i || _arr.length !== i); _n = !0); | |
| } catch (err) { | |
| _d = !0, _e = err | |
| } finally { | |
| try { | |
| !_n && _i.return && _i.return() | |
| } finally { | |
| if (_d) throw _e | |
| } | |
| } | |
| return _arr | |
| } | |
| return function(arr, i) { | |
| if (Array.isArray(arr)) return arr; | |
| if (Symbol.iterator in Object(arr)) return sliceIterator(arr, i); | |
| throw new TypeError("Invalid attempt to destructure non-iterable instance") | |
| } | |
| }(); | |
| angular.module("proton.attachments").factory("attachmentModel", function($q, attachmentApi, AttachmentLoader, authentication, $rootScope, embedded, notification, networkActivityTracker, composerRequestModel, attachmentDownloader, gettextCatalog) { | |
| function buildQueue(_ref2) { | |
| var messageID = _ref2.messageID, | |
| message = _ref2.message, | |
| queue = _ref2.queue; | |
| queue.files.length && (queueMessage[messageID] = queue, queue.hasEmbedded || dispatch("upload", { | |
| messageID: messageID, | |
| message: message, | |
| action: "attachment" | |
| })) | |
| } | |
| function create(file, message) { | |
| var insert = !(arguments.length > 2 && void 0 !== arguments[2]) || arguments[2], | |
| cid = arguments.length > 3 && void 0 !== arguments[3] ? arguments[3] : ""; | |
| return upload([{ | |
| file: file, | |
| isEmbedded: insert | |
| }], message, insert && "inline", !1, cid).then(function(_ref3) { | |
| var _ref4 = _slicedToArray(_ref3, 1), | |
| upload = _ref4[0]; | |
| return message.uploading = 0, upload | |
| }).catch(function(err) { | |
| throw console.error(err), err | |
| }) | |
| } | |
| function uploadQueue(_ref5) { | |
| var messageID = _ref5.messageID, | |
| message = _ref5.message, | |
| action = _ref5.action; | |
| if ("cancel" === action) return void delete queueMessage[messageID]; | |
| upload(queueMessage[messageID].files, message, action).then(function() { | |
| message.uploading = 0, delete queueMessage[messageID] | |
| }) | |
| } | |
| function upload() { | |
| var queue = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : [], | |
| message = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : {}, | |
| action = arguments.length > 2 && void 0 !== arguments[2] ? arguments[2] : "attachment", | |
| triggerEvent = !(arguments.length > 3 && void 0 !== arguments[3]) || arguments[3], | |
| cid = arguments.length > 4 && void 0 !== arguments[4] ? arguments[4] : "", | |
| deferred = $q.defer(), | |
| promises = _.map(queue, function(_ref6, i, list) { | |
| var file = _ref6.file, | |
| isEmbedded = _ref6.isEmbedded; | |
| return file.inline = +(isEmbedded && "inline" === action), addAttachment(file, message, list.length, cid) | |
| }); | |
| return message.uploading = promises.length, message.encryptingAttachment = !0, dispatchMessageAction(message), composerRequestModel.save(message, deferred), networkActivityTracker.track(deferred.promise), Promise.all(promises).then(function(upload) { | |
| return upload.filter(Boolean) | |
| }).then(function(upload) { | |
| message.uploading = 0, message.encryptingAttachment = !1, dispatchMessageAction(message); | |
| var embeddedMap = addEmbedded(upload, message); | |
| return _.map(upload, function(config) { | |
| return embeddedMap[config.attachment.ID] || config | |
| }) | |
| }).then(function(upload) { | |
| return message.addAttachments(upload.map(function(_ref7) { | |
| return _ref7.attachment | |
| })), updateMapAttachments(upload), triggerEvent && upload.length && dispatch("upload.success", { | |
| upload: upload, | |
| message: message, | |
| messageID: message.ID | |
| }), deferred.resolve(), upload | |
| }).catch(function(err) { | |
| dispatchMessageAction(message), deferred.reject(err) | |
| }) | |
| } | |
| function isEmbedded(_ref8) { | |
| var _ref8$Headers = _ref8.Headers; | |
| return "inline" === (void 0 === _ref8$Headers ? {} : _ref8$Headers)["content-disposition"] | |
| } | |
| function addEmbedded() { | |
| var list = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : [], | |
| message = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : {}; | |
| return _.chain(list).filter(function(_ref9) { | |
| var _ref9$attachment = _ref9.attachment; | |
| return isEmbedded(void 0 === _ref9$attachment ? {} : _ref9$attachment) | |
| }).filter(function(_ref10) { | |
| return _ref10.cid | |
| }).map(function(_ref11) { | |
| var packets = _ref11.packets, | |
| attachment = _ref11.attachment, | |
| sessionKey = _ref11.sessionKey, | |
| cid = _ref11.cid, | |
| REQUEST_ID = _ref11.REQUEST_ID; | |
| return { | |
| packets: packets, | |
| sessionKey: sessionKey, | |
| attachment: attachment, | |
| cid: cid, | |
| url: embedded.addEmbedded(message, cid, packets.Preview, attachment.MIMEType).url, | |
| REQUEST_ID: REQUEST_ID | |
| } | |
| }).reduce(function(acc, o) { | |
| return acc[o.attachment.ID] = o, acc | |
| }, {}).value() | |
| } | |
| function getConfigMapAttachment(id, attachment) { | |
| return MAP_ATTACHMENTS[id] ? MAP_ATTACHMENTS[id] : _.filter(MAP_ATTACHMENTS, function(config) { | |
| return config.attachment.ID === attachment.ID | |
| })[0] | |
| } | |
| function cleanMap(_ref12) { | |
| var REQUEST_ID = _ref12.REQUEST_ID; | |
| delete MAP_ATTACHMENTS[REQUEST_ID] | |
| } | |
| function remove(data) { | |
| var id = data.id, | |
| message = data.message, | |
| packet = data.packet, | |
| messageID = data.messageID, | |
| msg = message || { | |
| ID: messageID | |
| }, | |
| attachment = data.attachment || getAttachment(msg, id); | |
| attachmentApi.remove(msg, attachment).then(function() { | |
| var attConf = getConfigMapAttachment(id, attachment), | |
| state = _.extend({}, attConf || data, { | |
| message: message, | |
| attachment: attachment, | |
| id: id | |
| }); | |
| 1 === packet.Inline && "text/plain" !== message.MIMEType && dispatch("remove.embedded", state), message.removeAttachment(attachment), dispatch("remove.success", state), cleanMap(state) | |
| }).catch(function(exception) { | |
| dispatch("remove.error", { | |
| message: message, | |
| exception: exception | |
| }) | |
| }) | |
| } | |
| function removeAll(_ref13) { | |
| var message = _ref13.message; | |
| _ref13.list.forEach(function(attachment) { | |
| remove({ | |
| id: attachment.ID, | |
| attachment: attachment, | |
| message: message, | |
| packet: { | |
| Inline: +isEmbedded(attachment) | |
| } | |
| }) | |
| }) | |
| } | |
| function addAttachment(file, message) { | |
| var total = arguments.length > 2 && void 0 !== arguments[2] ? arguments[2] : 1, | |
| cid = arguments.length > 3 && void 0 !== arguments[3] ? arguments[3] : "", | |
| tempPacket = { | |
| filename: file.name, | |
| uploading: !0, | |
| Size: file.size, | |
| ContentID: cid, | |
| Inline: file.inline || 0 | |
| }; | |
| return tempPacket.Inline && message.NumEmbedded++, message.attachmentsToggle = !0, AttachmentLoader.load(file, message.From.Keys[0].PublicKey).then(function(packets) { | |
| return attachmentApi.upload(packets, message, tempPacket, total).then(function(_ref14) { | |
| var attachment = _ref14.attachment, | |
| sessionKey = _ref14.sessionKey, | |
| REQUEST_ID = _ref14.REQUEST_ID, | |
| isAborted = _ref14.isAborted, | |
| isError = _ref14.isError; | |
| if (isAborted || isError) throw new Error("Request error"); | |
| var contentId = (attachment.Headers || {})["content-id"] || "", | |
| cid = contentId.replace(/[<>]+/g, ""); | |
| return { | |
| attachment: attachment, | |
| sessionKey: sessionKey, | |
| packets: packets, | |
| cid: cid, | |
| REQUEST_ID: REQUEST_ID | |
| } | |
| }).catch(function(err) { | |
| console.error(err), notification.error(I18N.ERROR_UPLOAD) | |
| }) | |
| }).catch(function(err) { | |
| throw console.error(err), notification.error(I18N.ERROR_ENCRYPT), err | |
| }) | |
| } | |
| function downloadFromComposer(_ref16) { | |
| var id = _ref16.id, | |
| message = _ref16.message, | |
| config = MAP_ATTACHMENTS[id] || { | |
| attachment: message.getAttachment(id) | |
| }; | |
| config.attachment && attachmentDownloader.download(config.attachment, message) | |
| } | |
| var queueMessage = {}, | |
| MAP_ATTACHMENTS = {}, | |
| I18N = { | |
| ERROR_UPLOAD: gettextCatalog.getString("Error during file upload", null, "Compose message"), | |
| ERROR_ENCRYPT: gettextCatalog.getString("Error encrypting attachment", null, "Compose message") | |
| }, | |
| dispatch = function(type, data) { | |
| return $rootScope.$emit("attachment.upload", { | |
| type: type, | |
| data: data | |
| }) | |
| }, | |
| dispatchMessageAction = function(message) { | |
| return $rootScope.$emit("actionMessage", message) | |
| }, | |
| updateMapAttachments = function() { | |
| var uploads = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : []; | |
| MAP_ATTACHMENTS = uploads.reduce(function(acc, att) { | |
| return acc[att.REQUEST_ID] = att, acc | |
| }, MAP_ATTACHMENTS) | |
| }, | |
| getAttachment = function(message, id) { | |
| return MAP_ATTACHMENTS[id] ? MAP_ATTACHMENTS[id].attachment : _.findWhere(message.Attachments, { | |
| ID: id | |
| }) | |
| }; | |
| return $rootScope.$on("attachment.upload", function(e, _ref) { | |
| var type = _ref.type, | |
| data = _ref.data; | |
| switch (type) { | |
| case "close": | |
| attachmentApi.killUpload(data); | |
| break; | |
| case "uploading": | |
| data.message.encryptingAttachment = !1, dispatchMessageAction(data.message); | |
| break; | |
| case "cancel": | |
| dispatchMessageAction(data.message); | |
| break; | |
| case "remove": | |
| remove(data); | |
| break; | |
| case "remove.all": | |
| removeAll(data); | |
| break; | |
| case "drop": | |
| buildQueue(data); | |
| break; | |
| case "upload": | |
| uploadQueue(data); | |
| break; | |
| case "download.composer": | |
| downloadFromComposer(data) | |
| } | |
| }), { | |
| create: create, | |
| getCurrentQueue: function(_ref15) { | |
| var ID = _ref15.ID; | |
| return queueMessage[ID] | |
| } | |
| } | |
| }), angular.module("proton.attachments").factory("embeddedStore", function($rootScope, embeddedUtils) { | |
| function getHashKey(msg) { | |
| return ("" + (!!msg.isDraft && msg.isDraft() ? PREFIX_DRAFT : "") + (msg.ConversationID || msg.ID)).trim() | |
| } | |
| function deallocateList(key) { | |
| var list = MAP_BLOBS[key] || []; | |
| _.each(list, function(cid) { | |
| Blobs[cid] && (urlCreator().revokeObjectURL(Blobs[cid].url), delete Blobs[cid]) | |
| }), delete MAP_BLOBS[key] | |
| } | |
| function deallocate() { | |
| var message = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {}, | |
| key = getHashKey(message); | |
| Object.keys(MAP_BLOBS).filter(function(k) { | |
| return k !== key && 0 !== k.indexOf(PREFIX_DRAFT) | |
| }).forEach(deallocateList) | |
| } | |
| var Blobs = {}, | |
| MAP_BLOBS = {}, | |
| CIDList = {}, | |
| PREFIX_DRAFT = "draft_", | |
| urlCreator = function() { | |
| return window.URL || window.webkitURL | |
| }; | |
| $rootScope.$on("composer.update", function(e, _ref) { | |
| var type = _ref.type, | |
| _ref$data = _ref.data, | |
| data = void 0 === _ref$data ? {} : _ref$data; | |
| if ("close" === type) { | |
| var _data$message = data.message, | |
| ID = _data$message.ID, | |
| ConversationID = _data$message.ConversationID, | |
| key = "" + PREFIX_DRAFT + (ConversationID || ID); | |
| CIDList[ID] && delete CIDList[ID], MAP_BLOBS[key] && deallocateList(key) | |
| } | |
| }); | |
| var store = function() { | |
| var message = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : { | |
| isDraft: angular.noop | |
| }, | |
| cid = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : "", | |
| Attachments = CIDList[message.ID] || {}, | |
| _ref2 = Attachments[cid] || {}, | |
| _ref2$Headers = _ref2.Headers, | |
| Headers = void 0 === _ref2$Headers ? {} : _ref2$Headers, | |
| key = getHashKey(message); | |
| return MAP_BLOBS[key] = MAP_BLOBS[key] || [], | |
| function(data, MIME) { | |
| if (MAP_BLOBS[key]) { | |
| var blob = new Blob([data], { | |
| type: MIME | |
| }), | |
| imageUrl = urlCreator().createObjectURL(blob); | |
| Blobs[cid] = { | |
| url: imageUrl, | |
| isContentLocation: void 0 !== Headers["content-location"] && void 0 === Headers["content-id"] | |
| }, blob = null, imageUrl = null, MAP_BLOBS[key].push(cid) | |
| } | |
| } | |
| }, | |
| getBlob = function(cid) { | |
| return Blobs[cid] || {} | |
| }, | |
| hasBlob = function(cid) { | |
| return !!Blobs[cid] | |
| }, | |
| getMessageCIDs = function(_ref3) { | |
| var ID = _ref3.ID; | |
| return CIDList[ID] || {} | |
| }, | |
| containsMessageCIDs = function(_ref4) { | |
| var ID = _ref4.ID; | |
| return Object.keys(CIDList[ID] || {}).length > 0 | |
| }, | |
| addMessageCID = function(message, _ref5) { | |
| var _ref5$Headers = _ref5.Headers, | |
| Headers = void 0 === _ref5$Headers ? {} : _ref5$Headers, | |
| _ref5$Name = _ref5.Name, | |
| Name = void 0 === _ref5$Name ? "" : _ref5$Name; | |
| !CIDList[message.ID] && (CIDList[message.ID] = {}), !message.NumEmbedded && (message.NumEmbedded = 0); | |
| var cid = embeddedUtils.readCID(Headers); | |
| Headers.embedded = 1, message.NumEmbedded++, CIDList[message.ID][cid] = { | |
| Headers: Headers, | |
| Name: Name | |
| } | |
| }, | |
| existMessageCID = function(message, cid) { | |
| return !!getMessageCIDs(message)[cid] | |
| }; | |
| return { | |
| store: store, | |
| deallocate: deallocate, | |
| getBlob: getBlob, | |
| hasBlob: hasBlob, | |
| getBlobValue: function(cid) { | |
| var _getBlob = getBlob(cid), | |
| url = _getBlob.url; | |
| return embeddedUtils.getBlobFromURL(url) | |
| }, | |
| cid: { | |
| contains: containsMessageCIDs, | |
| exist: existMessageCID, | |
| add: addMessageCID, | |
| get: getMessageCIDs | |
| } | |
| } | |
| }); | |
| var _slicedToArray = function() { | |
| function sliceIterator(arr, i) { | |
| var _arr = [], | |
| _n = !0, | |
| _d = !1, | |
| _e = void 0; | |
| try { | |
| for (var _s, _i = arr[Symbol.iterator](); !(_n = (_s = _i.next()).done) && (_arr.push(_s.value), !i || _arr.length !== i); _n = !0); | |
| } catch (err) { | |
| _d = !0, _e = err | |
| } finally { | |
| try { | |
| !_n && _i.return && _i.return() | |
| } finally { | |
| if (_d) throw _e | |
| } | |
| } | |
| return _arr | |
| } | |
| return function(arr, i) { | |
| if (Array.isArray(arr)) return arr; | |
| if (Symbol.iterator in Object(arr)) return sliceIterator(arr, i); | |
| throw new TypeError("Invalid attempt to destructure non-iterable instance") | |
| } | |
| }(); | |
| angular.module("proton.attachments").factory("AttachmentLoader", function($cacheFactory, $log, $q, pmcw, authentication, $state, $stateParams, Eo, secureSessionStorage, attachmentApi) { | |
| function load(file, pubKeys, privKey) { | |
| var deferred = $q.defer(), | |
| reader = new FileReader; | |
| return file ? (reader.onloadend = function() { | |
| encrypt(reader.result, pubKeys, privKey, file).then(deferred.resolve).catch(function() { | |
| return deferred.reject("Failed to encrypt attachment. Please try again.") | |
| }) | |
| }, reader.readAsArrayBuffer(file), deferred.promise) : deferred.reject(new TypeError("You did not provide a file")) | |
| } | |
| var cache = $cacheFactory("attachments"), | |
| getCacheKey = function(_ref) { | |
| return "attachment." + _ref.ID | |
| }, | |
| isOutside = function() { | |
| return $state.is("eo.message") || $state.is("eo.reply") | |
| }, | |
| getRequest = function() { | |
| var _ref2 = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {}, | |
| ID = _ref2.ID; | |
| if (isOutside()) { | |
| var decryptedToken = secureSessionStorage.getItem("proton:decrypted_token"), | |
| token = $stateParams.tag; | |
| return Eo.attachment(decryptedToken, token, ID) | |
| } | |
| return attachmentApi.get(ID) | |
| }, | |
| decrypt = function(attachment, pubKey) { | |
| var sessionKey = arguments.length > 2 && void 0 !== arguments[2] ? arguments[2] : {}, | |
| at = new Uint8Array(attachment); | |
| return pmcw.decryptMessage({ | |
| message: pmcw.getMessage(at), | |
| sessionKey: sessionKey, | |
| format: "binary", | |
| publicKeys: pubKey ? pmcw.getKeys(pubKey) : [] | |
| }).then(function(_ref3) { | |
| return _ref3.data | |
| }).catch(function(err) { | |
| return $log.error(err), err | |
| }) | |
| }, | |
| encrypt = function(attachment, publicKeys, privateKeys) { | |
| var _ref4 = arguments.length > 3 && void 0 !== arguments[3] ? arguments[3] : {}, | |
| name = _ref4.name, | |
| type = _ref4.type, | |
| size = _ref4.size, | |
| inline = _ref4.inline, | |
| data = new Uint8Array(attachment); | |
| return pmcw.encryptMessage({ | |
| passwords: [], | |
| filename: name, | |
| armor: !1, | |
| data: data, | |
| publicKeys: pmcw.getKeys(publicKeys), | |
| privateKeys: privateKeys | |
| }).then(function(_ref5) { | |
| var message = _ref5.message, | |
| _pmcw$splitMessage = pmcw.splitMessage(message), | |
| asymmetric = _pmcw$splitMessage.asymmetric, | |
| encrypted = _pmcw$splitMessage.encrypted; | |
| return { | |
| Filename: name, | |
| MIMEType: type, | |
| FileSize: size, | |
| Inline: inline, | |
| Preview: data, | |
| keys: asymmetric[0], | |
| data: encrypted[0] | |
| } | |
| }) | |
| }, | |
| getSessionKey = function(message, attachment) { | |
| if (attachment.sessionKey) return Promise.resolve(attachment); | |
| var keyPackets = pmcw.binaryStringToArray(pmcw.decode_base64(attachment.KeyPackets)), | |
| options = { | |
| message: pmcw.getMessage(keyPackets) | |
| }; | |
| return isOutside() ? options.password = pmcw.decode_utf8_base64(secureSessionStorage.getItem("proton:encrypted_password")) : options.privateKeys = authentication.getPrivateKeys(message.AddressID), pmcw.decryptSessionKey(options).then(function(sessionKey) { | |
| return angular.extend({}, attachment, { | |
| sessionKey: sessionKey | |
| }) | |
| }) | |
| }; | |
| return { | |
| get: function() { | |
| var attachment = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {}, | |
| message = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : {}; | |
| if (cache.get("attachment." + attachment.ID)) return Promise.resolve(cache.get(getCacheKey(attachment))); | |
| if (attachment.Preview) return Promise.resolve(attachment.Preview); | |
| var request = getRequest(attachment), | |
| key = getSessionKey(message, attachment); | |
| return Promise.all([request, key]).then(function(_ref6) { | |
| var _ref7 = _slicedToArray(_ref6, 2), | |
| data = _ref7[0].data, | |
| sessionKey = _ref7[1].sessionKey; | |
| return decrypt(data, null, sessionKey) | |
| }).then(function(data) { | |
| return cache.put(getCacheKey(attachment), data), data | |
| }).catch(function(err) { | |
| throw err | |
| }) | |
| }, | |
| load: load, | |
| flushCache: function() { | |
| return cache.removeAll() | |
| }, | |
| getSessionKey: getSessionKey | |
| } | |
| }), angular.module("proton.attachments").factory("attachmentApi", function($http, url, $q, $rootScope, authentication, pmcw, CONFIG, CONSTANTS, secureSessionStorage, gettextCatalog, notification) { | |
| function killUpload(_ref) { | |
| var id = _ref.id, | |
| messageID = _ref.messageID; | |
| _.findWhere(pendingUpload, { | |
| id: id, | |
| messageID: messageID | |
| }).request.abort(), pendingUpload = pendingUpload.filter(function(up) { | |
| return up.id !== id | |
| }) | |
| } | |
| var pendingUpload = [], | |
| requestURL = url.build("attachments"), | |
| dispatch = function(type, data) { | |
| return $rootScope.$emit("attachment.upload", { | |
| type: type, | |
| data: data | |
| }) | |
| }, | |
| dispatchUpload = function(REQUEST_ID, message, packet) { | |
| return function(progress, status) { | |
| var isStart = arguments.length > 2 && void 0 !== arguments[2] && arguments[2]; | |
| dispatch("uploading", { | |
| id: REQUEST_ID, | |
| messageID: message.ID, | |
| message: message, | |
| status: status, | |
| progress: progress, | |
| packet: packet, | |
| isStart: isStart | |
| }) | |
| } | |
| }, | |
| parseJSON = function(xhr) { | |
| var response = function(json) { | |
| return { | |
| json: json, | |
| isInvalid: arguments.length > 1 && void 0 !== arguments[1] && arguments[1] | |
| } | |
| }; | |
| try { | |
| return response(JSON.parse(xhr.responseText)) | |
| } catch (e) { | |
| return response({ | |
| Error: "JSON parsing error: " + xhr.responseText | |
| }, !0) | |
| } | |
| }, | |
| makeFormUpload = function(packets, message, tempPacket) { | |
| var data = new FormData; | |
| return data.append("Filename", packets.Filename), data.append("MessageID", message.ID), data.append("ContentID", tempPacket.ContentID), data.append("MIMEType", packets.MIMEType), data.append("Inline", packets.Inline), data.append("KeyPackets", new Blob([packets.keys])), data.append("DataPacket", new Blob([packets.data])), data | |
| }; | |
| return { | |
| get: function(ID) { | |
| return $http.get(requestURL(ID), { | |
| responseType: "arraybuffer" | |
| }) | |
| }, | |
| upload: function(packets, message, tempPacket, total) { | |
| var REQUEST_ID = Math.random().toString(32).slice(2, 12) + "-" + Date.now(), | |
| dispatcher = dispatchUpload(REQUEST_ID, message, tempPacket), | |
| deferred = $q.defer(), | |
| xhr = new XMLHttpRequest, | |
| keys = authentication.getPrivateKeys(message.AddressID), | |
| unsubscribe = $rootScope.$on("AppModel", function(e, _ref2) { | |
| var type = _ref2.type, | |
| _ref2$data = _ref2.data, | |
| data = void 0 === _ref2$data ? {} : _ref2$data; | |
| "onLine" !== type || data.value || xhr.abort() | |
| }); | |
| return pendingUpload.push({ | |
| id: REQUEST_ID, | |
| messageID: message.ID, | |
| packet: tempPacket, | |
| request: xhr | |
| }), dispatcher(1, !0, !0), xhr.upload.onprogress = function(event) { | |
| var progress = event.loaded / event.total * 99; | |
| dispatcher(progress, !0) | |
| }, xhr.onerror = function() { | |
| pendingUpload = _.reject(pendingUpload, { | |
| id: REQUEST_ID, | |
| messageID: message.ID | |
| }), message.uploading = _.where(pendingUpload, { | |
| messageID: message.ID | |
| }).length, dispatch("error", { | |
| id: REQUEST_ID, | |
| messageID: message.ID, | |
| message: message | |
| }), deferred.resolve({ | |
| id: REQUEST_ID, | |
| isError: !0 | |
| }), unsubscribe() | |
| }, xhr.onabort = function() { | |
| pendingUpload = _.reject(pendingUpload, { | |
| id: REQUEST_ID, | |
| messageID: message.ID | |
| }), message.uploading = _.where(pendingUpload, { | |
| messageID: message.ID | |
| }).length, dispatch("cancel", { | |
| id: REQUEST_ID, | |
| messageID: message.ID, | |
| message: message | |
| }), deferred.resolve({ | |
| id: REQUEST_ID, | |
| isAborted: !0 | |
| }), unsubscribe() | |
| }, xhr.onload = function() { | |
| var _parseJSON = parseJSON(xhr), | |
| json = _parseJSON.json, | |
| isInvalid = _parseJSON.isInvalid, | |
| statusCode = this.status; | |
| if (unsubscribe(), 200 !== statusCode) return notification.error(gettextCatalog.getString("Unable to upload file. Please try again", null, "Error")), deferred.reject(json); | |
| if (json.Error) { | |
| var msgError = isInvalid ? gettextCatalog.getString("Unable to upload file. Please try again", null, "Error") : json.Error; | |
| return notification.error(msgError), deferred.reject(json) | |
| } | |
| dispatcher(100, !1), dispatch("uploaded.success", { | |
| id: REQUEST_ID, | |
| messageID: message.ID, | |
| packet: tempPacket, | |
| total: total, | |
| message: message | |
| }), pendingUpload = _.reject(pendingUpload, { | |
| id: REQUEST_ID, | |
| messageID: message.ID | |
| }); | |
| var msg = pmcw.getMessage(packets.keys); | |
| pmcw.decryptSessionKey({ | |
| message: msg, | |
| privateKeys: keys | |
| }).then(function(sessionKey) { | |
| return { | |
| REQUEST_ID: REQUEST_ID, | |
| sessionKey: sessionKey, | |
| attachment: _.extend({}, json.Attachment || {}, { | |
| sessionKey: sessionKey | |
| }) | |
| } | |
| }).then(deferred.resolve).catch(deferred.reject) | |
| }, xhr.open("post", requestURL("upload"), !0), xhr.withCredentials = !0, xhr.setRequestHeader("X-Requested-With", "XMLHttpRequest"), xhr.setRequestHeader("Accept", "application/vnd.protonmail.v1+json"), xhr.setRequestHeader("x-pm-appversion", "Web_" + CONFIG.app_version), xhr.setRequestHeader("x-pm-apiversion", CONFIG.api_version), xhr.setRequestHeader("x-pm-session", pmcw.decode_base64(secureSessionStorage.getItem(CONSTANTS.OAUTH_KEY + ":SessionToken") || "")), xhr.send(makeFormUpload(packets, message, tempPacket)), deferred.promise | |
| }, | |
| killUpload: killUpload, | |
| remove: function(message, attachment) { | |
| return $http.delete(requestURL(attachment.ID), { | |
| MessageID: message.ID | |
| }).then(function(_ref3) { | |
| var _ref3$data = _ref3.data, | |
| data = void 0 === _ref3$data ? {} : _ref3$data; | |
| if (1e3 !== data.Code) { | |
| var error = data.Error || "Error during the remove request"; | |
| throw new Error(error) | |
| } | |
| return data | |
| }).catch(function(error) { | |
| notification.error(error), console.error(error) | |
| }) | |
| } | |
| } | |
| }), angular.module("proton.attachments").factory("attachmentDownloader", function(gettextCatalog, AttachmentLoader, embeddedUtils, aboutClient, notification) { | |
| var isFileSaverSupported = aboutClient.isFileSaverSupported(), | |
| I18N = { | |
| NOT_SUPPORTED: gettextCatalog.getString("Your browser lacks features needed to download encrypted attachments directly. Please right-click on the attachment and select Save/Download As.", null, "Error"), | |
| ERROR_ZIP: gettextCatalog.getString("Cannot generate a zip of your attachments.", null, "Error") | |
| }, | |
| isNotSupported = function(e) { | |
| return !(!e.target.href || -1 === e.target.href.search(/^data.*/)) && (alert(I18N.NOT_SUPPORTED), e.preventDefault(), e.stopPropagation(), !0) | |
| }, | |
| downloadFile = function(blob, name, el) { | |
| try { | |
| if (isFileSaverSupported) return window.saveAs(blob, name); | |
| var reader = new FileReader; | |
| reader.onloadend = function() { | |
| el.href = reader.result | |
| }, reader.readAsDataURL(blob) | |
| } catch (error) { | |
| console.error(error) | |
| } | |
| }, | |
| generateDownload = function(attachment) { | |
| downloadFile(new Blob([attachment.data], { | |
| type: attachment.MIMEType | |
| }), attachment.Name, attachment.el) | |
| }, | |
| formatDownload = function(attachment, message, el) { | |
| return AttachmentLoader.get(attachment, message).then(function(buffer) { | |
| return { | |
| data: buffer, | |
| Name: attachment.Name, | |
| MIMEType: attachment.MIMEType, | |
| el: el | |
| } | |
| }) | |
| }; | |
| return { | |
| isNotSupported: isNotSupported, | |
| download: function(attachment, message, el) { | |
| return formatDownload(attachment, message, el).then(generateDownload) | |
| }, | |
| all: function() { | |
| var _ref = _asyncToGenerator(regeneratorRuntime.mark(function _callee() { | |
| var promises, list, zip, content, message = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {}, | |
| el = arguments[1]; | |
| return regeneratorRuntime.wrap(function(_context) { | |
| for (;;) switch (_context.prev = _context.next) { | |
| case 0: | |
| return _context.prev = 0, promises = (message.Attachments || []).filter(function(att) { | |
| return !embeddedUtils.isEmbedded(att) | |
| }).map(function(att) { | |
| return formatDownload(att, message) | |
| }), _context.next = 4, Promise.all(promises); | |
| case 4: | |
| return list = _context.sent, zip = new window.JSZip, list.forEach(function(_ref2) { | |
| var Name = _ref2.Name, | |
| data = _ref2.data; | |
| return zip.file(Name, data) | |
| }), _context.next = 9, zip.generateAsync({ | |
| type: "blob" | |
| }); | |
| case 9: | |
| content = _context.sent, downloadFile(content, "Attachments-" + message.Subject + ".zip", el), _context.next = 17; | |
| break; | |
| case 13: | |
| _context.prev = 13, _context.t0 = _context.catch(0), console.error(_context.t0), notification.error(I18N.ERROR_ZIP); | |
| case 17: | |
| case "end": | |
| return _context.stop() | |
| } | |
| }, _callee, void 0, [ | |
| [0, 13] | |
| ]) | |
| })); | |
| return function() { | |
| return _ref.apply(this, arguments) | |
| } | |
| }() | |
| } | |
| }), angular.module("proton.attachments").factory("embedded", function(embeddedFinder, embeddedStore, embeddedParser, embeddedUtils) { | |
| var REGEXP_CID_START = /^cid:/g; | |
| return { | |
| parser: function(message) { | |
| var _ref = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : {}, | |
| _ref$direction = _ref.direction, | |
| direction = void 0 === _ref$direction ? "blob" : _ref$direction, | |
| _ref$text = _ref.text, | |
| text = void 0 === _ref$text ? "" : _ref$text, | |
| _ref$isOutside = _ref.isOutside, | |
| isOutside = void 0 !== _ref$isOutside && _ref$isOutside, | |
| content = text || message.getDecryptedBody(); | |
| return embeddedFinder.find(message) ? embeddedParser.decrypt(message).then(function() { | |
| return embeddedParser.escapeHTML(message, direction, content) | |
| }).catch(function(error) { | |
| throw console.error(error), error | |
| }) : isOutside ? Promise.resolve(embeddedParser.escapeHTML(message, direction, content)) : Promise.resolve(content) | |
| }, | |
| addEmbedded: function(message, cid, data, MIME) { | |
| return embeddedStore.store(message, cid)(data, MIME), embeddedStore.getBlob(cid) | |
| }, | |
| getUrl: function(node) { | |
| var cid = embeddedUtils.srcToCID(node), | |
| _embeddedStore$getBlo = embeddedStore.getBlob(cid), | |
| _embeddedStore$getBlo2 = _embeddedStore$getBlo.url; | |
| return void 0 === _embeddedStore$getBlo2 ? "" : _embeddedStore$getBlo2 | |
| }, | |
| getAttachment: function(message, src) { | |
| var cid = src.replace(REGEXP_CID_START, ""); | |
| if (embeddedFinder.find(message)) return embeddedStore.cid.get(message)[cid] || {} | |
| }, | |
| isEmbedded: embeddedUtils.isEmbedded, | |
| getCid: embeddedUtils.readCID, | |
| getBlob: embeddedStore.getBlobValue, | |
| deallocator: embeddedStore.deallocate, | |
| clean: embeddedStore.cleanMemory, | |
| removeEmbedded: embeddedParser.removeEmbeddedHTML, | |
| exist: embeddedStore.cid.exist, | |
| generateCid: embeddedUtils.generateCid | |
| } | |
| }), angular.module("proton.attachments").factory("embeddedFinder", function(embeddedStore, embeddedUtils) { | |
| return { | |
| find: function(message) { | |
| var list = message.getAttachments(); | |
| return message.NumEmbedded = 0, !!list.length && (_.each(list, function(attachment) { | |
| embeddedUtils.isEmbedded(attachment) && embeddedStore.cid.add(message, attachment) | |
| }), embeddedStore.cid.contains(message)) | |
| }, | |
| listInlineAttachments: function(message) { | |
| var list = message.getAttachments(), | |
| MAP_CID = embeddedStore.cid.get(message); | |
| return Object.keys(MAP_CID).reduce(function(acc, cid) { | |
| var contentId = MAP_CID[cid].Headers["content-id"], | |
| contentName = embeddedUtils.getAttachementName(MAP_CID[cid].Headers), | |
| attachment = list.filter(function() { | |
| var _ref = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {}, | |
| _ref$Headers = _ref.Headers, | |
| Headers = void 0 === _ref$Headers ? {} : _ref$Headers, | |
| _ref$Name = _ref.Name, | |
| Name = void 0 === _ref$Name ? "" : _ref$Name; | |
| return Headers["content-location"] ? Name === contentName : Headers["content-id"] === contentId | |
| })[0]; | |
| return attachment && acc.push({ | |
| cid: cid, | |
| attachment: attachment | |
| }), acc | |
| }, []) | |
| } | |
| } | |
| }), angular.module("proton.attachments").factory("embeddedParser", function(embeddedStore, embeddedFinder, embeddedUtils, AttachmentLoader, attachmentFileFormat, authentication, $state) { | |
| var DIV = document.createElement("DIV"), | |
| getBodyParser = function() { | |
| return DIV.innerHTML = "", DIV | |
| }, | |
| actionDirection = { | |
| blob: function(nodes, cid, url) { | |
| _.each(nodes, function(node) { | |
| node.src = url, node.setAttribute("data-embedded-img", cid), node.removeAttribute("data-src"), node.classList.add("proton-embedded") | |
| }) | |
| }, | |
| cid: function(nodes, _cid) { | |
| _.each(nodes, function(node) { | |
| node.removeAttribute("data-embedded-img"), node.removeAttribute("src"), node.setAttribute("data-src", "cid:" + _cid) | |
| }) | |
| } | |
| }; | |
| return { | |
| escapeHTML: function(message, direction, body) { | |
| var testDiv = getBodyParser(); | |
| return testDiv.innerHTML = body.replace(/src="cid/g, 'data-src="cid'), Object.keys(embeddedStore.cid.get(message)).forEach(function(cid) { | |
| var current = embeddedStore.getBlob(cid), | |
| url = current ? current.url : "", | |
| selector = 'img[src="' + cid + '"], img[data-embedded-img="cid:' + cid + '"], img[data-embedded-img="' + cid + '"], img[data-src="cid:' + cid + '"]', | |
| nodes = [].slice.call(testDiv.querySelectorAll(selector)); | |
| nodes.length && (actionDirection[direction] || angular.noop)(nodes, cid, url) | |
| }), testDiv.innerHTML.replace(/data-src/g, "src") | |
| }, | |
| removeEmbeddedHTML: function(message) { | |
| var Headers = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : {}, | |
| content = arguments.length > 2 && void 0 !== arguments[2] ? arguments[2] : ""; | |
| if (embeddedUtils.isInline(Headers)) { | |
| var cid = embeddedUtils.readCID(Headers), | |
| tempDOM = $("<div>" + (content || message.getDecryptedBody()) + "</div>"); | |
| message.NumEmbedded--; | |
| var nodes = tempDOM.find('img[src="cid:' + cid + '"], img[data-embedded-img="cid:' + cid + '"], img[data-embedded-img="' + cid + '"]'); | |
| nodes.length && nodes.remove(), message.setDecryptedBody(tempDOM.html(), !0) | |
| } | |
| return message.getDecryptedBody() | |
| }, | |
| decrypt: function(message) { | |
| var list = embeddedFinder.listInlineAttachments(message), | |
| user = authentication.user || { | |
| ShowEmbedded: 0 | |
| }, | |
| show = !0 === message.showEmbedded || 1 === user.ShowEmbedded, | |
| isDraft = $state.includes("secured.drafts.**") || message.isDraft(), | |
| promise = _.chain(list).filter(function(_ref) { | |
| return _ref.attachment.KeyPackets | |
| }).filter(function(_ref2) { | |
| var cid = _ref2.cid; | |
| return !embeddedStore.hasBlob(cid) && (show || isDraft) | |
| }).map(function(_ref3) { | |
| var cid = _ref3.cid, | |
| attachment = _ref3.attachment, | |
| storeAttachement = embeddedStore.store(message, cid); | |
| return AttachmentLoader.get(attachment, message).then(function(buffer) { | |
| return storeAttachement(buffer, attachment.MIMEType) | |
| }) | |
| }).value(); | |
| return promise.length ? Promise.all(promise).then(function() { | |
| return list.reduce(function(acc, _ref4) { | |
| var cid = _ref4.cid; | |
| return acc[cid] = embeddedStore.getBlob(cid), acc | |
| }, Object.create(null)) | |
| }) : Promise.resolve({}) | |
| } | |
| } | |
| }); | |
| var _slicedToArray = function() { | |
| function sliceIterator(arr, i) { | |
| var _arr = [], | |
| _n = !0, | |
| _d = !1, | |
| _e = void 0; | |
| try { | |
| for (var _s, _i = arr[Symbol.iterator](); !(_n = (_s = _i.next()).done) && (_arr.push(_s.value), !i || _arr.length !== i); _n = !0); | |
| } catch (err) { | |
| _d = !0, _e = err | |
| } finally { | |
| try { | |
| !_n && _i.return && _i.return() | |
| } finally { | |
| if (_d) throw _e | |
| } | |
| } | |
| return _arr | |
| } | |
| return function(arr, i) { | |
| if (Array.isArray(arr)) return arr; | |
| if (Symbol.iterator in Object(arr)) return sliceIterator(arr, i); | |
| throw new TypeError("Invalid attempt to destructure non-iterable instance") | |
| } | |
| }(); | |
| angular.module("proton.attachments").factory("embeddedUtils", function(attachmentFileFormat, tools) { | |
| function trimQuotes(input) { | |
| var value = (input || "").trim(); | |
| return ['"', "'", "<"].indexOf(value.charAt(0)) > -1 && ['"', "'", ">"].indexOf(value.charAt(value.length - 1)) > -1 ? value.substr(1, value.length - 2) : value | |
| } | |
| function isEmbedded(_ref) { | |
| var _ref$Headers = _ref.Headers, | |
| Headers = void 0 === _ref$Headers ? {} : _ref$Headers, | |
| _ref$MIMEType = _ref.MIMEType, | |
| MIMEType = void 0 === _ref$MIMEType ? "" : _ref$MIMEType; | |
| return isInline(Headers) && attachmentFileFormat.isEmbedded(MIMEType) | |
| } | |
| var DIV = document.createElement("DIV"), | |
| REGEXP_CID_START = /^cid:/g, | |
| getBodyParser = function() { | |
| return DIV.innerHTML = "", DIV | |
| }, | |
| readCID = function() { | |
| var Headers = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {}; | |
| return Headers["content-id"] ? trimQuotes(Headers["content-id"]) : Headers["content-location"] ? trimQuotes(Headers["content-location"]) : "" | |
| }, | |
| isInline = function() { | |
| return !!(arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {})["content-id"] | |
| }; | |
| return { | |
| isInline: isInline, | |
| isEmbedded: isEmbedded, | |
| getAttachementName: function() { | |
| var Headers = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {}; | |
| if ("inline" !== Headers["content-disposition"]) { | |
| var _Headers$contentDisp = Headers["content-disposition"].split("filename="), | |
| _Headers$contentDisp2 = _slicedToArray(_Headers$contentDisp, 2), | |
| name = _Headers$contentDisp2[1]; | |
| if (name) return name.replace(/"/g, "") | |
| } | |
| return "" | |
| }, | |
| generateCid: function(input, email) { | |
| return tools.hash(input).toString(16) + "@" + email.split("@")[1] | |
| }, | |
| srcToCID: function(node) { | |
| return (node.getAttribute("data-embedded-img") || "").replace(REGEXP_CID_START, "") | |
| }, | |
| readCID: readCID, | |
| trimQuotes: trimQuotes, | |
| getBodyParser: getBodyParser, | |
| getBlobFromURL: function() { | |
| var url = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : "", | |
| xhr = new XMLHttpRequest; | |
| return new Promise(function(resolve, reject) { | |
| xhr.open("GET", url, !0), xhr.responseType = "blob", xhr.onload = function() { | |
| if (200 === xhr.status) return resolve(xhr.response); | |
| reject(xhr.response) | |
| }, xhr.send() | |
| }) | |
| } | |
| } | |
| }), angular.module("proton.authentication").controller("LoginController", function($rootScope, $state, $stateParams, $scope, $log, $timeout, $http, $location, CONSTANTS, CONFIG, gettextCatalog, authentication, networkActivityTracker, notify, helpLoginModal, AppModel, pmcw, tempStorage, aboutClient, settingsApi, srp) { | |
| function clearErrors() { | |
| $scope.error = null, notify.closeAll() | |
| } | |
| function setLoggedIn() { | |
| $rootScope.isLoggedIn = !$state.is("login") | |
| } | |
| function focusInput() { | |
| $timeout(function() { | |
| return $("#username").focus() | |
| }, 30, !1) | |
| } | |
| function selectPassword() { | |
| var input = document.getElementById("password"); | |
| input.focus(), input.select() | |
| } | |
| function selectTwoFactor() { | |
| var input = document.getElementById("twoFactorCode"); | |
| input.focus(), input.select() | |
| } | |
| function checkHelpTag() { | |
| "help" === $location.hash() && $scope.displayHelpModal() | |
| } | |
| function testSessionStorage() { | |
| !1 === aboutClient.hasSessionStorage() && notify({ | |
| message: gettextCatalog.getString('You are in Private Mode or have Session Storage disabled.\nPlease deactivate Private Mode and then reload the page.\n<a href="https://protonmail.com/support/knowledge-base/enabling-cookies/" target="_blank">More information here</a>.', null, "Error"), | |
| classes: "notification-danger", | |
| duration: "0" | |
| }) | |
| } | |
| function testCookie() { | |
| !1 === aboutClient.hasCookie() && notify({ | |
| message: gettextCatalog.getString('Cookies are disabled.\nPlease activate it and then reload the page.\n<a href="https://protonmail.com/support/knowledge-base/enabling-cookies/" target="_blank">More information here</a>.', null, "Error"), | |
| classes: "notification-danger", | |
| duration: "0" | |
| }) | |
| } | |
| function autoLogin() { | |
| if ($scope.creds = tempStorage.getItem("creds"), $state.is("login.unlock")) { | |
| if (!$scope.creds) return $state.go("login"); | |
| if (!$scope.creds.authResponse) return tempStorage.setItem("creds", $scope.creds), $state.go("login"); | |
| if (1 === $scope.creds.authResponse.PasswordMode) return unlock($scope.creds.password, $scope.creds.authResponse); | |
| AppModel.set("domoArigato", !1) | |
| } else if ($state.is("login.sub")) { | |
| var url = window.location.href, | |
| arr = url.split("/"), | |
| domain = arr[0] + "//" + arr[2], | |
| _login = function _login(event) { | |
| if (event.origin === domain) { | |
| window.removeEventListener("message", _login); | |
| var sessionToken = event.data.SessionToken, | |
| adminPassword = event.data.MailboxPassword; | |
| authentication.savePassword(adminPassword), authentication.saveAuthData({ | |
| SessionToken: sessionToken | |
| }), $rootScope.isSecure = !0, $rootScope.isLoggedIn = !0, $state.go("secured.inbox") | |
| } | |
| }; | |
| window.addEventListener("message", _login), window.opener.postMessage("ready", domain) | |
| } else { | |
| if (!$scope.creds || !$scope.creds.username || !$scope.creds.password) return void delete $scope.creds; | |
| srp.info($scope.creds.username).then(function(resp) { | |
| 0 === resp.data.TwoFactor ? login($scope.creds.username, $scope.creds.password, null, resp) : ($scope.twoFactor = 1, $scope.initialInfoResponse = resp, $timeout(selectTwoFactor, 100, !1)) | |
| }).catch(function(error) { | |
| console.log(error) | |
| }) | |
| } | |
| } | |
| function resetLoginInputs() { | |
| $scope.password = "", $scope.twoFactorCode = "" | |
| } | |
| function login(username, password, twoFactorCode, initialInfoResponse) { | |
| networkActivityTracker.track(authentication.loginWithCredentials({ | |
| Username: username, | |
| Password: password, | |
| TwoFactorCode: twoFactorCode | |
| }, initialInfoResponse).then(function(result) { | |
| if ($log.debug("loginWithCredentials:result.data ", result), angular.isDefined(result.data) && angular.isDefined(result.data.Code) && 401 === result.data.Code) selectPassword(), notify({ | |
| message: result.data.ErrorDescription, | |
| classes: "notification-danger" | |
| }); | |
| else if (result.data && 10002 === result.data.Code) { | |
| var message = void 0; | |
| message = result.data.Error ? result.data.Error : "Your account has been disabled.", notify({ | |
| message: message, | |
| classes: "notification-danger" | |
| }) | |
| } else if (result.data && void 0 === result.data.PrivateKey) authentication.receivedCredentials({ | |
| AccessToken: result.data.AccessToken, | |
| RefreshToken: result.data.RefreshToken, | |
| Uid: result.data.Uid, | |
| ExpiresIn: result.data.ExpiresIn, | |
| EventID: result.data.EventID | |
| }), authentication.setAuthCookie(result.data).then(function() { | |
| $rootScope.isLoggedIn = !0, $state.go("login.setup") | |
| }).catch(function(error) { | |
| notify({ | |
| message: error.message, | |
| classes: "notification-danger" | |
| }), $state.go("login") | |
| }); | |
| else if (result.data && result.data.AccessToken) { | |
| $rootScope.isLoggedIn = !0; | |
| var creds = { | |
| username: username, | |
| password: password, | |
| authResponse: result.data | |
| }; | |
| 1 === result.data.PasswordMode && AppModel.set("domoArigato", !0), tempStorage.setItem("creds", creds), $state.go("login.unlock") | |
| } else if (result.data && 5003 === result.data.Code); | |
| else if (result.data && result.data.Error) { | |
| var error = result.data.ErrorDescription ? result.data.ErrorDescription : result.data.Error; | |
| notify({ | |
| message: error, | |
| classes: "notification-danger" | |
| }), resetLoginInputs() | |
| } else notify({ | |
| message: "Unable to log you in.", | |
| classes: "notification-danger" | |
| }), resetLoginInputs() | |
| }, function(result) { | |
| void 0 === result.message && (result.message = "Sorry, our login server is down. Please try again later."), $scope.twoFactor = 0, $timeout(selectPassword, 100, !1), notify({ | |
| message: result.message, | |
| classes: "notification-danger" | |
| }), console.error(result), resetLoginInputs() | |
| })) | |
| } | |
| function unlock() { | |
| var mailboxPassword = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : "", | |
| authResponse = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : {}; | |
| return authentication.unlockWithPassword(mailboxPassword, authResponse).then(function(resp) { | |
| return $log.debug("unlockWithPassword:resp" + resp), authentication.setAuthCookie(authResponse).then(function(resp) { | |
| $log.debug("setAuthCookie:resp" + resp), $rootScope.isLoggedIn = authentication.isLoggedIn(), $rootScope.isLocked = authentication.isLocked(), $rootScope.isSecure = authentication.isSecured(), $state.go("secured.inbox") | |
| }) | |
| }).catch(function(error) { | |
| $log.error("login.unlock", error), selectPassword(), notify({ | |
| message: error.message, | |
| classes: "notification-danger" | |
| }) | |
| }) | |
| } | |
| $scope.twoFactor = 0, $scope.showOld = "old.protonmail.com" !== window.location.hostname, $scope.domoArigato = !0; | |
| var unsubscribe = $rootScope.$on("AppModel", function(event, _ref) { | |
| var type = _ref.type, | |
| data = _ref.data; | |
| switch (type) { | |
| case "domoArigato": | |
| $scope.domoArigato = data.value | |
| } | |
| }); | |
| $scope.$on("$destroy", function() { | |
| return unsubscribe() | |
| }), $scope.displayHelpModal = function() { | |
| helpLoginModal.activate({ | |
| params: { | |
| close: function() { | |
| helpLoginModal.deactivate() | |
| } | |
| } | |
| }) | |
| }, $scope.enterLoginPassword = function() { | |
| angular.element("input").blur(), angular.element("#pm_login").attr({ | |
| action: "/*" | |
| }), clearErrors(); | |
| var _$scope$username = $scope.username, | |
| username = void 0 === _$scope$username ? "" : _$scope$username, | |
| _$scope$password = $scope.password, | |
| password = void 0 === _$scope$password ? "" : _$scope$password; | |
| try { | |
| if (!username || !password) throw new Error(gettextCatalog.getString("Please enter your username and password", null, "Login error")); | |
| var usernameLowerCase = username.toLowerCase(); | |
| if (!pmcw.encode_utf8(password)) throw new Error(gettextCatalog.getString("Your password is missing", null, "Login error")); | |
| networkActivityTracker.track(srp.info(usernameLowerCase).then(function(resp) { | |
| $scope.initialInfoResponse = resp, 0 === resp.data.TwoFactor ? login(usernameLowerCase, password, null, $scope.initialInfoResponse) : ($scope.twoFactor = 1, $timeout(selectTwoFactor, 100, !1)) | |
| }, function(error) { | |
| return Promise.reject(error) | |
| })) | |
| } catch (error) { | |
| var message = error.message; | |
| notify({ | |
| message: message, | |
| classes: "notification-danger" | |
| }) | |
| } | |
| }, $scope.enterTwoFactor = function() { | |
| if (angular.isUndefined($scope.twoFactorCode) || 0 === $scope.twoFactorCode.length) return void notify({ | |
| message: gettextCatalog.getString("Please enter your two-factor passcode", null, "Error"), | |
| classes: "notification-danger" | |
| }); | |
| login($scope.username, $scope.password, $scope.twoFactorCode, $scope.initialInfoResponse) | |
| }, $scope.unlock = function(e) { | |
| e.preventDefault(), angular.element("[type=password]").blur(); | |
| var mailboxPassword = $scope.mailboxPassword; | |
| clearErrors(), networkActivityTracker.track(unlock(mailboxPassword, $scope.creds.authResponse)) | |
| }, $scope.reset = function() { | |
| CONSTANTS.KEY_PHASE > 2 ? ($rootScope.isLoggedIn = !1, $state.go("support.reset-password")) : (tempStorage.setItem("creds", $scope.creds), $state.go("reset")) | |
| }, | |
| function() { | |
| AppModel.set("domoArigato", !0), setLoggedIn(), focusInput(), checkHelpTag(), testSessionStorage(), testCookie(), autoLogin() | |
| }() | |
| }), angular.module("proton.authentication").directive("loginForm", function() { | |
| return { | |
| replace: !0, | |
| templateUrl: "templates/authentication/loginForm.tpl.html" | |
| } | |
| }), angular.module("proton.authentication").directive("loginTwoFactorForm", function() { | |
| return { | |
| replace: !0, | |
| templateUrl: "templates/authentication/loginTwoFactorForm.tpl.html" | |
| } | |
| }), angular.module("proton.authentication").directive("twoFaField", function() { | |
| return { | |
| restrict: "E", | |
| replace: !0, | |
| templateUrl: "templates/authentication/twoFaField.tpl.html" | |
| } | |
| }), angular.module("proton.authentication").factory("authHttpResponseInterceptor", function($q, $injector, $rootScope, AppModel, networkUtils) { | |
| var notification = !1, | |
| upgradeNotification = !1, | |
| NOTIFS = void 0, | |
| buildNotifs = function() { | |
| var gettextCatalog = $injector.get("gettextCatalog"); | |
| return { | |
| newVersion: gettextCatalog.getString("A new version of ProtonMail is available. Please refresh this page."), | |
| nonIntegerVersion: gettextCatalog.getString("Non-integer API version requested.", null, "Error"), | |
| unsupported: gettextCatalog.getString("Unsupported API version.", null, "Error"), | |
| offline: gettextCatalog.getString("The ProtonMail API is offline: ", null, "Error"), | |
| noInternet: gettextCatalog.getString("No Internet connection found.", null, "Error"), | |
| noServer: gettextCatalog.getString("Could not connect to server.", null, "Error"), | |
| timeout: gettextCatalog.getString("Request timed out, please try again.", null, "Error"), | |
| noReachProton: gettextCatalog.getString("ProtonMail cannot be reached right now, please try again later.", null, "Error") | |
| } | |
| }, | |
| notifyError = function(message) { | |
| return $injector.get("notification").error(message) | |
| }; | |
| return { | |
| response: function(_response) { | |
| if (/^(?!.*templates)/.test(_response.config.url) && AppModel.set("onLine", !0), !NOTIFS && (NOTIFS = buildNotifs()), notification && (notification.close(), notification = !1), angular.isDefined(_response.data) && angular.isDefined(_response.data.Code)) | |
| if (5003 === _response.data.Code) upgradeNotification && upgradeNotification.close(), upgradeNotification = $injector.get("notify")({ | |
| classes: "notification-info noclose", | |
| message: NOTIFS.newVersion, | |
| duration: "0" | |
| }); | |
| else if (5004 === _response.data.Code) notifyError(NOTIFS.nonIntegerVersion); | |
| else if (5005 === _response.data.Code) notifyError(NOTIFS.unsupported); | |
| else if (7001 === _response.data.Code) notifyError(NOTIFS.offline + _response.data.Error); | |
| else if (9001 === _response.data.Code) { | |
| var handle9001 = $injector.get("handle9001"); | |
| return handle9001(_response.config) | |
| } | |
| return _response || $q.when(_response) | |
| }, | |
| responseError: function(rejection) { | |
| if (0 !== rejection.status && -1 !== rejection.status || networkUtils.isCancelledRequest(rejection)) { | |
| if (401 === rejection.status) { | |
| return $injector.get("handle401")(rejection) | |
| } | |
| if (403 === rejection.status) { | |
| return $injector.get("handle403")(rejection.config) | |
| } | |
| 504 === rejection.status ? (notification = notifyError(NOTIFS.timeout), AppModel.set("requestTimeout", !0)) : [408, 503].indexOf(rejection.status) > -1 && (notification = notifyError(NOTIFS.noReachProton)) | |
| } else { | |
| var key = !0 === navigator.onLine ? "noServer" : "noInternet"; | |
| notifyError(NOTIFS[key]), AppModel.set("onLine", !1) | |
| } | |
| return $q.reject(rejection) | |
| } | |
| } | |
| }), angular.module("proton.core").factory("helpLoginModal", function(pmModal) { | |
| return pmModal({ | |
| controllerAs: "ctrl", | |
| templateUrl: "templates/authentication/modals/helpLoginModal.tpl.html", | |
| controller: function(params) { | |
| this.cancel = function() { | |
| params.close() | |
| } | |
| } | |
| }) | |
| }), angular.module("proton.core").factory("loginPasswordModal", function($timeout, pmModal, srp, networkActivityTracker, authentication) { | |
| return pmModal({ | |
| controllerAs: "ctrl", | |
| templateUrl: "templates/authentication/modals/loginPassword.tpl.html", | |
| controller: function(params) { | |
| var _this = this; | |
| if (this.loginPassword = "", this.twoFactorCode = "", this.userPasswordMode = authentication.user.PasswordMode, this.submit = function() { | |
| return params.submit(_this.loginPassword, _this.twoFactorCode) | |
| }, this.cancel = function() { | |
| return params.cancel() | |
| }, params.hasTwoFactor) this.hasTwoFactor = 1 === params.hasTwoFactor; | |
| else { | |
| var promise = srp.info().then(function() { | |
| var _ref = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {}, | |
| _ref$data = _ref.data, | |
| data = void 0 === _ref$data ? {} : _ref$data; | |
| 1e3 === data.Code && (_this.hasTwoFactor = 1 === data.TwoFactor) | |
| }); | |
| networkActivityTracker.track(promise) | |
| } | |
| $timeout(function() { | |
| return document.getElementById("loginPassword").focus() | |
| }, 100, !1) | |
| } | |
| }) | |
| }), angular.module("proton.authentication").provider("pmcw", function() { | |
| pmcrypto.checkMailboxPassword = function(prKey, prKeyPassCode, accessToken) { | |
| return new Promise(function(resolve, reject) { | |
| return void 0 === prKey ? reject(new Error("Missing private key.")) : void 0 === prKeyPassCode ? reject(new Error("Missing Mailbox Password.")) : void pmcrypto.decryptPrivateKey(prKey, prKeyPassCode).then(function(privateKey) { | |
| var message = pmcrypto.getMessage(accessToken); | |
| pmcrypto.decryptMessage({ | |
| message: message, | |
| privateKey: privateKey | |
| }).then(function(_ref) { | |
| var data = _ref.data; | |
| return resolve({ | |
| password: prKeyPassCode, | |
| token: data | |
| }) | |
| }).catch(function() { | |
| return reject(new Error("Unable to get Access Token.")) | |
| }) | |
| }).catch(function() { | |
| return reject(new Error("Wrong Mailbox Password.")) | |
| }) | |
| }) | |
| }, this.$get = function() { | |
| return pmcrypto | |
| } | |
| }), angular.module("proton.authentication").factory("authentication", function($http, $location, $log, $q, $rootScope, $state, $injector, $exceptionHandler, authApi, checkKeysFormat, CONFIG, CONSTANTS, contactEmails, Contact, errorReporter, gettextCatalog, upgradePassword, Key, Label, networkActivityTracker, pmcw, secureSessionStorage, organizationApi, User, passwords, srp, labelsModel, setupKeys, AppModel, tempStorage, sanitize, upgradeKeys) { | |
| function saveAuthData(data) { | |
| data.SessionToken ? (secureSessionStorage.setItem(CONSTANTS.OAUTH_KEY + ":SessionToken", pmcw.encode_base64(data.SessionToken)), auth.data = data) : (secureSessionStorage.setItem(CONSTANTS.OAUTH_KEY + ":Uid", data.Uid), secureSessionStorage.setItem(CONSTANTS.OAUTH_KEY + ":AccessToken", data.AccessToken), secureSessionStorage.setItem(CONSTANTS.OAUTH_KEY + ":RefreshToken", data.RefreshToken), auth.data = _.pick(data, "Uid", "AccessToken", "RefreshToken")), auth.setAuthHeaders() | |
| } | |
| function savePassword(pwd) { | |
| secureSessionStorage.setItem(CONSTANTS.MAILBOX_PASSWORD_KEY, pmcw.encode_utf8_base64(pwd)) | |
| } | |
| function receivedCredentials(data) { | |
| var eventManager = $injector.get("eventManager"); | |
| saveAuthData(data), eventManager.setEventID(data.EventID) | |
| } | |
| var _api, keys = {}, | |
| auth = { | |
| headersSet: !1, | |
| setAuthHeaders: function() { | |
| this.headersSet = !0, auth.data.SessionToken ? ($http.defaults.headers.common["x-pm-session"] = auth.data.SessionToken, $http.defaults.headers.common.Authorization = void 0, $http.defaults.headers.common["x-pm-uid"] = void 0, secureSessionStorage.removeItem(CONSTANTS.OAUTH_KEY + ":AccessToken"), secureSessionStorage.removeItem(CONSTANTS.OAUTH_KEY + ":Uid"), secureSessionStorage.removeItem(CONSTANTS.OAUTH_KEY + ":RefreshToken")) : ($http.defaults.headers.common["x-pm-session"] = void 0, $http.defaults.headers.common.Authorization = "Bearer " + auth.data.AccessToken, $http.defaults.headers.common["x-pm-uid"] = auth.data.Uid) | |
| }, | |
| fetchUserInfo: function() { | |
| return networkActivityTracker.track(User.get().then(function() { | |
| var _ref = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {}, | |
| _ref$data = _ref.data, | |
| data = void 0 === _ref$data ? {} : _ref$data; | |
| if (1e3 === data.Code) return data.User; | |
| throw new Error(data.Error || "Error during user request") | |
| }).then(function(user) { | |
| if (0 === user.Keys.length) return $state.go("login.setup"), Promise.resolve(user); | |
| user.subuser = angular.isDefined(user.OrganizationPrivateKey); | |
| return $q.all({ | |
| labels: Label.query(), | |
| contacts: contactEmails.load(), | |
| fix: function() { | |
| return user.Role === CONSTANTS.FREE_USER_ROLE && user.Subscribed ? setupKeys.generateOrganization(api.getPassword()).then(function(response) { | |
| return { | |
| DisplayName: "My Organization", | |
| PrivateKey: response.privateKeyArmored | |
| } | |
| }).then(function(params) { | |
| return organizationApi.create(params) | |
| }) : Promise.resolve() | |
| }(), | |
| organizationKey: function() { | |
| return user.subuser ? pmcw.decryptPrivateKey(user.OrganizationPrivateKey, api.getPassword()) : Promise.resolve() | |
| }() | |
| }).then(function(_ref2) { | |
| var labels = _ref2.labels, | |
| organizationKey = _ref2.organizationKey; | |
| if (labels.data && 1e3 === labels.data.Code) return labelsModel.set(labels.data.Labels), { | |
| user: user, | |
| organizationKey: organizationKey | |
| }; | |
| if (labels.data && labels.data.Error) throw new Error(labels.data.Error); | |
| throw new Error("Error during label / contact request") | |
| }).then(function(_ref3) { | |
| var user = _ref3.user, | |
| organizationKey = _ref3.organizationKey, | |
| storeKeys = function(keys) { | |
| api.clearKeys(), _.each(keys, function(_ref4) { | |
| var address = _ref4.address, | |
| key = _ref4.key, | |
| pkg = _ref4.pkg; | |
| api.storeKey(address.ID, key.ID, pkg) | |
| }) | |
| }; | |
| return setupKeys.decryptUser(user, organizationKey, api.getPassword()).then(function(_ref5) { | |
| var keys = _ref5.keys; | |
| return storeKeys(keys), user | |
| }).catch(function(error) { | |
| throw $exceptionHandler(error), error | |
| }) | |
| }) | |
| })) | |
| } | |
| }, | |
| api = (_api = { | |
| user: {}, | |
| saveAuthData: saveAuthData, | |
| savePassword: savePassword, | |
| receivedCredentials: receivedCredentials, | |
| detectAuthenticationState: function() { | |
| var session = secureSessionStorage.getItem(CONSTANTS.OAUTH_KEY + ":SessionToken"); | |
| session && (auth.data = { | |
| SessionToken: pmcw.decode_base64(session) | |
| }, this.getRefreshCookie()) | |
| } | |
| }, _defineProperty(_api, "savePassword", function(pwd) { | |
| this.user && this.user.OrganizationPrivateKey || secureSessionStorage.setItem(CONSTANTS.MAILBOX_PASSWORD_KEY, pmcw.encode_utf8_base64(pwd)) | |
| }), _defineProperty(_api, "getPassword", function() { | |
| var value = secureSessionStorage.getItem(CONSTANTS.MAILBOX_PASSWORD_KEY); | |
| return value ? pmcw.decode_utf8_base64(value) : void 0 | |
| }), _defineProperty(_api, "randomString", function(length) { | |
| var charset = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789", | |
| i = void 0, | |
| result = "", | |
| isOpera = "[object Opera]" === Object.prototype.toString.call(window.opera); | |
| if (window.crypto && window.crypto.getRandomValues) { | |
| var values = new Uint32Array(length); | |
| for (window.crypto.getRandomValues(values), i = 0; i < length; i++) result += charset[values[i] % charset.length]; | |
| return result | |
| } | |
| if (isOpera) { | |
| for (i = 0; i < length; i++) result += charset[Math.floor(Math.random() * charset.length)]; | |
| return result | |
| } | |
| return this.semiRandomString(length) | |
| }), _defineProperty(_api, "semiRandomString", function(size) { | |
| for (var string = "", i = 0; i++ < size;) string += "0123456789ABCDEF" [Math.floor(16 * Math.random())]; | |
| return string | |
| }), _defineProperty(_api, "getPrivateKeys", function(addressID) { | |
| return keys[addressID] | |
| }), _defineProperty(_api, "storeKey", function(addressID, keyID, pkg) { | |
| pkg.ID = keyID, keys[addressID] = keys[addressID] || [], keys[addressID].push(pkg) | |
| }), _defineProperty(_api, "clearKeys", function() { | |
| keys = {} | |
| }), _defineProperty(_api, "getRefreshCookie", function() { | |
| return $log.debug("getRefreshCookie"), authApi.refresh({}).then(function(response) { | |
| return $log.debug(response), void 0 !== response.data.SessionToken ? ($log.debug("new token", response.data.SessionToken), $log.debug("before", $http.defaults.headers.common["x-pm-session"]), $http.defaults.headers.common["x-pm-session"] = response.data.SessionToken, secureSessionStorage.setItem(CONSTANTS.OAUTH_KEY + ":SessionToken", pmcw.encode_base64(response.data.SessionToken)), $log.debug("after", $http.defaults.headers.common["x-pm-session"]), response) : $q.reject(response.data.Error) | |
| }) | |
| }), _defineProperty(_api, "setAuthCookie", function(authResponse) { | |
| return $log.debug("setAuthCookie"), authApi.cookies({ | |
| ResponseType: "token", | |
| ClientID: CONFIG.clientID, | |
| GrantType: "refresh_token", | |
| RefreshToken: authResponse.RefreshToken, | |
| Uid: authResponse.Uid, | |
| RedirectURI: "https://protonmail.com", | |
| State: this.randomString(24) | |
| }).then(function(result) { | |
| return $log.debug(result), 1e3 === result.data.Code ? ($log.debug("/auth/cookies:", result), $log.debug("/auth/cookies1: resolved"), AppModel.set("domoArigato", !0), $log.debug("/auth/cookies2: resolved"), $log.debug("headers change", $http.defaults.headers), saveAuthData({ | |
| SessionToken: result.data.SessionToken | |
| }), $rootScope.isLocked = !1, result) : Promise.reject({ | |
| message: result.data.Error | |
| }) | |
| }, function(error) { | |
| return $log.error("setAuthCookie2", error), error.data && error.data.Error ? Promise.reject({ | |
| message: error.data.Error | |
| }) : Promise.reject({ | |
| message: "Error setting authentication cookies." | |
| }) | |
| }) | |
| }), _defineProperty(_api, "loginWithCredentials", function(creds, initialInfoResponse) { | |
| var deferred = $q.defer(); | |
| return creds.Username && creds.Password ? (delete $http.defaults.headers.common.Accept, srp.performSRPRequest("POST", "/auth", { | |
| Username: creds.Username, | |
| ClientID: CONFIG.clientID, | |
| ClientSecret: CONFIG.clientSecret | |
| }, creds, initialInfoResponse).then(function(resp) { | |
| resp.authVersion < passwords.currentAuthVersion ? srp.getPasswordParams(creds.Password).then(function(data) { | |
| upgradePassword.store(data), deferred.resolve(resp) | |
| }) : deferred.resolve(resp) | |
| }, function(error) { | |
| console.error(error), deferred.reject({ | |
| message: error.error_description | |
| }) | |
| })) : deferred.reject({ | |
| message: "Username and Password are required to login" | |
| }), deferred.promise | |
| }), _defineProperty(_api, "sessionTokenIsDefined", function() { | |
| var isDefined = !1; | |
| return auth.data && void 0 !== auth.data.SessionToken && "undefined" !== auth.data.SessionToken && (isDefined = !0), isDefined | |
| }), _defineProperty(_api, "isLoggedIn", function() { | |
| var loggedIn = this.sessionTokenIsDefined(); | |
| return !0 === loggedIn && !1 === auth.headersSet && auth.setAuthHeaders(), loggedIn | |
| }), _defineProperty(_api, "isLocked", function() { | |
| return !1 === this.isLoggedIn() || angular.isUndefined(this.getPassword()) | |
| }), _defineProperty(_api, "hasPaidMail", function() { | |
| return 1 & this.user.Subscribed | |
| }), _defineProperty(_api, "hasPaidVpn", function() { | |
| return 4 & this.user.Subscribed | |
| }), _defineProperty(_api, "isSecured", function() { | |
| return this.isLoggedIn() && angular.isDefined(this.getPassword()) | |
| }), _defineProperty(_api, "state", function() { | |
| return this.isLoggedIn() ? this.isLocked() ? "login.unlock" : null : "login" | |
| }), _defineProperty(_api, "redirectIfNecessary", function() { | |
| var newState = this.state(); | |
| newState && $state.go(newState) | |
| }), _defineProperty(_api, "logout", function(redirect) { | |
| var _this = this, | |
| callApi = !(arguments.length > 1 && void 0 !== arguments[1]) || arguments[1], | |
| sessionToken = secureSessionStorage.getItem(CONSTANTS.OAUTH_KEY + ":SessionToken"), | |
| uid = secureSessionStorage.getItem(CONSTANTS.OAUTH_KEY + ":Uid"), | |
| process = function() { | |
| _this.clearData(), !0 === redirect && $state.go("login") | |
| }; | |
| $rootScope.loggingOut = !0, callApi && (angular.isDefined(sessionToken) || angular.isDefined(uid)) ? authApi.revoke().then(process, process) : process() | |
| }), _defineProperty(_api, "clearData", function() { | |
| $http.defaults.headers.common["x-pm-session"] = void 0, $http.defaults.headers.common.Authorization = void 0, $http.defaults.headers.common["x-pm-uid"] = void 0, secureSessionStorage.clear(), delete auth.data, keys = {}, auth.headersSet = !1, this.user = {}, window.onbeforeunload = void 0, $rootScope.loggingOut = !1, $rootScope.isLoggedIn = this.isLoggedIn(), $rootScope.isLocked = this.isLocked(), $rootScope.isSecure = this.isSecured(), AppModel.set("domoArigato", !1), AppModel.set("loggedIn", !1), contactEmails.clear() | |
| }), _defineProperty(_api, "unlockWithPassword", function(pwd) { | |
| var _ref6 = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : {}, | |
| _ref6$PrivateKey = _ref6.PrivateKey, | |
| PrivateKey = void 0 === _ref6$PrivateKey ? "" : _ref6$PrivateKey, | |
| _ref6$AccessToken = _ref6.AccessToken, | |
| AccessToken = void 0 === _ref6$AccessToken ? "" : _ref6$AccessToken, | |
| _ref6$RefreshToken = _ref6.RefreshToken, | |
| RefreshToken = void 0 === _ref6$RefreshToken ? "" : _ref6$RefreshToken, | |
| _ref6$Uid = _ref6.Uid, | |
| Uid = void 0 === _ref6$Uid ? "" : _ref6$Uid, | |
| _ref6$ExpiresIn = _ref6.ExpiresIn, | |
| ExpiresIn = void 0 === _ref6$ExpiresIn ? 0 : _ref6$ExpiresIn, | |
| _ref6$EventID = _ref6.EventID, | |
| EventID = void 0 === _ref6$EventID ? "" : _ref6$EventID, | |
| _ref6$KeySalt = _ref6.KeySalt, | |
| KeySalt = void 0 === _ref6$KeySalt ? "" : _ref6$KeySalt, | |
| req = $q.defer(); | |
| return pwd ? (tempStorage.setItem("plainMailboxPass", pwd), passwords.computeKeyPassword(pwd, KeySalt).then(function(pwd) { | |
| return pmcw.checkMailboxPassword(PrivateKey, pwd, AccessToken) | |
| }).then(function(_ref7) { | |
| var token = _ref7.token; | |
| savePassword(_ref7.password), receivedCredentials({ | |
| AccessToken: token, | |
| RefreshToken: RefreshToken, | |
| Uid: Uid, | |
| ExpiresIn: ExpiresIn, | |
| EventID: EventID | |
| }), upgradePassword.send(), req.resolve(200) | |
| }, function() { | |
| req.reject({ | |
| message: "Wrong decryption password." | |
| }) | |
| })) : req.reject({ | |
| message: "Password is required." | |
| }), req.promise | |
| }), _defineProperty(_api, "fetchUserInfo", function() { | |
| var _this2 = this; | |
| return auth.fetchUserInfo().then(function(user) { | |
| 0 === user.DisplayName.length && (user.DisplayName = user.Name), $rootScope.isLoggedIn = !0, _this2.user = user, $rootScope.user = user; | |
| var plainMailboxPass = tempStorage.getItem("plainMailboxPass"); | |
| return tempStorage.removeItem("plainMailboxPass"), !plainMailboxPass || user.OrganizationPrivateKey || checkKeysFormat(user) ? (AppModel.set("editorMode", user.DraftMIMEType || "text/html"), user) : (AppModel.set("upgradingKeys", !0), upgradeKeys({ | |
| mailboxPassword: plainMailboxPass, | |
| oldSaltedPassword: _this2.getPassword(), | |
| user: user | |
| }).then(function() { | |
| return Promise.resolve(user) | |
| })) | |
| }).catch(function(error) { | |
| throw $state.go("support.message", { | |
| data: {} | |
| }), error | |
| }) | |
| }), _defineProperty(_api, "params", function(_params) { | |
| return _params | |
| }), _api); | |
| return api | |
| }), angular.module("proton.authentication").factory("authApi", function($http, url) { | |
| var requestURL = url.build("auth"); | |
| return { | |
| authenticate: function() { | |
| var params = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {}; | |
| return $http.post(requestURL(), params) | |
| }, | |
| refresh: function() { | |
| var params = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {}; | |
| return $http.post(requestURL("refresh"), params) | |
| }, | |
| cookies: function() { | |
| var params = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {}; | |
| return $http.post(requestURL("cookies"), params) | |
| }, | |
| info: function() { | |
| var params = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {}; | |
| return $http.post(requestURL("info"), params) | |
| }, | |
| modulus: function() { | |
| return $http.get(requestURL("modulus")) | |
| }, | |
| revoke: function() { | |
| return $http.delete(requestURL()) | |
| }, | |
| revokeOthers: function() { | |
| return $http.delete(requestURL("others")) | |
| } | |
| } | |
| }), angular.module("proton.authentication").factory("handle401", function($http, authentication) { | |
| var CACHE = { | |
| promises: [] | |
| }, | |
| clearPromise = function() { | |
| return CACHE.promises.length = 0 | |
| }, | |
| logout = function() { | |
| return clearPromise(), authentication.logout(!0, !1) | |
| }, | |
| recall = function(_ref) { | |
| var config = _ref.config; | |
| return _.extend(config.headers, $http.defaults.headers.common), $http(config) | |
| }; | |
| return function(rejection) { | |
| if (!CACHE.promises.length) return CACHE.promises.push(rejection), authentication.getRefreshCookie().then(function() { | |
| return Promise.all(CACHE.promises.map(function(rejection) { | |
| return recall(rejection) | |
| })) | |
| }).then(function() { | |
| return clearPromise() | |
| }).catch(function() { | |
| return logout() | |
| }); | |
| CACHE.promises.push(rejection) | |
| } | |
| }), angular.module("proton.authentication").factory("handle403", function($http, $q, loginPasswordModal, User, authentication, notification) { | |
| return function(config) { | |
| var deferred = $q.defer(); | |
| return loginPasswordModal.activate({ | |
| params: { | |
| submit: function(Password, TwoFactorCode) { | |
| User.unlock({ | |
| Password: Password, | |
| TwoFactorCode: TwoFactorCode | |
| }).then(function() { | |
| loginPasswordModal.deactivate(), deferred.resolve($http(config)) | |
| }, function(error) { | |
| notification.error(error.error_description) | |
| }) | |
| }, | |
| cancel: function() { | |
| loginPasswordModal.deactivate(), deferred.reject(new Error("loginPassword:cancel")) | |
| } | |
| } | |
| }), deferred.promise | |
| } | |
| }), angular.module("proton.authentication").factory("handle9001", function($q, $http, humanVerificationModal) { | |
| return function(config) { | |
| var deferred = $q.defer(); | |
| return humanVerificationModal.activate({ | |
| params: { | |
| close: function() { | |
| var resend = arguments.length > 0 && void 0 !== arguments[0] && arguments[0]; | |
| humanVerificationModal.deactivate(), resend ? deferred.resolve($http(config)) : deferred.resolve() | |
| } | |
| } | |
| }), deferred.promise | |
| } | |
| }), angular.module("proton.authentication").factory("passwords", function($q, gettextCatalog, webcrypto) { | |
| function bcrypt(str, salt) { | |
| var deferred = $q.defer(); | |
| return dcodeIO.bcrypt.hash(str, salt, function(err, hash) { | |
| "string" != typeof hash ? deferred.reject(err) : deferred.resolve(hash) | |
| }), deferred.promise | |
| } | |
| function cleanUsername(name) { | |
| return name.replace(/\.|-|_/g, "").toLowerCase() | |
| } | |
| function expandHash(str) { | |
| return openpgp.util.concatUint8Array([openpgp.crypto.hash.sha512(pmcrypto.binaryStringToArray(str + "\0")), openpgp.crypto.hash.sha512(pmcrypto.binaryStringToArray(str + "")), openpgp.crypto.hash.sha512(pmcrypto.binaryStringToArray(str + "")), openpgp.crypto.hash.sha512(pmcrypto.binaryStringToArray(str + ""))]) | |
| } | |
| function computeKeyPassword(password, salt) { | |
| if (salt && salt.length) { | |
| var saltBinary = pmcrypto.binaryStringToArray(pmcrypto.decode_base64(salt)); | |
| return bcrypt(password, "$2y$10$" + dcodeIO.bcrypt.encodeBase64(saltBinary, 16)).then(function(hash) { | |
| return hash.slice(29) | |
| }) | |
| } | |
| var deferred = $q.defer(); | |
| return deferred.resolve(password), deferred.promise | |
| } | |
| function generateKeySalt() { | |
| return pmcrypto.encode_base64(pmcrypto.arrayToBinaryString(webcrypto.getRandomValues(new Uint8Array(16)))) | |
| } | |
| var hashPasswordVersion = { | |
| 4: function(password, salt, modulus) { | |
| return hashPasswordVersion[3](password, salt, modulus) | |
| }, | |
| 3: function(password, salt, modulus) { | |
| var saltBinary = pmcrypto.binaryStringToArray(salt + "proton"); | |
| return bcrypt(password, "$2y$10$" + dcodeIO.bcrypt.encodeBase64(saltBinary, 16)).then(function(unexpandedHash) { | |
| return expandHash(unexpandedHash + pmcrypto.arrayToBinaryString(modulus)) | |
| }) | |
| }, | |
| 2: function(password, userName, modulus) { | |
| return hashPasswordVersion[1](password, cleanUsername(userName), modulus) | |
| }, | |
| 1: function(password, userName, modulus) { | |
| for (var salt = openpgp.crypto.hash.md5(pmcrypto.binaryStringToArray(pmcrypto.encode_utf8(userName.toLowerCase()))), encodedSalt = "", i = 0; i < salt.length; i++) { | |
| var byte = salt[i].toString(16); | |
| 1 === byte.length && (byte = "0" + byte), encodedSalt += byte | |
| } | |
| return bcrypt(password, "$2y$10$" + encodedSalt).then(function(unexpandedHash) { | |
| return expandHash(unexpandedHash + pmcrypto.arrayToBinaryString(modulus)) | |
| }) | |
| }, | |
| 0: function(password, userName, modulus) { | |
| var prehashed = pmcrypto.encode_base64(pmcrypto.arrayToBinaryString(openpgp.crypto.hash.sha512(pmcrypto.binaryStringToArray(userName.toLowerCase() + pmcrypto.encode_utf8(password))))); | |
| return hashPasswordVersion[1](prehashed, userName, modulus) | |
| } | |
| }; | |
| return { | |
| currentAuthVersion: 4, | |
| cleanUsername: cleanUsername, | |
| expandHash: expandHash, | |
| hashPassword: function(version, password, salt, userName, modulus) { | |
| switch (version) { | |
| case 4: | |
| case 3: | |
| return hashPasswordVersion[version](password, salt, modulus); | |
| case 2: | |
| case 1: | |
| case 0: | |
| return hashPasswordVersion[version](password, userName, modulus); | |
| default: | |
| $q.reject({ | |
| message: gettextCatalog.getString("Unsupported auth version", null, "Error") | |
| }) | |
| } | |
| }, | |
| computeKeyPassword: computeKeyPassword, | |
| generateKeySalt: generateKeySalt | |
| } | |
| }), angular.module("proton.authentication").factory("srp", function($http, CONFIG, webcrypto, passwords, url, authApi) { | |
| function generateProofs(len, hash, modulus, hashedPassword, serverEphemeral) { | |
| function toBN(arr) { | |
| for (var reversed = new Uint8Array(arr.length), i = 0; i < arr.length; i++) reversed[arr.length - i - 1] = arr[i]; | |
| return new asmCrypto.BigNumber(reversed) | |
| } | |
| function fromBN(bn) { | |
| for (var arr = bn.toBytes(), reversed = new Uint8Array(len / 8), i = 0; i < arr.length; i++) reversed[arr.length - i - 1] = arr[i]; | |
| return reversed | |
| } | |
| var generator = new asmCrypto.BigNumber(2), | |
| multiplier = toBN(hash(openpgp.util.concatUint8Array([fromBN(generator), modulus]))); | |
| modulus = toBN(modulus), serverEphemeral = toBN(serverEphemeral), hashedPassword = toBN(hashedPassword); | |
| var modulusMinusOne = modulus.subtract(1); | |
| if (modulus.bitLength !== len) return { | |
| Type: "Error", | |
| Description: "SRP modulus has incorrect size" | |
| }; | |
| if (modulus = new asmCrypto.Modulus(modulus), multiplier = modulus.reduce(multiplier), multiplier.compare(1) <= 0 || multiplier.compare(modulusMinusOne) >= 0) return { | |
| Type: "Error", | |
| Description: "SRP multiplier is out of bounds" | |
| }; | |
| if (generator.compare(1) <= 0 || generator.compare(modulusMinusOne) >= 0) return { | |
| Type: "Error", | |
| Description: "SRP generator is out of bounds" | |
| }; | |
| if (serverEphemeral.compare(1) <= 0 || serverEphemeral.compare(modulusMinusOne) >= 0) return { | |
| Type: "Error", | |
| Description: "SRP server ephemeral is out of bounds" | |
| }; | |
| var clientSecret = void 0, | |
| clientEphemeral = void 0, | |
| scramblingParam = void 0; | |
| do { | |
| do { | |
| clientSecret = toBN(webcrypto.getRandomValues(new Uint8Array(len / 8))) | |
| } while (clientSecret.compare(2 * len) <= 0); | |
| clientEphemeral = modulus.power(generator, clientSecret), scramblingParam = toBN(hash(openpgp.util.concatUint8Array([fromBN(clientEphemeral), fromBN(serverEphemeral)]))) | |
| } while (0 === scramblingParam.compare(0)); | |
| var subtracted = serverEphemeral.subtract(modulus.reduce(modulus.power(generator, hashedPassword).multiply(multiplier))); | |
| subtracted.compare(0) < 0 && (subtracted = subtracted.add(modulus)); | |
| var exponent = scramblingParam.multiply(hashedPassword).add(clientSecret).divide(modulus.subtract(1)).remainder, | |
| sharedSession = modulus.power(subtracted, exponent), | |
| clientProof = hash(openpgp.util.concatUint8Array([fromBN(clientEphemeral), fromBN(serverEphemeral), fromBN(sharedSession)])), | |
| serverProof = hash(openpgp.util.concatUint8Array([fromBN(clientEphemeral), clientProof, fromBN(sharedSession)])); | |
| return { | |
| Type: "Success", | |
| ClientEphemeral: fromBN(clientEphemeral), | |
| ClientProof: clientProof, | |
| ExpectedServerProof: serverProof | |
| } | |
| } | |
| function generateVerifier(len, hashedPassword, modulus) { | |
| function toBN(arr) { | |
| for (var reversed = new Uint8Array(arr.length), i = 0; i < arr.length; i++) reversed[arr.length - i - 1] = arr[i]; | |
| return new asmCrypto.BigNumber(reversed) | |
| } | |
| var generator = new asmCrypto.BigNumber(2); | |
| modulus = new asmCrypto.Modulus(toBN(modulus)), hashedPassword = toBN(hashedPassword); | |
| var verifier = modulus.power(generator, hashedPassword); | |
| return function(bn) { | |
| for (var arr = bn.toBytes(), reversed = new Uint8Array(len / 8), i = 0; i < arr.length; i++) reversed[arr.length - i - 1] = arr[i]; | |
| return reversed | |
| }(verifier) | |
| } | |
| function tryRequest(method, endpoint, req, creds, headers, fallbackAuthVersion) { | |
| return authInfo(creds.Username).then(function(resp) { | |
| return tryAuth(resp, method, endpoint, req, creds, headers, fallbackAuthVersion) | |
| }) | |
| } | |
| function tryAuth(infoResp, method, endpoint, req, creds, headers, fallbackAuthVersion) { | |
| function srpHasher(arr) { | |
| return passwords.expandHash(pmcrypto.arrayToBinaryString(arr)) | |
| } | |
| var proofs = void 0, | |
| useFallback = void 0, | |
| session = infoResp.data.SRPSession, | |
| modulus = pmcrypto.binaryStringToArray(pmcrypto.decode_base64(openpgp.cleartext.readArmored(infoResp.data.Modulus).getText())), | |
| serverEphemeral = pmcrypto.binaryStringToArray(pmcrypto.decode_base64(infoResp.data.ServerEphemeral)), | |
| authVersion = infoResp.data.Version; | |
| if (useFallback = 0 === authVersion, useFallback && (authVersion = fallbackAuthVersion), authVersion < 3 && (creds.Username = infoResp.data.Username), 2 === authVersion && passwords.cleanUsername(creds.Username) !== passwords.cleanUsername(infoResp.data.Username) || authVersion <= 1 && creds.Username.toLowerCase() !== infoResp.data.Username.toLowerCase()) return Promise.reject({ | |
| error_description: "Please login with just your ProtonMail username (without @protonmail.com or @protonmail.ch)." | |
| }); | |
| var salt = ""; | |
| return authVersion >= 3 && (salt = pmcrypto.decode_base64(infoResp.data.Salt)), passwords.hashPassword(authVersion, creds.Password, salt, creds.Username, modulus).then(function(hashed) { | |
| if (proofs = generateProofs(2048, srpHasher, modulus, hashed, serverEphemeral), "Success" !== proofs.Type) return Promise.reject({ | |
| error_description: proofs.Description | |
| }); | |
| var httpReq = { | |
| method: method, | |
| url: url.get() + endpoint, | |
| data: _.extend(req, { | |
| SRPSession: session, | |
| ClientEphemeral: pmcrypto.encode_base64(pmcrypto.arrayToBinaryString(proofs.ClientEphemeral)), | |
| ClientProof: pmcrypto.encode_base64(pmcrypto.arrayToBinaryString(proofs.ClientProof)), | |
| TwoFactorCode: creds.TwoFactorCode | |
| }) | |
| }; | |
| return angular.isDefined(headers) && (httpReq.headers = headers), $http(httpReq) | |
| }, function(err) { | |
| return Promise.reject({ | |
| error_description: err.message | |
| }) | |
| }).then(function(resp) { | |
| return 1e3 !== resp.data.Code ? Promise.reject({ | |
| error_description: resp.data.Error, | |
| usedFallback: useFallback | |
| }) : pmcrypto.encode_base64(pmcrypto.arrayToBinaryString(proofs.ExpectedServerProof)) === resp.data.ServerProof ? Promise.resolve(_.extend(resp, { | |
| authVersion: authVersion | |
| })) : Promise.reject({ | |
| error_description: "Invalid server authentication" | |
| }) | |
| }, function(error) { | |
| return Promise.reject(error) | |
| }) | |
| } | |
| function randomVerifier(password) { | |
| return authApi.modulus().then(function(resp) { | |
| if (1e3 !== resp.data.Code) return Promise.reject({ | |
| error_description: resp.data.Error | |
| }); | |
| var modulus = pmcrypto.binaryStringToArray(pmcrypto.decode_base64(openpgp.cleartext.readArmored(resp.data.Modulus).getText())), | |
| salt = pmcrypto.arrayToBinaryString(webcrypto.getRandomValues(new Uint8Array(10))); | |
| return passwords.hashPassword(passwords.currentAuthVersion, password, salt, void 0, modulus).then(function(hashedPassword) { | |
| var verifier = generateVerifier(2048, hashedPassword, modulus); | |
| return { | |
| Auth: { | |
| Version: passwords.currentAuthVersion, | |
| ModulusID: resp.data.ModulusID, | |
| Salt: pmcrypto.encode_base64(salt), | |
| Verifier: pmcrypto.encode_base64(pmcrypto.arrayToBinaryString(verifier)) | |
| } | |
| } | |
| }) | |
| }) | |
| } | |
| function authInfo(Username) { | |
| return authApi.info({ | |
| Username: Username, | |
| ClientID: CONFIG.clientID, | |
| ClientSecret: CONFIG.clientSecret | |
| }).then(function(resp) { | |
| if (1e3 === resp.data.Code) return resp; | |
| if (resp.data.Error) throw new Error(resp.data.Error); | |
| var error = new Error("Cannot get auth information"); | |
| throw error.noNotify = !0, error | |
| }) | |
| } | |
| function performSRPRequest(method, endpoint, req, creds, initialInfoResp, headers) { | |
| var ret = void 0; | |
| return ret = initialInfoResp ? tryAuth(initialInfoResp, method, endpoint, req, creds, headers, 2) : tryRequest(method, endpoint, req, creds, headers, 2), ret = ret.catch(function(err) { | |
| return !0 === err.usedFallback && passwords.cleanUsername(creds.Username) !== creds.Username.toLowerCase() ? tryRequest(method, endpoint, req, creds, headers, 1) : Promise.reject(err) | |
| }), ret = ret.catch(function(err) { | |
| return !0 === err.usedFallback ? tryRequest(method, endpoint, req, creds, headers, 0) : Promise.reject(err) | |
| }) | |
| } | |
| function getPasswordParams(password) { | |
| var config = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : {}; | |
| return randomVerifier(password).then(function(data) { | |
| return _.extend({}, config, data) | |
| }) | |
| } | |
| return { | |
| randomVerifier: randomVerifier, | |
| info: authInfo, | |
| performSRPRequest: performSRPRequest, | |
| getPasswordParams: getPasswordParams | |
| } | |
| }), angular.module("proton.authentication").factory("upgradePassword", function(settingsApi, tempStorage) { | |
| function store(value) { | |
| tempStorage.setItem(key, value, tenMinutes) | |
| } | |
| function send() { | |
| var Auth = tempStorage.getItem(key); | |
| return Auth ? (tempStorage.removeItem(key), settingsApi.passwordUpgrade(Auth)) : Promise.resolve() | |
| } | |
| var key = "auth", | |
| tenMinutes = 6e5; | |
| return { | |
| store: store, | |
| send: send | |
| } | |
| }), angular.module("proton.autoresponder").directive("autoresponder", function(autoresponderModel, timepickerModel, $rootScope, autoresponderLanguage) { | |
| var frequencies = [{ | |
| label: autoresponderLanguage.DURATION_FOREVER, | |
| value: autoresponderModel.constants.FOREVER | |
| }, { | |
| label: autoresponderLanguage.DURATION_FIXED, | |
| value: autoresponderModel.constants.FIXED_INTERVAL | |
| }, { | |
| label: autoresponderLanguage.DURATION_DAILY, | |
| value: autoresponderModel.constants.DAILY | |
| }, { | |
| label: autoresponderLanguage.DURATION_WEEKLY, | |
| value: autoresponderModel.constants.WEEKLY | |
| }, { | |
| label: autoresponderLanguage.DURATION_MONTHLY, | |
| value: autoresponderModel.constants.MONTHLY | |
| }]; | |
| return { | |
| replace: !0, | |
| restrict: "E", | |
| templateUrl: "templates/autoresponder/autoresponder.tpl.html", | |
| scope: {}, | |
| link: function(scope, elem, _ref) { | |
| var mock = _ref.mock, | |
| unsubscribe = []; | |
| scope.mock = "true" === mock, scope.frequencies = frequencies, scope.datetimepickerStartTime = "startTimePickerKey", scope.datetimepickerEndTime = "endTimePickerKey", scope.submitting = !1, scope.model = { | |
| isEnabled: !1, | |
| message: null, | |
| repeat: 0, | |
| subject: null, | |
| startTime: null, | |
| endTime: null, | |
| daysSelected: { | |
| 0: !0, | |
| 1: !0, | |
| 2: !0, | |
| 3: !0, | |
| 4: !0, | |
| 5: !0, | |
| 6: !0 | |
| } | |
| }; | |
| var isEmpty = function(message) { | |
| return null !== message && 0 === $(message).text().trim().length | |
| }; | |
| scope.isValid = function() { | |
| return !scope.model.isEnabled || !isEmpty(scope.model.message) && scope.model.message.length < autoresponderModel.constants.MAX_MESSAGE_LENGTH && (scope.model.repeat === autoresponderModel.constants.FOREVER || null !== scope.model.startTime && null !== scope.model.endTime) | |
| }; | |
| var onFormSubmit = function() { | |
| scope.$applyAsync(function() { | |
| scope.submitting = !0, $rootScope.$emit("autoresponder", { | |
| type: "save", | |
| data: { | |
| autoresponder: scope.model | |
| } | |
| }) | |
| }) | |
| }; | |
| if (scope.timezones = autoresponderModel.timezones, scope.mock) unsubscribe.push($rootScope.$on("autoresponder", function(event, _ref2) { | |
| var type = _ref2.type, | |
| _ref2$data = _ref2.data, | |
| data = void 0 === _ref2$data ? {} : _ref2$data; | |
| "update" === type && (scope.model = data.autoresponder) | |
| })), autoresponderModel.mock(); | |
| else { | |
| unsubscribe.push($rootScope.$on("autoresponder", function(event, _ref3) { | |
| var type = _ref3.type, | |
| _ref3$data = _ref3.data, | |
| data = void 0 === _ref3$data ? {} : _ref3$data; | |
| switch (type) { | |
| case "update": | |
| scope.model = data.autoresponder; | |
| break; | |
| case "saved_success": | |
| case "saved_error": | |
| scope.submitting = !1 | |
| } | |
| })), unsubscribe.push($rootScope.$on("autoresponder.toggle", function() { | |
| return autoresponderModel.set(scope.model) | |
| })); | |
| var form = elem.find("form"); | |
| form.on("submit", onFormSubmit), unsubscribe.push(function() { | |
| return form.off("submit", onFormSubmit) | |
| }), autoresponderModel.load() | |
| } | |
| scope.$on("$destroy", function() { | |
| _.each(unsubscribe, function(cb) { | |
| return cb() | |
| }), unsubscribe.length = 0 | |
| }) | |
| } | |
| } | |
| }), angular.module("proton.autoresponder").directive("autoresponderMessage", function(autoresponderModel, $rootScope) { | |
| return { | |
| replace: !0, | |
| restrict: "E", | |
| templateUrl: "templates/autoresponder/autoresponderMessage.tpl.html", | |
| scope: { | |
| message: "=" | |
| }, | |
| link: function(scope, elem, _ref) { | |
| var disabled = _ref.disabled, | |
| unsubscribe = []; | |
| scope.disabled = "true" === disabled, scope.halfMessageLength = autoresponderModel.constants.HALF_MESSAGE_LENGTH, scope.maxMessageLength = autoresponderModel.constants.MAX_MESSAGE_LENGTH, scope.isEmpty = function(message) { | |
| return null !== message && 0 === $(message).text().trim().length | |
| }, unsubscribe.push($rootScope.$on("autoresponder", function(event, _ref2) { | |
| var type = _ref2.type, | |
| _ref2$data = _ref2.data, | |
| data = void 0 === _ref2$data ? {} : _ref2$data; | |
| "update" === type && (scope.message = data.autoresponder.message) | |
| })), scope.$on("$destroy", function() { | |
| _.each(unsubscribe, function(cb) { | |
| return cb() | |
| }), unsubscribe.length = 0 | |
| }) | |
| } | |
| } | |
| }), angular.module("proton.autoresponder").directive("autoresponderTimePicker", function($rootScope, autoresponderModel, timepickerModel) { | |
| return { | |
| replace: !0, | |
| restrict: "E", | |
| templateUrl: "templates/autoresponder/autoresponderTimePicker.tpl.html", | |
| scope: { | |
| form: "=" | |
| }, | |
| link: function(scope, elem, _ref) { | |
| var datePickerKey = _ref.datePickerKey, | |
| labelId = _ref.labelId, | |
| repeat = _ref.repeat, | |
| zone = _ref.zone, | |
| timestamp = _ref.timestamp, | |
| disableInput = _ref.disableInput, | |
| unsubscribe = []; | |
| scope.repeat = Number(repeat), scope.timestamp = String(Number(timestamp)) === timestamp ? Number(timestamp) : null, scope.disableInput = "true" === disableInput, scope.zone = zone, scope.constants = autoresponderModel.constants, scope.labelId = labelId, scope.datePickerKey = datePickerKey, repeat === autoresponderModel.constants.DAILY && timepickerModel.initTimePicker(datePickerKey, { | |
| disableInput: disableInput, | |
| labelId: labelId | |
| }), unsubscribe.push($rootScope.$on("timepicker", function(event, _ref2) { | |
| var type = _ref2.type, | |
| data = _ref2.data; | |
| "update" === type && data.eventKey === datePickerKey && (scope.timestamp = data.timestamp, autoresponderModel.set(_defineProperty({}, labelId, data.timestamp))) | |
| })), unsubscribe.push($rootScope.$on("autoresponder", function(event, _ref3) { | |
| var type = _ref3.type, | |
| _ref3$data = _ref3.data, | |
| data = void 0 === _ref3$data ? {} : _ref3$data; | |
| if ("update" === type) { | |
| var refresh = data.autoresponder.repeat !== scope.repeat || scope.timestamp !== data.autoresponder[labelId]; | |
| scope.repeat = data.autoresponder.repeat, scope.timestamp = data.autoresponder[labelId], scope.zone = data.autoresponder.zone, data.autoresponder.repeat === autoresponderModel.constants.DAILY && timepickerModel.initTimePicker(datePickerKey, { | |
| disableInput: disableInput, | |
| labelId: labelId | |
| }), refresh && timepickerModel.refresh(scope.datePickerKey, scope.timestamp, scope.zone) | |
| } | |
| })), scope.$on("$destroy", function() { | |
| _.each(unsubscribe, function(cb) { | |
| return cb() | |
| }), unsubscribe.length = 0 | |
| }) | |
| } | |
| } | |
| }), angular.module("proton.autoresponder").directive("autoresponderTimeSection", function(autoresponderModel, dateUtils, $rootScope) { | |
| var days = _.map(dateUtils.getSortedWeekdays(), function(day) { | |
| return { | |
| value: day.value, | |
| label: day.shortLabel | |
| } | |
| }); | |
| return { | |
| replace: !0, | |
| restrict: "E", | |
| templateUrl: "templates/autoresponder/autoresponderTimeSection.tpl.html", | |
| scope: { | |
| form: "=" | |
| }, | |
| link: function(scope, elem, _ref) { | |
| var mock = _ref.mock, | |
| unsubscribe = []; | |
| scope.days = days, scope.constants = autoresponderModel.constants, scope.timezones = autoresponderModel.timezones, scope.mock = "true" === mock, scope.model = autoresponderModel.get(), unsubscribe.push($rootScope.$on("autoresponder", function(event, _ref2) { | |
| var type = _ref2.type, | |
| _ref2$data = _ref2.data, | |
| data = void 0 === _ref2$data ? {} : _ref2$data; | |
| "update" === type && (scope.model = data.autoresponder) | |
| })), unsubscribe.push($rootScope.$on("multiselect", function(event, _ref3) { | |
| var type = _ref3.type, | |
| name = _ref3.name, | |
| _ref3$data = _ref3.data, | |
| data = void 0 === _ref3$data ? {} : _ref3$data; | |
| "update" === type && "autoresponder.daysSelected" === name && autoresponderModel.set({ | |
| daysSelected: data.value | |
| }) | |
| })), scope.$on("$destroy", function() { | |
| _.each(unsubscribe, function(cb) { | |
| return cb() | |
| }), unsubscribe.length = 0 | |
| }) | |
| } | |
| } | |
| }), angular.module("proton.autoresponder").directive("autoresponderView", function(authentication) { | |
| return { | |
| replace: !0, | |
| restrict: "E", | |
| templateUrl: "templates/autoresponder/autoresponderView.tpl.html", | |
| scope: {}, | |
| link: function(scope) { | |
| scope.isFree = !(1 & authentication.user.Subscribed) | |
| } | |
| } | |
| }), angular.module("proton.autoresponder").directive("durationselect", function($rootScope, autoresponderModel, autoresponderLanguage) { | |
| var frequencies = [{ | |
| label: autoresponderLanguage.DURATION_FIXED, | |
| value: autoresponderModel.constants.FIXED_INTERVAL | |
| }, { | |
| label: autoresponderLanguage.DURATION_DAILY, | |
| value: autoresponderModel.constants.DAILY | |
| }, { | |
| label: autoresponderLanguage.DURATION_WEEKLY, | |
| value: autoresponderModel.constants.WEEKLY | |
| }, { | |
| label: autoresponderLanguage.DURATION_MONTHLY, | |
| value: autoresponderModel.constants.MONTHLY | |
| }, { | |
| label: autoresponderLanguage.DURATION_FOREVER, | |
| value: autoresponderModel.constants.FOREVER | |
| }]; | |
| return { | |
| replace: !0, | |
| restrict: "E", | |
| templateUrl: "templates/autoresponder/durationselect.tpl.html", | |
| scope: {}, | |
| link: function(scope, elem, _ref) { | |
| function onInput() { | |
| scope.$applyAsync(function() { | |
| autoresponderModel.set({ | |
| repeat: scope.repeat.value | |
| }) | |
| }) | |
| } | |
| var disableInput = _ref.disableInput, | |
| repeat = _ref.repeat, | |
| unsubscribe = []; | |
| scope.frequencies = frequencies, scope.repeat = _.findWhere(scope.frequencies, { | |
| value: Number(repeat) | |
| }), "true" === disableInput && elem.attr("disabled", "disabled"), unsubscribe.push($rootScope.$on("autoresponder", function(event, _ref2) { | |
| var type = _ref2.type, | |
| _ref2$data = _ref2.data, | |
| data = void 0 === _ref2$data ? {} : _ref2$data; | |
| "update" === type && (scope.repeat = _.findWhere(scope.frequencies, { | |
| value: data.autoresponder.repeat | |
| })) | |
| })), elem.on("change", onInput), unsubscribe.push(function() { | |
| return elem.off("change", onInput) | |
| }), scope.$on("$destroy", function() { | |
| _.each(unsubscribe, function(cb) { | |
| return cb() | |
| }), unsubscribe.length = 0 | |
| }) | |
| } | |
| } | |
| }), angular.module("proton.autoresponder").directive("zoneselect", function($rootScope, autoresponderModel) { | |
| return { | |
| replace: !0, | |
| restrict: "E", | |
| template: '<select id="time-zone" name="time-zone" ng-options="zone.label for zone in timezones track by zone.value" ng-model="zone"></select>', | |
| scope: {}, | |
| link: function(scope, elem, _ref) { | |
| var zone = _ref.zone, | |
| disableInput = _ref.disableInput, | |
| unsubscribe = []; | |
| scope.timezones = autoresponderModel.timezones, "true" === disableInput && elem.attr("disabled", "disabled"), scope.zone = _.findWhere(scope.timezones, { | |
| value: zone | |
| }); | |
| var onChange = function() { | |
| scope.$applyAsync(function() { | |
| return autoresponderModel.set({ | |
| zone: scope.zone.value | |
| }) | |
| }) | |
| }; | |
| unsubscribe.push($rootScope.$on("autoresponder", function(event, _ref2) { | |
| var type = _ref2.type, | |
| _ref2$data = _ref2.data, | |
| data = void 0 === _ref2$data ? {} : _ref2$data; | |
| "update" === type && (scope.zone = _.findWhere(scope.timezones, { | |
| value: data.autoresponder.zone | |
| })) | |
| })), elem.on("change", onChange), scope.$on("$destroy", function() { | |
| _.each(unsubscribe, function(cb) { | |
| return cb() | |
| }), unsubscribe.length = 0 | |
| }) | |
| } | |
| } | |
| }), angular.module("proton.autoresponder").factory("autoresponderModel", function($rootScope, gettextCatalog, authentication, tools, settingsApi, networkActivityTracker, notification, eventManager, autoresponderLanguage, signatureBuilder) { | |
| function getBaseResponder() { | |
| var base = _.extend({}, authentication.user.AutoResponder); | |
| if (null === base || !base.isEnabled) return getDefaultAutoResponder(); | |
| var daysSelected = base.daysSelected; | |
| return base.daysSelected = daysSelected.reduce(function(previous, value) { | |
| return previous[value] = !0, previous | |
| }, _.extend({}, [].concat(_toConsumableArray(new Array(7))).map(function() { | |
| return !1 | |
| }))), base | |
| } | |
| function getDefaultAutoResponder() { | |
| var defaultAutoresponder = { | |
| isEnabled: !1, | |
| startTime: Math.floor(Date.now() / 1e3) + constants.HOUR, | |
| endTime: null, | |
| daysSelected: _.extend({}, [].concat(_toConsumableArray(new Array(7))).map(function() { | |
| return !0 | |
| })), | |
| repeat: constants.FIXED_INTERVAL, | |
| subject: autoresponderLanguage.DEFAULT_SUBJECT_PREFIX, | |
| message: null, | |
| zone: moment.tz.guess() | |
| }, | |
| body = autoresponderLanguage.DEFAULT_BODY, | |
| bodyPlusSig = signatureBuilder.insert({ | |
| getDecryptedBody: function() { | |
| return body | |
| } | |
| }, { | |
| action: "new", | |
| isAfter: !0 | |
| }).replace(/<img[^>]*>/g, ""); | |
| return bodyPlusSig.length > constants.MAX_MESSAGE_LENGTH ? defaultAutoresponder.message = body : defaultAutoresponder.message = bodyPlusSig, defaultAutoresponder | |
| } | |
| function load() { | |
| clearChangedAutoresponder(); | |
| var data = get(); | |
| dispatch("update", { | |
| autoresponder: data | |
| }) | |
| } | |
| function mock() { | |
| var data = getDefaultAutoResponder(); | |
| data.isEnabled = !0, data.repeat = 0, data.startTime = Math.floor(Date.now() / 1e3), data.endTime = data.startTime + 7 * constants.DAY + 8 * constants.HOUR, updateChangedAutoresponder(data); | |
| var outData = get(); | |
| dispatch("update", { | |
| autoresponder: outData | |
| }) | |
| } | |
| function set(autoresponderIn) { | |
| var newAutoresponder = _.extend({}, autoresponderIn), | |
| oldAutoresponder = get(), | |
| tempAutoresponder = _.extend({}, oldAutoresponder, newAutoresponder); | |
| if (tempAutoresponder.zone !== oldAutoresponder.zone && tempAutoresponder.repeat === constants.FIXED_INTERVAL) { | |
| var startTime = tempAutoresponder.startTime, | |
| endTime = tempAutoresponder.endTime, | |
| oldZone = oldAutoresponder.zone, | |
| newZone = newAutoresponder.zone; | |
| null !== startTime && (newAutoresponder.startTime = Number(moment.tz(moment.tz(1e3 * startTime, oldZone).format("YYYY-MM-DDTHH:mm:ss"), newZone).format("X"))), null !== endTime && (newAutoresponder.endTime = Number(moment.tz(moment.tz(1e3 * endTime, oldZone).format("YYYY-MM-DDTHH:mm:ss"), newZone).format("X"))) | |
| } | |
| if (void 0 !== newAutoresponder.repeat && oldAutoresponder.repeat !== newAutoresponder.repeat) { | |
| var isForever = newAutoresponder.repeat === constants.FOREVER; | |
| newAutoresponder.startTime = isForever ? 0 : null, newAutoresponder.endTime = isForever ? 0 : null, newAutoresponder.repeat === constants.FIXED_INTERVAL && (newAutoresponder.startTime = Math.floor(Date.now() / 1e3) + constants.HOUR), void 0 === newAutoresponder.daysSelected && (newAutoresponder.daysSelected = { | |
| 0: !0, | |
| 1: !0, | |
| 2: !0, | |
| 3: !0, | |
| 4: !0, | |
| 5: !0, | |
| 6: !0 | |
| }) | |
| } | |
| updateChangedAutoresponder(newAutoresponder); | |
| var data = get(); | |
| dispatch("update", { | |
| autoresponder: data | |
| }) | |
| } | |
| function getAutoresponderInAPIFormat() { | |
| var autoresponder = get(); | |
| return autoresponder.daysSelected = Object.keys(_.pick(autoresponder.daysSelected, Boolean)).map(Number), autoresponder.isEnabled ? (autoresponder.repeat === constants.FOREVER && (autoresponder.startTime = 0, autoresponder.endTime = 0), autoresponder) : _.extend(autoresponder, { | |
| repeat: constants.FOREVER, | |
| startTime: 0, | |
| endTime: 0, | |
| daysSelected: [0, 1, 2, 3, 4, 5, 6], | |
| zone: "utc", | |
| message: "", | |
| subject: null | |
| }) | |
| } | |
| function getResponseMessage(oldEnabled, newEnabled) { | |
| return oldEnabled === newEnabled ? autoresponderLanguage.AUTORESPONDER_UPDATED_MESSAGE : newEnabled ? autoresponderLanguage.AUTORESPONDER_INSTALLED_MESSAGE : autoresponderLanguage.AUTORESPONDER_REMOVED_MESSAGE | |
| } | |
| function save() { | |
| var autoresponder = getAutoresponderInAPIFormat(), | |
| original = authentication.user.AutoResponder || getDefaultAutoResponder(), | |
| responseMessage = getResponseMessage(original.isEnabled, autoresponder.isEnabled), | |
| promise = settingsApi.setAutoresponder({ | |
| Parameters: autoresponder | |
| }).then(function(_ref) { | |
| var _ref$data = _ref.data, | |
| data = void 0 === _ref$data ? {} : _ref$data; | |
| if (data.Error) throw dispatch("saved_error", data), new Error(data.Error); | |
| if (1e3 === data.Code) return dispatch("saved_success", data), eventManager.call().then(function() { | |
| return notification.success(responseMessage) | |
| }) | |
| }).catch(function(error) { | |
| return dispatch("saved_error", { | |
| Error: error | |
| }) | |
| }); | |
| networkActivityTracker.track(promise) | |
| } | |
| var now = new Date, | |
| momentNow = moment(now), | |
| timezones = _.map(moment.tz.names(), function(name) { | |
| return { | |
| label: name + ": UTC " + momentNow.tz(name).format("Z"), | |
| value: name | |
| } | |
| }), | |
| constants = { | |
| FIXED_INTERVAL: 0, | |
| DAILY: 1, | |
| WEEKLY: 2, | |
| MONTHLY: 3, | |
| FOREVER: 4, | |
| HALF_MESSAGE_LENGTH: 2048, | |
| MAX_MESSAGE_LENGTH: 4096, | |
| HOUR: 3600, | |
| DAY: 86400 | |
| }, | |
| changedAutoresponder = {}, | |
| getChangedAutoresponder = function() { | |
| return changedAutoresponder | |
| }, | |
| updateChangedAutoresponder = function(autoresponder) { | |
| return changedAutoresponder = _.extend({}, changedAutoresponder, autoresponder) | |
| }, | |
| clearChangedAutoresponder = function() { | |
| return changedAutoresponder = {} | |
| }, | |
| get = function() { | |
| return _.extend({}, getBaseResponder(), getChangedAutoresponder()) | |
| }, | |
| dispatch = function(type, data) { | |
| return $rootScope.$emit("autoresponder", { | |
| type: type, | |
| data: data | |
| }) | |
| }; | |
| return $rootScope.$on("autoresponder", function(event, _ref2) { | |
| var type = _ref2.type, | |
| _ref2$data = _ref2.data, | |
| data = void 0 === _ref2$data ? {} : _ref2$data; | |
| "save" === type && (set(data.autoresponder), save()) | |
| }), $rootScope.$on("autoresponder.isEnabled", function(event, _ref3) { | |
| set({ | |
| isEnabled: _ref3.status | |
| }) | |
| }), { | |
| init: angular.noop, | |
| constants: constants, | |
| load: load, | |
| mock: mock, | |
| get: get, | |
| set: set, | |
| timezones: timezones | |
| } | |
| }), angular.module("proton.autoresponder").factory("autoresponderLanguage", function(gettextCatalog) { | |
| return { | |
| AUTORESPONDER_UPDATED_MESSAGE: gettextCatalog.getString("Autoresponder updated", null, "Success"), | |
| AUTORESPONDER_INSTALLED_MESSAGE: gettextCatalog.getString("Autoresponder installed", null, "Success"), | |
| AUTORESPONDER_REMOVED_MESSAGE: gettextCatalog.getString("Autoresponder removed", null, "Success"), | |
| DEFAULT_SUBJECT_PREFIX: "Auto", | |
| DEFAULT_BODY: gettextCatalog.getString("<div>I'm out of the office with limited access to my email.</div>", null, "Default autoresponder message without signature (no regards, etcetera)"), | |
| DURATION_FOREVER: gettextCatalog.getString("Permanent", null, "Duration/repetition of autoresponder"), | |
| DURATION_FIXED: gettextCatalog.getString("Fixed duration", null, "Duration/repetition of autoresponder"), | |
| DURATION_DAILY: gettextCatalog.getString("Repeat daily", null, "Duration/repetition of autoresponder"), | |
| DURATION_WEEKLY: gettextCatalog.getString("Repeat weekly", null, "Duration/repetition of autoresponder"), | |
| DURATION_MONTHLY: gettextCatalog.getString("Repeat monthly", null, "Duration/repetition of autoresponder") | |
| } | |
| }), angular.module("proton.blackFriday").directive("blackFridayFree", function() { | |
| return { | |
| replace: !0, | |
| restrict: "E", | |
| templateUrl: "templates/blackFriday/blackFridayFree.tpl.html" | |
| } | |
| }), angular.module("proton.blackFriday").directive("blackFridayPaid", function() { | |
| return { | |
| replace: !0, | |
| restrict: "E", | |
| templateUrl: "templates/blackFriday/blackFridayPaid.tpl.html" | |
| } | |
| }), angular.module("proton.blackFriday").directive("blackFridayPrice", function() { | |
| return { | |
| restrict: "E", | |
| replace: !0, | |
| scope: { | |
| amount: "=", | |
| strike: "=", | |
| currency: "=" | |
| }, | |
| templateUrl: "templates/blackFriday/blackFridayPrice.tpl.html" | |
| } | |
| }), angular.module("proton.blackFriday").factory("blackFridayModel", function($rootScope, authentication, CONSTANTS, dashboardModel, networkActivityTracker, Payment, paymentModal, subscriptionModel, paymentModel) { | |
| function isBlackFridayPeriod() { | |
| var force = arguments.length > 0 && void 0 !== arguments[0] && arguments[0], | |
| subscription = subscriptionModel.get(), | |
| isLifetime = "LIFETIME" === subscription.CouponCode, | |
| isMember = authentication.user.Role === PAID_MEMBER_ROLE, | |
| isSubuser = authentication.user.subuser, | |
| isTwoYears = subscription.Cycle === TWO_YEARS; | |
| return !isLifetime && (!isMember && !isSubuser && (!isTwoYears && (!(!force && localStorage.getItem(BLACK_FRIDAY_ITEM)) && inInterval()))) | |
| } | |
| function loadPlanIDs() { | |
| var plan = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : "current"; | |
| return dashboardModel.fetchPlans(CACHE.currency, TWO_YEARS).then(function() { | |
| var _ref = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {}, | |
| _ref$Plans = _ref.Plans, | |
| Plans = void 0 === _ref$Plans ? [] : _ref$Plans, | |
| PlanIDs = [], | |
| MAP_PLAN_ID = _.reduce(Plans, function(acc, _ref2) { | |
| var Name = _ref2.Name, | |
| ID = _ref2.ID; | |
| return acc[Name] = ID, acc | |
| }, {}); | |
| if (plan === PLUS && PlanIDs.push(MAP_PLAN_ID[PLUS]), plan === VPN_PLUS && PlanIDs.push(MAP_PLAN_ID[VPN_PLUS]), plan === PLUS + "+" + VPN_PLUS && PlanIDs.push(MAP_PLAN_ID[PLUS], MAP_PLAN_ID[VPN_PLUS]), "current" === plan) { | |
| var subscription = subscriptionModel.get(); | |
| PlanIDs.push.apply(PlanIDs, _toConsumableArray(subscription.Plans.map(function(_ref3) { | |
| var Name = _ref3.Name; | |
| return MAP_PLAN_ID[Name] | |
| }))) | |
| } | |
| return PlanIDs | |
| }) | |
| } | |
| function buy(_ref4) { | |
| var _ref4$plan = _ref4.plan, | |
| plan = void 0 === _ref4$plan ? "current" : _ref4$plan, | |
| promise = loadPlanIDs(plan).then(function(PlanIDs) { | |
| return Payment.valid({ | |
| Cycle: TWO_YEARS, | |
| Currency: CACHE.currency, | |
| PlanIDs: PlanIDs, | |
| Coupon: subscriptionModel.coupon() | |
| }).then(function() { | |
| var _ref5 = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {}, | |
| _ref5$data = _ref5.data, | |
| valid = void 0 === _ref5$data ? {} : _ref5$data; | |
| paymentModal.activate({ | |
| params: { | |
| planIDs: PlanIDs, | |
| valid: valid, | |
| cancel: function() { | |
| paymentModal.deactivate() | |
| } | |
| } | |
| }) | |
| }).catch(function() { | |
| var _ref6 = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {}, | |
| _ref6$data = _ref6.data, | |
| data = void 0 === _ref6$data ? {} : _ref6$data; | |
| throw Error(data.Error) | |
| }) | |
| }); | |
| networkActivityTracker.track(promise) | |
| } | |
| function set(key, value) { | |
| CACHE[key] = value | |
| } | |
| function saveClose() { | |
| localStorage.setItem(BLACK_FRIDAY_ITEM, "closed") | |
| } | |
| function load() { | |
| Promise.all([paymentModel.getMethods(), paymentModel.getStatus()]).then(function() { | |
| return $rootScope.$emit("blackFriday", { | |
| type: "loaded" | |
| }) | |
| }) | |
| } | |
| var PAID_MEMBER_ROLE = CONSTANTS.PAID_MEMBER_ROLE, | |
| CYCLE = CONSTANTS.CYCLE, | |
| PLANS = CONSTANTS.PLANS, | |
| BLACK_FRIDAY_INTERVAL = CONSTANTS.BLACK_FRIDAY_INTERVAL, | |
| TWO_YEARS = CYCLE.TWO_YEARS, | |
| _PLANS$PLAN = PLANS.PLAN, | |
| PLUS = _PLANS$PLAN.PLUS, | |
| VPN_PLUS = _PLANS$PLAN.VPN_PLUS, | |
| CACHE = {}, | |
| BLACK_FRIDAY_ITEM = "protonmail_black_friday", | |
| inInterval = function() { | |
| return moment().isBetween("2017-11-24", "2017-11-28") | |
| }; | |
| return setInterval(function() { | |
| $rootScope.$emit("blackFriday", { | |
| type: "tictac" | |
| }) | |
| }, BLACK_FRIDAY_INTERVAL), $rootScope.$on("blackFriday", function(event, _ref7) { | |
| var _ref7$type = _ref7.type, | |
| type = void 0 === _ref7$type ? "" : _ref7$type, | |
| _ref7$data = _ref7.data, | |
| data = void 0 === _ref7$data ? {} : _ref7$data; | |
| "buy" === type && buy(data), "load" === type && load() | |
| }), { | |
| init: angular.noop, | |
| isBlackFridayPeriod: isBlackFridayPeriod, | |
| set: set, | |
| saveClose: saveClose, | |
| inInterval: inInterval | |
| } | |
| }), angular.module("proton.blackFriday").factory("blackFridayModal", function($rootScope, $state, authentication, CONSTANTS, pmModal, blackFridayModel, subscriptionModel) { | |
| var TWO_YEARS = CONSTANTS.CYCLE.TWO_YEARS; | |
| return pmModal({ | |
| controllerAs: "ctrl", | |
| templateUrl: "templates/blackFriday/blackFridayModal.tpl.html", | |
| controller: function(params, $scope) { | |
| var _this = this, | |
| unsubscribe = $rootScope.$on("blackFriday", function(event, _ref) { | |
| var _ref$type = _ref.type; | |
| "loaded" === (void 0 === _ref$type ? "" : _ref$type) && $scope.$applyAsync(function() { | |
| _this.loaded = !0 | |
| }) | |
| }); | |
| this.loaded = !1, this.isFreeUser = !authentication.user.Subscribed, this.isPaidUser = authentication.user.Subscribed, this.close = function() { | |
| blackFridayModel.saveClose(), params.close() | |
| }, this.dashboard = function() { | |
| $state.is("secured.dashboard") || $state.go("secured.dashboard", { | |
| noBlackFridayModal: !0, | |
| currency: _this.currency, | |
| cycle: TWO_YEARS | |
| }), _this.close() | |
| }, this.buy = function() { | |
| var plan = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : "current"; | |
| $rootScope.$emit("blackFriday", { | |
| type: "buy", | |
| data: { | |
| plan: plan | |
| } | |
| }), _this.close() | |
| }, this.changeCurrency = function() { | |
| var currency = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : "EUR"; | |
| _this.currency = currency, blackFridayModel.set("currency", currency), $rootScope.$emit("closeDropdown") | |
| }, this.$onDestroy = function() { | |
| unsubscribe() | |
| }, this.currency = subscriptionModel.currency(), this.changeCurrency(this.currency), $rootScope.$emit("blackFriday", { | |
| type: "load" | |
| }) | |
| } | |
| }) | |
| }), angular.module("proton.bridge").directive("bridgeFreePanel", function(gettextCatalog, notification) { | |
| var I18N = { | |
| info: gettextCatalog.getString("This feature is only available for paid users.", null, "Info") | |
| }, | |
| onClick = function() { | |
| return notification.info(I18N.info) | |
| }; | |
| return { | |
| replace: !0, | |
| restrict: "E", | |
| scope: {}, | |
| templateUrl: "templates/bridge/bridgeFreePanel.tpl.html", | |
| link: function(scope, el) { | |
| var $btn = el.find(".bridgeFreePanel-btn"); | |
| $btn.on("click", onClick), scope.$on("$destroy", function() { | |
| $btn.off("click", onClick) | |
| }) | |
| } | |
| } | |
| }), angular.module("proton.bridge").directive("bridgePaidPanel", function() { | |
| return { | |
| replace: !0, | |
| restrict: "E", | |
| scope: {}, | |
| templateUrl: "templates/bridge/bridgePaidPanel.tpl.html" | |
| } | |
| }), angular.module("proton.bridge").directive("bridgeView", function(authentication) { | |
| return { | |
| replace: !0, | |
| restrict: "E", | |
| scope: {}, | |
| templateUrl: "templates/bridge/bridgeView.tpl.html", | |
| link: function(scope) { | |
| scope.isFree = !(1 & authentication.user.Subscribed) | |
| } | |
| } | |
| }), angular.module("proton.browserSupport").factory("browserFixes", function(safari) { | |
| function applyFixes() { | |
| _.each(browsers, function(browser) { | |
| browser.isCurrentBrowser() && browser.applyFixes() | |
| }) | |
| } | |
| var browsers = [safari]; | |
| return { | |
| init: applyFixes | |
| } | |
| }), angular.module("proton.browserSupport").factory("safari", function(aboutClient) { | |
| var fixes = [function() { | |
| $(document).on("click.fixSafariDownloadBug", function(e) { | |
| var target = e.target; | |
| target && "A" === target.tagName && "_blank" === target.getAttribute("target") && target.hasAttribute("href") && (e.preventDefault(), window.open(target.href)) | |
| }) | |
| }], | |
| applyFixes = function() { | |
| return _.each(fixes, function(fix) { | |
| return fix() | |
| }) | |
| }; | |
| return { | |
| isCurrentBrowser: aboutClient.isSafari, | |
| applyFixes: applyFixes | |
| } | |
| }), angular.module("proton.bugReport").directive("newBugReport", function($rootScope) { | |
| return { | |
| replace: !0, | |
| templateUrl: "templates/bugReport/newBugReport.tpl.html", | |
| link: function(scope, el) { | |
| var onClick = function() { | |
| $rootScope.$emit("bugReport", { | |
| type: "new", | |
| data: {} | |
| }) | |
| }; | |
| el.on("click", onClick), scope.$on("$destroy", function() { | |
| el.off("click", onClick) | |
| }) | |
| } | |
| } | |
| }), angular.module("proton.bugReport").factory("bugReportModel", function($rootScope, bugReportApi, bugModal) { | |
| function open() { | |
| bugModal.activate(getModalParam()) | |
| } | |
| $rootScope.$on("bugReport", function(e, _ref) { | |
| "new" === _ref.type && open() | |
| }); | |
| var takeScreenshot = function(_ref2) { | |
| return _ref2.attachScreenshot ? bugReportApi.takeScreenshot() : Promise.resolve() | |
| }, | |
| getModalParam = function() { | |
| return { | |
| params: { | |
| form: bugReportApi.getForm(), | |
| submit: function(data) { | |
| var form = angular.copy(data); | |
| bugModal.deactivate(), takeScreenshot(form).then(function(screenshot) { | |
| return bugReportApi.report(form, screenshot) | |
| }) | |
| }, | |
| cancel: function() { | |
| bugModal.deactivate() | |
| } | |
| } | |
| } | |
| }; | |
| return { | |
| init: angular.noop | |
| } | |
| }), angular.module("proton.bugReport").factory("Bug", function($http, $q, url, gettextCatalog) { | |
| var ERROR_REPORT = gettextCatalog.getString("Error communicating with the server", null, "Report bug request"); | |
| return { | |
| crash: function(data) { | |
| return $http.post(url.get() + "/bugs/crash", data) | |
| }, | |
| report: function(data) { | |
| return $http.post(url.get() + "/bugs", data).then(function() { | |
| var _ref = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {}, | |
| _ref$data = _ref.data, | |
| data = void 0 === _ref$data ? {} : _ref$data; | |
| if (1e3 === data.Code) return data; | |
| throw new Error(data.Error || ERROR_REPORT) | |
| }) | |
| }, | |
| uploadScreenshot: function(image, form) { | |
| var deferred = $q.defer(); | |
| return $.ajax({ | |
| url: "https://api.imgur.com/3/image", | |
| headers: { | |
| Authorization: "Client-ID 864920c2f37d63f" | |
| }, | |
| type: "POST", | |
| data: { | |
| image: image | |
| }, | |
| dataType: "json", | |
| success: function() { | |
| var _ref2 = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {}, | |
| _ref2$data = _ref2.data, | |
| data = void 0 === _ref2$data ? {} : _ref2$data; | |
| data.link ? deferred.resolve(angular.extend({}, form, { | |
| Description: form.Description + "\n\n\n\n" + data.link | |
| })) : deferred.reject() | |
| }, | |
| error: function() { | |
| deferred.reject() | |
| } | |
| }), deferred.promise | |
| } | |
| } | |
| }); | |
| var _slicedToArray = function() { | |
| function sliceIterator(arr, i) { | |
| var _arr = [], | |
| _n = !0, | |
| _d = !1, | |
| _e = void 0; | |
| try { | |
| for (var _s, _i = arr[Symbol.iterator](); !(_n = (_s = _i.next()).done) && (_arr.push(_s.value), !i || _arr.length !== i); _n = !0); | |
| } catch (err) { | |
| _d = !0, _e = err | |
| } finally { | |
| try { | |
| !_n && _i.return && _i.return() | |
| } finally { | |
| if (_d) throw _e | |
| } | |
| } | |
| return _arr | |
| } | |
| return function(arr, i) { | |
| if (Array.isArray(arr)) return arr; | |
| if (Symbol.iterator in Object(arr)) return sliceIterator(arr, i); | |
| throw new TypeError("Invalid attempt to destructure non-iterable instance") | |
| } | |
| }(); | |
| angular.module("proton.bugReport").factory("bugReportApi", function(Bug, CONFIG, $state, aboutClient, authentication, gettextCatalog, networkActivityTracker, notification, CONSTANTS) { | |
| var _layout, _view, ROW_MODE = CONSTANTS.ROW_MODE, | |
| COLUMN_MODE = CONSTANTS.COLUMN_MODE, | |
| MESSAGE_VIEW_MODE = CONSTANTS.MESSAGE_VIEW_MODE, | |
| CONVERSATION_VIEW_MODE = CONSTANTS.CONVERSATION_VIEW_MODE, | |
| MAP_MODE = { | |
| layout: (_layout = {}, _defineProperty(_layout, ROW_MODE, "row"), _defineProperty(_layout, COLUMN_MODE, "column"), _layout), | |
| view: (_view = {}, _defineProperty(_view, MESSAGE_VIEW_MODE, "row"), _defineProperty(_view, CONVERSATION_VIEW_MODE, "column"), _view) | |
| }, | |
| getViewLayout = function(type) { | |
| return MAP_MODE.layout[type] || "unknown" | |
| }, | |
| getViewMode = function(type) { | |
| return MAP_MODE.view[type] || "undefined" | |
| }, | |
| getClient = function() { | |
| var _ref = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {}, | |
| _ref$ViewLayout = _ref.ViewLayout, | |
| ViewLayout = void 0 === _ref$ViewLayout ? "" : _ref$ViewLayout, | |
| _ref$ViewMode = _ref.ViewMode, | |
| ViewMode = void 0 === _ref$ViewMode ? "" : _ref$ViewMode, | |
| os = aboutClient.getOS(), | |
| browser = aboutClient.getBrowser(), | |
| device = aboutClient.getDevice(); | |
| return { | |
| OS: os.name, | |
| OSVersion: os.version || "", | |
| Browser: browser.name, | |
| BrowserVersion: browser.version, | |
| Client: "Angular", | |
| ClientVersion: CONFIG.app_version, | |
| ViewLayout: getViewLayout(ViewLayout), | |
| ViewMode: getViewMode(ViewMode), | |
| DeviceName: device.vendor, | |
| DeviceModel: device.model | |
| } | |
| }, | |
| getForm = function() { | |
| var _authentication$user = authentication.user, | |
| _authentication$user$ = _authentication$user.Name, | |
| Name = void 0 === _authentication$user$ ? "" : _authentication$user$, | |
| _authentication$user$2 = _authentication$user.Addresses, | |
| Addresses = void 0 === _authentication$user$2 ? [] : _authentication$user$2, | |
| _$sortBy = _.sortBy(Addresses, "Order"), | |
| _$sortBy2 = _slicedToArray(_$sortBy, 1), | |
| _$sortBy2$ = _$sortBy2[0]; | |
| _$sortBy2$ = void 0 === _$sortBy2$ ? {} : _$sortBy2$; | |
| var _$sortBy2$$Email = _$sortBy2$.Email, | |
| Email = void 0 === _$sortBy2$$Email ? "" : _$sortBy2$$Email; | |
| return _.extend(getClient(authentication.user), { | |
| Resolution: window.innerHeight + " x " + window.innerWidth, | |
| Title: "[Angular] Bug [" + $state.$current.name + "]", | |
| Description: "", | |
| Username: Name, | |
| Email: Email, | |
| attachScreenshot: !1 | |
| }) | |
| }, | |
| takeScreenshot = function() { | |
| return new Promise(function(resolve) { | |
| if (!window.html2canvas) return resolve(); | |
| window.html2canvas(document.body, { | |
| onrendered: function(canvas) { | |
| try { | |
| resolve(canvas.toDataURL("image/jpeg", .9).split(",")[1]) | |
| } catch (e) { | |
| resolve(canvas.toDataURL().split(",")[1]) | |
| } | |
| } | |
| }) | |
| }) | |
| }, | |
| send = function(form) { | |
| return Bug.report(form).then(function() { | |
| return notification.success(gettextCatalog.getString("Bug reported", null, "Bug report successfully")) | |
| }) | |
| }; | |
| return { | |
| getForm: getForm, | |
| takeScreenshot: takeScreenshot, | |
| report: function(form, screenshot) { | |
| var promise = void 0; | |
| return promise = form.attachScreenshot ? Bug.uploadScreenshot(screenshot, form).then(send) : send(form), networkActivityTracker.track(promise), promise | |
| }, | |
| getClient: getClient, | |
| crash: function(error) { | |
| var crashData = _.extend(getClient(authentication.user), { | |
| Debug: { | |
| state: $state.$current.name, | |
| error: error | |
| } | |
| }); | |
| return Bug.crash(crashData).catch(angular.noop) | |
| } | |
| } | |
| }), angular.module("proton.commons").directive("appConfigBody", function($rootScope, AppModel) { | |
| var className = function() { | |
| return "appConfigBody-" + (arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : "") | |
| }, | |
| mapClassNames = { | |
| mobile: className("is-mobile"), | |
| tablet: className("is-tablet"), | |
| requestTimeout: className("request-timeout"), | |
| tourActive: className("tourActive"), | |
| activeComposer: className("activeComposer"), | |
| maximizedComposer: className("maximizedComposer"), | |
| modalOpen: className("modalOpen"), | |
| showSidebar: className("showSidebar") | |
| }; | |
| return { | |
| link: function(scope, el) { | |
| AppModel.is("mobile") && el[0].classList.add(mapClassNames.mobile), AppModel.is("tablet") && el[0].classList.add(mapClassNames.tablet); | |
| var toggleClass = function(className) { | |
| var data = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : {}, | |
| method = data.value ? "add" : "remove"; | |
| _rAF(function() { | |
| return el[0].classList[method](className) | |
| }) | |
| }; | |
| $rootScope.$on("AppModel", function(e, _ref) { | |
| var type = _ref.type, | |
| data = _ref.data, | |
| className = mapClassNames[type]; | |
| className && toggleClass(className, data) | |
| }), $rootScope.$on("$stateChangeSuccess", function(e, toState) { | |
| el[0].id = toState.name.replace(/[.]+/g, "-") | |
| }) | |
| } | |
| } | |
| }), angular.module("proton.commons").directive("appCopyright", function(CONFIG, gettextCatalog) { | |
| var label = gettextCatalog.getString("ProtonMail.com - Made globally, hosted in Switzerland.", null, "copyright"); | |
| return { | |
| replace: !0, | |
| template: '<span class="appCopyright-container">' + CONFIG.year + " " + label + "</span>" | |
| } | |
| }), angular.module("proton.commons").directive("copy", function(gettextCatalog, notification) { | |
| var I18N = { | |
| copy: gettextCatalog.getString("Copy to your clipboard", null), | |
| copied: gettextCatalog.getString("Copied to clipboard", null) | |
| }; | |
| return { | |
| restrict: "E", | |
| replace: !0, | |
| scope: { | |
| value: "=" | |
| }, | |
| template: '\n <button class="copy-button" type="button" data-tooltip="' + I18N.copy + '">\n <span class="copy-icon"></span>\n </button>\n ', | |
| link: function(scope, element) { | |
| var clipboard = new Clipboard(element[0], { | |
| text: function() { | |
| return scope.value | |
| } | |
| }); | |
| clipboard.on("success", function() { | |
| element.attr("data-tooltip", I18N.copied), notification.success(I18N.copied) | |
| }), clipboard.on("error", function() { | |
| element.addClass("error") | |
| }), scope.$on("$destroy", function() { | |
| return clipboard.destroy() | |
| }) | |
| } | |
| } | |
| }), angular.module("proton.commons").directive("placeholderTranslate", generateDirective("placeholder")).directive("titleTranslate", generateDirective("title")).directive("ptTooltipTranslate", generateDirective("pt-tooltip")), angular.module("proton.commons").factory("AppModel", function($rootScope) { | |
| var MODEL = {}, | |
| dispatch = function(type) { | |
| var data = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : {}; | |
| return $rootScope.$emit("AppModel", { | |
| type: type, | |
| data: data | |
| }) | |
| }, | |
| set = function() { | |
| var key = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : "", | |
| value = arguments[1], | |
| previous = MODEL[key]; | |
| MODEL[key] = value, previous !== value && dispatch(key, { | |
| value: value | |
| }) | |
| }, | |
| is = function() { | |
| var key = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : ""; | |
| return !!MODEL[key] | |
| }, | |
| get = function() { | |
| var key = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : ""; | |
| return MODEL[key] | |
| }; | |
| return { | |
| is: is, | |
| set: set, | |
| store: function() { | |
| var key = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : "", | |
| value = arguments[1]; | |
| return MODEL[key] = value | |
| }, | |
| get: get | |
| } | |
| }), angular.module("proton.commons").factory("contactEncryption", function($injector, $rootScope, CONSTANTS, chunk, gettextCatalog, pmcw, vcard) { | |
| function generateUID() { | |
| var s4 = function() { | |
| return Math.floor(65536 * (1 + Math.random())).toString(16).substring(1) | |
| }; | |
| return "proton-web-" + s4() + s4() + "-" + s4() + "-" + s4() + "-" + s4() + "-" + s4() + s4() + s4() | |
| } | |
| function mergeContactData() { | |
| var data = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : [], | |
| vcfString = _.reduce(data, function(acc, _ref2) { | |
| return "" + acc + _ref2.data + "\r\n" | |
| }, ""), | |
| vcards = vcard.from(vcfString); | |
| return vcard.merge(vcards) | |
| } | |
| function prepareCards(_ref3) { | |
| function getGroupName() { | |
| itemCounter++; | |
| var groupName = "item" + itemCounter; | |
| return _.contains(groups, groupName) ? getGroupName() : groupName | |
| } | |
| var data = _ref3.data, | |
| publicKeys = _ref3.publicKeys, | |
| privateKeys = _ref3.privateKeys, | |
| promises = [], | |
| itemCounter = 0, | |
| properties = vcard.extractProperties(data), | |
| groups = _.reduce(properties, function(acc, property) { | |
| var group = property.getGroup(); | |
| return -1 === acc.indexOf(group) && acc.push(group), acc | |
| }, []), | |
| _$reduce = _.reduce(vcard.extractProperties(data), function(acc, property) { | |
| var key = property.getField(), | |
| isClear = _.contains(CLEAR_FIELDS, key), | |
| isSigned = _.contains(SIGNED_FIELDS, key); | |
| return _.contains(GROUP_FIELDS, key) && !property.group && (property.group = getGroupName()), isClear && acc.clearText.push(property), isSigned && acc.toSign.push(property), isClear || isSigned || acc.toEncryptAndSign.push(property), acc | |
| }, { | |
| toEncryptAndSign: [], | |
| toSign: [], | |
| clearText: [] | |
| }), | |
| toEncryptAndSign = _$reduce.toEncryptAndSign, | |
| toSign = _$reduce.toSign, | |
| clearText = _$reduce.clearText; | |
| if (toEncryptAndSign.length > 0) { | |
| var _data = vcard.build(toEncryptAndSign).toString(VCARD_VERSION); | |
| promises.push(pmcw.encryptMessage({ | |
| data: _data, | |
| publicKeys: publicKeys, | |
| privateKeys: privateKeys, | |
| armor: !0, | |
| detached: !0 | |
| }).then(function(_ref4) { | |
| var data = _ref4.data, | |
| signature = _ref4.signature; | |
| return { | |
| Type: ENCRYPTED_AND_SIGNED, | |
| Data: data, | |
| Signature: signature | |
| } | |
| })) | |
| } | |
| if (toSign.length > 0) { | |
| var signedFields = _.pluck(toSign, "_field"); | |
| if (-1 === signedFields.indexOf("uid") && toSign.push(new vCard.Property("uid", generateUID())), -1 === signedFields.indexOf("fn")) { | |
| var fn = gettextCatalog.getString("Unknown", null, "Default display name vcard"), | |
| nameProperty = _.findWhere(toEncryptAndSign, { | |
| _field: "n" | |
| }); | |
| if (nameProperty) fn = nameProperty.valueOf().split(";").join(" "); | |
| else { | |
| var firstEmail = _.findWhere(toSign, { | |
| _field: "email" | |
| }); | |
| firstEmail && (fn = firstEmail.valueOf()) | |
| } | |
| toSign.push(new vCard.Property("fn", fn)) | |
| } | |
| var _data2 = vcard.build(toSign).toString(VCARD_VERSION); | |
| promises.push(pmcw.signMessage({ | |
| data: _data2, | |
| privateKeys: privateKeys, | |
| armor: !0, | |
| detached: !0 | |
| }).then(function(_ref5) { | |
| var signature = _ref5.signature; | |
| return { | |
| Type: SIGNED, | |
| Data: _data2, | |
| Signature: signature | |
| } | |
| })) | |
| } | |
| if (clearText.length > 0) { | |
| var _data3 = vcard.build(clearText).toString(VCARD_VERSION); | |
| promises.push(Promise.resolve({ | |
| Type: CLEAR_TEXT, | |
| Data: _data3, | |
| Signature: null | |
| })) | |
| } | |
| return Promise.all(promises) | |
| } | |
| function extractCards(_ref6) { | |
| var _ref6$cards = _ref6.cards, | |
| cards = void 0 === _ref6$cards ? [] : _ref6$cards, | |
| _ref6$privateKeys = _ref6.privateKeys, | |
| privateKeys = void 0 === _ref6$privateKeys ? [] : _ref6$privateKeys, | |
| _ref6$publicKeys = _ref6.publicKeys, | |
| publicKeys = void 0 === _ref6$publicKeys ? [] : _ref6$publicKeys, | |
| promises = _.map(cards, function(_ref7) { | |
| var Type = _ref7.Type, | |
| _ref7$Data = _ref7.Data, | |
| Data = void 0 === _ref7$Data ? "" : _ref7$Data, | |
| _ref7$Signature = _ref7.Signature, | |
| Signature = void 0 === _ref7$Signature ? "" : _ref7$Signature; | |
| switch (Type) { | |
| case ENCRYPTED_AND_SIGNED: | |
| return pmcw.decryptMessage({ | |
| message: pmcw.getMessage(Data), | |
| privateKeys: privateKeys, | |
| publicKeys: publicKeys, | |
| armor: !0, | |
| signature: pmcw.getSignature(Signature) | |
| }).then(function(_ref8) { | |
| var data = _ref8.data; | |
| return 1 !== _ref8.verified ? { | |
| error: TYPE3_CONTACT_VERIFICATION, | |
| data: data | |
| } : { | |
| data: data | |
| } | |
| }).catch(function() { | |
| return { | |
| error: TYPE3_CONTACT_DECRYPTION, | |
| data: (new vCard).toString(VCARD_VERSION) | |
| } | |
| }); | |
| case SIGNED: | |
| return pmcw.verifyMessage({ | |
| message: pmcw.getCleartextMessage(Data), | |
| publicKeys: publicKeys, | |
| signature: pmcw.getSignature(Signature) | |
| }).then(function(_ref9) { | |
| return 1 !== _ref9.verified ? { | |
| error: TYPE2_CONTACT, | |
| data: Data | |
| } : { | |
| data: Data | |
| } | |
| }); | |
| case ENCRYPTED: | |
| return pmcw.decryptMessage({ | |
| message: pmcw.getMessage(Data), | |
| privateKeys: privateKeys, | |
| armor: !0 | |
| }).catch(function() { | |
| return { | |
| error: TYPE1_CONTACT, | |
| data: (new vCard).toString(VCARD_VERSION) | |
| } | |
| }); | |
| case CLEAR_TEXT: | |
| return Promise.resolve({ | |
| data: Data | |
| }) | |
| } | |
| }); | |
| return Promise.all(promises) | |
| } | |
| function decrypt() { | |
| var contacts = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : [], | |
| authentication = $injector.get("authentication"), | |
| privateKeys = authentication.getPrivateKeys(MAIN_KEY), | |
| publicKeys = pmcw.getKeys(authentication.user.Keys[0].PublicKey), | |
| total = contacts.length, | |
| count = 0; | |
| return _.reduce(chunk(contacts, CONTACTS_LIMIT_ENCRYPTION), function(promise, chunkedContacts) { | |
| return promise.then(function() { | |
| var previousContacts = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : []; | |
| return Promise.all(chunkedContacts.map(function(_ref10) { | |
| var ID = _ref10.ID, | |
| _ref10$Cards = _ref10.Cards, | |
| Cards = void 0 === _ref10$Cards ? [] : _ref10$Cards; | |
| return extractCards({ | |
| cards: Cards, | |
| privateKeys: privateKeys, | |
| publicKeys: publicKeys | |
| }).then(function(data) { | |
| count++; | |
| var progress = Math.floor(100 * count / total); | |
| return $rootScope.$emit("progressBar", { | |
| type: "contactsProgressBar", | |
| data: { | |
| progress: progress | |
| } | |
| }), buildContact(ID, data, Cards) | |
| }) | |
| })).then(function(newContacts) { | |
| return previousContacts.concat(newContacts) | |
| }) | |
| }, []) | |
| }, Promise.resolve()) | |
| } | |
| function encrypt() { | |
| var contacts = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : [], | |
| authentication = $injector.get("authentication"), | |
| privateKeys = authentication.getPrivateKeys(MAIN_KEY), | |
| publicKeys = pmcw.getKeys(authentication.user.Keys[0].PublicKey), | |
| total = contacts.length, | |
| count = 0; | |
| return _.reduce(chunk(contacts, CONTACTS_LIMIT_ENCRYPTION), function(promise, chunkedContacts) { | |
| return promise.then(function() { | |
| var previousContacts = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : []; | |
| return Promise.all(chunkedContacts.map(function(contact) { | |
| return prepareCards({ | |
| data: contact.vCard, | |
| publicKeys: publicKeys, | |
| privateKeys: privateKeys | |
| }).then(function(Cards) { | |
| count++; | |
| var progress = Math.floor(50 * count / total); | |
| return $rootScope.$emit("progressBar", { | |
| type: "contactsProgressBar", | |
| data: { | |
| progress: progress | |
| } | |
| }), { | |
| Cards: Cards | |
| } | |
| }) | |
| })).then(function(newContacts) { | |
| return previousContacts.concat(newContacts) | |
| }) | |
| }) | |
| }, Promise.resolve()) | |
| } | |
| var KEY_FIELDS = ["key", "x-pm-mimetype", "x-pm-encrypt", "x-pm-sign", "x-pm-scheme", "x-pm-tls", "x-pm-dane"], | |
| CLEAR_FIELDS = ["version", "prodid", "x-pm-label", "x-pm-group"], | |
| SIGNED_FIELDS = ["version", "prodid", "fn", "uid", "email"].concat(KEY_FIELDS), | |
| GROUP_FIELDS = ["email"], | |
| CONTACT_MODE = CONSTANTS.CONTACT_MODE, | |
| CONTACTS_LIMIT_ENCRYPTION = CONSTANTS.CONTACTS_LIMIT_ENCRYPTION, | |
| MAIN_KEY = CONSTANTS.MAIN_KEY, | |
| VCARD_VERSION = CONSTANTS.VCARD_VERSION, | |
| CONTACT_ERROR = CONSTANTS.CONTACT_ERROR, | |
| CLEAR_TEXT = CONTACT_MODE.CLEAR_TEXT, | |
| ENCRYPTED_AND_SIGNED = CONTACT_MODE.ENCRYPTED_AND_SIGNED, | |
| ENCRYPTED = CONTACT_MODE.ENCRYPTED, | |
| SIGNED = CONTACT_MODE.SIGNED, | |
| TYPE3_CONTACT_VERIFICATION = CONTACT_ERROR.TYPE3_CONTACT_VERIFICATION, | |
| TYPE3_CONTACT_DECRYPTION = CONTACT_ERROR.TYPE3_CONTACT_DECRYPTION, | |
| TYPE2_CONTACT = CONTACT_ERROR.TYPE2_CONTACT, | |
| TYPE1_CONTACT = CONTACT_ERROR.TYPE1_CONTACT, | |
| getErrors = function() { | |
| var data = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : []; | |
| return _.pluck(data, "error").filter(Boolean) | |
| }, | |
| buildContact = function(ID) { | |
| var data = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : [], | |
| cards = arguments[2]; | |
| return { | |
| ID: ID, | |
| vCard: mergeContactData(data), | |
| errors: getErrors(data), | |
| types: cards.map(function(_ref) { | |
| return _ref.Type | |
| }) | |
| } | |
| }; | |
| return { | |
| decrypt: decrypt, | |
| encrypt: encrypt | |
| } | |
| }), angular.module("proton.commons").factory("pmModal", function($animate, $compile, $rootScope, $controller, $q, $http, AppModel, $templateCache) { | |
| var $body = $("#body"); | |
| return function(config) { | |
| function activate(locals) { | |
| return html.then(function(html) { | |
| element || attach(html, locals), $body.append('<div class="modal-backdrop fade in"></div>'), AppModel.set("modalOpen", !0); | |
| var id = setTimeout(function() { | |
| $(".modal").addClass("in"), window.scrollTo(0, 0), Mousetrap.bind("escape", function() { | |
| return deactivate() | |
| }), clearTimeout(id) | |
| }, 100); | |
| unsubscribeLogoutListener = $rootScope.$on("logout", function() { | |
| deactivate() | |
| }) | |
| }) | |
| } | |
| function attach(html, locals) { | |
| if (element = angular.element(html), 0 === element.length) throw new Error("The template contains no elements; you need to wrap text nodes"); | |
| if (scope = $rootScope.$new(!0), controller) { | |
| locals || (locals = {}), locals.$scope = scope; | |
| var ctrl = $controller(controller, locals); | |
| controllerAs && (scope[controllerAs] = ctrl) | |
| } else if (locals) | |
| for (var prop in locals) scope[prop] = locals[prop]; | |
| return $compile(element)(scope), $animate.enter(element, container) | |
| } | |
| function deactivate() { | |
| return element ? (unsubscribeLogoutListener(), $animate.leave(element).then(function() { | |
| element && (Mousetrap.unbind("escape"), scope && scope.$destroy(), (scope[controllerAs].$onDestroy || angular.noop)(), scope = null, element.remove(), element = null, AppModel.set("modalOpen", !1), $(".modal-backdrop").remove()) | |
| })) : $q.when() | |
| } | |
| function active() { | |
| return !!element | |
| } | |
| if (!(!config.template ^ !config.templateUrl)) throw new Error("Expected modal to have exactly one of either template or templateUrl"); | |
| var controller = config.controller || null, | |
| controllerAs = config.controllerAs, | |
| container = angular.element(config.container || document.body), | |
| element = null, | |
| html = void 0, | |
| scope = void 0, | |
| unsubscribeLogoutListener = angular.noop; | |
| return html = config.template ? $q.when(config.template) : $http.get(config.templateUrl, { | |
| cache: $templateCache | |
| }).then(function(_ref) { | |
| return _ref.data | |
| }), { | |
| activate: activate, | |
| deactivate: deactivate, | |
| active: active | |
| } | |
| } | |
| }), angular.module("proton.commons").factory("tempStorage", function($timeout) { | |
| function deleteKey(key) { | |
| return function() { | |
| delete data[key] | |
| } | |
| } | |
| function cancelTimeout(key) { | |
| timeouts[key] && ($timeout.cancel(timeouts[key]), delete timeouts[key]) | |
| } | |
| var data = {}, | |
| timeouts = {}; | |
| return { | |
| getItem: function(key) { | |
| if (angular.isString(key) && data[key]) { | |
| cancelTimeout(key); | |
| var rv = data[key]; | |
| return deleteKey(key)(), rv | |
| } | |
| return null | |
| }, | |
| setItem: function(key, value) { | |
| var lifetime = arguments.length > 2 && void 0 !== arguments[2] ? arguments[2] : 1e4; | |
| angular.isString(key) && (cancelTimeout(key), data[key] = value, timeouts[key] = $timeout(deleteKey(key), lifetime, !1)) | |
| }, | |
| removeItem: function(key) { | |
| angular.isString(key) && data[key] && (cancelTimeout(key), delete data[key]) | |
| }, | |
| clear: function() { | |
| Object.keys(timeouts).forEach(cancelTimeout), data = {} | |
| } | |
| } | |
| }), angular.module("proton.commons").factory("Address", function($http, url, gettextCatalog) { | |
| var I18N = { | |
| ERROR_UPDATE: gettextCatalog.getString("Error during updating", null, "Error"), | |
| ERROR_ORDER: gettextCatalog.getString("Unable to save your changes, please try again.", null, "Error"), | |
| ERROR_DELETE: gettextCatalog.getString("Error during deletion", null, "Error"), | |
| ERROR_DISABLE: gettextCatalog.getString("Error during disable request", null, "Error"), | |
| ERROR_ENABLE: gettextCatalog.getString("Error during enable request", null, "Error"), | |
| ERROR_CREATE: gettextCatalog.getString("Address creation failed", null, "Error") | |
| }, | |
| requestUrl = url.build("addresses"), | |
| filterError = function(error) { | |
| return function(_ref) { | |
| var _ref$data = _ref.data, | |
| data = void 0 === _ref$data ? {} : _ref$data; | |
| if (1e3 !== data.Code) throw new Error(data.Error || error); | |
| return data | |
| } | |
| }; | |
| return { | |
| create: function(address) { | |
| return $http.post(requestUrl(), address).then(filterError(I18N.ERROR_CREATE)) | |
| }, | |
| setup: function(params) { | |
| return $http.post(requestUrl("setup"), params) | |
| }, | |
| edit: function(addressID, params) { | |
| return $http.put(requestUrl(addressID), params).then(filterError(I18N.ERROR_UPDATE)) | |
| }, | |
| enable: function(addressID) { | |
| return $http.put(requestUrl(addressID, "enable")).then(filterError(I18N.ERROR_ENABLE)) | |
| }, | |
| disable: function(addressID) { | |
| return $http.put(requestUrl(addressID, "disable")).then(filterError(I18N.ERROR_DISABLE)) | |
| }, | |
| remove: function(addressID) { | |
| return $http.delete(requestUrl(addressID)).then(filterError(I18N.ERROR_DELETE)) | |
| }, | |
| order: function(params) { | |
| return $http.post(requestUrl("order"), params).then(filterError(I18N.ERROR_ORDER)) | |
| } | |
| } | |
| }), angular.module("proton.commons").factory("Contact", function($http, $rootScope, CONSTANTS, url, chunk, contactEncryption, sanitize) { | |
| function clearContacts() { | |
| return (arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : []).map(function(contact) { | |
| return contact.Email = sanitize.input(contact.Email), contact.Name = sanitize.input(contact.Name), contact | |
| }) | |
| } | |
| function request(route) { | |
| var params = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : {}; | |
| return $http.get(route, { | |
| params: params | |
| }).then(function() { | |
| var _ref = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {}, | |
| _ref$data = _ref.data, | |
| data = void 0 === _ref$data ? {} : _ref$data; | |
| if (data.Error) throw new Error(data.Error); | |
| return data | |
| }) | |
| } | |
| function hydrate() { | |
| var PageSize = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : CONSTANTS.CONTACT_EMAILS_LIMIT; | |
| return queryContacts(requestURL("emails"), { | |
| key: "ContactEmails", | |
| PageSize: PageSize | |
| }).then(clearContacts) | |
| } | |
| function get(contactID) { | |
| return request(requestURL(contactID)).then(function(_ref4) { | |
| var Contact = _ref4.Contact; | |
| return contactEncryption.decrypt([Contact]) | |
| }).then(function(contacts) { | |
| return contacts[0] | |
| }) | |
| } | |
| function handleUpload() { | |
| var result = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : [], | |
| _$reduce = _.reduce(result, function(acc) { | |
| var _ref5 = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : {}, | |
| _ref5$data = _ref5.data, | |
| data = void 0 === _ref5$data ? {} : _ref5$data; | |
| return data.Error ? (acc.errors.push({ | |
| code: data.Code, | |
| error: data.Error | |
| }), acc) : (_.each(data.Responses, function(_ref6) { | |
| var _ref6$Response = _ref6.Response, | |
| Response = void 0 === _ref6$Response ? {} : _ref6$Response; | |
| acc.total++, Response.Error && acc.errors.push({ | |
| code: Response.Code, | |
| name: Response.Name, | |
| emails: Response.Emails, | |
| error: Response.Error | |
| }), 1e3 === Response.Code && acc.created.push(Response.Contact) | |
| }), acc) | |
| }, { | |
| created: [], | |
| total: 0, | |
| errors: [] | |
| }), | |
| _$reduce$created = _$reduce.created, | |
| created = void 0 === _$reduce$created ? [] : _$reduce$created, | |
| _$reduce$total = _$reduce.total, | |
| total = void 0 === _$reduce$total ? 0 : _$reduce$total, | |
| _$reduce$errors = _$reduce.errors; | |
| return { | |
| created: created, | |
| total: total, | |
| errors: void 0 === _$reduce$errors ? [] : _$reduce$errors | |
| } | |
| } | |
| function uploadContacts() { | |
| var cards = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : [], | |
| total = arguments[1], | |
| progress = 50, | |
| chunkCards = chunk(cards, CONTACTS_LIMIT_UPLOAD), | |
| promises = _.map(chunkCards, function(Contacts) { | |
| var params = { | |
| Contacts: Contacts, | |
| Groups: 1, | |
| Overwrite: 1, | |
| Labels: 1 | |
| }; | |
| return $http.post(requestURL(), params).then(function(data) { | |
| return progress += Math.floor(50 * Contacts.length / total), $rootScope.$emit("progressBar", { | |
| type: "contactsProgressBar", | |
| data: { | |
| progress: progress | |
| } | |
| }), data | |
| }) | |
| }); | |
| return Promise.all(promises).then(handleUpload) | |
| } | |
| function add() { | |
| var contacts = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : []; | |
| return contactEncryption.encrypt(contacts).then(function() { | |
| return uploadContacts(arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : [], contacts.length) | |
| }).then(function(data) { | |
| return $rootScope.$emit("contacts", { | |
| type: "contactsUpdated" | |
| }), data | |
| }) | |
| } | |
| function update(contact) { | |
| return contactEncryption.encrypt([contact]).then(function(contacts) { | |
| return $http.put(requestURL(contact.ID), contacts[0]).then(function() { | |
| var _ref7 = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {}, | |
| _ref7$data = _ref7.data, | |
| data = void 0 === _ref7$data ? {} : _ref7$data; | |
| if (data.Error) throw new Error(data.Error); | |
| return data.cards = contacts[0].Cards, data | |
| }) | |
| }) | |
| } | |
| function exportAll() { | |
| var PageSize = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : EXPORT_CONTACTS_LIMIT; | |
| return queryContacts(requestURL("export"), { | |
| key: "Contacts", | |
| PageSize: PageSize | |
| }).then(function(contacts) { | |
| return contactEncryption.decrypt(contacts) | |
| }) | |
| } | |
| var queryContacts = function() { | |
| var _ref2 = _asyncToGenerator(regeneratorRuntime.mark(function _callee() { | |
| var data, promises, n, list, route = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : "", | |
| _ref3 = arguments[1], | |
| PageSize = _ref3.PageSize, | |
| _ref3$key = _ref3.key, | |
| key = void 0 === _ref3$key ? "" : _ref3$key; | |
| return regeneratorRuntime.wrap(function(_context) { | |
| for (;;) switch (_context.prev = _context.next) { | |
| case 0: | |
| return _context.next = 2, request(route, { | |
| PageSize: PageSize | |
| }); | |
| case 2: | |
| return data = _context.sent, promises = [Promise.resolve(data[key])], n = Math.ceil(data.Total / PageSize) - 1, n > 0 && _.times(n, function(index) { | |
| var promise = request(route, { | |
| PageSize: PageSize, | |
| Page: index + 1 | |
| }).then(function(data) { | |
| return data[key] | |
| }); | |
| promises.push(promise) | |
| }), _context.next = 8, Promise.all(promises); | |
| case 8: | |
| return list = _context.sent, _context.abrupt("return", list.reduce(function(acc, item) { | |
| return acc.concat(item) | |
| }, [])); | |
| case 10: | |
| case "end": | |
| return _context.stop() | |
| } | |
| }, _callee, this) | |
| })); | |
| return function() { | |
| return _ref2.apply(this, arguments) | |
| } | |
| }(), | |
| requestURL = url.build("contacts"), | |
| CONTACTS_LIMIT_UPLOAD = CONSTANTS.CONTACTS_LIMIT_UPLOAD, | |
| EXPORT_CONTACTS_LIMIT = CONSTANTS.EXPORT_CONTACTS_LIMIT, | |
| all = function() { | |
| var PageSize = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : CONSTANTS.CONTACTS_LIMIT; | |
| return queryContacts(requestURL(), { | |
| key: "Contacts", | |
| PageSize: PageSize | |
| }) | |
| }, | |
| load = function() { | |
| var type = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : ""; | |
| return request(type ? requestURL(type) : requestURL(), { | |
| PageSize: type ? CONSTANTS.CONTACT_EMAILS_LIMIT : CONSTANTS.CONTACTS_LIMIT / 10 | |
| }) | |
| }; | |
| return { | |
| hydrate: hydrate, | |
| all: all, | |
| get: get, | |
| add: add, | |
| update: update, | |
| remove: function(contacts) { | |
| return $http.put(requestURL("delete"), contacts) | |
| }, | |
| clear: function() { | |
| return $http.delete(requestURL()) | |
| }, | |
| exportAll: exportAll, | |
| groups: function() { | |
| return $http.get(requestURL("groups")) | |
| }, | |
| load: load | |
| } | |
| }), angular.module("proton.commons").factory("Eo", function($http, url, CONFIG) { | |
| var requestURL = url.build("eo"), | |
| parseJSON = function(xhr) { | |
| var response = function(json) { | |
| return { | |
| json: json, | |
| isInvalid: arguments.length > 1 && void 0 !== arguments[1] && arguments[1] | |
| } | |
| }; | |
| try { | |
| return response(JSON.parse(xhr.responseText)) | |
| } catch (e) { | |
| return response({ | |
| Error: "JSON parsing error: " + xhr.responseText | |
| }, !0) | |
| } | |
| }; | |
| return { | |
| token: function(tokenID) { | |
| return $http.get(requestURL("token", encodeURIComponent(tokenID)), { | |
| headers: { | |
| "Content-Type": "application/json;charset=utf-8", | |
| Accept: "application/vnd.protonmail.v1+json" | |
| } | |
| }) | |
| }, | |
| message: function(Authorization, token) { | |
| return $http.get(requestURL("message"), { | |
| headers: { | |
| Authorization: Authorization, | |
| "x-eo-uid": token | |
| } | |
| }) | |
| }, | |
| attachment: function(Authorization, token, attachmentID) { | |
| return $http.get(requestURL("attachment", attachmentID), { | |
| responseType: "arraybuffer", | |
| headers: { | |
| Authorization: Authorization, | |
| "x-eo-uid": token | |
| } | |
| }) | |
| }, | |
| reply: function(decryptedToken, token, data) { | |
| var fd = new FormData, | |
| xhr = new XMLHttpRequest; | |
| return Object.keys(data || {}).forEach(function(key) { | |
| Array.isArray(data[key]) ? _.each(data[key], function(v) { | |
| return fd.append(key, v) | |
| }) : fd.append(key + "", data[key]) | |
| }), new Promise(function(resolve, reject) { | |
| xhr.onload = function() { | |
| var _parseJSON = parseJSON(xhr), | |
| json = _parseJSON.json, | |
| isInvalid = _parseJSON.isInvalid; | |
| if (200 !== xhr.status) return reject(new Error("Unable to send the message")); | |
| if (json.Error) { | |
| var msgError = isInvalid ? "Unable to send the message." : json.Error; | |
| return reject(new Error(msgError)) | |
| } | |
| resolve("Message send") | |
| }, xhr.open("post", requestURL("reply"), !0), xhr.setRequestHeader("X-Requested-With", "XMLHttpRequest"), xhr.setRequestHeader("Accept", "application/vnd.protonmail.v1+json"), xhr.setRequestHeader("x-pm-appversion", "Web_" + CONFIG.app_version), xhr.setRequestHeader("x-pm-apiversion", CONFIG.api_version), xhr.setRequestHeader("Authorization", decryptedToken), xhr.setRequestHeader("x-eo-uid", token), xhr.send(fd) | |
| }) | |
| } | |
| } | |
| }), angular.module("proton.commons").factory("Events", function($http, url) { | |
| var requestURL = url.build("events"); | |
| return { | |
| get: function(id) { | |
| return $http.get(requestURL(id)) | |
| }, | |
| getLatestID: function() { | |
| return $http.get(requestURL("latest")) | |
| } | |
| } | |
| }), angular.module("proton.commons").factory("Filter", function($http, url) { | |
| function transformRequestFilter(filter) { | |
| return angular.isDefined(filter.Simple) && (filter.Tree = Sieve.toTree(filter.Simple)), angular.toJson(filter) | |
| } | |
| function transformResponseFilter(data) { | |
| var json = angular.fromJson(data); | |
| return json && 1e3 === json.Code && _.each(json.Filters, function(filter) { | |
| var simple = Sieve.fromTree(filter.Tree); | |
| _.isEqual(filter.Tree, Sieve.toTree(simple)) ? filter.Simple = simple : delete filter.Simple | |
| }), json || {} | |
| } | |
| return { | |
| create: function(filter) { | |
| return $http.post(url.get() + "/filters", filter, { | |
| transformRequest: transformRequestFilter | |
| }) | |
| }, | |
| check: function(filter) { | |
| return $http.post(url.get() + "/filters/check", filter, { | |
| transformRequest: transformRequestFilter | |
| }) | |
| }, | |
| query: function() { | |
| return $http.get(url.get() + "/filters", { | |
| transformResponse: transformResponseFilter | |
| }) | |
| }, | |
| update: function(filter) { | |
| return $http.put(url.get() + "/filters/" + filter.ID, filter, { | |
| transformRequest: transformRequestFilter | |
| }) | |
| }, | |
| enable: function(filter) { | |
| return $http.put(url.get() + "/filters/" + filter.ID + "/enable") | |
| }, | |
| disable: function(filter) { | |
| return $http.put(url.get() + "/filters/" + filter.ID + "/disable") | |
| }, | |
| order: function(_order) { | |
| return $http.put(url.get() + "/filters/order", _order) | |
| }, | |
| delete: function(filter) { | |
| return $http.delete(url.get() + "/filters/" + filter.ID) | |
| }, | |
| clear: function() { | |
| return $http.delete(url.get() + "/filters") | |
| } | |
| } | |
| }), angular.module("proton.commons").factory("IncomingDefault", function($http, url) { | |
| var requestURL = url.build("incomingdefaults"); | |
| return { | |
| get: function(params) { | |
| return $http.get(requestURL(), { | |
| params: params | |
| }) | |
| }, | |
| add: function(params) { | |
| return $http.post(requestURL(), params) | |
| }, | |
| update: function() { | |
| var opt = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {}; | |
| return $http.put(requestURL(opt.ID), opt) | |
| }, | |
| delete: function(params) { | |
| return $http.put(requestURL("delete"), params) | |
| }, | |
| clear: function() { | |
| return $http.delete(requestURL()) | |
| } | |
| } | |
| }), angular.module("proton.commons").factory("Invite", function($http, url) { | |
| var requestURL = url.build("invites"); | |
| return { | |
| check: function(Token, Selector, Type) { | |
| return $http.post(requestURL("check"), { | |
| Token: Token, | |
| Selector: Selector, | |
| Type: Type | |
| }) | |
| } | |
| } | |
| }), angular.module("proton.commons").factory("Key", function($http, url, srp) { | |
| var requestUrl = url.build("keys"), | |
| create = function() { | |
| var params = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {}; | |
| return $http.post(requestUrl(), params) | |
| }, | |
| setup = function() { | |
| var params = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {}, | |
| newPassword = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : ""; | |
| return newPassword.length ? srp.getPasswordParams(newPassword, params).then(function(authParams) { | |
| return $http.post(requestUrl("setup"), authParams) | |
| }) : $http.post(requestUrl("setup"), params) | |
| }, | |
| reset = function() { | |
| var params = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {}, | |
| newPassword = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : ""; | |
| return newPassword.length ? srp.getPasswordParams(newPassword, params).then(function(authParams) { | |
| return $http.post(requestUrl("reset"), authParams) | |
| }) : $http.post(requestUrl("reset"), params) | |
| }, | |
| order = function() { | |
| var params = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {}; | |
| return $http.post(requestUrl("order"), params) | |
| }, | |
| activate = function(keyID) { | |
| var params = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : {}; | |
| return $http.put(requestUrl(keyID, "activate"), params) | |
| }, | |
| privateKey = function() { | |
| var params = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {}, | |
| newPassword = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : ""; | |
| return newPassword.length ? srp.getPasswordParams(newPassword, params).then(function(authParams) { | |
| return $http.put(requestUrl("private"), authParams) | |
| }) : $http.put(requestUrl("private"), params) | |
| }; | |
| return { | |
| create: create, | |
| setup: setup, | |
| reset: reset, | |
| order: order, | |
| activate: activate, | |
| upgrade: function() { | |
| var params = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {}, | |
| newPassword = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : ""; | |
| return newPassword.length ? srp.getPasswordParams(newPassword, params).then(function(authParams) { | |
| return $http.put(requestUrl("private", "upgrade"), authParams) | |
| }) : $http.put(requestUrl("private", "upgrade"), params) | |
| }, | |
| private: privateKey, | |
| delete: function(keyID) { | |
| return $http.delete(requestUrl(keyID)) | |
| }, | |
| salts: function() { | |
| return $http.get(requestUrl("salts")) | |
| }, | |
| reactivate: function(keyID, params) { | |
| return $http.put(requestUrl(keyID), params) | |
| } | |
| } | |
| }), angular.module("proton.commons").factory("Label", function($http, url) { | |
| return { | |
| query: function() { | |
| return $http.get(url.get() + "/labels") | |
| }, | |
| apply: function(labelID, messageIDs) { | |
| return $http.put(url.get() + "/labels/apply/" + labelID, messageIDs) | |
| }, | |
| remove: function(labelID, messageIDs) { | |
| return $http.put(url.get() + "/labels/remove/" + labelID, messageIDs) | |
| }, | |
| order: function(newOrder) { | |
| return $http.put(url.get() + "/labels/order", newOrder) | |
| }, | |
| update: function(label) { | |
| return $http.put(url.get() + "/labels/" + label.ID, label) | |
| }, | |
| create: function(label) { | |
| return $http.post(url.get() + "/labels", label) | |
| }, | |
| delete: function(labelID) { | |
| return $http.delete(url.get() + "/labels/" + labelID) | |
| } | |
| } | |
| }), angular.module("proton.commons").factory("Logs", function($http, url) { | |
| var requestURL = url.build("logs"); | |
| return { | |
| get: function() { | |
| return $http.get(requestURL("auth")) | |
| }, | |
| clear: function() { | |
| return $http.delete(requestURL("auth")) | |
| } | |
| } | |
| }), angular.module("proton.commons").factory("MemberKey", function($http, url, srp) { | |
| return { | |
| create: function(Obj) { | |
| return $http.post(url.get() + "/memberkeys", Obj) | |
| }, | |
| setup: function() { | |
| var params = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {}, | |
| password = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : ""; | |
| return srp.randomVerifier(password).then(function(passParams) { | |
| return $http.post(url.get() + "/memberkeys/setup", _.extend(params, passParams)) | |
| }) | |
| }, | |
| order: function(Obj) { | |
| return $http.post(url.get() + "/memberkeys/order", Obj) | |
| }, | |
| update: function(keyID, Obj) { | |
| return $http.put(url.get() + "/memberkeys" + keyID, Obj) | |
| }, | |
| delete: function(keyID) { | |
| return $http.delete(url.get() + "/memberkeys/" + keyID) | |
| } | |
| } | |
| }), angular.module("proton.commons").factory("Payment", function($http, authentication, url, brick, paymentPlansFormator) { | |
| function generateFingerprint() { | |
| var params = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {}, | |
| paymentMethodID = params.PaymentMethodID, | |
| payment = getPayment(params); | |
| return new Promise(function(resolve, reject) { | |
| try { | |
| if (void 0 === paymentMethodID && "card" === payment.Type) return brick.getFingerprint(function(fingerprint) { | |
| payment.Fingerprint = fingerprint, resolve(params) | |
| }); | |
| resolve(params) | |
| } catch (e) { | |
| reject(e) | |
| } | |
| }) | |
| } | |
| var requestUrl = url.build("payments"), | |
| transformRepBillingCycle = function(data) { | |
| var json = angular.fromJson(data); | |
| if (json && 1e3 === json.Code) { | |
| _.each(json.Payments, function(invoice) { | |
| 1 === parseInt((invoice.PeriodEnd - invoice.PeriodStart) / 2592e3, 10) ? invoice.BillingCycle = 12 : invoice.BillingCycle = 1 | |
| }) | |
| } | |
| return json || {} | |
| }, | |
| getPayment = function() { | |
| var params = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {}; | |
| return params.Payment ? params.Payment : params.PaymentMethod ? params.PaymentMethod : params | |
| }, | |
| credit = function(params) { | |
| return generateFingerprint(params).then(function(params) { | |
| return $http.post(requestUrl("credit"), params) | |
| }) | |
| }, | |
| validateCredit = function(params) { | |
| return $http.post(requestUrl("credit", "check"), params) | |
| }, | |
| validateVerify = function(params) { | |
| return $http.post(requestUrl("verify", "check"), params) | |
| }, | |
| donate = function(params) { | |
| return generateFingerprint(params).then(function(params) { | |
| return $http.post(requestUrl("donate"), params) | |
| }) | |
| }, | |
| unsubscribe = function(opt) { | |
| return $http.post(requestUrl("unsubscribe"), opt) | |
| }, | |
| paypal = function(opt) { | |
| var config = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : {}; | |
| return $http.post(requestUrl("paypal"), opt, config) | |
| }, | |
| verify = function(params) { | |
| return generateFingerprint(params).then(function(params) { | |
| return $http.post(requestUrl("verify"), params) | |
| }) | |
| }, | |
| status = function() { | |
| return $http.get(requestUrl("status")) | |
| }, | |
| invoices = function(params) { | |
| return $http.get(requestUrl("invoices"), { | |
| params: params | |
| }) | |
| }, | |
| invoice = function(id) { | |
| return $http.get(requestUrl("invoices", id), { | |
| responseType: "arraybuffer" | |
| }) | |
| }, | |
| check = function(id) { | |
| return $http.post(requestUrl("invoices", id, "check")) | |
| }, | |
| pay = function(id, params) { | |
| return generateFingerprint(params).then(function(params) { | |
| return $http.post(requestUrl("invoices", id), params) | |
| }) | |
| }, | |
| plans = function(Currency, Cycle) { | |
| return $http.get(requestUrl("plans"), { | |
| params: { | |
| Currency: Currency, | |
| Cycle: Cycle | |
| } | |
| }).then(paymentPlansFormator(Currency, Cycle)).then(function(data) { | |
| return { | |
| data: data | |
| } | |
| }) | |
| }, | |
| subscription = function() { | |
| if (authentication.user.Role > 1) return $http.get(requestUrl("subscription"), { | |
| transformResponse: function(datas) { | |
| var json = angular.fromJson(datas); | |
| if (json && 1e3 === json.Code) { | |
| var _ref = _.findWhere(json.Subscription.Plans, { | |
| Type: 1 | |
| }) || {}, | |
| Name = _ref.Name, | |
| Title = _ref.Title; | |
| json.Subscription.Name = Name, json.Subscription.Title = Title | |
| } | |
| return json || {} | |
| } | |
| }); | |
| var sub = { | |
| Name: "free", | |
| Title: "ProtonMail Free", | |
| MaxDomains: 0, | |
| CouponCode: null, | |
| MaxAddresses: 1, | |
| MaxSpace: 5368709120, | |
| MaxMembers: 1, | |
| Cycle: 12, | |
| Currency: authentication.user.Currency | |
| }; | |
| return Promise.resolve({ | |
| data: { | |
| Code: 1e3, | |
| Subscription: sub | |
| } | |
| }) | |
| }, | |
| valid = function(opt) { | |
| return $http.post(requestUrl("subscription", "check"), opt) | |
| }, | |
| updateMethod = function(params) { | |
| return generateFingerprint(params).then(function(params) { | |
| return $http.post(requestUrl("methods"), params) | |
| }) | |
| }, | |
| deleteMethod = function(id) { | |
| return $http.delete(requestUrl("methods", id)) | |
| }, | |
| methods = function() { | |
| return $http.get(requestUrl("methods")) | |
| }, | |
| order = function(opt) { | |
| return $http.post(requestUrl("methods", "order"), opt) | |
| }, | |
| subscribe = function(params) { | |
| return generateFingerprint(params).then(function(params) { | |
| return $http.post(requestUrl("subscription"), params) | |
| }) | |
| }, | |
| destroy = function() { | |
| return $http.delete(requestUrl("subscription")) | |
| }, | |
| user = function(Time, Limit) { | |
| return $http.get(requestUrl("user"), { | |
| params: { | |
| Time: Time, | |
| Limit: Limit | |
| }, | |
| transformResponse: transformRepBillingCycle | |
| }) | |
| }, | |
| organization = function(Time, Limit) { | |
| return $http.get(requestUrl("organization"), { | |
| params: { | |
| Time: Time, | |
| Limit: Limit | |
| }, | |
| transformResponse: transformRepBillingCycle | |
| }) | |
| }; | |
| return { | |
| credit: credit, | |
| donate: donate, | |
| paypal: paypal, | |
| validateCredit: validateCredit, | |
| validateVerify: validateVerify, | |
| invoices: invoices, | |
| invoice: invoice, | |
| order: order, | |
| verify: verify, | |
| status: status, | |
| check: check, | |
| pay: pay, | |
| valid: valid, | |
| plans: plans, | |
| subscription: subscription, | |
| updateMethod: updateMethod, | |
| deleteMethod: deleteMethod, | |
| methods: methods, | |
| subscribe: subscribe, | |
| unsubscribe: unsubscribe, | |
| delete: destroy, | |
| btc: function(Amount, Currency) { | |
| return $http.post(requestUrl("bcinfo"), { | |
| Amount: Amount, | |
| Currency: Currency | |
| }) | |
| }, | |
| organization: organization, | |
| user: user | |
| } | |
| }), angular.module("proton.commons").factory("Reset", function($http, url, srp) { | |
| return { | |
| requestResetToken: function() { | |
| var params = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {}; | |
| return $http.post(url.get() + "/reset", params) | |
| }, | |
| resetPassword: function() { | |
| var params = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {}, | |
| newPassword = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : "", | |
| request = function(data) { | |
| var requestUrl = url.get() + "/reset/" + encodeURIComponent(data.Token); | |
| return $http.post(requestUrl, data) | |
| }; | |
| return srp.getPasswordParams(newPassword, params).then(request) | |
| }, | |
| getMailboxResetToken: function() { | |
| var params = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {}; | |
| return $http.post(url.get() + "/reset/mailbox", params) | |
| }, | |
| resetMailbox: function() { | |
| var params = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {}; | |
| return $http.post(url.get() + "/reset/mailbox/" + encodeURIComponent(params.Token), params) | |
| }, | |
| validateResetToken: function() { | |
| var params = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {}; | |
| return $http.get(url.get() + "/reset/" + params.Username + "/" + encodeURIComponent(params.Token)) | |
| } | |
| } | |
| }), angular.module("proton.commons").factory("User", function($http, url, srp) { | |
| var requestURL = url.build("users"); | |
| return { | |
| create: function(params, password) { | |
| return srp.getPasswordParams(password, params).then(function(data) { | |
| return $http.post(requestURL(), data) | |
| }) | |
| }, | |
| code: function(params) { | |
| return $http.post(requestURL("code"), params) | |
| }, | |
| get: function() { | |
| return $http.get(requestURL()) | |
| }, | |
| human: function() { | |
| return $http.get(url.get() + "/users/human") | |
| }, | |
| check: function(params) { | |
| return $http.post(url.get() + "/users/human", params) | |
| }, | |
| pubkeys: function(emails) { | |
| return $http.get(requestURL("pubkeys", window.encodeURIComponent(emails))) | |
| }, | |
| available: function(username) { | |
| return $http.get(requestURL("available", username)) | |
| }, | |
| direct: function() { | |
| return $http.get(requestURL("direct")) | |
| }, | |
| lock: function() { | |
| return $http.put(requestURL("lock")) | |
| }, | |
| unlock: function() { | |
| var creds = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {}; | |
| return srp.performSRPRequest("PUT", "/users/unlock", {}, creds) | |
| }, | |
| password: function() { | |
| var creds = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {}; | |
| return srp.performSRPRequest("PUT", "/users/password", {}, creds) | |
| }, | |
| delete: function() { | |
| var creds = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {}; | |
| return srp.performSRPRequest("PUT", "/users/delete", {}, creds) | |
| } | |
| } | |
| }), angular.module("proton.commons").provider("notification", function() { | |
| var CONFIG = { | |
| classNames: { | |
| error: "notification-danger", | |
| success: "notification-success", | |
| info: "notification-info" | |
| } | |
| }; | |
| this.typeClasses = function() { | |
| var config = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {}; | |
| return _.extend(CONFIG.classNames, config) | |
| }, this.duration = function() { | |
| var value = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : 6e3; | |
| return CONFIG.duration = value | |
| }, this.template = function() { | |
| var value = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : ""; | |
| return CONFIG.template = value | |
| }, this.$get = ["notify", function(notify) { | |
| var action = function(type) { | |
| return function(input) { | |
| var options = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : {}, | |
| message = input instanceof Error ? input.message : input; | |
| options.classes = ((options.classes || "") + " " + CONFIG.classNames[type]).trim(), "error" === type && (options.duration = 1e4), notify(_.extend({ | |
| message: message | |
| }, options)) | |
| } | |
| }, | |
| config = { | |
| position: "center", | |
| maximumOpen: 5, | |
| duration: 6e3 | |
| }; | |
| return CONFIG.template && (config.templateUrl = CONFIG.template), notify.config(config), { | |
| success: action("success"), | |
| error: action("error"), | |
| info: action("info") | |
| } | |
| }] | |
| }), angular.module("proton.commons").provider("url", function() { | |
| var base = void 0, | |
| make = function(key) { | |
| var prefix = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : ""; | |
| return function() { | |
| for (var _len = arguments.length, path = Array(_len), _key = 0; _key < _len; _key++) path[_key] = arguments[_key]; | |
| return [(prefix + "/" + key).trim()].concat(path).join("/") | |
| } | |
| }; | |
| this.setBaseUrl = function(newUrl) { | |
| base = newUrl | |
| }, this.$get = function() { | |
| return { | |
| host: function() { | |
| var link = document.createElement("a"); | |
| return link.href = base, link.host | |
| }, | |
| get: function() { | |
| return base | |
| }, | |
| make: make, | |
| build: function(key) { | |
| return make(key, this.get()) | |
| } | |
| } | |
| } | |
| }); | |
| var _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function(obj) { | |
| return typeof obj | |
| } : function(obj) { | |
| return obj && "function" == typeof Symbol && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj | |
| }; | |
| angular.module("proton.commons").factory("aboutClient", function() { | |
| var hasSessionStorage = function() { | |
| var mod = "modernizr"; | |
| try { | |
| return sessionStorage.setItem(mod, mod), sessionStorage.removeItem(mod), !0 | |
| } catch (error) { | |
| return !1 | |
| } | |
| }, | |
| hasCookie = function() { | |
| return navigator.cookieEnabled | |
| }, | |
| getBrowser = function() { | |
| return $.ua.browser | |
| }, | |
| getDevice = function() { | |
| return $.ua.device | |
| }, | |
| getOS = function() { | |
| var _$$ua$os = $.ua.os, | |
| _$$ua$os$name = _$$ua$os.name, | |
| name = void 0 === _$$ua$os$name ? "other" : _$$ua$os$name, | |
| _$$ua$os$version = _$$ua$os.version; | |
| return { | |
| name: name, | |
| version: void 0 === _$$ua$os$version ? "" : _$$ua$os$version | |
| } | |
| }, | |
| isSafari = function() { | |
| var browsers = ["Safari", "Mobile Safari"]; | |
| return _.contains(browsers, $.ua.browser.name) | |
| }, | |
| isSafariMobile = function() { | |
| return "Mobile Safari" === $.ua.browser.name | |
| }, | |
| isIE11 = function() { | |
| return "IE" === $.ua.browser.name && "11" === $.ua.browser.major | |
| }, | |
| isEdge = function() { | |
| return "Edge" === $.ua.browser.name | |
| }, | |
| isFirefox = function() { | |
| return "Firefox" === $.ua.browser.name | |
| }, | |
| isMac = function() { | |
| return "Mac OS" === getOS().name | |
| }, | |
| isFileSaverSupported = function() { | |
| return "download" in document.createElement("a") || navigator.msSaveOrOpenBlob | |
| }, | |
| prngAvailable = function() { | |
| return !("undefined" == typeof window || !window.crypto || !window.crypto.getRandomValues) || "undefined" != typeof window && "object" === _typeof(window.msCrypto) && "function" == typeof window.msCrypto.getRandomValues | |
| }; | |
| return { | |
| doNotTrack: function() { | |
| return "1" === navigator.doNotTrack || "yes" === navigator.doNotTrack || "1" === navigator.msDoNotTrack || "1" === window.doNotTrack | |
| }, | |
| hasSessionStorage: hasSessionStorage, | |
| hasCookie: hasCookie, | |
| getOS: getOS, | |
| getBrowser: getBrowser, | |
| getDevice: getDevice, | |
| isMac: isMac, | |
| isIE11: isIE11, | |
| isEdge: isEdge, | |
| isSafari: isSafari, | |
| isFirefox: isFirefox, | |
| isSafariMobile: isSafariMobile, | |
| isFileSaverSupported: isFileSaverSupported, | |
| prngAvailable: prngAvailable | |
| } | |
| }), angular.module("proton.commons").factory("dedentTpl", function() { | |
| function dedent(callSite) { | |
| function format() { | |
| var str = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : "", | |
| size = -1; | |
| return str.replace(/\n(\s+)/g, function(m, m1) { | |
| return size < 0 && (size = m1.replace(/\t/g, " ").length), "\n" + m1.slice(Math.min(m1.length, size)) | |
| }) | |
| } | |
| for (var _len = arguments.length, args = Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) args[_key - 1] = arguments[_key]; | |
| return "string" == typeof callSite ? format(callSite) : "function" == typeof callSite ? function() { | |
| return format(callSite.apply(void 0, arguments)) | |
| } : format(callSite.slice(0, args.length + 1).map(function(text, i) { | |
| return (0 === i ? "" : args[i - 1]) + text | |
| }).join("")) | |
| } | |
| return dedent | |
| }); | |
| var _slicedToArray = function() { | |
| function sliceIterator(arr, i) { | |
| var _arr = [], | |
| _n = !0, | |
| _d = !1, | |
| _e = void 0; | |
| try { | |
| for (var _s, _i = arr[Symbol.iterator](); !(_n = (_s = _i.next()).done) && (_arr.push(_s.value), !i || _arr.length !== i); _n = !0); | |
| } catch (err) { | |
| _d = !0, _e = err | |
| } finally { | |
| try { | |
| !_n && _i.return && _i.return() | |
| } finally { | |
| if (_d) throw _e | |
| } | |
| } | |
| return _arr | |
| } | |
| return function(arr, i) { | |
| if (Array.isArray(arr)) return arr; | |
| if (Symbol.iterator in Object(arr)) return sliceIterator(arr, i); | |
| throw new TypeError("Invalid attempt to destructure non-iterable instance") | |
| } | |
| }(); | |
| angular.module("proton.commons").factory("dispatchers", function($rootScope) { | |
| var createMap = function() { | |
| return (arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : []).reduce(function(acc, key) { | |
| return "$" !== key.charAt(0) && (acc[key] = function(type) { | |
| var data = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : {}; | |
| $rootScope.$emit(key, { | |
| type: type, | |
| data: data | |
| }) | |
| }), acc | |
| }, Object.create(null)) | |
| }, | |
| log = function(type, cb) { | |
| return function() { | |
| for (var _len = arguments.length, arg = Array(_len), _key = 0; _key < _len; _key++) arg[_key] = arguments[_key]; | |
| var namespace = "type [" + type + "]:", | |
| _arg$slice = arg.slice(-1), | |
| _arg$slice2 = _slicedToArray(_arg$slice, 1), | |
| data = _arg$slice2[0]; | |
| console.group(namespace), console.log(data), cb.apply(void 0, arg), console.groupEnd(namespace) | |
| } | |
| }; | |
| return function() { | |
| var list = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : [], | |
| verbose = arguments[1], | |
| listeners = []; | |
| return { | |
| dispatcher: createMap(list), | |
| on: function(type, cb) { | |
| var callback = verbose ? log(type, cb) : cb; | |
| listeners.push($rootScope.$on(type, callback)) | |
| }, | |
| unsubscribe: function() { | |
| listeners.forEach(function(cb) { | |
| return cb() | |
| }), listeners.length = 0 | |
| } | |
| } | |
| } | |
| }), angular.module("proton.commons").factory("errorReporter", function(notify) { | |
| var newNotification = function(msg) { | |
| return msg && notify(msg) | |
| }; | |
| return { | |
| clear: notify.closeAll, | |
| catcher: function(msg, promise) { | |
| return function(error) { | |
| newNotification(msg), promise && promise.reject() | |
| } | |
| }, | |
| resolve: function(msg, currentPromise, defaultResult) { | |
| return new Promise(function(resolve) { | |
| currentPromise.then(resolve, function(error) { | |
| newNotification(msg), resolve(defaultResult) | |
| }) | |
| }) | |
| }, | |
| notify: newNotification | |
| } | |
| }); | |
| var _slicedToArray = function() { | |
| function sliceIterator(arr, i) { | |
| var _arr = [], | |
| _n = !0, | |
| _d = !1, | |
| _e = void 0; | |
| try { | |
| for (var _s, _i = arr[Symbol.iterator](); !(_n = (_s = _i.next()).done) && (_arr.push(_s.value), !i || _arr.length !== i); _n = !0); | |
| } catch (err) { | |
| _d = !0, _e = err | |
| } finally { | |
| try { | |
| !_n && _i.return && _i.return() | |
| } finally { | |
| if (_d) throw _e | |
| } | |
| } | |
| return _arr | |
| } | |
| return function(arr, i) { | |
| if (Array.isArray(arr)) return arr; | |
| if (Symbol.iterator in Object(arr)) return sliceIterator(arr, i); | |
| throw new TypeError("Invalid attempt to destructure non-iterable instance") | |
| } | |
| }(); | |
| angular.module("proton.commons").factory("i18nLoader", function(CONFIG, $rootScope, gettextCatalog, pikadayConfiguration, dateUtils) { | |
| var upperCaseLocale = function() { | |
| var locale = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : ""; | |
| return ("en" === locale ? "us" : locale).toUpperCase() | |
| }, | |
| dispatch = function(type) { | |
| var data = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : {}; | |
| return $rootScope.$emit("i18n", { | |
| type: type, | |
| data: data | |
| }) | |
| }, | |
| formatLocale = function(locale) { | |
| var firstLanguage = window.navigator.languages && window.navigator.languages.length ? window.navigator.languages[0] : null, | |
| value = (locale || firstLanguage || window.navigator.userLanguage || window.navigator.language).replace("-", "_"); | |
| return 2 === value.length ? value + "_" + upperCaseLocale(value) : value | |
| }, | |
| getLocale = function() { | |
| try { | |
| var queryParams = new window.URL(window.location).searchParams; | |
| return formatLocale(queryParams.get("language")) | |
| } catch (e) { | |
| var _ref = location.search.match(/language=(([a-z]{2,}(_|-)[A-Z]{2,})|([a-z]{2,}))/) || [], | |
| _ref2 = _slicedToArray(_ref, 2), | |
| locale = _ref2[1]; | |
| return formatLocale(locale) | |
| } | |
| }, | |
| localeRanker = function(navigatorLocaleData) { | |
| return function(localeA, localeB) { | |
| var localeAData = moment.localeData(localeA), | |
| localeBData = moment.localeData(localeB), | |
| localeAfirstday = localeAData.firstDayOfWeek(), | |
| localeBfirstday = localeBData.firstDayOfWeek(), | |
| navigatorFirstDay = navigatorLocaleData.firstDayOfWeek(); | |
| if (localeAfirstday !== localeBfirstday && (localeAfirstday === navigatorFirstDay || localeBfirstday === navigatorFirstDay)) return localeAfirstday === navigatorFirstDay ? -1 : 1; | |
| var localeADateFormat = localeAData.longDateFormat("L"), | |
| localeBDatelformat = localeBData.longDateFormat("L"), | |
| navigatorDateformat = navigatorLocaleData.longDateFormat("L"); | |
| if (localeADateFormat !== localeBDatelformat && (localeADateFormat === navigatorDateformat || localeBDatelformat === navigatorDateformat)) return localeADateFormat === navigatorDateformat ? -1 : 1; | |
| var woSymbols = function(str) { | |
| return str.replace(/[^a-zA-Z]/g, "") | |
| }, | |
| localeAStrippedFormat = woSymbols(localeADateFormat), | |
| localeBStrippedFormat = woSymbols(localeBDatelformat), | |
| navigatorStrippedFormat = woSymbols(navigatorDateformat); | |
| return localeAStrippedFormat === localeBStrippedFormat || localeAStrippedFormat !== navigatorStrippedFormat && localeBStrippedFormat !== navigatorStrippedFormat ? "en-gb" === localeA || "en-gb" === localeB ? "en-gb" === localeA ? -1 : 1 : localeA.length - localeB.length : localeAStrippedFormat === navigatorStrippedFormat ? -1 : 1 | |
| } | |
| }, | |
| selectLocale = function(baseLocale, navigatorLocale) { | |
| var navigatorLocaleData = moment.localeData(navigatorLocale), | |
| normalizedNavLocale = navigatorLocale.toLowerCase().replace("_", "-"); | |
| if (null !== navigatorLocaleData) { | |
| var possibleLocales = moment.locales().filter(function(val) { | |
| return 0 === val.lastIndexOf(baseLocale, 0) | |
| }); | |
| if (possibleLocales.sort(localeRanker(navigatorLocaleData)), _.contains(possibleLocales, normalizedNavLocale)) return normalizedNavLocale; | |
| if (possibleLocales.length) return possibleLocales[0] | |
| } | |
| return baseLocale | |
| }, | |
| localizePikaday = function(response) { | |
| var americanDays = _.sortBy(dateUtils.I18N.days.slice(), function(day) { | |
| return day.value | |
| }), | |
| locale = { | |
| previousMonth: gettextCatalog.getString("Previous Month", null, "Pikaday"), | |
| nextMonth: gettextCatalog.getString("Next Month", null, "Pikaday"), | |
| months: dateUtils.I18N.months, | |
| weekdays: americanDays.map(function(day) { | |
| return day.longLabel | |
| }), | |
| weekdaysShort: americanDays.map(function(day) { | |
| return day.shortLabel | |
| }) | |
| }; | |
| return pikadayConfiguration.update({ | |
| i18n: locale, | |
| firstDay: moment.localeData().firstDayOfWeek(), | |
| format: moment.localeData().longDateFormat("L") | |
| }), response | |
| }, | |
| localizeDateUtils = function() { | |
| var _ref3 = _asyncToGenerator(regeneratorRuntime.mark(function _callee() { | |
| return regeneratorRuntime.wrap(function(_context) { | |
| for (;;) switch (_context.prev = _context.next) { | |
| case 0: | |
| return _context.abrupt("return", dateUtils.init()); | |
| case 1: | |
| case "end": | |
| return _context.stop() | |
| } | |
| }, _callee, void 0) | |
| })); | |
| return function() { | |
| return _ref3.apply(this, arguments) | |
| } | |
| }(), | |
| loadGettextCatalog = function(lang) { | |
| var navigatorLocale = getLocale(), | |
| locale = lang || navigatorLocale; | |
| gettextCatalog.debugPrefix = "", gettextCatalog.setCurrentLanguage(locale), gettextCatalog.debug = CONFIG.debug || !1; | |
| var _locale$split = locale.split("_"), | |
| _locale$split2 = _slicedToArray(_locale$split, 1), | |
| shortLocale = _locale$split2[0]; | |
| if (moment.locale(selectLocale(shortLocale, navigatorLocale)), document.documentElement.lang = shortLocale, CONFIG.translations.includes(locale)) return gettextCatalog.loadRemote("/i18n/" + locale + ".json"); | |
| var languageMatch = _.find(CONFIG.translations, function(lang) { | |
| return lang.substr(0, 2) === shortLocale | |
| }); | |
| return languageMatch ? gettextCatalog.loadRemote("/i18n/" + languageMatch + ".json") : Promise.resolve() | |
| }; | |
| return function load(lang) { | |
| return loadGettextCatalog(lang).then(localizeDateUtils).then(localizePikaday).then(function() { | |
| return load.langCountry = moment.locale() | |
| }).then(function() { | |
| return dispatch("load", { | |
| lang: load.langCountry | |
| }) | |
| }) | |
| } | |
| }); | |
| var _templateObject = _taggedTemplateLiteral(["\n >>> ", "\n Code: ", "\n Original: ", ",\n Stack: ", "\n "], ["\n >>> ", "\n Code: ", "\n Original: ", ",\n Stack: ", "\n "]); | |
| angular.module("proton.commons").factory("networkActivityTracker", function(errorReporter, $rootScope, notification, dedentTpl) { | |
| var promises = [], | |
| dispatch = function(action) { | |
| return $rootScope.$emit("networkActivity", action) | |
| }, | |
| loading = function() { | |
| return !_.isEmpty(promises) | |
| }, | |
| formatError = function() { | |
| var error = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {}; | |
| return error.originalMessage ? dedentTpl(_templateObject, error.message, error.code, error.originalMessage, error.stack) : error | |
| }, | |
| track = function(promise) { | |
| function cleanup() { | |
| promises = _.without(promises, promise), promises.length || dispatch("close") | |
| } | |
| return errorReporter.clear(), promises.length || dispatch("load"), promises = _.union(promises, [promise]), promise.catch(function(error) { | |
| if (console.error(formatError(error)), angular.isString(error) && notification.error(error), angular.isObject(error) && !error.noNotify) { | |
| var _error$data = error.data, | |
| data = void 0 === _error$data ? {} : _error$data, | |
| message = void 0; | |
| return message = error.message ? error.message : error.Error ? error.Error : error.error_description ? error.error_description : data.Error ? data.Error : "An error has occurred. <br> Please try again or refresh the page.", "loginPassword:cancel" !== message && notification.error(message), Promise.reject(error) | |
| } | |
| }), promise.then(cleanup, cleanup), promise | |
| }; | |
| return { | |
| loading: loading, | |
| clear: function() { | |
| return errorReporter.clear(), promises.length = 0, promises | |
| }, | |
| track: track, | |
| dispatch: dispatch | |
| } | |
| }), angular.module("proton.commons").factory("networkUtils", function(CONSTANTS) { | |
| var CANCEL_REQUEST = CONSTANTS.CANCEL_REQUEST; | |
| return { | |
| isCancelledRequest: function() { | |
| var _ref = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {}, | |
| _ref$config = _ref.config; | |
| return (((void 0 === _ref$config ? {} : _ref$config).timeout || {}).$$state || {}).value === CANCEL_REQUEST | |
| } | |
| } | |
| }), angular.module("proton.commons").factory("secureSessionStorage", function(CONSTANTS, webcrypto) { | |
| var storage = window.sessionStorage, | |
| nameStorage = void 0; | |
| try { | |
| nameStorage = JSON.parse(window.name) | |
| } catch (e) { | |
| nameStorage = {} | |
| } | |
| for (var data = {}, whitelist = [CONSTANTS.MAILBOX_PASSWORD_KEY, CONSTANTS.OAUTH_KEY + ":SessionToken", CONSTANTS.OAUTH_KEY + ":Uid", CONSTANTS.OAUTH_KEY + ":AccessToken", CONSTANTS.OAUTH_KEY + ":RefreshToken", "proton:decrypted_token", "proton:encrypted_password"], i = 0; i < whitelist.length; i++) | |
| if (nameStorage.hasOwnProperty(whitelist[i])) { | |
| var item = storage.getItem(whitelist[i]), | |
| nameItem = nameStorage[whitelist[i]]; | |
| if (angular.isString(item) && angular.isString(nameItem)) { | |
| try { | |
| item = pmcrypto.binaryStringToArray(pmcrypto.decode_base64(item)), nameItem = pmcrypto.binaryStringToArray(pmcrypto.decode_base64(nameItem)) | |
| } catch (e) { | |
| continue | |
| } | |
| if (item.length === nameItem.length) { | |
| for (var xored = new Array(item.length), j = 0; j < item.length; j++) xored[j] = item[j] ^ nameItem[j]; | |
| for (var unpaddedLength = item.length; unpaddedLength > 0 && 0 === xored[unpaddedLength - 1];) unpaddedLength--; | |
| data[whitelist[i]] = pmcrypto.arrayToBinaryString(xored.slice(0, unpaddedLength)) | |
| } | |
| } | |
| } | |
| storage.clear(), window.name = "", nameStorage = {}; | |
| var api = { | |
| getItem: function(key) { | |
| return angular.isString(key) && data.hasOwnProperty(key) ? data[key] : null | |
| }, | |
| setItem: function(key, value) { | |
| angular.isString(key) && angular.isString(value) && (data[key] = value) | |
| }, | |
| removeItem: function(key) { | |
| angular.isString(key) && data.hasOwnProperty(key) && delete data[key] | |
| }, | |
| clear: function() { | |
| data = {} | |
| } | |
| }, | |
| flush = function() { | |
| for (var key in data) | |
| if (data.hasOwnProperty(key)) { | |
| for (var _item = pmcrypto.binaryStringToArray(data[key]), paddedLength = 256 * Math.ceil(_item.length / 256), share1 = webcrypto.getRandomValues(new Uint8Array(paddedLength)), share2 = new Uint8Array(share1), _i = 0; _i < _item.length; _i++) share2[_i] ^= _item[_i]; | |
| nameStorage[key] = pmcrypto.encode_base64(pmcrypto.arrayToBinaryString(share1)), storage.setItem(key, pmcrypto.encode_base64(pmcrypto.arrayToBinaryString(share2))) | |
| } | |
| _.isEmpty(nameStorage) || (window.name = JSON.stringify(nameStorage)) | |
| }; | |
| if (window.addEventListener) window.addEventListener("unload", flush, !1); | |
| else { | |
| if (!window.attachEvent) throw new Error("No method for adding event listeners!"); | |
| window.attachEvent("onunload", flush) | |
| } | |
| return api | |
| }), angular.module("proton.commons").factory("webcrypto", function() { | |
| return window.crypto && window.crypto.getRandomValues ? window.crypto : window.msCrypto && window.msCrypto.getRandomValues ? window.msCrypto : { | |
| getRandomValues: function() { | |
| throw new Error("No cryptographic randomness!") | |
| } | |
| } | |
| }), angular.module("proton.composer").constant("ComposerRequestStatus", { | |
| SUCCESS: 1e3, | |
| DRAFT_NOT_EXIST: 15033, | |
| MESSAGE_ALREADY_SEND: 15034 | |
| }), angular.module("proton.composer").controller("ComposeMessageController", function($filter, $rootScope, $scope, $state, $stateParams, $timeout, gettextCatalog, authentication, cache, confirmModal, CONSTANTS, hotkeys, messageModel, embedded, networkActivityTracker, composerRequestModel, messageBuilder, notification, AppModel, outsidersMap, encryptMessage, extractDataURI, messageRequest, validateMessage, postMessage, sendMessage, eventManager) { | |
| function checkComposerNumber() { | |
| var limit = $scope.messages.length >= CONSTANTS.MAX_NUMBER_COMPOSER || 1 === $scope.messages.length && AppModel.is("mobile"); | |
| return limit && notification.error(gettextCatalog.getString("Maximum composer reached", null, "Notify the user when he try to open more than " + CONSTANTS.MAX_NUMBER_COMPOSER + " composer")), limit | |
| } | |
| function bindFrom(_ref11) { | |
| var AddressID = _ref11.AddressID, | |
| addresses = _.chain(authentication.user.Addresses).where({ | |
| Status: 1, | |
| Receive: 1 | |
| }).sortBy("Order").value(); | |
| if (AddressID) { | |
| var adr = _.findWhere(addresses, { | |
| ID: AddressID | |
| }); | |
| return { | |
| From: adr || addresses[0], | |
| AddressID: adr ? AddressID : addresses[0].ID | |
| } | |
| } | |
| return { | |
| From: addresses[0], | |
| AddressID: addresses[0].ID | |
| } | |
| } | |
| function initMessage(message) { | |
| 1 === authentication.user.ComposerMode && (message.maximized = !0, AppModel.set("maximizedComposer", !0)), message.attachmentsToggle = message.Attachments.length - message.NumEmbedded > 0 && message.Attachments.length > message.NumEmbedded, message.ccbcc = !1, message.autocompletesFocussed = !1, message.uid = $scope.uid++, message.pendingAttachements = [], message.askEmbedding = !1, delete message.asEmbedded, message.uploading = 0, message.sending = !1; | |
| var _bindFrom = bindFrom(message), | |
| From = _bindFrom.From, | |
| AddressID = _bindFrom.AddressID; | |
| message.From = From, message.AddressID = AddressID, $scope.$applyAsync(function() { | |
| var size = $scope.messages.unshift(message); | |
| postMessage(message).then(function() { | |
| $rootScope.$emit("composer.update", { | |
| type: "loaded", | |
| data: { | |
| size: size, | |
| message: message | |
| } | |
| }) | |
| }).catch(function() { | |
| var _$scope$messages = _toArray($scope.messages), | |
| list = _$scope$messages.slice(1); | |
| $scope.messages = list | |
| }) | |
| }) | |
| } | |
| function dispatchMessageAction(message) { | |
| $rootScope.$emit("actionMessage", message) | |
| } | |
| function removeMessage(list, message) { | |
| return list.filter(function(item) { | |
| return message.ID !== item.ID | |
| }) | |
| } | |
| function closeComposer(msg, discard, save) { | |
| var _this = this, | |
| message = messageModel(msg), | |
| process = function() { | |
| $scope.messages = removeMessage($scope.messages, message), composerRequestModel.clear(message), outsidersMap.remove(message.ID), commitComposer(message, !0), $(".tooltip").not(_this).hide(), $rootScope.$emit("composer.update", { | |
| type: "close", | |
| data: { | |
| size: $scope.messages.length, | |
| message: message | |
| } | |
| }) | |
| }; | |
| if (!0 === discard) { | |
| var ids = [message.ID]; | |
| $rootScope.$emit("messageActions", { | |
| action: "delete", | |
| data: { | |
| ids: ids | |
| } | |
| }) | |
| } | |
| $timeout.cancel(message.defferredSaveLater), !0 === save ? postMessage(message, { | |
| autosaving: !0 | |
| }).then(process) : process() | |
| } | |
| var unsubscribe = [], | |
| unicodeTagView = $filter("unicodeTagView"); | |
| $scope.messages = [], $scope.uid = 1; | |
| var commitComposer = function(_ref, clear) { | |
| var ID = _ref.ID, | |
| ConversationID = _ref.ConversationID, | |
| list = AppModel.get("composerList") || []; | |
| if (!clear) return AppModel.store("composerList", (list.push({ | |
| ID: ID, | |
| ConversationID: ConversationID | |
| }), list)); | |
| AppModel.store("composerList", list.filter(function(item) { | |
| return item.ID !== ID | |
| })) | |
| }; | |
| unsubscribe.push($scope.$watch("messages.length", function() { | |
| $scope.messages.length > 0 ? (AppModel.set("activeComposer", !0), window.onbeforeunload = function() { | |
| return gettextCatalog.getString("By leaving now, you will lose what you have written in this email. You can save a draft if you want to come back to it later on.", null) | |
| }, hotkeys.unbind(), hotkeys.bind(["meta+s"])) : (AppModel.set("activeComposer", !1), window.onbeforeunload = void 0, 1 === authentication.user.Hotkeys ? hotkeys.bind() : hotkeys.unbind()) | |
| })), unsubscribe.push($scope.$on("updateUser", function() { | |
| $scope.addresses = authentication.user.Addresses | |
| })), unsubscribe.push($scope.$on("onDrag", function() { | |
| _.each($scope.messages, function(message) { | |
| $scope.togglePanel(message, "attachments") | |
| }) | |
| })), unsubscribe.push($scope.$on("deleteConversation", function(event, ID) { | |
| _.each($scope.messages, function(message) { | |
| ID === message.ID && $scope.close(message, !1, !1) | |
| }) | |
| })); | |
| var isSent = function() { | |
| var _ref2 = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {}, | |
| Type = _ref2.Type; | |
| return Type === CONSTANTS.INBOX_AND_SENT || Type === CONSTANTS.SENT | |
| }; | |
| unsubscribe.push($rootScope.$on("app.event", function(event, _ref3) { | |
| var type = _ref3.type, | |
| data = _ref3.data; | |
| switch (type) { | |
| case "activeMessages": | |
| var removed = $scope.messages.filter(function(_ref4) { | |
| var _ref4$ID = _ref4.ID, | |
| ID = void 0 === _ref4$ID ? "" : _ref4$ID, | |
| msg = _.findWhere(data.messages, { | |
| ID: ID | |
| }); | |
| return msg && isSent(msg) | |
| }); | |
| removed.length && removed.forEach(function(message) { | |
| closeComposer(message), !isSent(message) && notification.info(gettextCatalog.getString("Email was already sent", null, "Info")) | |
| }) | |
| } | |
| })), unsubscribe.push($rootScope.$on("message.refresh", function(event, messageIDs) { | |
| $scope.messages.forEach(function(message) { | |
| var ID = message.ID; | |
| if (messageIDs.indexOf(ID) > -1) { | |
| var messageCached = cache.getMessageCached(ID); | |
| messageCached && (message.Time = messageCached.Time, message.ConversationID = messageCached.ConversationID) | |
| } | |
| }) | |
| })), unsubscribe.push($rootScope.$on("composer.new", function(e, _ref5) { | |
| var type = _ref5.type, | |
| _ref5$data = _ref5.data, | |
| data = void 0 === _ref5$data ? {} : _ref5$data; | |
| !checkComposerNumber() && AppModel.is("onLine") && validateMessage.canWrite() && initMessage(messageBuilder.create(type, data.message)) | |
| })), unsubscribe.push($rootScope.$on("composer.load", function(event, _ref6) { | |
| var ID = _ref6.ID, | |
| found = _.findWhere($scope.messages, { | |
| ID: ID | |
| }), | |
| limitReached = checkComposerNumber(); | |
| found || limitReached || cache.queryMessage(ID).then(function(message) { | |
| message.clearTextBody().then(function() { | |
| return initMessage(message) | |
| }).then(function() { | |
| return commitComposer(message) | |
| }).catch(notification.error) | |
| }) | |
| })), unsubscribe.push($rootScope.$on("composer.update", function(e, _ref7) { | |
| var type = _ref7.type, | |
| data = _ref7.data; | |
| switch (type) { | |
| case "loaded": | |
| commitComposer(data.message); | |
| break; | |
| case "key.autosave": | |
| $scope.$applyAsync(function() { | |
| postMessage(_.find($scope.messages, { | |
| focussed: !0 | |
| }), { | |
| autosaving: !0 | |
| }) | |
| }); | |
| break; | |
| case "editor.focus": | |
| var message = data.message; | |
| data.isMessage && $scope.$applyAsync(function() { | |
| message.autocompletesFocussed = !1, message.attachmentsToggle = !1, message.ccbcc = !1 | |
| }); | |
| break; | |
| case "send.message": | |
| $scope.send(data.message); | |
| break; | |
| case "send.success": | |
| case "close.message": | |
| $scope.close(data.message, !1, !1); | |
| break; | |
| case "close.panel": | |
| $scope.closePanel(data.message) | |
| } | |
| })), unsubscribe.push($rootScope.$on("message.updated", function(e, _ref8) { | |
| var message = _ref8.message; | |
| postMessage(message, { | |
| autosaving: !0 | |
| }) | |
| })), unsubscribe.push($rootScope.$on("squire.editor", function(e, _ref9) { | |
| var type = _ref9.type, | |
| data = _ref9.data; | |
| "input" === type && $scope.saveLater(data.message) | |
| })), unsubscribe.push($rootScope.$on("attachment.upload", function(e, _ref10) { | |
| var type = _ref10.type, | |
| data = _ref10.data; | |
| "remove.success" === type && "text/plain" !== data.message.MIMEType && postMessage(data.message, { | |
| autosaving: !0 | |
| }) | |
| })); | |
| var onResize = _.debounce(function() { | |
| $rootScope.$emit("composer.update", { | |
| type: "refresh", | |
| data: { | |
| size: $scope.messages.length | |
| } | |
| }) | |
| }, 1e3); | |
| $(window).on("resize", onResize), $scope.$on("$destroy", function() { | |
| $(window).off("resize", onResize), window.onbeforeunload = void 0, unsubscribe.forEach(function(cb) { | |
| return cb() | |
| }), unsubscribe.length = 0 | |
| }), $scope.slideDown = function(message) { | |
| message.attachmentsToggle = !message.attachmentsToggle | |
| }, $scope.isEmbedded = function(attachment) { | |
| return embedded.isEmbedded(attachment) | |
| }, $scope.togglePanel = function(message, panelName) { | |
| !0 === message.displayPanel ? $scope.closePanel(message) : $scope.openPanel(message, panelName) | |
| }, $scope.openPanel = function(message, panelName) { | |
| message.displayPanel = !0, message.panelName = panelName, "encrypt" === panelName && $timeout(function() { | |
| angular.element("#uid" + message.uid + ' input[name="outsidePw"]').focus() | |
| }, 100, !1) | |
| }, $scope.closePanel = function(message) { | |
| message.displayPanel = !1, message.panelName = "" | |
| }, $scope.saveLater = function(message) { | |
| return !message.sending && postMessage(message, { | |
| autosaving: !0, | |
| loader: !1 | |
| }) | |
| }, $scope.save = function(message) { | |
| var notification = arguments.length > 1 && void 0 !== arguments[1] && arguments[1], | |
| autosaving = arguments.length > 2 && void 0 !== arguments[2] && arguments[2], | |
| msg = messageModel(message); | |
| return embedded.parser(msg, { | |
| direction: "cid" | |
| }).then(function(result) { | |
| return msg.Body = result, postMessage(msg, { | |
| notification: notification, | |
| autosaving: autosaving | |
| }) | |
| }) | |
| }, $scope.subject = function(message) { | |
| return message.Subject || gettextCatalog.getString("New message", null, "Title") | |
| }, $scope.send = function() { | |
| var _ref12 = _asyncToGenerator(regeneratorRuntime.mark(function _callee(msg) { | |
| var message, setStateSending, promise; | |
| return regeneratorRuntime.wrap(function(_context) { | |
| for (;;) switch (_context.prev = _context.next) { | |
| case 0: | |
| return message = messageModel(msg), setStateSending = function(is) { | |
| return message.sending = is, msg.sending = is | |
| }, message.Password = message.Password || "", message.PasswordHint = message.PasswordHint || "", _context.prev = 4, _context.next = 7, validateMessage.checkSubject(message); | |
| case 7: | |
| _context.next = 12; | |
| break; | |
| case 9: | |
| return _context.prev = 9, _context.t0 = _context.catch(4), _context.abrupt("return"); | |
| case 12: | |
| setStateSending(!0), dispatchMessageAction(message), promise = validateMessage.validate(message).then(eventManager.stop).then(function() { | |
| return extractDataURI(message) | |
| }).then(function() { | |
| return postMessage(message) | |
| }).then(function(messageSaved) { | |
| return message.ID = messageSaved.ID, message | |
| }).then(function(msg) { | |
| return sendMessage(msg) | |
| }).then(eventManager.start).catch(function(e) { | |
| throw setStateSending(!1), message.encrypting = !1, dispatchMessageAction(message), eventManager.start(), new Error(e.raw ? e.message : unicodeTagView(e.message)) | |
| }), networkActivityTracker.track(promise); | |
| case 16: | |
| case "end": | |
| return _context.stop() | |
| } | |
| }, _callee, void 0, [ | |
| [4, 9] | |
| ]) | |
| })); | |
| return function(_x4) { | |
| return _ref12.apply(this, arguments) | |
| } | |
| }(), $scope.focusFirstComposer = function(message) { | |
| $rootScope.$emit("composer.update", { | |
| type: "focus.first", | |
| data: { | |
| message: message | |
| } | |
| }) | |
| }, $scope.minimize = function(message) { | |
| message.minimized = !0, message.previousMaximized = message.maximized, message.maximized = !1, message.ccbcc = !1, AppModel.set("maximizedComposer", !1), $(".tooltip").not(void 0).hide(), $scope.focusFirstComposer(message) | |
| }, $scope.unminimize = function(message) { | |
| message.minimized = !1, message.maximized = message.previousMaximized, $(".tooltip").not(void 0).hide() | |
| }, $scope.maximize = function(message) { | |
| message.maximized = !0, AppModel.set("maximizedComposer", !0) | |
| }, $scope.normalize = function(message) { | |
| var width = window.innerWidth, | |
| height = window.innerHeight, | |
| isSmall = width <= 640 || height <= 500; | |
| message.minimized = !1, message.maximized = isSmall, AppModel.set("maximizedComposer", isSmall) | |
| }, $scope.openCloseModal = function(message) { | |
| var discard = arguments.length > 1 && void 0 !== arguments[1] && arguments[1]; | |
| $scope.close(message, discard, !discard) | |
| }, $scope.close = closeComposer, $scope.discard = function(message) { | |
| var title = gettextCatalog.getString("Delete", null), | |
| question = gettextCatalog.getString("Permanently delete this draft?", null); | |
| confirmModal.activate({ | |
| params: { | |
| title: title, | |
| message: question, | |
| confirm: function() { | |
| $scope.openCloseModal(message, !0), notification.success(gettextCatalog.getString("Message discarded", null)), confirmModal.deactivate() | |
| }, | |
| cancel: function() { | |
| confirmModal.deactivate() | |
| } | |
| } | |
| }) | |
| } | |
| }), angular.module("proton.composer").directive("actionCompose", function($rootScope) { | |
| return { | |
| scope: { | |
| model: "=actionCompose" | |
| }, | |
| link: function(scope, element, _ref) { | |
| function onClick(e) { | |
| if (e.preventDefault(), /addFile|addEmbedded/.test(actionComposeType)) return $rootScope.$emit("addFile", { | |
| asEmbedded: "addEmbedded" === actionComposeType, | |
| message: scope.model | |
| }); | |
| $rootScope.$emit("composer.new", { | |
| type: actionComposeType, | |
| data: { | |
| message: scope.model | |
| } | |
| }) | |
| } | |
| var actionComposeType = _ref.actionComposeType; | |
| element[0].addEventListener("click", onClick), scope.$on("$destroy", function() { | |
| element[0].removeEventListener("click", onClick) | |
| }) | |
| } | |
| } | |
| }), angular.module("proton.composer").directive("btnSendMessage", function($rootScope, gettextCatalog) { | |
| var getLabel = function(msg) { | |
| var label = void 0; | |
| switch (!!msg) { | |
| case !0 === msg.encryptingAttachment: | |
| label = gettextCatalog.getString("Encrypting attachments", null, "Action"); | |
| break; | |
| case msg.uploading > 0: | |
| label = gettextCatalog.getString("Uploading", null, "Action"); | |
| break; | |
| case !0 === msg.encrypting: | |
| label = gettextCatalog.getString("Encrypting", null, "Action"); | |
| break; | |
| case !0 === msg.saving && !1 === msg.autosaving: | |
| label = gettextCatalog.getString("Saving", null, "Action"); | |
| break; | |
| case !0 === msg.sending: | |
| label = gettextCatalog.getString("Sending", null, "Action"); | |
| break; | |
| case msg.disableSend && msg.disableSend(): | |
| default: | |
| label = gettextCatalog.getString("Send", null, "Action") | |
| } | |
| return label | |
| }; | |
| return { | |
| replace: !0, | |
| scope: { | |
| model: "=message" | |
| }, | |
| template: '<button class="btnSendMessage-btn-action"></button>', | |
| link: function(scope, el) { | |
| var isCurrentMsg = function(msg) { | |
| return msg.ID === scope.model.ID | |
| }; | |
| el[0].textContent = getLabel(scope.model); | |
| var onClick = function() { | |
| $rootScope.$emit("composer.update", { | |
| type: "send.message", | |
| data: { | |
| message: scope.model | |
| } | |
| }) | |
| }, | |
| unsubscribe = $rootScope.$on("actionMessage", function(e, message) { | |
| isCurrentMsg(message) && (el[0].textContent = getLabel(message), message.disableSend && (el[0].disabled = message.disableSend())) | |
| }); | |
| el.on("click", onClick), scope.$on("$destroy", function() { | |
| el.off("click", onClick), unsubscribe() | |
| }) | |
| } | |
| } | |
| }), angular.module("proton.composer").directive("composer", function(AppModel, $rootScope, embedded, attachmentFileFormat, authentication) { | |
| var addDragenterClassName = function(el) { | |
| var className = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : "composer-draggable"; | |
| return el.classList.add(className) | |
| }, | |
| addDragleaveClassName = function(el) { | |
| el.classList.remove("composer-draggable"), el.classList.remove("composer-draggable-editor") | |
| }, | |
| isMessage = function(_ref, _ref2) { | |
| var ID = _ref.ID, | |
| _ref2$message = _ref2.message, | |
| message = void 0 === _ref2$message ? {} : _ref2$message; | |
| return ID === _ref2.messageID || ID === message.ID | |
| }, | |
| onAction = function(scope, el) { | |
| return function(e, _ref3) { | |
| var type = _ref3.type, | |
| data = _ref3.data; | |
| if (isMessage(scope.message, data)) switch (type) { | |
| case "dragenter": | |
| attachmentFileFormat.isUploadAbleType(data.event) && addDragenterClassName(el); | |
| break; | |
| case "drop": | |
| if ("attachment.upload" === e.name && data.queue.files.length && data.queue.hasEmbedded) return addDragenterClassName(el, "composer-draggable-editor"); | |
| addDragleaveClassName(el); | |
| break; | |
| case "upload": | |
| addDragleaveClassName(el); | |
| break; | |
| case "upload.success": | |
| _rAF(function() { | |
| return addDragleaveClassName(el) | |
| }) | |
| } | |
| } | |
| }; | |
| return { | |
| replace: !0, | |
| templateUrl: "templates/directives/composer/composer.tpl.html", | |
| link: function(scope, el) { | |
| var onClick = function(_ref4) { | |
| var target = _ref4.target; | |
| /composerHeader-btn/.test(target.classList.toString()) || $rootScope.$emit("composer.update", { | |
| type: "focus.click", | |
| data: { | |
| message: scope.message, | |
| composer: el, | |
| index: +el[0].getAttribute("data-index") | |
| } | |
| }), /squireToolbar/.test(target.classList.toString()) && scope.$applyAsync(function() { | |
| scope.message.ccbcc = !1 | |
| }) | |
| }, | |
| onDragLeave = _.debounce(function(e) { | |
| var target = e.target; | |
| (target.classList.contains("composer-dropzone") || target.classList.contains("composer-dropzone-wrapper")) && addDragleaveClassName(el[0]) | |
| }, 500), | |
| onDragEnter = function(_ref5) { | |
| var originalEvent = _ref5.originalEvent; | |
| attachmentFileFormat.isUploadAbleType(originalEvent) && addDragenterClassName(el[0]) | |
| }, | |
| onKeydown = function(_ref6) { | |
| if (27 === _ref6.keyCode) { | |
| if (document.activeElement && document.activeElement.classList.contains("autocompleteEmails-input")) return; | |
| 1 === authentication.user.Hotkeys && $rootScope.$emit("composer.update", { | |
| type: "close.message", | |
| data: { | |
| message: scope.message | |
| } | |
| }) | |
| } | |
| }; | |
| el.on("dragenter", onDragEnter), el.on("dragleave", onDragLeave), el.on("click", onClick), el.on("keydown", onKeydown); | |
| var unsubscribeEditor = $rootScope.$on("editor.draggable", onAction(scope, el[0])), | |
| unsubscribeAtt = $rootScope.$on("attachment.upload", onAction(scope, el[0])); | |
| scope.$on("$destroy", function() { | |
| el.off("dragenter", onDragEnter), el.off("dragleave", onDragLeave), el.off("click", onClick), el.off("keydown", onKeydown), unsubscribeEditor(), unsubscribeAtt(), AppModel.set("activeComposer", !1), AppModel.set("maximizedComposer", !1), scope.selected = void 0 | |
| }) | |
| } | |
| } | |
| }), angular.module("proton.composer").directive("composerAskEmbedded", function($rootScope, gettextCatalog) { | |
| var buildTitle = function(node, pending) { | |
| var counterTranslateKey = gettextCatalog.getPlural(pending, "image detected", "images detected", {}, "Composer, message drag and drop images"); | |
| node.textContent = pending + " " + counterTranslateKey | |
| }; | |
| return { | |
| replace: !0, | |
| templateUrl: "templates/directives/composer/composerAskEmbedded.tpl.html", | |
| link: function(scope, el, _ref) { | |
| var _ref$action = _ref.action, | |
| action = void 0 === _ref$action ? "" : _ref$action, | |
| key = ["attachment.upload", action].filter(Boolean).join("."), | |
| dispatch = function(data) { | |
| return $rootScope.$emit(key, { | |
| type: "upload", | |
| data: data | |
| }) | |
| }, | |
| $title = el[0].querySelector(".composerAskEmbdded-title"), | |
| unsubscribe = $rootScope.$on(key, function(e, _ref2) { | |
| var type = _ref2.type, | |
| data = _ref2.data; | |
| "drop" === type && buildTitle($title, data.queue.files.filter(function(_ref3) { | |
| return _ref3.isEmbedded | |
| }).length) | |
| }), | |
| onClick = function(_ref4) { | |
| var target = _ref4.target; | |
| "BUTTON" === target.nodeName && dispatch({ | |
| messageID: scope.message.ID, | |
| message: scope.message, | |
| action: target.getAttribute("data-action") | |
| }) | |
| }; | |
| el.on("click", onClick), scope.$on("$destroy", function() { | |
| el.off("click", onClick), unsubscribe() | |
| }) | |
| } | |
| } | |
| }), angular.module("proton.composer").directive("composerAttachments", function($rootScope, gettextCatalog) { | |
| var CLASS_HIDDEN = "composerAttachments-hidden", | |
| labelHeader = { | |
| show: gettextCatalog.getString("Show", null, "Action"), | |
| hide: gettextCatalog.getString("Hide", null, "Action") | |
| }, | |
| togglePanel = function(scope, el) { | |
| var doAction = function(action, label) { | |
| return function() { | |
| "remove" === action && el.classList.remove(CLASS_HIDDEN), el.classList[action]("composerAttachments-close"), scope.$applyAsync(function() { | |
| return scope.labelHeader = labelHeader[label] | |
| }) | |
| } | |
| }, | |
| open = doAction("remove", "hide"), | |
| close = doAction("add", "show"), | |
| show = function() { | |
| return el.classList.remove(CLASS_HIDDEN) | |
| }, | |
| hide = function() { | |
| return el.classList.add(CLASS_HIDDEN) | |
| }, | |
| isOpened = function() { | |
| return !el.classList.contains("composerAttachments-close") | |
| }; | |
| return { | |
| open: open, | |
| close: close, | |
| isOpened: isOpened, | |
| hide: hide, | |
| show: show, | |
| toggle: function() { | |
| return isOpened() ? close() : open() | |
| } | |
| } | |
| }, | |
| formatAttachments = function(scope) { | |
| return (arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : []).map(function(_ref) { | |
| var ID = _ref.ID, | |
| _ref$Headers = _ref.Headers, | |
| Headers = void 0 === _ref$Headers ? {} : _ref$Headers; | |
| return { | |
| id: ID, | |
| packet: { | |
| filename: _ref.Name, | |
| uploading: !1, | |
| Size: _ref.Size, | |
| Inline: +("inline" === Headers["content-disposition"]) | |
| }, | |
| messageID: scope.message.ID, | |
| message: scope.message | |
| } | |
| }) | |
| }, | |
| isMessage = function(_ref2, _ref3) { | |
| var ID = _ref2.ID, | |
| _ref3$message = _ref3.message, | |
| message = void 0 === _ref3$message ? {} : _ref3$message; | |
| return ID === _ref3.messageID || ID === message.ID | |
| }, | |
| onAction = function(scope, actionsPanel) { | |
| return function(e, _ref4) { | |
| var type = _ref4.type, | |
| data = _ref4.data, | |
| status = data.status, | |
| packet = data.packet, | |
| id = data.id, | |
| messageID = data.messageID, | |
| REQUEST_ID = data.REQUEST_ID, | |
| isStart = data.isStart; | |
| if (isMessage(scope.message, data)) switch (type) { | |
| case "upload": | |
| if ("cancel" !== data.action) return; | |
| if (scope.message.Attachments.length) return actionsPanel.close(); | |
| actionsPanel.hide(); | |
| break; | |
| case "cancel": | |
| case "remove.success": | |
| scope.$applyAsync(function() { | |
| scope.list = scope.list.filter(function(o) { | |
| return o.id !== id | |
| }).filter(function(o) { | |
| return o.id !== REQUEST_ID | |
| }), !scope.list.length && actionsPanel.hide() | |
| }); | |
| break; | |
| case "uploading": | |
| status && isStart && (actionsPanel.open(), scope.$applyAsync(function() { | |
| scope.list.push({ | |
| id: id, | |
| packet: packet, | |
| messageID: messageID, | |
| message: scope.message | |
| }) | |
| })); | |
| break; | |
| case "error": | |
| scope.$applyAsync(function() { | |
| scope.list = scope.list.filter(function(item) { | |
| return item.id !== id && item.message.ID !== scope.message.ID | |
| }), actionsPanel.close(), !scope.list.length && actionsPanel.hide() | |
| }); | |
| break; | |
| case "upload.success": | |
| actionsPanel.close() | |
| } | |
| } | |
| }; | |
| return { | |
| replace: !0, | |
| scope: { | |
| message: "=model" | |
| }, | |
| templateUrl: "templates/directives/composer/composerAttachments.tpl.html", | |
| link: function(scope, el) { | |
| scope.list = formatAttachments(scope, scope.message.Attachments), scope.labelHeader = labelHeader.show; | |
| var actionsPanel = togglePanel(scope, el[0]), | |
| $header = angular.element(el[0].querySelector(".composerAttachments-header")); | |
| !scope.list.length && actionsPanel.hide(); | |
| var onClick = function() { | |
| return actionsPanel.toggle() | |
| }; | |
| $header.on("click", onClick); | |
| var unsubscribe = $rootScope.$on("attachment.upload", onAction(scope, actionsPanel)); | |
| scope.$on("$destroy", function() { | |
| $header.off("click", onClick), unsubscribe() | |
| }) | |
| } | |
| } | |
| }), angular.module("proton.composer").directive("composerAttachmentsItem", function($rootScope, gettextCatalog, attachmentDownloader) { | |
| var getTitle = function(name) { | |
| return gettextCatalog.getString("Download the attachment " + name) | |
| }, | |
| dispatcher = function(isOutside) { | |
| return function(type) { | |
| var data = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : {}, | |
| event = ("attachment.upload" + (isOutside ? ".outside" : "")).trim(); | |
| $rootScope.$emit(event, { | |
| type: type, | |
| data: data | |
| }) | |
| } | |
| }; | |
| return { | |
| replace: !0, | |
| template: '<a class="composerAttachmentsItem-container"><progress-upload data-model="attachment"></progress-upload></a>', | |
| link: function(scope, el, _ref) { | |
| var _ref$isOutside = _ref.isOutside, | |
| isOutside = void 0 !== _ref$isOutside && _ref$isOutside, | |
| dispatch = dispatcher(isOutside); | |
| el[0].title = getTitle(scope.attachment.packet.filename); | |
| var onClick = function(e) { | |
| attachmentDownloader.isNotSupported(e) || dispatch("download.composer", scope.attachment) | |
| }; | |
| el.on("click", onClick), scope.$on("$destroy", function() { | |
| el.off("click", onClick) | |
| }) | |
| } | |
| } | |
| }), angular.module("proton.composer").directive("composerContainer", function($rootScope, composerRender, composerLoader) { | |
| return { | |
| link: function(scope, el) { | |
| var focusMessage = composerLoader(scope), | |
| renderList = function(data) { | |
| var $list = [].slice.call(el[0].querySelectorAll(".composer-container")); | |
| _rAF(function() { | |
| return composerRender.render($list, data) | |
| }) | |
| }, | |
| openClose = function(type) { | |
| var data = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : {}; | |
| scope.$applyAsync(function() { | |
| if (scope.messages.length) { | |
| var message = "close" === type ? scope.messages[0] : data.message; | |
| message.focussed = !1; | |
| var _composerRender$findC = composerRender.findComposer(el[0], message), | |
| index = _composerRender$findC.index, | |
| composer = _composerRender$findC.composer, | |
| position = index - 1 >= 0 ? index - 1 : index, | |
| state = angular.extend({}, data, { | |
| message: message, | |
| composer: composer, | |
| index: position, | |
| size: scope.messages.length, | |
| keepState: !1 | |
| }); | |
| focusMessage(state); | |
| var id = setTimeout(function() { | |
| return renderList(state), clearTimeout(id) | |
| }, 160) | |
| } | |
| }) | |
| }, | |
| onOrientationChange = function() { | |
| return openClose("close") | |
| }; | |
| window.addEventListener("orientationchange", onOrientationChange, !1); | |
| var unsubscribe = $rootScope.$on("composer.update", function(e, _ref) { | |
| var type = _ref.type, | |
| data = _ref.data; | |
| switch (type) { | |
| case "focus.click": | |
| scope.$applyAsync(function() { | |
| return focusMessage(data) | |
| }); | |
| break; | |
| case "focus.first": | |
| var notMinimized = _.findWhere(scope.messages, { | |
| minimized: !1 | |
| }); | |
| notMinimized && openClose(type, { | |
| message: notMinimized | |
| }); | |
| break; | |
| case "close": | |
| openClose(type, data); | |
| break; | |
| case "editor.loaded": | |
| case "editor.focus": | |
| var message = data.message, | |
| editor = data.editor; | |
| if (!data.isMessage) break; | |
| if (message.focussed) { | |
| scope.$applyAsync(function() { | |
| return message.autocompletesFocussed = !1 | |
| }); | |
| break | |
| } | |
| scope.$applyAsync(function() { | |
| var _composerRender$findC2 = composerRender.findComposer(el[0], message), | |
| index = _composerRender$findC2.index, | |
| composer = _composerRender$findC2.composer, | |
| state = angular.extend({}, data, { | |
| composer: composer, | |
| index: index, | |
| keepState: !1, | |
| focusEditor: "editor.focus" === type, | |
| size: scope.messages.length | |
| }); | |
| focusMessage(state, editor), "editor.loaded" === type && renderList(state) | |
| }) | |
| } | |
| }); | |
| scope.$on("$destroy", function() { | |
| window.removeEventListener("orientationchange", onOrientationChange, !1), unsubscribe() | |
| }) | |
| } | |
| } | |
| }), angular.module("proton.composer").directive("composerDropzone", function($rootScope, attachmentFileFormat, tools, attachmentModel, notification, gettextCatalog, CONSTANTS, $state) { | |
| function getDropFileConfigMessage(message, file) { | |
| return { | |
| currentSize: message.attachmentsSize() + (message.queuedFilesSize || 0) + file.size, | |
| numberFiles: (message.Attachments || []).length + (message.queuedFiles || 0) | |
| } | |
| } | |
| function buildQueue(message, dropzone) { | |
| return function(queue, file) { | |
| var _getDropFileConfigMes = getDropFileConfigMessage(message, file), | |
| currentSize = _getDropFileConfigMes.currentSize; | |
| if (_getDropFileConfigMes.numberFiles === ATTACHMENT_NUMBER_LIMIT) { | |
| var msg = dropMessages[ATTACHMENT_NUMBER_LIMIT]; | |
| return dropzone.removeFile(file), notification.error(msg), queue | |
| } | |
| if (currentSize >= ATTACHMENT_MAX_SIZE) { | |
| var _msg = dropMessages[ATTACHMENT_MAX_SIZE](currentSize); | |
| return dropzone.removeFile(file), notification.error(_msg), queue | |
| } | |
| if (0 === currentSize) { | |
| var _msg2 = dropMessages[0]; | |
| return dropzone.removeFile(file), notification.error(_msg2), queue | |
| } | |
| return queue.files.push({ | |
| file: file, | |
| isEmbedded: attachmentFileFormat.isEmbedded(file.type) | |
| }), queue.size += file.size, queue | |
| } | |
| } | |
| var _dropMessages; | |
| Dropzone.autoDiscover = !1; | |
| var BASE_SIZE = CONSTANTS.BASE_SIZE, | |
| ATTACHMENT_SIZE_LIMIT = CONSTANTS.ATTACHMENT_SIZE_LIMIT, | |
| ATTACHMENT_NUMBER_LIMIT = CONSTANTS.ATTACHMENT_NUMBER_LIMIT, | |
| ATTACHMENT_MAX_SIZE = ATTACHMENT_SIZE_LIMIT * BASE_SIZE * BASE_SIZE, | |
| isEO = $state.includes("eo.*"), | |
| dropMessages = (_dropMessages = { | |
| 0: gettextCatalog.getString("Empty attachment", null, "Composer") | |
| }, _defineProperty(_dropMessages, ATTACHMENT_NUMBER_LIMIT, gettextCatalog.getString("Messages are limited to " + ATTACHMENT_NUMBER_LIMIT + " attachments", null, "Composer")), _defineProperty(_dropMessages, ATTACHMENT_SIZE_LIMIT, gettextCatalog.getString("Attachments are limited to " + ATTACHMENT_SIZE_LIMIT + " MB.", null, "Composer")), _defineProperty(_dropMessages, ATTACHMENT_MAX_SIZE, function(bytes) { | |
| var total = Math.round(10 * bytes / BASE_SIZE / BASE_SIZE) / 10; | |
| return gettextCatalog.getString("Attachments are limited to " + ATTACHMENT_SIZE_LIMIT + " MB. Total attached would be: " + total + " MB.", null, "Composer") | |
| }), _dropMessages), | |
| ERROR_EO_NUMBER_ATT = gettextCatalog.getString("Maximum number of attachments (10) exceeded.", null, "Composer"), | |
| dictDefaultMessage = gettextCatalog.getString("Drop a file here to upload", null, "Info"), | |
| canUploadList = function(message) { | |
| var list = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : [], | |
| _ref = arguments.length > 2 && void 0 !== arguments[2] ? arguments[2] : {}, | |
| _ref$size = _ref.size, | |
| size = void 0 === _ref$size ? 0 : _ref$size, | |
| listSize = [].slice.call(list).reduce(function(acc, file) { | |
| return acc + file.size | |
| }, 0); | |
| return message.attachmentsSize() + size + listSize <= ATTACHMENT_MAX_SIZE | |
| }, | |
| getConfig = function(message, dispatchAction) { | |
| return { | |
| addRemoveLinks: !1, | |
| dictDefaultMessage: dictDefaultMessage, | |
| url: "/file/post", | |
| autoProcessQueue: !1, | |
| paramName: "file", | |
| previewTemplate: '<div style="display:none"></div>', | |
| init: function() { | |
| var _this = this; | |
| _.forEach(message.Attachments, function(_ref2) { | |
| var Name = _ref2.Name, | |
| Size = _ref2.Size, | |
| MIMEType = _ref2.MIMEType, | |
| ID = _ref2.ID, | |
| mockFile = { | |
| name: Name, | |
| size: Size, | |
| type: MIMEType, | |
| ID: ID | |
| }; | |
| _this.options.addedfile.call(_this, mockFile) | |
| }, this), this.on("addedfiles", function(list) { | |
| if (!canUploadList(message, list, attachmentModel.getCurrentQueue(message))) { | |
| _this.removeAllFiles(); | |
| var id = void 0; | |
| return id = setTimeout(function() { | |
| notification.error(dropMessages[ATTACHMENT_SIZE_LIMIT]), dispatchAction(message, { | |
| size: 0, | |
| files: [] | |
| }), clearTimeout(id) | |
| }, 100) | |
| } | |
| var queue = [].slice.call(list).reduce(buildQueue(message, _this), { | |
| files: [], | |
| size: 0 | |
| }); | |
| if (_this.removeAllFiles(), queue.hasEmbedded = queue.files.every(function(_ref3) { | |
| return _ref3.isEmbedded && "text/plain" !== message.MIMEType | |
| }), isEO && queue.files.length + message.Attachments.length > 10) return dispatchAction(message, queue, "attachments.limit.error"), notification.error(ERROR_EO_NUMBER_ATT); | |
| dispatchAction(message, queue) | |
| }) | |
| } | |
| } | |
| }; | |
| return { | |
| link: function(scope, el, _ref4) { | |
| var _ref4$action = _ref4.action, | |
| action = void 0 === _ref4$action ? "" : _ref4$action, | |
| key = ["attachment.upload", action].filter(Boolean).join("."), | |
| dispatchAction = function(message) { | |
| var queue = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : [], | |
| type = arguments.length > 2 && void 0 !== arguments[2] ? arguments[2] : "drop"; | |
| $rootScope.$emit(key, { | |
| type: type, | |
| data: { | |
| messageID: message.ID, | |
| message: message, | |
| queue: queue | |
| } | |
| }) | |
| }, | |
| dropzone = new Dropzone(el[0], getConfig(scope.message, dispatchAction)), | |
| unsubscribe = $rootScope.$on("addFile", function(e, _ref5) { | |
| var asEmbedded = _ref5.asEmbedded; | |
| _ref5.message.ID === scope.message.ID && (scope.message.asEmbedded = asEmbedded, dropzone.element.click()) | |
| }); | |
| scope.$on("$destroy", function() { | |
| dropzone.off("dragover"), dropzone.off("addedfiles"), dropzone.destroy(), unsubscribe() | |
| }) | |
| } | |
| } | |
| }), angular.module("proton.composer").directive("composerEncrypt", function(notification, gettextCatalog, $rootScope) { | |
| var MESSAGES = { | |
| noPassword: gettextCatalog.getString("Please enter a password for this email.", null, "Error"), | |
| noMatchPassword: gettextCatalog.getString("Message passwords do not match.", null, "Error") | |
| }, | |
| dispatch = function(type, message) { | |
| return $rootScope.$emit("composer.update", { | |
| type: type, | |
| data: { | |
| message: message, | |
| type: "encryption" | |
| } | |
| }) | |
| }; | |
| return { | |
| replace: !0, | |
| scope: { | |
| message: "=" | |
| }, | |
| templateUrl: "templates/composer/composerEncrypt.tpl.html", | |
| link: function(scope, el) { | |
| var $cancel = el.find(".composerEncrypt-btn-cancel"); | |
| scope.model = { | |
| password: "", | |
| confirm: "", | |
| hint: "" | |
| }; | |
| var onSubmit = function(e) { | |
| return e.stopPropagation(), scope.model.password.length ? scope.model.password !== scope.model.confirm ? notification.error(MESSAGES.noMatchPassword) : void scope.$applyAsync(function() { | |
| scope.message.IsEncrypted = 1, scope.message.Password = scope.model.password, scope.message.PasswordHint = scope.model.hint, dispatch("close.panel", scope.message) | |
| }) : notification.error(MESSAGES.noPassword) | |
| }, | |
| onCancel = function() { | |
| scope.$applyAsync(function() { | |
| scope.model.password = "", scope.model.confirm = "", scope.model.hint = "", scope.encryptForm.$setUntouched(), delete scope.message.PasswordHint, scope.message.IsEncrypted = 0, dispatch("close.panel", scope.message) | |
| }) | |
| }; | |
| el.on("submit", onSubmit), $cancel.on("click", onCancel), scope.$on("$destroy", function() { | |
| el.off("submit", onSubmit), $cancel.off("click", onCancel) | |
| }) | |
| } | |
| } | |
| }), angular.module("proton.composer").directive("composerExpiration", function(notification, gettextCatalog, $rootScope, CONSTANTS) { | |
| var MESSAGES = { | |
| maxEpiration: gettextCatalog.getString("The maximum expiration is 4 weeks.", null, "Error"), | |
| invalid: gettextCatalog.getString("Invalid expiration time.", null, "Error") | |
| }, | |
| dispatch = function(type, message) { | |
| return $rootScope.$emit("composer.update", { | |
| type: type, | |
| data: { | |
| message: message, | |
| type: "expiration" | |
| } | |
| }) | |
| }, | |
| formatOption = function(size) { | |
| return _.range(size).map(function(value) { | |
| return { | |
| label: "" + value, | |
| value: value | |
| } | |
| }) | |
| }, | |
| OPTIONS = { | |
| week: formatOption(5), | |
| day: formatOption(7), | |
| hour: formatOption(24) | |
| }, | |
| initModel = function(message) { | |
| if (angular.isDefined(message.ExpirationTime)) { | |
| var deltaHours = message.ExpirationTime / 3600, | |
| deltaDays = Math.floor(deltaHours / 24); | |
| return { | |
| weeks: angular.copy(_.findWhere(OPTIONS.week, { | |
| value: Math.floor(deltaDays / 7) | |
| })), | |
| days: angular.copy(_.findWhere(OPTIONS.day, { | |
| value: deltaDays % 7 | |
| })), | |
| hours: angular.copy(_.findWhere(OPTIONS.hour, { | |
| value: deltaHours % 24 | |
| })) | |
| } | |
| } | |
| return { | |
| days: 0, | |
| hours: 0, | |
| weeks: 0 | |
| } | |
| }, | |
| computeHours = function(_ref) { | |
| var days = _ref.days, | |
| hours = _ref.hours, | |
| weeks = _ref.weeks; | |
| return hours.value + 24 * (days.value + 7 * weeks.value) | |
| }; | |
| return { | |
| replace: !0, | |
| scope: { | |
| message: "=" | |
| }, | |
| templateUrl: "templates/composer/composerExpiration.tpl.html", | |
| link: function(scope, el) { | |
| var $cancel = el.find(".composerExpiration-btn-cancel"); | |
| scope.model = initModel(scope.message), scope.options = OPTIONS; | |
| var onSubmit = function(e) { | |
| e.stopPropagation(); | |
| var hours = computeHours(scope.model); | |
| return parseInt(hours, 10) > CONSTANTS.MAX_EXPIRATION_TIME ? notification.error(MESSAGES.maxEpiration) : isNaN(hours) ? notification.error(MESSAGES.invalid) : void scope.$applyAsync(function() { | |
| scope.message.ExpirationTime = 3600 * hours, dispatch("close.panel", scope.message) | |
| }) | |
| }, | |
| onCancel = function() { | |
| scope.$applyAsync(function() { | |
| delete scope.message.ExpirationTime, scope.expirationForm.$setUntouched(), dispatch("close.panel", scope.message) | |
| }) | |
| }; | |
| el.on("submit", onSubmit), $cancel.on("click", onCancel), scope.$on("$destroy", function() { | |
| el.off("submit", onSubmit), $cancel.off("click", onCancel) | |
| }) | |
| } | |
| } | |
| }), angular.module("proton.composer").directive("composerHeader", function() { | |
| return { | |
| replace: !0, | |
| templateUrl: "templates/directives/composer/composer-header.tpl.html" | |
| } | |
| }), angular.module("proton.composer").directive("composerInputMeta", function() { | |
| var containsInvalid = function(_ref) { | |
| var _ref$ToList = _ref.ToList, | |
| ToList = void 0 === _ref$ToList ? [] : _ref$ToList, | |
| _ref$CCList = _ref.CCList, | |
| CCList = void 0 === _ref$CCList ? [] : _ref$CCList, | |
| _ref$BCCList = _ref.BCCList, | |
| BCCList = void 0 === _ref$BCCList ? [] : _ref$BCCList; | |
| return _.some([].concat(_toConsumableArray(ToList), _toConsumableArray(CCList), _toConsumableArray(BCCList)), { | |
| invalid: !0 | |
| }) | |
| }, | |
| containsRecipient = function(scope) { | |
| return function() { | |
| var _scope$message = scope.message, | |
| _scope$message$ToList = _scope$message.ToList, | |
| ToList = void 0 === _scope$message$ToList ? [] : _scope$message$ToList, | |
| _scope$message$CCList = _scope$message.CCList, | |
| CCList = void 0 === _scope$message$CCList ? [] : _scope$message$CCList, | |
| _scope$message$BCCLis = _scope$message.BCCList, | |
| BCCList = void 0 === _scope$message$BCCLis ? [] : _scope$message$BCCLis; | |
| return !containsInvalid(scope.message) && (ToList.length || CCList.length || BCCList.length) | |
| } | |
| }, | |
| containsBCC = function(_ref2) { | |
| var _ref2$CCList = _ref2.CCList, | |
| CCList = void 0 === _ref2$CCList ? [] : _ref2$CCList, | |
| _ref2$BCCList = _ref2.BCCList, | |
| BCCList = void 0 === _ref2$BCCList ? [] : _ref2$BCCList; | |
| return CCList.length || BCCList.length | |
| }, | |
| getNameAutocomplete = function(label) { | |
| return "composerAutocomplete" + label + Math.random().toString(32).slice(2, 12) | |
| }; | |
| return { | |
| replace: !0, | |
| templateUrl: "templates/directives/composer/composerInputMeta.tpl.html", | |
| compile: function(element, _ref3) { | |
| var label = _ref3.label, | |
| key = _ref3.key, | |
| $label = element[0].querySelector(".composerInputMeta-label"), | |
| $input = element[0].querySelector(".composerInputMeta-autocomplete"); | |
| return $label && ($label.textContent = label), $input && ($input.setAttribute("data-name", getNameAutocomplete(label)), $input.setAttribute("data-emails", "message." + key)), | |
| function(scope, el) { | |
| var isCurrentMsg = function() { | |
| return scope.message.ID === scope.selected.ID | |
| }, | |
| $btn = el[0].querySelector(".composerInputMeta-overlay-button"); | |
| scope.containsRecipient = containsRecipient(scope), scope.containsInvalid = containsInvalid; | |
| var onClick = function(_ref4) { | |
| _ref4.target.classList.contains("autocompleteEmails-label") || scope.$applyAsync(function() { | |
| scope.selected.autocompletesFocussed = !0, containsBCC(scope.selected) && (scope.message.ccbcc = !0, scope.message.attachmentsToggle = !0), _rAF(function() { | |
| return el.find("input").focus() | |
| }) | |
| }) | |
| }, | |
| onClickBtn = function(e) { | |
| e.stopPropagation(), isCurrentMsg() && scope.$applyAsync(function() { | |
| scope.message.ccbcc = !scope.message.ccbcc, scope.message.autocompletesFocussed = !0, scope.message.attachmentsToggle = !1 | |
| }) | |
| }; | |
| $btn.addEventListener("click", onClickBtn, !1), el.on("click", onClick), scope.$on("$destroy", function() { | |
| $btn.removeEventListener("click", onClickBtn, !1), el.off("click", onClick) | |
| }) | |
| } | |
| } | |
| } | |
| }), angular.module("proton.composer").directive("composerMessage", function() { | |
| return { | |
| replace: !0, | |
| scope: {}, | |
| templateUrl: "templates/partials/composer.tpl.html", | |
| controller: "ComposeMessageController" | |
| } | |
| }), angular.module("proton.composer").directive("composerSelectFrom", function(notification, authentication, editorModel, aboutClient, gettextCatalog) { | |
| var I18N = { | |
| ATTACHMENT_SEND_CHANGE: gettextCatalog.getString("Attachments and inline images must be removed first before changing sender", null, "Compose message") | |
| }, | |
| listAddress = function() { | |
| return _.chain(authentication.user.Addresses).where({ | |
| Status: 1, | |
| Receive: 1 | |
| }).sortBy("Order").value() | |
| }; | |
| return { | |
| scope: { | |
| message: "=model" | |
| }, | |
| replace: !0, | |
| templateUrl: "templates/directives/composer/composerSelectFrom.tpl.html", | |
| link: function(scope, el) { | |
| var $select = el.find("select"); | |
| scope.addresses = listAddress(); | |
| var onClick = function(e) { | |
| if (scope.message.Attachments.length) return e.preventDefault(), notification.error(I18N.ATTACHMENT_SEND_CHANGE) | |
| }, | |
| onChange = function() { | |
| scope.$applyAsync(function() { | |
| scope.message.AddressID = scope.message.From.ID, editorModel.find(scope.message).editor.fireEvent("refresh", { | |
| action: "message.changeFrom" | |
| }) | |
| }) | |
| }, | |
| onMouseDown = function() { | |
| return $select.focus() | |
| }; | |
| aboutClient.isIE11() && $select.on("mousedown", onMouseDown), el.on("click", onClick), el.on("change", onChange), scope.$on("$destroy", function() { | |
| aboutClient.isIE11() && $select.off("mousedown", onMouseDown), el.off("click", onClick), el.off("change", onChange) | |
| }) | |
| } | |
| } | |
| }), angular.module("proton.composer").directive("composerSubject", function(editorModel) { | |
| return { | |
| replace: !0, | |
| templateUrl: "templates/directives/composer/composerSubject.tpl.html", | |
| link: function(scope, el) { | |
| var $input = el[0].querySelector("input"), | |
| onFocus = function() { | |
| scope.$applyAsync(function() { | |
| scope.message.autocompletesFocussed = !1, scope.message.ccbcc = !1, scope.message.attachmentsToggle = !1 | |
| }) | |
| }, | |
| onKeydown = _.throttle(function(e) { | |
| if (9 === e.which) { | |
| if ("text/plain" === scope.message.MIMEType) return e.preventDefault(), el.parents(".composer").find("textarea").focus(); | |
| var _editorModel$find = editorModel.find(scope.message), | |
| editor = _editorModel$find.editor; | |
| editor && "text/plain" !== scope.message.MIMEType && (e.preventDefault(), editor.focus()) | |
| } | |
| }, 150), | |
| onBlur = function() { | |
| scope.$applyAsync(function() { | |
| return scope.saveLater(scope.message) | |
| }) | |
| }; | |
| $input.addEventListener("focus", onFocus, !0), $input.addEventListener("keydown", onKeydown, !1), $input.addEventListener("blur", onBlur, !1), scope.$on("$destroy", function() { | |
| $input.removeEventListener("focus", onFocus, !0), $input.removeEventListener("keydown", onKeydown, !1), $input.removeEventListener("blur", onBlur, !1) | |
| }) | |
| } | |
| } | |
| }), angular.module("proton.composer").directive("composerTime", function($rootScope, gettextCatalog) { | |
| var getTime = function(_ref) { | |
| var Time = _ref.Time; | |
| return moment.unix(Time).format("LT") | |
| }, | |
| I18N = { | |
| saveAt: gettextCatalog.getString("Saved at", null, "Info display in the composer footer"), | |
| saving: gettextCatalog.getString("Saving", null, "Info display in the composer footer") | |
| }; | |
| return { | |
| restrict: "E", | |
| replace: !0, | |
| template: '<time class="composerTime-container"></time>', | |
| link: function(scope, element) { | |
| var update = function(message) { | |
| if (message.saving) return void(element[0].textContent = I18N.saving); | |
| message.Time && (element[0].textContent = I18N.saveAt + " " + getTime(message)) | |
| }, | |
| unsubscribe = $rootScope.$on("actionMessage", function(event, message) { | |
| scope.message.ID === message.ID && update(message) | |
| }); | |
| update(scope.message), scope.$on("$destroy", unsubscribe) | |
| } | |
| } | |
| }), angular.module("proton.composer").directive("responsiveComposer", function($rootScope, authentication) { | |
| var latestState = {}, | |
| computeType = function(scope) { | |
| return function() { | |
| var width = window.innerWidth, | |
| height = window.innerHeight, | |
| isSmall = width <= 640 || height <= 600; | |
| scope.message.maximized && !latestState.isSmall || scope.message.minimized || (latestState.isSmall = isSmall, scope.$applyAsync(function() { | |
| $rootScope.small = height < 700 && height >= 600, $rootScope.mini = height < 600, isSmall && scope.maximize(scope.message), !isSmall && 0 === authentication.user.ComposerMode && scope.normalize(scope.message) | |
| })) | |
| } | |
| }; | |
| return { | |
| restrict: "A", | |
| link: function(scope) { | |
| var resizable = computeType(scope), | |
| onResize = _.debounce(resizable, 100), | |
| id = setTimeout(function() { | |
| resizable(), clearTimeout(id) | |
| }, 100); | |
| window.addEventListener("resize", onResize), scope.$on("$destroy", function() { | |
| window.removeEventListener("resize", onResize) | |
| }) | |
| } | |
| } | |
| }), angular.module("proton.composer").factory("composerLoader", function(editorModel, $rootScope) { | |
| function customFocus(el, scope, message) { | |
| if (el[0] && (!el[0].contains(document.activeElement) || el[0] === document.activeElement)) var id = setTimeout(function() { | |
| clearTimeout(id); | |
| var _scope$selected = scope.selected, | |
| _scope$selected$ToLis = _scope$selected.ToList, | |
| ToList = void 0 === _scope$selected$ToLis ? [] : _scope$selected$ToLis, | |
| _scope$selected$CCLis = _scope$selected.CCList, | |
| CCList = void 0 === _scope$selected$CCLis ? [] : _scope$selected$CCLis, | |
| _scope$selected$BCCLi = _scope$selected.BCCList; | |
| if (![].concat(ToList, CCList, void 0 === _scope$selected$BCCLi ? [] : _scope$selected$BCCLi).length) { | |
| var input = el.find(".toRow").find("input").eq(0); | |
| if (input.get(0)) return scope.$applyAsync(function() { | |
| scope.selected.autocompletesFocussed = !0, _rAF(function() { | |
| return input.focus() | |
| }) | |
| }) | |
| } | |
| if (!scope.selected.Subject.length) return el.find(".subject").focus(); | |
| if ("text/plain" === message.MIMEType) return el.find(".plaintext-editor").focus(); | |
| var _editorModel$find = editorModel.find(message), | |
| editor = _editorModel$find.editor; | |
| if (editor) return _rAF(function() { | |
| return editor.focus() | |
| }); | |
| var unsubscribe = $rootScope.$on("composer.update", function(e, _ref) { | |
| var type = _ref.type, | |
| data = _ref.data; | |
| "editor.loaded" === type && message.ID === data.message.ID && (data.editor.focus(), unsubscribe()) | |
| }) | |
| }, 300) | |
| } | |
| function focusMessage(scope) { | |
| return function(_ref2) { | |
| var composer = _ref2.composer, | |
| index = _ref2.index, | |
| message = _ref2.message, | |
| focusEditor = _ref2.focusEditor, | |
| _ref2$keepState = _ref2.keepState, | |
| keepState = void 0 === _ref2$keepState || _ref2$keepState; | |
| if (!message.focussed) { | |
| var messagesLength = scope.messages.length; | |
| if (_.each(scope.messages, function(msg, iteratee) { | |
| msg.focussed = !1, msg.zIndex = iteratee > index ? 100 * (messagesLength - (iteratee - index)) : 100 * messagesLength | |
| }), message.focussed = !0, scope.selected = message, !keepState && (scope.selected.autocompletesFocussed = !1), focusEditor) { | |
| return editorModel.find(message).editor.focus() | |
| }!keepState && customFocus(composer, scope, message) | |
| } | |
| } | |
| } | |
| return focusMessage | |
| }), angular.module("proton.composer").factory("composerRender", function() { | |
| function sizes(element, count) { | |
| var width = element.offsetWidth, | |
| margin = document.documentElement.classList.contains("ua-windows_nt") ? 40 : 20, | |
| windowWidth = document.body.offsetWidth, | |
| overlap = 0; | |
| return windowWidth / count < width && (overlap = (windowWidth - width - margin) / (count - 1)), { | |
| width: width, | |
| margin: margin, | |
| windowWidth: windowWidth, | |
| overlap: overlap | |
| } | |
| } | |
| function getPositionRight(_ref, index) { | |
| var width = _ref.width, | |
| margin = _ref.margin, | |
| overlap = _ref.overlap, | |
| right = overlap ? index * overlap : index * (width + margin) + margin; | |
| return parseInt(right, 10) || margin | |
| } | |
| function bindStyles(element, styles) { | |
| Object.keys(styles).forEach(function(key) { | |
| return element.style[key] = styles[key] | |
| }) | |
| } | |
| function render($list) { | |
| var _ref2 = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : {}, | |
| _ref2$size = _ref2.size, | |
| size = void 0 === _ref2$size ? 1 : _ref2$size; | |
| $list.forEach(function(node, index) { | |
| var config = sizes(node, size), | |
| styles = { | |
| visibility: "visible" | |
| }; | |
| styles.transform = "translateX(-" + getPositionRight(config, index) + "px)", bindStyles(node, styles) | |
| }) | |
| } | |
| function findComposer(node, _ref3) { | |
| var ID = _ref3.ID, | |
| composer = node.querySelector('[data-composer-id="' + ID + '"]'); | |
| return composer ? { | |
| composer: angular.element(composer), | |
| index: +composer.getAttribute("data-index") | |
| } : { | |
| composer: angular.element(node.querySelector(".composer")), | |
| index: 0 | |
| } | |
| } | |
| return { | |
| render: render, | |
| findComposer: findComposer | |
| } | |
| }), angular.module("proton.composer").factory("composerRequestModel", function($q) { | |
| var MAP_REQUEST = {}, | |
| read = function(key) { | |
| return MAP_REQUEST["key." + key] || [] | |
| }, | |
| clear = function(_ref) { | |
| var uid = _ref.uid; | |
| delete MAP_REQUEST["key." + uid] | |
| }; | |
| return { | |
| save: function(message, promise) { | |
| var key = "key." + message.uid; | |
| MAP_REQUEST[key] = MAP_REQUEST[key] || [], MAP_REQUEST[key].push(promise) | |
| }, | |
| clear: clear, | |
| chain: function(_ref2) { | |
| var uid = _ref2.uid, | |
| list = read(uid).map(function(_ref3) { | |
| return _ref3.promise | |
| }); | |
| return $q.all(list) | |
| } | |
| } | |
| }), angular.module("proton.composer").factory("outsidersMap", function() { | |
| var MAP = {}, | |
| set = function(key, value) { | |
| return MAP[key] = value | |
| }, | |
| get = function(key) { | |
| return MAP[key] | |
| }, | |
| remove = function(key) { | |
| return delete MAP[key] | |
| }; | |
| return { | |
| set: set, | |
| get: get, | |
| clear: function() { | |
| return MAP = {} | |
| }, | |
| remove: remove | |
| } | |
| }); | |
| var _slicedToArray = function() { | |
| function sliceIterator(arr, i) { | |
| var _arr = [], | |
| _n = !0, | |
| _d = !1, | |
| _e = void 0; | |
| try { | |
| for (var _s, _i = arr[Symbol.iterator](); !(_n = (_s = _i.next()).done) && (_arr.push(_s.value), !i || _arr.length !== i); _n = !0); | |
| } catch (err) { | |
| _d = !0, _e = err | |
| } finally { | |
| try { | |
| !_n && _i.return && _i.return() | |
| } finally { | |
| if (_d) throw _e | |
| } | |
| } | |
| return _arr | |
| } | |
| return function(arr, i) { | |
| if (Array.isArray(arr)) return arr; | |
| if (Symbol.iterator in Object(arr)) return sliceIterator(arr, i); | |
| throw new TypeError("Invalid attempt to destructure non-iterable instance") | |
| } | |
| }(); | |
| angular.module("proton.composer").factory("encryptMessage", function($rootScope, pmcw, srp, ComposerRequestStatus, outsidersMap, CONSTANTS, gettextCatalog) { | |
| var encryptFromPublicKeys = function() { | |
| var _ref17 = _asyncToGenerator(regeneratorRuntime.mark(function _callee7(message, emails, publicKeys) { | |
| var _ref18, sessionKey, dataPacket, _parseRecipients, promises, cleartext, packageSet; | |
| return regeneratorRuntime.wrap(function(_context7) { | |
| for (;;) switch (_context7.prev = _context7.next) { | |
| case 0: | |
| return _context7.next = 2, message.cleartextBodyPackets(); | |
| case 2: | |
| return _ref18 = _context7.sent, sessionKey = _ref18.sessionKey, dataPacket = _ref18.dataPacket, _parseRecipients = parseRecipients(message, emails, { | |
| sessionKey: sessionKey, | |
| dataPacket: dataPacket, | |
| publicKeys: publicKeys | |
| }), promises = _parseRecipients.promises, cleartext = _parseRecipients.cleartext, packageSet = _parseRecipients.packageSet, outsidersMap.set(message.ID, cleartext), _context7.abrupt("return", { | |
| cleartext: cleartext, | |
| encrypt: function() { | |
| return Promise.all(promises).then(function() { | |
| return [packageSet] | |
| }) | |
| } | |
| }); | |
| case 8: | |
| case "end": | |
| return _context7.stop() | |
| } | |
| }, _callee7, this) | |
| })); | |
| return function(_x7, _x8, _x9) { | |
| return _ref17.apply(this, arguments) | |
| } | |
| }(), | |
| encryptFromEmails = function() { | |
| var _ref19 = _asyncToGenerator(regeneratorRuntime.mark(function _callee8(message, emails) { | |
| var uniqueEmails, _ref20, data; | |
| return regeneratorRuntime.wrap(function(_context8) { | |
| for (;;) switch (_context8.prev = _context8.next) { | |
| case 0: | |
| return _context8.prev = 0, uniqueEmails = _.uniq(emails), _context8.next = 4, message.getPublicKeys(uniqueEmails); | |
| case 4: | |
| if (_ref20 = _context8.sent, data = _ref20.data, data.Code === ComposerRequestStatus.SUCCESS) { | |
| _context8.next = 8; | |
| break | |
| } | |
| throw new Error(data.Error || ERROR_REQUEST_KEYS); | |
| case 8: | |
| return _context8.abrupt("return", encryptFromPublicKeys(message, uniqueEmails, data)); | |
| case 11: | |
| throw _context8.prev = 11, _context8.t0 = _context8.catch(0), console.error("Cannot encrypt message", _context8.t0), message.encrypting = !1, dispatchMessageAction(message), _context8.t0; | |
| case 17: | |
| case "end": | |
| return _context8.stop() | |
| } | |
| }, _callee8, this, [ | |
| [0, 11] | |
| ]) | |
| })); | |
| return function(_x10, _x11) { | |
| return _ref19.apply(this, arguments) | |
| } | |
| }(), | |
| SEND_TYPES = CONSTANTS.SEND_TYPES, | |
| ERROR_REQUEST_KEYS = gettextCatalog.getString("Cannot get public keys", null, "Encrypt message"), | |
| dispatchMessageAction = function(message) { | |
| return $rootScope.$emit("actionMessage", message) | |
| }, | |
| cleartextUser = function() { | |
| var _ref = _asyncToGenerator(regeneratorRuntime.mark(function _callee() { | |
| return regeneratorRuntime.wrap(function(_context) { | |
| for (;;) switch (_context.prev = _context.next) { | |
| case 0: | |
| return _context.abrupt("return", { | |
| Type: SEND_TYPES.SEND_CLEAR, | |
| Signature: 0 | |
| }); | |
| case 1: | |
| case "end": | |
| return _context.stop() | |
| } | |
| }, _callee, void 0) | |
| })); | |
| return function() { | |
| return _ref.apply(this, arguments) | |
| } | |
| }(), | |
| getCleartextBodyKeyPacket = function(_ref2) { | |
| var data = _ref2.data; | |
| return _asyncToGenerator(regeneratorRuntime.mark(function _callee2() { | |
| return regeneratorRuntime.wrap(function(_context2) { | |
| for (;;) switch (_context2.prev = _context2.next) { | |
| case 0: | |
| return _context2.abrupt("return", pmcw.encode_base64(pmcw.arrayToBinaryString(data))); | |
| case 1: | |
| case "end": | |
| return _context2.stop() | |
| } | |
| }, _callee2, void 0) | |
| })) | |
| }, | |
| encryptBodyKeyPacket = function() { | |
| var _ref4 = _asyncToGenerator(regeneratorRuntime.mark(function _callee3(_ref5) { | |
| var _ref6, message, _ref5$sessionKey = _ref5.sessionKey, | |
| sessionKey = void 0 === _ref5$sessionKey ? {} : _ref5$sessionKey, | |
| _ref5$publicKeys = _ref5.publicKeys, | |
| publicKeys = void 0 === _ref5$publicKeys ? [] : _ref5$publicKeys, | |
| _ref5$passwords = _ref5.passwords, | |
| passwords = void 0 === _ref5$passwords ? [] : _ref5$passwords; | |
| return regeneratorRuntime.wrap(function(_context3) { | |
| for (;;) switch (_context3.prev = _context3.next) { | |
| case 0: | |
| return _context3.next = 2, pmcw.encryptSessionKey({ | |
| data: sessionKey.data, | |
| algorithm: sessionKey.algorithm, | |
| publicKeys: publicKeys.length > 0 ? pmcw.getKeys(publicKeys) : [], | |
| passwords: passwords | |
| }); | |
| case 2: | |
| return _ref6 = _context3.sent, message = _ref6.message, _context3.abrupt("return", pmcw.encode_base64(pmcw.arrayToBinaryString(message.packets.write()))); | |
| case 5: | |
| case "end": | |
| return _context3.stop() | |
| } | |
| }, _callee3, void 0) | |
| })); | |
| return function(_x) { | |
| return _ref4.apply(this, arguments) | |
| } | |
| }(), | |
| insideUser = function() { | |
| var _ref7 = _asyncToGenerator(regeneratorRuntime.mark(function _callee4(message, publicKey, sessionKey) { | |
| var _ref8, _ref9, BodyKeyPacket, AttachmentKeyPackets; | |
| return regeneratorRuntime.wrap(function(_context4) { | |
| for (;;) switch (_context4.prev = _context4.next) { | |
| case 0: | |
| return _context4.next = 2, Promise.all([encryptBodyKeyPacket({ | |
| sessionKey: sessionKey, | |
| publicKeys: publicKey | |
| }), message.encryptAttachmentKeyPackets(publicKey)]); | |
| case 2: | |
| return _ref8 = _context4.sent, _ref9 = _slicedToArray(_ref8, 2), BodyKeyPacket = _ref9[0], AttachmentKeyPackets = _ref9[1], _context4.abrupt("return", { | |
| Type: CONSTANTS.SEND_TYPES.SEND_PM, | |
| BodyKeyPacket: BodyKeyPacket, | |
| AttachmentKeyPackets: AttachmentKeyPackets, | |
| Signature: 0 | |
| }); | |
| case 7: | |
| case "end": | |
| return _context4.stop() | |
| } | |
| }, _callee4, void 0) | |
| })); | |
| return function(_x2, _x3, _x4) { | |
| return _ref7.apply(this, arguments) | |
| } | |
| }(), | |
| encryptedOutsideUser = function() { | |
| var _ref10 = _asyncToGenerator(regeneratorRuntime.mark(function _callee5(message, sessionKey) { | |
| var Token, _ref11, _ref12, EncToken, BodyKeyPacket, AttachmentKeyPackets, verifier; | |
| return regeneratorRuntime.wrap(function(_context5) { | |
| for (;;) switch (_context5.prev = _context5.next) { | |
| case 0: | |
| return _context5.prev = 0, Token = message.generateReplyToken(), _context5.next = 4, Promise.all([pmcw.encryptMessage({ | |
| data: Token, | |
| publicKeys: [], | |
| passwords: [message.Password] | |
| }), encryptBodyKeyPacket({ | |
| passwords: message.Password, | |
| sessionKey: sessionKey | |
| }), message.encryptAttachmentKeyPackets([], [message.Password]), srp.randomVerifier(message.Password)]); | |
| case 4: | |
| return _ref11 = _context5.sent, _ref12 = _slicedToArray(_ref11, 4), EncToken = _ref12[0].data, BodyKeyPacket = _ref12[1], AttachmentKeyPackets = _ref12[2], verifier = _ref12[3], _context5.abrupt("return", { | |
| Auth: verifier.Auth, | |
| Type: SEND_TYPES.SEND_EO, | |
| PasswordHint: message.PasswordHint, | |
| Token: Token, | |
| EncToken: EncToken, | |
| BodyKeyPacket: BodyKeyPacket, | |
| AttachmentKeyPackets: AttachmentKeyPackets, | |
| Signature: 0 | |
| }); | |
| case 13: | |
| throw _context5.prev = 13, _context5.t0 = _context5.catch(0), message.encrypting = !1, dispatchMessageAction(message), console.error(_context5.t0), _context5.t0; | |
| case 19: | |
| case "end": | |
| return _context5.stop() | |
| } | |
| }, _callee5, void 0, [ | |
| [0, 13] | |
| ]) | |
| })); | |
| return function(_x5, _x6) { | |
| return _ref10.apply(this, arguments) | |
| } | |
| }(), | |
| parseRecipients = function(message, emails, _ref13) { | |
| var publicKeys = _ref13.publicKeys, | |
| sessionKey = _ref13.sessionKey, | |
| dataPacket = _ref13.dataPacket, | |
| packageSet = { | |
| Type: 0, | |
| Addresses: {}, | |
| MIMEType: message.MIMEType || "text/html", | |
| Body: pmcw.encode_base64(pmcw.arrayToBinaryString(dataPacket[0])) | |
| }, | |
| cleartextBodyKeyPacket = getCleartextBodyKeyPacket(sessionKey), | |
| bindPackageSet = function(promise, email) { | |
| return promise.then(function(pkg) { | |
| packageSet.Addresses[email] = pkg, packageSet.Type |= pkg.Type | |
| }) | |
| }, | |
| _emails$reduce = emails.reduce(function(acc, email) { | |
| return publicKeys[email] && publicKeys[email].length > 0 ? (acc.promises.push(bindPackageSet(insideUser(message, publicKeys[email], sessionKey), email)), acc) : 1 === message.IsEncrypted ? (acc.promises.push(bindPackageSet(encryptedOutsideUser(message, sessionKey), email)), acc) : (acc.cleartext = !0, acc.promises.push(bindPackageSet(cleartextUser(), email)), acc) | |
| }, { | |
| cleartext: !1, | |
| promises: [] | |
| }), | |
| promises = _emails$reduce.promises, | |
| cleartext = _emails$reduce.cleartext; | |
| if (cleartext) { | |
| var cleartextBodyAttachments = function() { | |
| var _ref14 = _asyncToGenerator(regeneratorRuntime.mark(function _callee6() { | |
| var _ref15, _ref16, bodyKey, attachmentKeys; | |
| return regeneratorRuntime.wrap(function(_context6) { | |
| for (;;) switch (_context6.prev = _context6.next) { | |
| case 0: | |
| return _context6.next = 2, Promise.all([cleartextBodyKeyPacket(), message.cleartextAttachmentKeyPackets()]); | |
| case 2: | |
| _ref15 = _context6.sent, _ref16 = _slicedToArray(_ref15, 2), bodyKey = _ref16[0], attachmentKeys = _ref16[1], packageSet.BodyKey = bodyKey, packageSet.AttachmentKeys = attachmentKeys; | |
| case 8: | |
| case "end": | |
| return _context6.stop() | |
| } | |
| }, _callee6, void 0) | |
| })); | |
| return function() { | |
| return _ref14.apply(this, arguments) | |
| } | |
| }(); | |
| promises.push(cleartextBodyAttachments()) | |
| } | |
| return { | |
| promises: promises, | |
| cleartext: cleartext, | |
| packageSet: packageSet | |
| } | |
| }; | |
| return encryptFromEmails | |
| }); | |
| var _slicedToArray = function() { | |
| function sliceIterator(arr, i) { | |
| var _arr = [], | |
| _n = !0, | |
| _d = !1, | |
| _e = void 0; | |
| try { | |
| for (var _s, _i = arr[Symbol.iterator](); !(_n = (_s = _i.next()).done) && (_arr.push(_s.value), !i || _arr.length !== i); _n = !0); | |
| } catch (err) { | |
| _d = !0, _e = err | |
| } finally { | |
| try { | |
| !_n && _i.return && _i.return() | |
| } finally { | |
| if (_d) throw _e | |
| } | |
| } | |
| return _arr | |
| } | |
| return function(arr, i) { | |
| if (Array.isArray(arr)) return arr; | |
| if (Symbol.iterator in Object(arr)) return sliceIterator(arr, i); | |
| throw new TypeError("Invalid attempt to destructure non-iterable instance") | |
| } | |
| }(); | |
| angular.module("proton.composer").factory("extractDataURI", function(attachmentModel, embedded) { | |
| function dataURItoBlob() { | |
| for (var dataURI = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : "", _dataURI$split = dataURI.split(","), _dataURI$split2 = _slicedToArray(_dataURI$split, 2), _dataURI$split2$ = _dataURI$split2[0], mime = void 0 === _dataURI$split2$ ? "" : _dataURI$split2$, _dataURI$split2$2 = _dataURI$split2[1], byte = void 0 === _dataURI$split2$2 ? "" : _dataURI$split2$2, byteString = atob(byte), mimeString = mime.split(":")[1].split(";")[0], ab = new ArrayBuffer(byteString.length), dw = new DataView(ab), i = 0; i < byteString.length; i++) dw.setUint8(i, byteString.charCodeAt(i)); | |
| return new Blob([ab], { | |
| type: mimeString | |
| }) | |
| } | |
| return function() { | |
| var _ref = _asyncToGenerator(regeneratorRuntime.mark(function _callee(message) { | |
| var content, testDiv, images, promises; | |
| return regeneratorRuntime.wrap(function(_context) { | |
| for (;;) switch (_context.prev = _context.next) { | |
| case 0: | |
| if ("text/plain" !== message.MIMEType) { | |
| _context.next = 2; | |
| break | |
| } | |
| return _context.abrupt("return", message); | |
| case 2: | |
| return content = message.getDecryptedBody(), testDiv = document.createElement("DIV"), testDiv.innerHTML = content, images = testDiv.querySelectorAll("img"), promises = _.chain([].slice.call(images)).filter(function(_ref2) { | |
| return /data:image/.test(_ref2.src) | |
| }).filter(function(_ref3) { | |
| return _ref3.src.includes(",") | |
| }).map(function(image) { | |
| var cid = embedded.generateCid(image.src, message.From.Email), | |
| setEmbeddedImg = function() { | |
| return image.setAttribute("data-embedded-img", cid), Promise.resolve() | |
| }; | |
| if (embedded.exist(message, cid)) return setEmbeddedImg(); | |
| var file = dataURItoBlob(image.src); | |
| return file.name = image.alt || "image" + Date.now(), file.inline = 1, attachmentModel.create(file, message, !0, cid).then(setEmbeddedImg) | |
| }).value(), _context.next = 9, Promise.all(promises); | |
| case 9: | |
| return message.setDecryptedBody(testDiv.innerHTML), _context.abrupt("return", message); | |
| case 11: | |
| case "end": | |
| return _context.stop() | |
| } | |
| }, _callee, this) | |
| })); | |
| return function(_x2) { | |
| return _ref.apply(this, arguments) | |
| } | |
| }() | |
| }), angular.module("proton.composer").factory("messageRequest", function($rootScope, messageApi, ComposerRequestStatus, CONSTANTS, gettextCatalog) { | |
| function getSendError(data) { | |
| return _.has(data, "data") ? getSendError(data.data) : data.ErrorDescription ? new Error(data.Error + ": " + data.ErrorDescription) : new Error(data.Error || I18N.ERROR_SENDING) | |
| } | |
| var draft = function() { | |
| var _ref = _asyncToGenerator(regeneratorRuntime.mark(function _callee(parameters, message, type) { | |
| var _ref2, data; | |
| return regeneratorRuntime.wrap(function(_context) { | |
| for (;;) switch (_context.prev = _context.next) { | |
| case 0: | |
| return _context.next = 2, getEditPromise(type, parameters); | |
| case 2: | |
| if (_ref2 = _context.sent, data = _ref2.data, data.Code !== ComposerRequestStatus.SUCCESS && data.Code !== ComposerRequestStatus.DRAFT_NOT_EXIST) { | |
| _context.next = 6; | |
| break | |
| } | |
| return _context.abrupt("return", data); | |
| case 6: | |
| if (data.Code !== ComposerRequestStatus.MESSAGE_ALREADY_SEND) { | |
| _context.next = 8; | |
| break | |
| } | |
| return _context.abrupt("return", dispatch("close.message", { | |
| message: message | |
| })); | |
| case 8: | |
| throw new Error(data.Error || I18N.ERROR_REQUEST_DRAFT); | |
| case 9: | |
| case "end": | |
| return _context.stop() | |
| } | |
| }, _callee, this) | |
| })); | |
| return function(_x3, _x4, _x5) { | |
| return _ref.apply(this, arguments) | |
| } | |
| }(), | |
| send = function() { | |
| var _ref3 = _asyncToGenerator(regeneratorRuntime.mark(function _callee2(parameters) { | |
| var _ref4, _ref4$data, data, err; | |
| return regeneratorRuntime.wrap(function(_context2) { | |
| for (;;) switch (_context2.prev = _context2.next) { | |
| case 0: | |
| return _context2.prev = 0, _context2.next = 3, messageApi.send(parameters); | |
| case 3: | |
| return _ref4 = _context2.sent, _ref4$data = _ref4.data, data = void 0 === _ref4$data ? {} : _ref4$data, _context2.abrupt("return", data); | |
| case 9: | |
| throw _context2.prev = 9, _context2.t0 = _context2.catch(0), err = getSendError(_context2.t0), err.code = _context2.t0.Code, err; | |
| case 14: | |
| case "end": | |
| return _context2.stop() | |
| } | |
| }, _callee2, this, [ | |
| [0, 9] | |
| ]) | |
| })); | |
| return function(_x6) { | |
| return _ref3.apply(this, arguments) | |
| } | |
| }(), | |
| STATUS = CONSTANTS.STATUS, | |
| I18N = { | |
| ERROR_REQUEST_DRAFT: gettextCatalog.getString("Saving draft failed, please try again", null, "Error"), | |
| ERROR_SENDING: gettextCatalog.getString("Cannot send message", null, "Error") | |
| }, | |
| dispatch = function(type) { | |
| var data = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : {}; | |
| return $rootScope.$emit("composer.update", { | |
| type: type, | |
| data: data | |
| }) | |
| }, | |
| getEditPromise = function() { | |
| var type = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : STATUS.CREATE, | |
| parameters = arguments[1]; | |
| return type === STATUS.UPDATE ? messageApi.updateDraft(parameters) : messageApi.createDraft(parameters) | |
| }; | |
| return { | |
| draft: draft, | |
| send: send | |
| } | |
| }), angular.module("proton.composer").factory("onCurrentMessage", function($rootScope) { | |
| var isCurrent = function(_ref) { | |
| var _ref$message = _ref.message, | |
| message = void 0 === _ref$message ? {} : _ref$message, | |
| _ref2 = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : {}, | |
| _ref2$ID = _ref2.ID; | |
| return (void 0 === _ref2$ID ? "editor" : _ref2$ID) === (message.ID || "editor") | |
| }, | |
| onCurrentMessage = function(scope, cb) { | |
| return function(e, _ref3) { | |
| var type = _ref3.type, | |
| _ref3$data = _ref3.data, | |
| data = void 0 === _ref3$data ? {} : _ref3$data; | |
| isCurrent(scope, data.message) && cb(type, data) | |
| } | |
| }; | |
| return function(event, scope, cb) { | |
| return $rootScope.$on(event, onCurrentMessage(scope, cb)) | |
| } | |
| }); | |
| var _slicedToArray = function() { | |
| function sliceIterator(arr, i) { | |
| var _arr = [], | |
| _n = !0, | |
| _d = !1, | |
| _e = void 0; | |
| try { | |
| for (var _s, _i = arr[Symbol.iterator](); !(_n = (_s = _i.next()).done) && (_arr.push(_s.value), !i || _arr.length !== i); _n = !0); | |
| } catch (err) { | |
| _d = !0, _e = err | |
| } finally { | |
| try { | |
| !_n && _i.return && _i.return() | |
| } finally { | |
| if (_d) throw _e | |
| } | |
| } | |
| return _arr | |
| } | |
| return function(arr, i) { | |
| if (Array.isArray(arr)) return arr; | |
| if (Symbol.iterator in Object(arr)) return sliceIterator(arr, i); | |
| throw new TypeError("Invalid attempt to destructure non-iterable instance") | |
| } | |
| }(); | |
| angular.module("proton.composer").factory("postMessage", function(CONSTANTS, $rootScope, messageRequest, ComposerRequestStatus, cache, notify, gettextCatalog, messageApi, composerRequestModel, embedded, outsidersMap, networkActivityTracker, $filter) { | |
| function syncAttachmentsRemote(collection, list) { | |
| var map = collection.reduce(function(acc, att) { | |
| return acc[att.ID] = att, att.AttachmentID && (acc[att.AttachmentID] = att), acc | |
| }, {}); | |
| return list.reduce(function(acc) { | |
| var att = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : {}; | |
| return acc.push(_.extend({}, map[att.ID], att)), acc | |
| }, []) | |
| } | |
| var STATUS = CONSTANTS.STATUS, | |
| I18N = { | |
| SAVE_MESSAGE_SUCCESS: gettextCatalog.getString("Message saved", null, "Record message") | |
| }, | |
| unicodeTagView = $filter("unicodeTagView"), | |
| dispatchMessageAction = function(message) { | |
| return $rootScope.$emit("actionMessage", message) | |
| }, | |
| makeParams = function(message, autosaving) { | |
| var parameters = { | |
| Message: _.pick(message, "ToList", "CCList", "BCCList", "Subject", "IsRead", "MIMEType") | |
| }; | |
| return parameters.Message.Subject = parameters.Message.Subject || "", message.saving = !0, message.autosaving = autosaving, dispatchMessageAction(message), angular.isString(parameters.Message.ToList) && (parameters.Message.ToList = []), angular.isString(parameters.Message.CCList) && (parameters.Message.CCList = []), angular.isString(parameters.Message.BCCList) && (parameters.Message.BCCList = []), angular.isDefined(message.ParentID) && (parameters.ParentID = message.ParentID, parameters.Action = message.Action), angular.isDefined(message.ID) ? parameters.id = message.ID : parameters.Message.IsRead = 1, !1 === autosaving && (parameters.Message.IsRead = 1), parameters.Message.AddressID = message.AddressID, parameters | |
| }, | |
| saveDraft = function() { | |
| var _ref = _asyncToGenerator(regeneratorRuntime.mark(function _callee(message, _ref2) { | |
| var data, Message, Code, conversation, contextNumUnread, numMessages, firstConversation, events, _ref3, _ref3$data, _data, actionType = _ref2.actionType, | |
| parameters = _ref2.parameters, | |
| notification = _ref2.notification; | |
| return regeneratorRuntime.wrap(function(_context) { | |
| for (;;) switch (_context.prev = _context.next) { | |
| case 0: | |
| return _context.next = 2, messageRequest.draft(parameters, message, actionType); | |
| case 2: | |
| if (data = _context.sent, Message = data.Message, Code = data.Code, Code !== ComposerRequestStatus.SUCCESS) { | |
| _context.next = 25; | |
| break | |
| } | |
| return conversation = cache.getConversationCached(Message.ConversationID) || {}, contextNumUnread = conversation.ContextNumUnread || 0, numMessages = void 0, actionType === STATUS.CREATE ? (numMessages = (conversation.NumMessages || 0) + 1, message.ID = Message.ID) : actionType === STATUS.UPDATE && (numMessages = conversation.NumMessages || 0), message.IsRead = Message.IsRead, message.Time = Message.Time, message.Type = Message.Type, message.LabelIDs = Message.LabelIDs, Message.Attachments.length > 0 && (message.Attachments = syncAttachmentsRemote(message.Attachments, Message.Attachments)), Message.Senders = [Message.Sender], Message.Recipients = _.uniq(Message.ToList.concat(Message.CCList, Message.BCCList)), firstConversation = { | |
| Recipients: Message.Recipients, | |
| Senders: Message.Senders, | |
| Subject: Message.Subject | |
| }, events = [{ | |
| Action: actionType, | |
| ID: Message.ID, | |
| Message: Message | |
| }], events.push({ | |
| Action: STATUS.UPDATE_FLAGS, | |
| ID: Message.ConversationID, | |
| Conversation: angular.extend({ | |
| NumAttachments: Message.Attachments.length, | |
| NumMessages: numMessages, | |
| ContextNumUnread: contextNumUnread, | |
| ID: Message.ConversationID, | |
| LabelIDsAdded: [CONSTANTS.MAILBOX_IDENTIFIERS.allDrafts, CONSTANTS.MAILBOX_IDENTIFIERS.drafts] | |
| }, 1 === numMessages ? firstConversation : {}) | |
| }), cache.events(events), !0 === notification && notify({ | |
| message: I18N.SAVE_MESSAGE_SUCCESS, | |
| classes: "notification-success" | |
| }), message.saving = !1, message.autosaving = !1, dispatchMessageAction(message), _context.abrupt("return", Message); | |
| case 25: | |
| if (Code !== ComposerRequestStatus.DRAFT_NOT_EXIST) { | |
| _context.next = 33; | |
| break | |
| } | |
| return delete parameters.id, _context.next = 29, messageApi.createDraft(parameters); | |
| case 29: | |
| return _ref3 = _context.sent, _ref3$data = _ref3.data, _data = void 0 === _ref3$data ? {} : _ref3$data, _context.abrupt("return", _data.Message); | |
| case 33: | |
| case "end": | |
| return _context.stop() | |
| } | |
| }, _callee, void 0) | |
| })); | |
| return function(_x2, _x3) { | |
| return _ref.apply(this, arguments) | |
| } | |
| }(), | |
| save = function() { | |
| var _ref4 = _asyncToGenerator(regeneratorRuntime.mark(function _callee2(message, _ref5) { | |
| var parameters, _ref6, _ref7, _ref7$, ID, body, encryptedBody, actionType, notification = _ref5.notification, | |
| autosaving = _ref5.autosaving; | |
| return regeneratorRuntime.wrap(function(_context2) { | |
| for (;;) switch (_context2.prev = _context2.next) { | |
| case 0: | |
| return _context2.prev = 0, parameters = makeParams(message, autosaving), _context2.next = 4, composerRequestModel.chain(message); | |
| case 4: | |
| return _ref6 = _context2.sent, _ref7 = _slicedToArray(_ref6, 1), _ref7$ = _ref7[0], _ref7$ = void 0 === _ref7$ ? {} : _ref7$, ID = _ref7$.ID, ID && (message.ID = ID, parameters.id = ID), _context2.next = 12, embedded.parser(message, { | |
| direction: "cid", | |
| isOutside: outsidersMap.get(message.ID) | |
| }); | |
| case 12: | |
| return body = _context2.sent, message.setDecryptedBody(body, !message.isPlainText()), _context2.next = 16, message.encryptBody(message.From.Keys[0].PublicKey); | |
| case 16: | |
| return encryptedBody = _context2.sent, actionType = message.ID ? STATUS.UPDATE : STATUS.CREATE, parameters.Message.Body = encryptedBody, _context2.next = 21, saveDraft(message, { | |
| actionType: actionType, | |
| parameters: parameters, | |
| notification: notification | |
| }); | |
| case 21: | |
| return _context2.abrupt("return", _context2.sent); | |
| case 24: | |
| throw _context2.prev = 24, _context2.t0 = _context2.catch(0), message.saving = !1, message.autosaving = !1, dispatchMessageAction(message), composerRequestModel.clear(message), _context2.t0; | |
| case 31: | |
| case "end": | |
| return _context2.stop() | |
| } | |
| }, _callee2, void 0, [ | |
| [0, 24] | |
| ]) | |
| })); | |
| return function(_x4, _x5) { | |
| return _ref4.apply(this, arguments) | |
| } | |
| }(); | |
| return function() { | |
| var _ref8 = _asyncToGenerator(regeneratorRuntime.mark(function _callee3(message) { | |
| var promise, _message, _ref9 = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : {}, | |
| _ref9$notification = _ref9.notification, | |
| notification = void 0 !== _ref9$notification && _ref9$notification, | |
| _ref9$autosaving = _ref9.autosaving, | |
| autosaving = void 0 !== _ref9$autosaving && _ref9$autosaving, | |
| _ref9$loader = _ref9.loader, | |
| loader = void 0 === _ref9$loader || _ref9$loader; | |
| return regeneratorRuntime.wrap(function(_context3) { | |
| for (;;) switch (_context3.prev = _context3.next) { | |
| case 0: | |
| return _context3.prev = 0, promise = save(message, { | |
| notification: notification, | |
| autosaving: autosaving | |
| }), (!1 === autosaving || loader) && networkActivityTracker.track(promise), composerRequestModel.save(message, promise), _context3.next = 6, promise; | |
| case 6: | |
| return _context3.abrupt("return", _context3.sent); | |
| case 9: | |
| if (_context3.prev = 9, _context3.t0 = _context3.catch(0), _message = unicodeTagView(_context3.t0.message), !autosaving) { | |
| _context3.next = 14; | |
| break | |
| } | |
| return _context3.abrupt("return", notify({ | |
| message: _message, | |
| classes: "notification-danger" | |
| })); | |
| case 14: | |
| throw new Error(_message); | |
| case 15: | |
| case "end": | |
| return _context3.stop() | |
| } | |
| }, _callee3, void 0, [ | |
| [0, 9] | |
| ]) | |
| })); | |
| return function(_x6) { | |
| return _ref8.apply(this, arguments) | |
| } | |
| }() | |
| }), angular.module("proton.composer").factory("sendMessage", function(CONSTANTS, messageModel, gettextCatalog, encryptMessage, messageRequest, notification, cache, $rootScope) { | |
| var STATUS = CONSTANTS.STATUS, | |
| I18N = { | |
| SEND_SUCCESS: gettextCatalog.getString("Message sent", null, "Send message"), | |
| EXPIRE_ERROR: gettextCatalog.getString("Expiring emails to non-ProtonMail recipients require a message password to be set. For more information, {{link}}click here", { | |
| link: '<a href="https://protonmail.com/support/knowledge-base/expiration/" target="_blank">' | |
| }, "Send message") | |
| }, | |
| dispatchMessageAction = function(message) { | |
| return $rootScope.$emit("actionMessage", message) | |
| }, | |
| prepare = function(message, parameters) { | |
| return message.encrypting = !0, dispatchMessageAction(message), parameters.id = message.ID, parameters.ExpirationTime = message.ExpirationTime, message.emailsToString() | |
| }, | |
| send = function() { | |
| var _ref = _asyncToGenerator(regeneratorRuntime.mark(function _callee(message, parameters) { | |
| var emails, _ref2, encrypt, cleartext, error, packages; | |
| return regeneratorRuntime.wrap(function(_context) { | |
| for (;;) switch (_context.prev = _context.next) { | |
| case 0: | |
| return emails = prepare(message, parameters), _context.next = 3, encryptMessage(message, emails); | |
| case 3: | |
| if (_ref2 = _context.sent, encrypt = _ref2.encrypt, !(cleartext = _ref2.cleartext) || message.Password.length || !message.ExpirationTime) { | |
| _context.next = 10; | |
| break | |
| } | |
| throw error = new Error(I18N.EXPIRE_ERROR + "</a>."), error.raw = !0, error; | |
| case 10: | |
| return _context.next = 12, encrypt(); | |
| case 12: | |
| return packages = _context.sent, parameters.Packages = packages, message.encrypting = !1, dispatchMessageAction(message), _context.abrupt("return", messageRequest.send(parameters)); | |
| case 17: | |
| case "end": | |
| return _context.stop() | |
| } | |
| }, _callee, void 0) | |
| })); | |
| return function(_x, _x2) { | |
| return _ref.apply(this, arguments) | |
| } | |
| }(); | |
| return function() { | |
| var _ref3 = _asyncToGenerator(regeneratorRuntime.mark(function _callee2(message) { | |
| var _ref4, Parent, _ref4$Sent, Sent, conversation, NumMessages, ContextNumUnread, events, parameters = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : {}; | |
| return regeneratorRuntime.wrap(function(_context2) { | |
| for (;;) switch (_context2.prev = _context2.next) { | |
| case 0: | |
| return _context2.next = 2, send(message, parameters); | |
| case 2: | |
| _ref4 = _context2.sent, Parent = _ref4.Parent, _ref4$Sent = _ref4.Sent, Sent = void 0 === _ref4$Sent ? {} : _ref4$Sent, $rootScope.$emit("composer.update", { | |
| type: "send.success", | |
| data: { | |
| message: message, | |
| discard: !1, | |
| save: !1 | |
| } | |
| }), conversation = cache.getConversationCached(Sent.ConversationID), NumMessages = angular.isDefined(conversation) ? conversation.NumMessages : 1, ContextNumUnread = angular.isDefined(conversation) ? conversation.ContextNumUnread : 0, Sent.Senders = [Sent.Sender], Sent.Recipients = _.uniq(message.ToList.concat(message.CCList, message.BCCList)), events = [{ | |
| Action: STATUS.UPDATE_FLAGS, | |
| ID: Sent.ID, | |
| Message: Sent | |
| }], Parent && events.push({ | |
| Action: STATUS.UPDATE_FLAGS, | |
| ID: Parent.ID, | |
| Message: Parent | |
| }), events.push({ | |
| Action: STATUS.UPDATE_FLAGS, | |
| ID: Sent.ConversationID, | |
| Conversation: { | |
| NumMessages: NumMessages, | |
| ContextNumUnread: ContextNumUnread, | |
| Recipients: Sent.Recipients, | |
| Senders: Sent.Senders, | |
| Subject: Sent.Subject, | |
| ID: Sent.ConversationID, | |
| LabelIDsAdded: [CONSTANTS.MAILBOX_IDENTIFIERS.allSent, CONSTANTS.MAILBOX_IDENTIFIERS.sent], | |
| LabelIDsRemoved: [CONSTANTS.MAILBOX_IDENTIFIERS.allDrafts, CONSTANTS.MAILBOX_IDENTIFIERS.drafts] | |
| } | |
| }), notification.success(I18N.SEND_SUCCESS), cache.events(events, !1, !0), _.delay(function() { | |
| $rootScope.$emit("message.open", { | |
| type: "save.success", | |
| data: { | |
| message: messageModel(Sent) | |
| } | |
| }) | |
| }, 500); | |
| case 18: | |
| case "end": | |
| return _context2.stop() | |
| } | |
| }, _callee2, void 0) | |
| })); | |
| return function(_x3) { | |
| return _ref3.apply(this, arguments) | |
| } | |
| }() | |
| }), angular.module("proton.composer").factory("validateMessage", function(gettextCatalog, tools, regexEmail, CONSTANTS, confirmModal, authentication, notification, addressWithoutKeys) { | |
| function canWrite() { | |
| return authentication.user.Delinquent >= UNPAID_STATE.DELINQUENT ? notification.error(I18N.ERROR_DELINQUENT) : !addressWithoutKeys.allDirty() || notification.error(I18N.ERROR_ADDRESSES + "<br>" + getErrorInfo()) | |
| } | |
| var validate = function() { | |
| var _ref = _asyncToGenerator(regeneratorRuntime.mark(function _callee(message) { | |
| var emailStats; | |
| return regeneratorRuntime.wrap(function(_context) { | |
| for (;;) switch (_context.prev = _context.next) { | |
| case 0: | |
| if ("text/plain" !== message.MIMEType && message.setDecryptedBody(tools.fixImages(message.getDecryptedBody())), !(message.uploading > 0)) { | |
| _context.next = 3; | |
| break | |
| } | |
| throw new Error(I18N.STILL_UPLOADING); | |
| case 3: | |
| if (cleanEmails(message), emailStats = message.ToList.concat(message.CCList, message.BCCList).reduce(function(acc, _ref2) { | |
| var _ref2$Address = _ref2.Address, | |
| Address = void 0 === _ref2$Address ? "" : _ref2$Address; | |
| return acc.all.push(Address), !regexEmail.test(Address) && acc.invalid.push(Address), acc.total++, acc | |
| }, { | |
| all: [], | |
| invalid: [], | |
| total: 0 | |
| }), !emailStats.invalid.length) { | |
| _context.next = 7; | |
| break | |
| } | |
| throw new Error(I18N.invalidEmails(emailStats.invalid.join(","))); | |
| case 7: | |
| if (!(emailStats.total > 25)) { | |
| _context.next = 9; | |
| break | |
| } | |
| throw new Error(I18N.maxRecipients(emailStats.total)); | |
| case 9: | |
| if (emailStats.total) { | |
| _context.next = 11; | |
| break | |
| } | |
| throw new Error(I18N.NO_RECIPIENT); | |
| case 11: | |
| if (!(message.Subject && message.Subject.length > MAX_TITLE_LENGTH)) { | |
| _context.next = 13; | |
| break | |
| } | |
| throw new Error(I18N.MAX_SUBJECT_LENGTH); | |
| case 13: | |
| if (!(message.getDecryptedBody().length > 16e6)) { | |
| _context.next = 15; | |
| break | |
| } | |
| throw new Error(I18N.MAX_BODY_LENGTH); | |
| case 15: | |
| case "end": | |
| return _context.stop() | |
| } | |
| }, _callee, this) | |
| })); | |
| return function(_x) { | |
| return _ref.apply(this, arguments) | |
| } | |
| }(), | |
| checkSubject = function() { | |
| var _ref3 = _asyncToGenerator(regeneratorRuntime.mark(function _callee2(_ref4) { | |
| var Subject = _ref4.Subject; | |
| return regeneratorRuntime.wrap(function(_context2) { | |
| for (;;) switch (_context2.prev = _context2.next) { | |
| case 0: | |
| if (!Subject) { | |
| _context2.next = 2; | |
| break | |
| } | |
| return _context2.abrupt("return"); | |
| case 2: | |
| return _context2.abrupt("return", new Promise(function(resolve, reject) { | |
| confirmModal.activate({ | |
| params: { | |
| title: I18N.NO_SUBJECT_TITLE, | |
| message: I18N.NO_SUBJECT_MESSAGE, | |
| confirm: function() { | |
| confirmModal.deactivate(), resolve() | |
| }, | |
| cancel: function() { | |
| confirmModal.deactivate(), reject() | |
| } | |
| } | |
| }) | |
| })); | |
| case 3: | |
| case "end": | |
| return _context2.stop() | |
| } | |
| }, _callee2, this) | |
| })); | |
| return function(_x2) { | |
| return _ref3.apply(this, arguments) | |
| } | |
| }(), | |
| MAX_TITLE_LENGTH = CONSTANTS.MAX_TITLE_LENGTH, | |
| UNPAID_STATE = CONSTANTS.UNPAID_STATE, | |
| I18N = { | |
| STILL_UPLOADING: gettextCatalog.getString("Wait for attachment to finish uploading or cancel upload.", null, "Error"), | |
| invalidEmails: function(total) { | |
| return gettextCatalog.getString("Invalid email(s): " + total + ".", null, "Error") | |
| }, | |
| MAX_BODY_LENGTH: gettextCatalog.getString("The maximum length of the message body is 16,000,000 characters.", null, "Error"), | |
| NO_RECIPIENT: gettextCatalog.getString("Please enter at least one recipient.", null, "Error"), | |
| MAX_SUBJECT_LENGTH: gettextCatalog.getString("The maximum length of the subject is " + MAX_TITLE_LENGTH + ".", null, "Error"), | |
| maxRecipients: function(total) { | |
| return gettextCatalog.getString("The maximum number (" + total + ") of Recipients is 25.", null, "Error") | |
| }, | |
| NO_SUBJECT_TITLE: gettextCatalog.getString("No subject", null, "Title"), | |
| NO_SUBJECT_MESSAGE: gettextCatalog.getString("No subject, send anyway?", null, "Info"), | |
| ERROR_ADDRESSES_INFO_PRIVATE: gettextCatalog.getString("You can generate your keys here", null, "Error"), | |
| ERROR_ADDRESSES: gettextCatalog.getString("No address with keys available to compose a message.", null, "Error"), | |
| MEMBER: gettextCatalog.getString("Addresses / Users", null, "Title"), | |
| ERROR_ADDRESSES_INFO: gettextCatalog.getString("Contact your organization’s administrator to resolve this.", null, "Error"), | |
| ERROR_DELINQUENT: gettextCatalog.getString("Your account currently has an overdue invoice. Please pay all unpaid invoices.", null, "Info") | |
| }, | |
| cleanEmails = function(message) { | |
| message.ToList.concat(message.CCList, message.BCCList).forEach(function(item) { | |
| item.Address = item.Address.trim() | |
| }) | |
| }, | |
| getErrorInfo = function() { | |
| return authentication.user.Private ? I18N.ERROR_ADDRESSES_INFO_PRIVATE + ' <a href="/members">' + I18N.MEMBER + "</a>" : I18N.ERROR_ADDRESSES_INFO | |
| }; | |
| return { | |
| checkSubject: checkSubject, | |
| validate: validate, | |
| canWrite: canWrite | |
| } | |
| }), angular.module("proton.config", []).constant("CONFIG", { | |
| app_version: "3.12.13", | |
| api_version: "2", | |
| date_version: "Wed Dec 06 2017", | |
| year: 2017, | |
| clientID: "Web", | |
| clientSecret: "4957cc9a2e0a2a49d02475c9d013478d", | |
| articleLink: "https://protonmail.com/blog/protonmail-v3-12-release-notes/", | |
| translations: ["de_DE", "en_US", "es_ES", "fr_FR", "it_IT", "nl_NL", "pl_PL", "pt_BR", "ru_RU", "tr_TR", "uk_UA"], | |
| debug: !1, | |
| apiUrl: "/api", | |
| statsConfig: { | |
| isEnabled: !0, | |
| statsHost: "stats.protonmail.ch", | |
| domains: ["*.protonmail.com", "*.mail.protonmail.com"], | |
| cookieDomain: "*.protonmail.com", | |
| siteId: 5, | |
| abSiteId: 8 | |
| } | |
| }), angular.module("proton.constants", []).constant("regexEmail", /(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))/i).constant("CONSTANTS", { | |
| GIFT_CODE_LENGTH: 16, | |
| BLACK_FRIDAY_INTERVAL: 6e5, | |
| PLANS: { | |
| PLAN: { | |
| PLUS: "plus", | |
| PROFESSIONAL: "professional", | |
| VISIONARY: "visionary", | |
| VPN_BASIC: "vpnbasic", | |
| VPN_PLUS: "vpnplus" | |
| }, | |
| ADDON: { | |
| ADDRESS: "5address", | |
| MEMBER: "1member", | |
| DOMAIN: "1domain", | |
| SPACE: "1gb", | |
| VPN: "1vpn" | |
| } | |
| }, | |
| PLANS_TYPE: { | |
| PLAN: 1, | |
| ADDON: 0 | |
| }, | |
| CONTACTS_LIMIT_ENCRYPTION: 20, | |
| CONTACTS_LIMIT_UPLOAD: 50, | |
| VCARD_VERSION: "4.0", | |
| VCARD_KEYS: ["email", "adr", "tel", "note", "kind", "source", "xml", "nickname", "photo", "bday", "anniversary", "gender", "impp", "lang", "tz", "geo", "title", "role", "logo", "org", "member", "related", "categories", "rev", "sound", "uid", "clientpidmap", "url", "key", "fburl", "caladruri", "caluri"], | |
| VCARD_TYPES: ["work", "home", "text", "voice", "fax", "cell", "video", "pager", "textphone", "iana-token", "x-name", "contact", "acquaintance", "friend", "met", "co-worker", "colleague", "co-resident", "neighbor", "child", "parent", "sibling", "spouse", "kin", "muse", "crush", "date", "sweetheart", "me", "agent", "emergency"], | |
| CONTACT_MODE: { | |
| ENCRYPTED_AND_SIGNED: 3, | |
| SIGNED: 2, | |
| ENCRYPTED: 1, | |
| CLEAR_TEXT: 0 | |
| }, | |
| CONTACT_ERROR: { | |
| TYPE3_CONTACT_VERIFICATION: 3, | |
| TYPE3_CONTACT_DECRYPTION: 2, | |
| TYPE2_CONTACT: 1, | |
| TYPE1_CONTACT: 0 | |
| }, | |
| CONTACT_EMAILS_LIMIT: 1e3, | |
| CONTACTS_LIMIT: 1e3, | |
| EXPORT_CONTACTS_LIMIT: 50, | |
| MAX_VPN: 100, | |
| MAX_MEMBER: 100, | |
| AWESOMEPLETE_MAX_ITEMS: 20, | |
| MAIN_KEY: "0", | |
| TIMEOUT: 3e4, | |
| BASE_SIZE: 1024, | |
| PM_SIGNATURE: 'Sent with <a href="https://protonmail.com" target="_blank">ProtonMail</a> Secure Email.', | |
| KEY_PHASE: 5, | |
| KEY_VERSION: 3, | |
| MAX_OUTSIDE_REPLY: 4, | |
| MAILBOX_PASSWORD_KEY: "proton:mailbox_pwd", | |
| OAUTH_KEY: "proton:oauth", | |
| WHITELIST: ["[email protected]"], | |
| INVITE_MAIL: 1, | |
| INVITE_VPN: 2, | |
| FREE_USER_ROLE: 0, | |
| PAID_MEMBER_ROLE: 1, | |
| PAID_ADMIN_ROLE: 2, | |
| UNPAID_STATE: { | |
| NOT: 0, | |
| AVAILABLE: 1, | |
| OVERDUE: 2, | |
| DELINQUENT: 3, | |
| NO_RECEIVE: 4 | |
| }, | |
| INBOX: 0, | |
| DRAFT: 1, | |
| SENT: 2, | |
| INBOX_AND_SENT: 3, | |
| PM_ADDRESS: 1, | |
| PM_ALIAS: 2, | |
| CUSTOM_DOMAIN_ADDRESS: 3, | |
| REPLY: 0, | |
| REPLY_ALL: 1, | |
| FORWARD: 2, | |
| FILTER_VERSION: 1, | |
| ROW_MODE: 1, | |
| COLUMN_MODE: 0, | |
| ATTACHMENT_SIZE_LIMIT: 25, | |
| ATTACHMENT_NUMBER_LIMIT: 100, | |
| MAX_TITLE_LENGTH: 255, | |
| MAX_NUMBER_COMPOSER: 3, | |
| MESSAGE_VIEW_MODE: 1, | |
| CONVERSATION_VIEW_MODE: 0, | |
| MESSAGE_LIMIT: 100, | |
| CONVERSATION_LIMIT: 100, | |
| ENCRYPTED_STATUS: { | |
| NONE: 0, | |
| INTERNAL: 1, | |
| EXTERNAL: 2, | |
| OUT_ENC: 3, | |
| OUT_PLAIN: 4, | |
| STORED_ENC: 5, | |
| AUTOREPLY: 10 | |
| }, | |
| INTERVAL_EVENT_TIMER: 3e4, | |
| TIMEOUT_PRELOAD_MESSAGE: 500, | |
| UPLOAD_GRADIENT_DARK: "147, 145, 209", | |
| UPLOAD_GRADIENT_LIGHT: "255, 255, 255", | |
| ENC_OUT_ENC_REPLY: 6, | |
| SAVE_TIMEOUT_TIME: 3e3, | |
| SAVE_THROTTLE_TIME: 1e4, | |
| MAX_EXPIRATION_TIME: 672, | |
| ELEMENTS_PER_PAGE: 50, | |
| CONTACTS_PER_PAGE: 1e3, | |
| HD_BREAKPOINT: 1920, | |
| DESKTOP_BREAKPOINT: 1200, | |
| ROW_BREAKPOINT: 960, | |
| MOBILE_BREAKPOINT: 800, | |
| WIZARD_ENABLED: !0, | |
| MAILBOX_IDENTIFIERS: { | |
| inbox: "0", | |
| allDrafts: "1", | |
| allSent: "2", | |
| trash: "3", | |
| spam: "4", | |
| allmail: "5", | |
| starred: "10", | |
| archive: "6", | |
| sent: "7", | |
| drafts: "8", | |
| search: "search", | |
| label: "label" | |
| }, | |
| EMAIL_FORMATING: { | |
| OPEN_TAG_AUTOCOMPLETE: "‹", | |
| CLOSE_TAG_AUTOCOMPLETE: "›", | |
| OPEN_TAG_AUTOCOMPLETE_RAW: "<", | |
| CLOSE_TAG_AUTOCOMPLETE_RAW: ">" | |
| }, | |
| STATUS: { | |
| DELETE: 0, | |
| CREATE: 1, | |
| UPDATE: 2, | |
| UPDATE_DRAFT: 2, | |
| UPDATE_FLAGS: 3 | |
| }, | |
| DEFAULT_SQUIRE_VALUE: { | |
| LINK: "", | |
| IMAGE: "", | |
| HEADER_CLASS: "h4", | |
| IFRAMECLASSNAME: "angular-squire-iframe" | |
| }, | |
| URL_INFO: "https://mail.protonmail.com/assets/host.png", | |
| MIN_PAYPAL_AMOUNT: 500, | |
| MAX_PAYPAL_AMOUNT: 99999900, | |
| MIN_BITCOIN_AMOUNT: 500, | |
| BTC_DONATION_ADDRESS: "1Q1nhq1NbxPYAbw1BppwKbCqg58ZqMb9A8", | |
| CURRENCIES: ["USD", "EUR", "CHF"], | |
| BILLING_CYCLE: [1, 12, 24], | |
| CYCLE: { | |
| MONTHLY: 1, | |
| YEARLY: 12, | |
| TWO_YEARS: 24 | |
| }, | |
| IFRAME_SECURE_ORIGIN: "https://secure.protonmail.com", | |
| INVITE_URL: "https://protonmail.com/invite", | |
| DEFAULT_CURRENCY: "EUR", | |
| DEFAULT_CYCLE: 12, | |
| TRACKER_ROUTE: "proton.php", | |
| PIWIK_SCRIPT: "proton.js", | |
| METRIC_GOALS: { | |
| SIGNUP_ALL: 2, | |
| SIGNUP_FREE: 4, | |
| SIGNUP_PAID: 3, | |
| SIGNUP_PLUS: 6, | |
| SIGNUP_VISIONARY: 5 | |
| }, | |
| SEND_TYPES: { | |
| SEND_PM: 1, | |
| SEND_EO: 2, | |
| SEND_CLEAR: 4, | |
| SEND_PGP_INLINE: 8, | |
| SEND_PGP_MIME: 16, | |
| SEND_MIME: 32 | |
| }, | |
| AUTOCOMPLETE_DOMAINS: ["protonmail.com", "protonmail.ch", "gmail.com", "hotmail.com", "live.com", "yahoo.com", "outlook.com"], | |
| FONT_SIZE: { | |
| small: 8, | |
| normal: 14, | |
| large: 20, | |
| huge: 26 | |
| }, | |
| COMPOSER_COLOR: { | |
| COLOR: "#222222", | |
| BACKGROUND: "#FFFFFF" | |
| }, | |
| FONT_COLOR: { | |
| white: ["#FFFFFF", "#DADADA", "#B5B5B5", "#909090", "#6B6B6B", "#464646", "#222222"], | |
| magenta: ["#F6CBCB", "#EC9798", "#E36667", "#ED4139", "#CF3932", "#9A2B25", "#681D19"], | |
| blue: ["#CDE1F2", "#9CC3E5", "#6CA6D9", "#3B83C2", "#2A47F6", "#145390", "#0F3A62"], | |
| green: ["#D7EAD3", "#B3D6A9", "#8FC380", "#77F241", "#66A657", "#3A762B", "#29501F"], | |
| yellow: ["#FFF2CD", "#FEE59C", "#FCD86F", "#FDF84E", "#F2C246", "#BE8F35", "#7F6124"] | |
| }, | |
| CANCEL_REQUEST: "CANCEL_REQUEST", | |
| ENCRYPTION_DEFAULT: 2048 | |
| }); | |
| var _slicedToArray = function() { | |
| function sliceIterator(arr, i) { | |
| var _arr = [], | |
| _n = !0, | |
| _d = !1, | |
| _e = void 0; | |
| try { | |
| for (var _s, _i = arr[Symbol.iterator](); !(_n = (_s = _i.next()).done) && (_arr.push(_s.value), !i || _arr.length !== i); _n = !0); | |
| } catch (err) { | |
| _d = !0, _e = err | |
| } finally { | |
| try { | |
| !_n && _i.return && _i.return() | |
| } finally { | |
| if (_d) throw _e | |
| } | |
| } | |
| return _arr | |
| } | |
| return function(arr, i) { | |
| if (Array.isArray(arr)) return arr; | |
| if (Symbol.iterator in Object(arr)) return sliceIterator(arr, i); | |
| throw new TypeError("Invalid attempt to destructure non-iterable instance") | |
| } | |
| }(); | |
| angular.module("proton.contact").directive("contactAddressInput", function() { | |
| var FIELD = "contactAddressInput-field", | |
| FOCUSSED = "contactAddressInput-focussed", | |
| DELAY = 200; | |
| return { | |
| restrict: "E", | |
| replace: !0, | |
| scope: { | |
| value: "=", | |
| form: "=", | |
| focused: "=" | |
| }, | |
| templateUrl: "templates/contact/contactAddressInput.tpl.html", | |
| link: function(scope, element) { | |
| function onFocus() { | |
| element.addClass(FOCUSSED), setTimeout(function() { | |
| return element.find(".contactAddressInput-street").focus() | |
| }, DELAY), scope.$applyAsync(function() { | |
| return scope.focused = !0 | |
| }) | |
| } | |
| function onBlur() { | |
| setTimeout(function() { | |
| element.find("." + FIELD + ":focus").length || (element.removeClass(FOCUSSED), scope.$applyAsync(function() { | |
| return scope.focused = !1 | |
| })) | |
| }, DELAY) | |
| } | |
| function onChange() { | |
| scope.$applyAsync(function() { | |
| var _scope$model = scope.model, | |
| postBox = _scope$model.postBox, | |
| extended = _scope$model.extended, | |
| street = _scope$model.street, | |
| locality = _scope$model.locality, | |
| region = _scope$model.region, | |
| postalCode = _scope$model.postalCode, | |
| country = _scope$model.country; | |
| scope.value = [postBox, extended, street, locality, region, postalCode, country], scope.model.default = formatDefaultValue() | |
| }) | |
| } | |
| var defaultInput = element.find(".contactAddressInput-default"), | |
| defaultValue = Array.isArray(scope.value) && scope.value.length > 1 ? scope.value : ["", "", scope.value], | |
| _defaultValue = _slicedToArray(defaultValue, 7), | |
| _defaultValue$ = _defaultValue[0], | |
| postBoxValue = void 0 === _defaultValue$ ? "" : _defaultValue$, | |
| _defaultValue$2 = _defaultValue[1], | |
| extendedValue = void 0 === _defaultValue$2 ? "" : _defaultValue$2, | |
| _defaultValue$3 = _defaultValue[2], | |
| streetValue = void 0 === _defaultValue$3 ? "" : _defaultValue$3, | |
| _defaultValue$4 = _defaultValue[3], | |
| localityValue = void 0 === _defaultValue$4 ? "" : _defaultValue$4, | |
| _defaultValue$5 = _defaultValue[4], | |
| regionValue = void 0 === _defaultValue$5 ? "" : _defaultValue$5, | |
| _defaultValue$6 = _defaultValue[5], | |
| postalCodeValue = void 0 === _defaultValue$6 ? "" : _defaultValue$6, | |
| _defaultValue$7 = _defaultValue[6], | |
| countryValue = void 0 === _defaultValue$7 ? "" : _defaultValue$7, | |
| fields = element.find("." + FIELD), | |
| formatDefaultValue = function() { | |
| return (arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : scope.value).filter(function() { | |
| return (arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : "").trim() | |
| }).join("\n") | |
| }; | |
| scope.model = { | |
| default: formatDefaultValue(defaultValue), | |
| postBox: postBoxValue, | |
| extended: extendedValue, | |
| street: streetValue, | |
| locality: localityValue, | |
| region: regionValue, | |
| postalCode: postalCodeValue, | |
| country: countryValue | |
| }, postBoxValue.length && element.addClass("contactAddressInput-show-post-box"), extendedValue.length && element.addClass("contactAddressInput-show-extended"), defaultInput.on("focus", onFocus), fields.on("change", onChange), fields.on("blur", onBlur), scope.$on("$destroy", function() { | |
| defaultInput.off("focus", onFocus), fields.off("change", onChange), fields.off("blur", onBlur) | |
| }) | |
| } | |
| } | |
| }), angular.module("proton.contact").directive("contactClear", function() { | |
| return { | |
| replace: !0, | |
| templateUrl: "templates/contact/contactClear.tpl.html" | |
| } | |
| }), angular.module("proton.contact").directive("contactDetails", function($state, CONSTANTS, contactDetailsModel, contactBeforeToLeaveModal, gettextCatalog, notification, subscriptionModel, memberModel, dispatchers, vcard) { | |
| var MAP_FIELDS = { | |
| Name: "FN", | |
| Emails: "EMAIL", | |
| Tels: "TEL", | |
| Adrs: "ADR", | |
| Notes: "NOTE" | |
| }, | |
| MAP_EVENT = { | |
| deleteContact: function(_ref) { | |
| return { | |
| type: "deleteContacts", | |
| data: { | |
| contactIDs: [_ref.ID] | |
| } | |
| } | |
| }, | |
| downloadContact: function(_ref2) { | |
| return { | |
| type: "exportContacts", | |
| data: { | |
| contactID: _ref2.ID | |
| } | |
| } | |
| } | |
| }, | |
| I18N = { | |
| invalidForm: gettextCatalog.getString("This form is invalid", null, "Error displays when the user try to leave an unsaved and invalid contact details") | |
| }, | |
| getFieldKey = function() { | |
| var type = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : ""; | |
| return MAP_FIELDS[type] || type.toUpperCase() | |
| }; | |
| return { | |
| restrict: "E", | |
| replace: !0, | |
| scope: { | |
| contact: "=", | |
| modal: "=" | |
| }, | |
| templateUrl: "templates/contact/contactDetails.tpl.html", | |
| link: function(scope, element) { | |
| function saveBeforeToLeave(toState, toParams) { | |
| contactBeforeToLeaveModal.activate({ | |
| params: { | |
| save: function() { | |
| contactBeforeToLeaveModal.deactivate(), saveContact() && $state.go(toState.name, toParams) | |
| }, | |
| discard: function() { | |
| contactBeforeToLeaveModal.deactivate(), scope.contactForm.$setPristine(!0), $state.go(toState.name, toParams) | |
| }, | |
| cancel: function() { | |
| contactBeforeToLeaveModal.deactivate() | |
| } | |
| } | |
| }) | |
| } | |
| function onClick(_ref5) { | |
| var target = _ref5.target, | |
| action = target.getAttribute("data-action"); | |
| action && ("back" === action && $state.go("secured.contacts"), dispatch(action, scope.contact)) | |
| } | |
| function isValidForm() { | |
| return !scope.contactForm.$invalid && _.chain(scope.model).values().reduce(function(acc) { | |
| var child = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : []; | |
| return acc.concat(child.filter(function(_ref6) { | |
| var _ref6$value = _ref6.value; | |
| return void 0 === _ref6$value ? "" : _ref6$value | |
| })) | |
| }, []).value().length | |
| } | |
| function saveContact() { | |
| if (!isValidForm()) return notification.error(I18N.invalidForm), !1; | |
| var contact = contactDetailsModel.prepare(scope); | |
| return scope.contact.ID ? (contact.ID = scope.contact.ID, dispatch("updateContact", { | |
| contact: contact | |
| })) : dispatch("createContact", { | |
| contacts: [contact] | |
| }), scope.contactForm.$setSubmitted(!0), scope.contactForm.$setPristine(!0), !0 | |
| } | |
| var _dispatchers = dispatchers(["contacts", "$stateChangeStart"]), | |
| on = _dispatchers.on, | |
| unsubscribe = _dispatchers.unsubscribe, | |
| dispatcher = _dispatchers.dispatcher, | |
| dispatch = function(type) { | |
| var data = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : {}, | |
| opt = (MAP_EVENT[type] || _.noop)(data) || { | |
| type: type, | |
| data: data | |
| }; | |
| dispatcher.contacts(opt.type, opt.data) | |
| }, | |
| updateType = function() { | |
| var types = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : []; | |
| return _.contains(types, CONSTANTS.CONTACT_MODE.ENCRYPTED_AND_SIGNED) && element.addClass("contactDetails-encrypted-and-signed") | |
| }, | |
| onSubmit = function() { | |
| return saveContact() | |
| }, | |
| isFree = !subscriptionModel.hasPaid("mail") && !memberModel.isMember(), | |
| properties = vcard.extractProperties(scope.contact.vCard), | |
| hasEmail = _.filter(properties, function(property) { | |
| return "email" === property.getField() | |
| }).length; | |
| scope.model = {}, scope.state = { | |
| encrypting: !1, | |
| ID: scope.contact.ID, | |
| hasEmail: hasEmail, | |
| isFree: isFree | |
| }, on("contacts", function(event, _ref3) { | |
| var _ref3$type = _ref3.type, | |
| type = void 0 === _ref3$type ? "" : _ref3$type, | |
| _ref3$data = _ref3.data, | |
| data = void 0 === _ref3$data ? {} : _ref3$data; | |
| scope.modal && "submitContactForm" === type && onSubmit(), "contactUpdated" === type && data.contact.ID === scope.contact.ID && updateType(data.cards.map(function(_ref4) { | |
| return _ref4.Type | |
| })) | |
| }), on("$stateChangeStart", function(event, toState, toParams) { | |
| !scope.modal && scope.contactForm.$dirty && (event.preventDefault(), saveBeforeToLeave(toState, toParams)) | |
| }), updateType(scope.contact.types), scope.contact.errors && (-1 !== scope.contact.errors.indexOf(3) && element.addClass("contactDetails-encrypted-verification-error"), -1 !== scope.contact.errors.indexOf(2) && element.addClass("contactDetails-encrypted-error"), -1 !== scope.contact.errors.indexOf(1) && element.addClass("contactDetails-verification-error")), element.on("click", onClick), element.on("submit", onSubmit), scope.get = function(type) { | |
| if (type) return contactDetailsModel.extract({ | |
| vcard: scope.contact.vCard, | |
| field: getFieldKey(type) | |
| }) | |
| }, scope.$on("$destroy", function() { | |
| element.off("click", onClick), element.off("submit", onSubmit), unsubscribe() | |
| }) | |
| } | |
| } | |
| }), angular.module("proton.contact").directive("contactEncrypted", function(gettextCatalog) { | |
| var SHOW_CLASS = "contactDetails-show-custom-fields", | |
| I18N = { | |
| SHOW: gettextCatalog.getString("Show custom fields", null, "Action in contact details"), | |
| HIDE: gettextCatalog.getString("Hide custom fields", null, "Action in contact details") | |
| }; | |
| return { | |
| restrict: "E", | |
| replace: !0, | |
| templateUrl: "templates/contact/contactEncrypted.tpl.html", | |
| link: function(scope, el) { | |
| var button = el.find(".contactDetails-toggle-custom-fields"), | |
| updateText = function() { | |
| var key = el[0].classList.contains(SHOW_CLASS) ? "HIDE" : "SHOW"; | |
| button[0].textContent = I18N[key] | |
| }, | |
| onClick = function() { | |
| return el[0].classList.toggle(SHOW_CLASS), updateText() | |
| }; | |
| button.on("click", onClick), updateText(), scope.$on("$destroy", function() { | |
| button.off("click", onClick) | |
| }) | |
| } | |
| } | |
| }), angular.module("proton.contact").directive("contactError", function() { | |
| return { | |
| replace: !0, | |
| templateUrl: "templates/contact/contactError.tpl.html" | |
| } | |
| }), angular.module("proton.contact").directive("contactItem", function($rootScope, contactTransformLabel, contactUI, messageModel) { | |
| var AS_SORTABLE_DISABLED = "as-sortable-disabled", | |
| addX = function() { | |
| var value = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : ""; | |
| return value.startsWith("x") ? value : "X-" + value | |
| }; | |
| return { | |
| restrict: "E", | |
| require: "^form", | |
| templateUrl: "templates/directives/contact/contactItem.tpl.html", | |
| scope: { | |
| form: "=", | |
| model: "=", | |
| state: "=", | |
| getDatas: "&datas", | |
| type: "@type" | |
| }, | |
| link: function(scope, element, attr, ngFormController) { | |
| function onClick(e) { | |
| e.stopPropagation(); | |
| var action = e.target.getAttribute("data-action"), | |
| index = parseInt(e.target.getAttribute("data-index"), 10); | |
| switch (action) { | |
| case "add": | |
| add(); | |
| break; | |
| case "composeTo": | |
| composeTo(e.target.getAttribute("data-email")); | |
| break; | |
| case "remove": | |
| remove(scope.UI.items[index]); | |
| break; | |
| case "toggleSortable": | |
| scope.$applyAsync(function() { | |
| scope.UI.sortableState = !scope.UI.sortableState, list.toggleClass(AS_SORTABLE_DISABLED) | |
| }) | |
| } | |
| } | |
| function add() { | |
| var populated = contactUI.populate(scope.UI, type); | |
| ngFormController.$setDirty(), scope.$applyAsync(function() { | |
| contactUI.add(scope.UI, populated.key, populated.type, ""), setTimeout(function() { | |
| return element.find(".contactItem-field").focus() | |
| }, 100) | |
| }) | |
| } | |
| function remove(item) { | |
| $(".tooltip").not(this).hide(), contactUI.remove(scope.UI, item), ngFormController.$setDirty(), scope.change() | |
| } | |
| function composeTo(Address) { | |
| var message = messageModel(); | |
| message.ToList = [{ | |
| Address: Address, | |
| Name: Address | |
| }], $rootScope.$emit("composer.new", { | |
| data: { | |
| message: message | |
| }, | |
| type: "new" | |
| }) | |
| } | |
| var datas = scope.getDatas(), | |
| type = scope.type, | |
| state = scope.state, | |
| list = element.find(".contactItem-container"); | |
| scope.config = { | |
| isFocusedAddress: !1 | |
| }, list.addClass("contactItem-container-" + scope.type), list.addClass(AS_SORTABLE_DISABLED), scope.itemContactDragControlListeners = { | |
| containment: ".contactDetails-container", | |
| containerPositioning: "relative", | |
| accept: function(sourceItemHandleScope, destSortableScope) { | |
| return sourceItemHandleScope.itemScope.sortableScope.$id === destSortableScope.$id | |
| }, | |
| dragStart: function() { | |
| scope.itemMoved = !0 | |
| }, | |
| dragEnd: function() { | |
| scope.itemMoved = !1 | |
| }, | |
| orderChanged: function() { | |
| ngFormController.$setDirty() | |
| } | |
| }, scope.UI = contactUI.initialize(datas, type, state), scope.getAddressValue = function(item) { | |
| var itemValue = item.value; | |
| return angular.isArray(itemValue) ? itemValue.join(" ") : angular.isString(itemValue) ? itemValue : "" | |
| }, scope.change = function() { | |
| return scope.$applyAsync(function() { | |
| return scope.model[type] = scope.UI.items | |
| }) | |
| }, scope.visibleItems = function() { | |
| return scope.UI.items.filter(function(_ref) { | |
| return !_ref.hide | |
| }) | |
| }, scope.onFocus = function(item) { | |
| return item.displaySelector = !0 | |
| }, scope.onBlur = function(item) { | |
| return item.displaySelector = !1 | |
| }, scope.toggleSelector = function(event, item) { | |
| item.displaySelector = !item.displaySelector, event.preventDefault(), event.stopPropagation() | |
| }, scope.setLabel = function() { | |
| var item = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {}, | |
| value = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : ""; | |
| item.label = value || item.label, "Customs" === type && (item.type = addX(item.label)), "Personals" === type && (item.type = contactTransformLabel.toVCard(item.label)), ngFormController.$setDirty(), scope.change() | |
| }, scope.change(), element.on("click", onClick), scope.$on("$destroy", function() { | |
| element.off("click", onClick) | |
| }) | |
| } | |
| } | |
| }), angular.module("proton.contact").directive("contactList", function($filter, dispatchers, $state, $stateParams, contactCache) { | |
| var ITEM_CLASS = "contactList-item", | |
| ACTIVE_CLASS = "contactList-item-activeContact"; | |
| return { | |
| restrict: "E", | |
| replace: !0, | |
| scope: {}, | |
| templateUrl: "templates/contact/contactList.tpl.html", | |
| link: function(scope, element) { | |
| function updateContacts() { | |
| var filteredContacts = contactCache.paginate(contactCache.get("filtered")); | |
| scope.$applyAsync(function() { | |
| scope.contacts = filteredContacts, _.defer(function() { | |
| activeContact(isLoadedContact), isLoadedContact = !1 | |
| }, 1e3) | |
| }) | |
| } | |
| function activeContact() { | |
| var scroll = arguments.length > 0 && void 0 !== arguments[0] && arguments[0]; | |
| if (element.find("." + ITEM_CLASS).removeClass(ACTIVE_CLASS), $stateParams.id) { | |
| var $row = element.find("." + ITEM_CLASS + '[data-contact-id="' + unescape($stateParams.id) + '"]'); | |
| $row.addClass(ACTIVE_CLASS), scroll && $row[0] && element.animate({ | |
| scrollTop: $row.offset().top - 120 | |
| }, 1e3) | |
| } | |
| } | |
| function onClick(e) { | |
| var target = e.target, | |
| shiftKey = e.shiftKey; | |
| /customCheckbox/.test(target.className) && (e.stopPropagation(), setContactSelection(target.dataset.contactId, target.checked, shiftKey)); | |
| var action = target.getAttribute("data-action"); | |
| if ("showContact" === action && $state.go("secured.contacts.details", { | |
| id: target.dataset.contactId | |
| }), "toggleSort" === action) { | |
| var sort = target.getAttribute("data-sort"), | |
| prefix = ($stateParams.sort || "").startsWith("-") ? "" : "-"; | |
| $state.go("secured.contacts", { | |
| sort: "" + prefix + sort | |
| }) | |
| } | |
| } | |
| var _dispatchers = dispatchers(["contacts", "$stateChangeSuccess"]), | |
| dispatcher = _dispatchers.dispatcher, | |
| on = _dispatchers.on, | |
| unsubscribe = _dispatchers.unsubscribe, | |
| lastChecked = null, | |
| isLoadedContact = !!$stateParams.id; | |
| scope.contacts = [], scope.showContact = function(contactID) { | |
| return $state.go("secured.contacts.details", { | |
| id: contactID | |
| }) | |
| }; | |
| var selectContact = function(contact, isChecked, shiftKey) { | |
| var contactIDs = [contact.ID]; | |
| if (lastChecked) { | |
| if (shiftKey) { | |
| var start = scope.contacts.indexOf(contact), | |
| end = _.findIndex(scope.contacts, { | |
| ID: lastChecked.ID | |
| }), | |
| col = scope.contacts.slice(Math.min(start, end), Math.max(start, end) + 1); | |
| contactIDs.push.apply(contactIDs, _toConsumableArray(_.pluck(col, "ID"))) | |
| } | |
| lastChecked = contact | |
| } else lastChecked = contact; | |
| dispatcher.contacts("selectContacts", { | |
| contactIDs: contactIDs, | |
| isChecked: isChecked | |
| }) | |
| }, | |
| setContactSelection = function(ID, checked, shiftKey) { | |
| return scope.$applyAsync(function() { | |
| var contact = _.findWhere(scope.contacts, { | |
| ID: ID | |
| }); | |
| selectContact(contact, checked, shiftKey) | |
| }) | |
| }; | |
| on("contacts", function(event, _ref) { | |
| var _ref$type = _ref.type; | |
| "contactsUpdated" === (void 0 === _ref$type ? "" : _ref$type) && scope.$applyAsync(function() { | |
| return updateContacts() | |
| }) | |
| }), on("$stateChangeSuccess", function() { | |
| scope.$applyAsync(function() { | |
| return activeContact() | |
| }) | |
| }), element.on("click", onClick), contactCache.hydrate(), scope.$on("$destroy", function() { | |
| element.off("click", onClick), unsubscribe() | |
| }) | |
| } | |
| } | |
| }), angular.module("proton.contact").directive("contactNoResult", function($rootScope) { | |
| function onClick(event) { | |
| var action = event.target.getAttribute("data-action"); | |
| MAP[action] && $rootScope.$emit("contacts", { | |
| type: MAP[action] | |
| }) | |
| } | |
| var MAP = { | |
| add: "addContact", | |
| import: "importContacts" | |
| }; | |
| return { | |
| replace: !0, | |
| templateUrl: "templates/contact/contactNoResult.tpl.html", | |
| link: function(scope, element) { | |
| element.on("click", onClick), scope.$on("$destroy", function() { | |
| element.off("click", onClick) | |
| }) | |
| } | |
| } | |
| }), angular.module("proton.contact").directive("contactPlaceholder", function() { | |
| return { | |
| restrict: "E", | |
| replace: !0, | |
| scope: {}, | |
| templateUrl: "templates/contact/contactPlaceholder.tpl.html" | |
| } | |
| }), angular.module("proton.contact").directive("contactToolbar", function($rootScope, $state, $stateParams, CONSTANTS, contactCache, gettextCatalog, messageModel, notification, dispatchers) { | |
| function composeSelectedContacts(dispatcher) { | |
| var list = getList().filter(function(_ref) { | |
| var _ref$Emails = _ref.Emails; | |
| return (void 0 === _ref$Emails ? [] : _ref$Emails).length | |
| }).map(function(_ref2) { | |
| var Emails = _ref2.Emails, | |
| Name = _ref2.Name; | |
| return { | |
| Address: Emails[0].Email, | |
| Name: Name | |
| } | |
| }); | |
| if (list.length) { | |
| var message = messageModel(); | |
| return message.ToList = list, dispatcher["composer.new"]("new", { | |
| message: message | |
| }) | |
| } | |
| notification.error(gettextCatalog.getString("Contact does not contain email address", null, "Error")) | |
| } | |
| var getList = function() { | |
| return contactCache.get("selected").length ? contactCache.get("selected") : [contactCache.getItem($stateParams.id)].filter(Boolean) | |
| }; | |
| return { | |
| restrict: "E", | |
| replace: !0, | |
| scope: {}, | |
| templateUrl: "templates/contact/contactToolbar.tpl.html", | |
| link: function(scope, element) { | |
| function update() { | |
| var paginatedContacts = contactCache.paginate(contactCache.get("filtered")), | |
| selectedContacts = contactCache.get("selected"), | |
| checkedContacts = _.where(paginatedContacts, { | |
| selected: !0 | |
| }); | |
| scope.$applyAsync(function() { | |
| scope.totalItems = contactCache.total(), scope.disabled = !paginatedContacts.length, scope.noSelection = !($stateParams.id || selectedContacts.length), scope.checkAll = paginatedContacts.length === checkedContacts.length | |
| }) | |
| } | |
| function onClick(_ref3) { | |
| var target = _ref3.target, | |
| type = target.getAttribute("data-action"); | |
| return "composeSelectedContacts" === type && composeSelectedContacts(dispatcher), "deleteSelectedContacts" === type ? dispatcher.contacts("deleteContacts", { | |
| contactIDs: _.pluck(getList(), "ID") | |
| }) : "addContact" === type || /^(merge|export|import)Contacts$/.test(type) ? dispatcher.contacts(type) : void 0 | |
| } | |
| var _dispatchers = dispatchers(["composer.new", "contacts", "$stateChangeSuccess"]), | |
| on = _dispatchers.on, | |
| unsubscribe = _dispatchers.unsubscribe, | |
| dispatcher = _dispatchers.dispatcher; | |
| scope.numPerPage = CONSTANTS.CONTACTS_PER_PAGE, scope.selectPage = function(page) { | |
| return $state.go($state.$current.name, { | |
| page: page | |
| }) | |
| }, scope.currentPage = +($stateParams.page || 1), scope.selectAll = function(event) { | |
| var contactIDs = _.pluck(contactCache.paginate(contactCache.get("filtered")), "ID"); | |
| dispatcher.contacts("selectContacts", { | |
| contactIDs: contactIDs, | |
| isChecked: !!event.target.checked | |
| }) | |
| }, on("contacts", function(e, _ref4) { | |
| var type = _ref4.type; | |
| ("contactsUpdated" === type || "selectContacts" === type) && update() | |
| }), on("$stateChangeSuccess", function(e, state) { | |
| "secured.contacts.details" === state.name && scope.noSelection && update() | |
| }), element.on("click", onClick), update(), scope.$on("$destroy", function() { | |
| element.off("click", onClick), unsubscribe() | |
| }) | |
| } | |
| } | |
| }), angular.module("proton.contact").directive("contactView", function($rootScope, $stateParams, contactCache) { | |
| var CONTACTS_EMPTY = "contacts-empty", | |
| CONTACTS_NO_RESULT = "contacts-no-result"; | |
| return { | |
| restrict: "E", | |
| replace: !0, | |
| scope: {}, | |
| templateUrl: "templates/views/contacts.tpl.html", | |
| link: function(scope, element) { | |
| function update() { | |
| var contacts = contactCache.paginate(contactCache.get("filtered")); | |
| element[0].classList.remove(CONTACTS_EMPTY, CONTACTS_NO_RESULT), !contacts.length && !$stateParams.keyword && element[0].classList.add(CONTACTS_EMPTY), !contacts.length && $stateParams.keyword && element[0].classList.add(CONTACTS_NO_RESULT) | |
| } | |
| var unsubscribe = $rootScope.$on("contacts", function(event, _ref) { | |
| var _ref$type = _ref.type; | |
| "contactsUpdated" === (void 0 === _ref$type ? "" : _ref$type) && scope.$applyAsync(function() { | |
| return update() | |
| }) | |
| }); | |
| update(), scope.$on("$destroy", function() { | |
| unsubscribe() | |
| }) | |
| } | |
| } | |
| }), angular.module("proton.contact").factory("contactCache", function($filter, $rootScope, $state, $stateParams, networkActivityTracker, CONSTANTS, Contact, contactDownloader, contactEmails, contactImporter) { | |
| function selected() { | |
| var selected = _.chain(get()).filter(function(_ref2) { | |
| return _ref2.selected | |
| }).pluck("ID").value(); | |
| return !selected.length && $stateParams.id ? [$stateParams.id] : selected | |
| } | |
| function filter() { | |
| var keyword = $stateParams.keyword || ""; | |
| return keyword ? _.pluck(orderBy(search(keyword, get())), "ID") : _.pluck(orderBy(get()), "ID") | |
| } | |
| function get() { | |
| var key = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : "all"; | |
| return "all" === key ? angular.copy(CACHE.contacts) : _.map(CACHE.map[key], function(contactID) { | |
| return CACHE.map.all[contactID] | |
| }) | |
| } | |
| function hydrate(force) { | |
| if (isHydrated() && !force) return emit(), Promise.resolve(); | |
| var promise = Contact.all().then(function() { | |
| var contacts = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : []; | |
| return CACHE.hydrated = !0, CACHE.contacts = contacts, sync(), get() | |
| }).then(function() { | |
| return emit() | |
| }); | |
| return networkActivityTracker.track(promise), promise | |
| } | |
| function load() { | |
| var promise = Contact.load().then(function(_ref3) { | |
| var _ref3$Contacts = _ref3.Contacts, | |
| Contacts = void 0 === _ref3$Contacts ? [] : _ref3$Contacts; | |
| return CACHE.contacts = Contacts, sync(), get() | |
| }).then(function() { | |
| return emit() | |
| }); | |
| return networkActivityTracker.track(promise), promise | |
| } | |
| function find(id) { | |
| var promise = Contact.get(id); | |
| return networkActivityTracker.track(promise), promise | |
| } | |
| function sync() { | |
| var emails = contactEmails.fetch(); | |
| CACHE.contacts = _.map(get(), function(contact) { | |
| return contact.Emails = _.where(emails, { | |
| ContactID: contact.ID | |
| }), contact.emails = contact.Emails.map(function(_ref4) { | |
| var _ref4$Email = _ref4.Email; | |
| return void 0 === _ref4$Email ? "" : _ref4$Email | |
| }).join(", "), contact | |
| }), CACHE.map = { | |
| all: _.reduce(get(), function(acc, contact) { | |
| return acc[contact.ID] = contact, acc | |
| }, {}), | |
| selected: selected(), | |
| filtered: filter() | |
| } | |
| } | |
| function clear() { | |
| CACHE.contacts.length = 0, CACHE.hydrated = !1 | |
| } | |
| function create(contact) { | |
| CACHE.contacts.push(contact), CACHE.map.all[contact.ID] = contact | |
| } | |
| function update(contact, index) { | |
| CACHE.contacts[index] = contact, CACHE.map.all[contact.ID] = contact | |
| } | |
| function deleteContactEmail(EmailID) { | |
| var contact = _.find(get(), function(contact) { | |
| return _.some(contact.Emails, { | |
| ID: EmailID | |
| }) | |
| }); | |
| contact && updateContact({ | |
| ID: contact.ID, | |
| contact: contact | |
| }) | |
| } | |
| function updateContact(_ref5) { | |
| var ID = _ref5.ID, | |
| contact = _ref5.contact, | |
| index = findIndex(ID); - 1 !== index ? update(contact, index) : create(contact), emit() | |
| } | |
| function refreshContactEmails(_ref6) { | |
| var ID = _ref6.ID, | |
| index = findIndex(ID); | |
| if (-1 !== index) { | |
| updateContact({ | |
| ID: ID, | |
| contact: CACHE.contacts[index] | |
| }) | |
| } | |
| } | |
| function paginate() { | |
| var contacts = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : [], | |
| currentPage = $stateParams.page || 1, | |
| begin = (currentPage - 1) * CONTACTS_PER_PAGE, | |
| end = begin + CONTACTS_PER_PAGE; | |
| return contacts.slice(begin, end) | |
| } | |
| function deletedContactEmail(_ref7) { | |
| var ID = _ref7.ID; | |
| CACHE.contacts.length > 0 && deleteContactEmail(ID) | |
| } | |
| function resetContacts() { | |
| clear(), hydrate() | |
| } | |
| function search() { | |
| var keyword = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : "", | |
| contacts = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : [], | |
| value = lowerCase(keyword); | |
| return _.filter(contacts, function(_ref8) { | |
| var _ref8$Name = _ref8.Name, | |
| Name = void 0 === _ref8$Name ? "" : _ref8$Name, | |
| _ref8$Emails = _ref8.Emails, | |
| Emails = void 0 === _ref8$Emails ? [] : _ref8$Emails; | |
| return lowerCase(Name).indexOf(value) > -1 || filterEmails(Emails, value).length | |
| }) | |
| } | |
| function searchingContact() { | |
| CACHE.map.filtered = filter(), emit() | |
| } | |
| function selectContacts(_ref9) { | |
| var _ref9$contactIDs = _ref9.contactIDs, | |
| contactIDs = void 0 === _ref9$contactIDs ? [] : _ref9$contactIDs, | |
| isChecked = _ref9.isChecked; | |
| CACHE.contacts = _.map(get(), function(contact) { | |
| return contactIDs.indexOf(contact.ID) > -1 && (contact.selected = isChecked), contact | |
| }), sync(), emit() | |
| } | |
| function contactEvents(_ref10) { | |
| var _ref10$events = _ref10.events, | |
| events = void 0 === _ref10$events ? [] : _ref10$events, | |
| todo = events.reduce(function(acc, _ref11) { | |
| var ID = _ref11.ID, | |
| _ref11$Contact = _ref11.Contact, | |
| Contact = void 0 === _ref11$Contact ? {} : _ref11$Contact, | |
| Action = _ref11.Action, | |
| action = ACTIONS[Action]; | |
| return "create" === action ? (acc[action].push(Contact), acc) : (acc[action][ID] = Contact, acc) | |
| }, { | |
| update: {}, | |
| create: [], | |
| remove: {} | |
| }); | |
| CACHE.contacts = _.chain(get()).map(function(contact) { | |
| return todo.update[contact.ID] || contact | |
| }).filter(function(_ref12) { | |
| var ID = _ref12.ID; | |
| return !todo.remove[ID] | |
| }).value().concat(todo.create), sync(), emit() | |
| } | |
| var _ACTIONS, CACHE = { | |
| hydrated: !1, | |
| contacts: [], | |
| map: { | |
| all: {}, | |
| selected: [], | |
| filtered: [] | |
| } | |
| }, | |
| CONTACTS_PER_PAGE = CONSTANTS.CONTACTS_PER_PAGE, | |
| ACTIONS = (_ACTIONS = {}, _defineProperty(_ACTIONS, CONSTANTS.STATUS.DELETE, "remove"), _defineProperty(_ACTIONS, CONSTANTS.STATUS.CREATE, "create"), _defineProperty(_ACTIONS, CONSTANTS.STATUS.UPDATE, "update"), _ACTIONS), | |
| getItem = function(ID) { | |
| return _.findWhere(CACHE.contacts, { | |
| ID: ID | |
| }) | |
| }, | |
| findIndex = function(ID) { | |
| return _.findIndex(CACHE.contacts, { | |
| ID: ID | |
| }) | |
| }, | |
| emit = function() { | |
| return $rootScope.$emit("contacts", { | |
| type: "contactsUpdated", | |
| data: { | |
| all: get() | |
| } | |
| }) | |
| }, | |
| orderBy = function() { | |
| var contacts = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : []; | |
| return $filter("orderBy")(contacts, $stateParams.sort || "Name") | |
| }, | |
| lowerCase = function() { | |
| return (arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : "").toLowerCase() | |
| }, | |
| filterEmails = function() { | |
| var emails = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : [], | |
| value = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : ""; | |
| return _.filter(emails, function(_ref) { | |
| var _ref$Email = _ref.Email; | |
| return lowerCase(void 0 === _ref$Email ? "" : _ref$Email).indexOf(value) > -1 | |
| }) | |
| }, | |
| total = function() { | |
| return $stateParams.keyword ? CACHE.map.filtered.length : CACHE.contacts.length | |
| }, | |
| isHydrated = function() { | |
| return CACHE.hydrated | |
| }; | |
| return $rootScope.$on("contacts", function(event, _ref13) { | |
| var type = _ref13.type, | |
| _ref13$data = _ref13.data, | |
| data = void 0 === _ref13$data ? {} : _ref13$data; | |
| "contactEvents" === type && contactEvents(data), "refreshContactEmails" === type && refreshContactEmails(data), "deletedContactEmail" === type && deletedContactEmail(data), "resetContacts" === type && resetContacts(), "importContacts" === type && contactImporter(data.contactID), "exportContacts" === type && contactDownloader(data.contactID), "selectContacts" === type && selectContacts(data), "searchingContact" === type && searchingContact() | |
| }), { | |
| hydrate: hydrate, | |
| isHydrated: isHydrated, | |
| clear: clear, | |
| get: get, | |
| total: total, | |
| paginate: paginate, | |
| load: load, | |
| find: find, | |
| getItem: getItem | |
| } | |
| }), angular.module("proton.contact").factory("contactDetailsModel", function(contactTransformLabel, CONSTANTS, contactSchema, gettextCatalog) { | |
| function getKeys() { | |
| var field = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : "", | |
| vcard = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : {}; | |
| return "CUSTOMS" === field ? _.difference(Object.keys(vcard.data), [].concat(FIELDS.AVOID, FIELDS.FN, FIELDS.EMAIL, FIELDS.TEL, FIELDS.ADR, FIELDS.NOTE, FIELDS.PERSONALS)) : FIELDS[field] | |
| } | |
| function getType(property) { | |
| var type = property.getType(); | |
| return Array.isArray(type) ? type[0] : type | |
| } | |
| function getParams() { | |
| var item = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {}, | |
| pref = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : 0, | |
| params = item.params || {}; | |
| return item.label && MAP_KEYS[item.type] !== item.label && (params.type = contactTransformLabel.toVCard(item.label)), pref && (params.pref = pref), params | |
| } | |
| function prepare(scope) { | |
| var params = angular.copy(contactSchema.contactAPI); | |
| Object.keys(scope.model).forEach(function(key) { | |
| var child = scope.model[key]; | |
| switch (key) { | |
| case "Emails": | |
| case "Tels": | |
| case "Adrs": | |
| child.forEach(function(item, index) { | |
| item.value && params.vCard.add(item.type, escapeValue(item.value), getParams(item, child.length > 1 && index + 1)) | |
| }); | |
| break; | |
| default: | |
| child.forEach(function(item) { | |
| item.value && params.vCard.add(item.type, escapeValue(item.value), getParams(item)) | |
| }) | |
| } | |
| }); | |
| var fnProperty = params.vCard.get("fn"); | |
| if (!fnProperty || fnProperty.isEmpty()) { | |
| var value = "", | |
| emailProperty = params.vCard.get("email"); | |
| if (emailProperty) { | |
| var emailValue = emailProperty.valueOf(); | |
| value = Array.isArray(emailValue) ? emailValue[0].valueOf() : emailValue | |
| } | |
| params.vCard.add("fn", value || I18N.unknown) | |
| } | |
| return params | |
| } | |
| function extract(_ref) { | |
| var _ref$vcard = _ref.vcard, | |
| vcard = void 0 === _ref$vcard ? {} : _ref$vcard, | |
| _ref$field = _ref.field, | |
| field = void 0 === _ref$field ? "" : _ref$field; | |
| return _.reduce(getKeys(field, vcard), function(acc, key) { | |
| var property = vcard.get(key); | |
| if (!checkProperty(property)) return acc; | |
| var value = property.valueOf(); | |
| return Array.isArray(value) ? (_.each(orderByPref(value), function(prop) { | |
| return acc.push(buildProperty(prop)) | |
| }), acc) : (acc.push(buildProperty(property)), acc) | |
| }, []) | |
| } | |
| function orderByPref() { | |
| var properties = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : []; | |
| return _.sortBy(properties, function(property) { | |
| var _ref2 = property.getParams() || {}, | |
| _ref2$pref = _ref2.pref; | |
| return void 0 === _ref2$pref ? 0 : _ref2$pref | |
| }) | |
| } | |
| var ESCAPE_REGEX = /:|,|;|"/gi, | |
| UNESCAPE_REGEX = /\\:|\\,|\\;|\\"/gi, | |
| I18N = { | |
| unknown: gettextCatalog.getString("Unknown", null, "Default display name vcard") | |
| }, | |
| FIELDS = { | |
| AVOID: ["version", "n", "prodid", "abuid"], | |
| FN: ["fn"], | |
| EMAIL: ["email"], | |
| TEL: ["tel"], | |
| ADR: ["adr"], | |
| NOTE: ["note"], | |
| PERSONALS: ["kind", "source", "xml", "nickname", "photo", "bday", "anniversary", "gender", "impp", "lang", "tz", "geo", "title", "role", "logo", "org", "member", "related", "categories", "rev", "sound", "uid", "clientpidmap", "url", "key", "fburl", "caladruri", "caluri"] | |
| }, | |
| MAP_KEYS = CONSTANTS.VCARD_KEYS.reduce(function(acc, key) { | |
| return acc[key] = contactTransformLabel.toLang(key), acc | |
| }, {}), | |
| unescapeValue = function() { | |
| return (arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : "").replace(UNESCAPE_REGEX, function(val) { | |
| return val.substr(1) | |
| }) | |
| }, | |
| processEscape = function() { | |
| return (arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : "").replace(ESCAPE_REGEX, function(val) { | |
| return "\\" + val | |
| }) | |
| }, | |
| escapeValue = function() { | |
| var value = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : ""; | |
| return Array.isArray(value) ? value.map(processEscape) : processEscape(value) | |
| }, | |
| cleanValue = function() { | |
| var value = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : "", | |
| key = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : ""; | |
| return "adr" === key || "n" === key ? value.split(";").map(unescapeValue) : unescapeValue(value) | |
| }, | |
| buildProperty = function() { | |
| var property = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {}, | |
| key = property.getField(); | |
| return { | |
| value: cleanValue(property.valueOf(), key), | |
| type: getType(property), | |
| key: key, | |
| params: property.getParams() | |
| } | |
| }, | |
| checkProperty = function(property) { | |
| return !!Array.isArray(property) || property && !property.isEmpty() | |
| }; | |
| return { | |
| extract: extract, | |
| prepare: prepare, | |
| unescapeValue: unescapeValue, | |
| escapeValue: escapeValue | |
| } | |
| }); | |
| var _slicedToArray = function() { | |
| function sliceIterator(arr, i) { | |
| var _arr = [], | |
| _n = !0, | |
| _d = !1, | |
| _e = void 0; | |
| try { | |
| for (var _s, _i = arr[Symbol.iterator](); !(_n = (_s = _i.next()).done) && (_arr.push(_s.value), !i || _arr.length !== i); _n = !0); | |
| } catch (err) { | |
| _d = !0, _e = err | |
| } finally { | |
| try { | |
| !_n && _i.return && _i.return() | |
| } finally { | |
| if (_d) throw _e | |
| } | |
| } | |
| return _arr | |
| } | |
| return function(arr, i) { | |
| if (Array.isArray(arr)) return arr; | |
| if (Symbol.iterator in Object(arr)) return sliceIterator(arr, i); | |
| throw new TypeError("Invalid attempt to destructure non-iterable instance") | |
| } | |
| }(); | |
| angular.module("proton.contact").factory("contactDownloader", function(Contact, contactLoaderModal, contactDetailsModel, downloadFile, vcard) { | |
| var getFileName = function(id, _ref) { | |
| var _ref2 = _slicedToArray(_ref, 1), | |
| card = _ref2[0], | |
| nameProperty = card.get("fn"); | |
| return "all" !== id && nameProperty ? contactDetailsModel.unescapeValue(nameProperty.valueOf()) + ".vcf" : "proton.vcf" | |
| }, | |
| get = function() { | |
| var _ref3 = _asyncToGenerator(regeneratorRuntime.mark(function _callee(id) { | |
| var _ref4, vCard, list; | |
| return regeneratorRuntime.wrap(function(_context) { | |
| for (;;) switch (_context.prev = _context.next) { | |
| case 0: | |
| if ("all" === id) { | |
| _context.next = 6; | |
| break | |
| } | |
| return _context.next = 3, Contact.get(id); | |
| case 3: | |
| return _ref4 = _context.sent, vCard = _ref4.vCard, _context.abrupt("return", [vCard]); | |
| case 6: | |
| return _context.next = 8, Contact.exportAll(); | |
| case 8: | |
| return list = _context.sent, _context.abrupt("return", list.map(function(_ref5) { | |
| return _ref5.vCard | |
| })); | |
| case 10: | |
| case "end": | |
| return _context.stop() | |
| } | |
| }, _callee, void 0) | |
| })); | |
| return function(_x) { | |
| return _ref3.apply(this, arguments) | |
| } | |
| }(); | |
| return function() { | |
| var id = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : "all", | |
| promise = get(id); | |
| contactLoaderModal.activate({ | |
| params: { | |
| mode: "export", | |
| close: function() { | |
| contactLoaderModal.deactivate() | |
| } | |
| } | |
| }), promise.then(function(data) { | |
| var blob = new Blob([vcard.to(data)], { | |
| type: "data:attachment/vcard;" | |
| }); | |
| contactLoaderModal.deactivate(), downloadFile(blob, getFileName(id, data)) | |
| }).catch(contactLoaderModal.deactivate) | |
| } | |
| }), angular.module("proton.contact").factory("contactEditor", function($rootScope, $state, eventManager, Contact, contactModal, contactEmails, contactCache, contactLoaderModal, contactSchema, confirmModal, gettextCatalog, networkActivityTracker, notification) { | |
| function create(_ref) { | |
| var _ref$contacts = _ref.contacts, | |
| contacts = void 0 === _ref$contacts ? [] : _ref$contacts, | |
| mode = _ref.mode, | |
| promise = Contact.add(contacts).then(function(_ref2) { | |
| var created = _ref2.created, | |
| total = _ref2.total, | |
| errors = _ref2.errors; | |
| return eventManager.call().then(function() { | |
| $rootScope.$emit("contacts", { | |
| type: "contactCreated", | |
| data: { | |
| created: created, | |
| total: total, | |
| errors: errors, | |
| mode: mode | |
| } | |
| }) | |
| }) | |
| }); | |
| return "import" === mode && contactLoaderModal.activate({ | |
| params: { | |
| mode: "import", | |
| close: function() { | |
| contactLoaderModal.deactivate() | |
| } | |
| } | |
| }), promise | |
| } | |
| function update(_ref3) { | |
| var _ref3$contact = _ref3.contact, | |
| contact = void 0 === _ref3$contact ? {} : _ref3$contact, | |
| promise = Contact.update(contact).then(function(_ref4) { | |
| var Contact = _ref4.Contact, | |
| cards = _ref4.cards; | |
| return $rootScope.$emit("contacts", { | |
| type: "contactUpdated", | |
| data: { | |
| contact: Contact, | |
| cards: cards | |
| } | |
| }), notification.success(gettextCatalog.getString("Contact edited", null, "Success message")), eventManager.call() | |
| }); | |
| return networkActivityTracker.track(promise), promise | |
| } | |
| function remove(_ref5) { | |
| var _ref5$contactIDs = _ref5.contactIDs, | |
| contactIDs = void 0 === _ref5$contactIDs ? [] : _ref5$contactIDs, | |
| _ref5$confirm = _ref5.confirm, | |
| confirm = void 0 === _ref5$confirm || _ref5$confirm, | |
| success = "all" === contactIDs ? gettextCatalog.getString("All contacts deleted", null, "Success") : gettextCatalog.getPlural(contactIDs.length, "Contact deleted", "Contacts deleted", null, "Success"), | |
| process = function() { | |
| requestDeletion(contactIDs).then(function() { | |
| notification.success(success), $state.go("secured.contacts") | |
| }) | |
| }; | |
| if (confirm) return confirmDeletion(contactIDs, function() { | |
| return process() | |
| }); | |
| process() | |
| } | |
| function requestDeletion() { | |
| var IDs = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : [], | |
| promise = "all" === IDs ? Contact.clear() : Contact.remove({ | |
| IDs: IDs | |
| }); | |
| return networkActivityTracker.track(promise), promise.then(function() { | |
| return "all" === IDs && (contactCache.clear(), contactEmails.clear()), eventManager.call() | |
| }) | |
| } | |
| function confirmDeletion() { | |
| var contactIDs = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : [], | |
| callback = arguments[1], | |
| message = "all" === contactIDs ? gettextCatalog.getString("Are you sure you want to delete all your contacts?", null, "Info") : gettextCatalog.getPlural(contactIDs.length, "Are you sure you want to delete this contact?", "Are you sure you want to delete the selected contacts?", null, "Info"), | |
| title = "all" === contactIDs ? gettextCatalog.getString("Delete all", null, "Title") : gettextCatalog.getString("Delete", null, "Title"); | |
| confirmModal.activate({ | |
| params: { | |
| title: title, | |
| message: message, | |
| confirm: function() { | |
| callback(), confirmModal.deactivate() | |
| }, | |
| cancel: function() { | |
| confirmModal.deactivate() | |
| } | |
| } | |
| }) | |
| } | |
| function add(_ref6) { | |
| var email = _ref6.email, | |
| name = _ref6.name, | |
| contact = angular.copy(contactSchema.contactAPI); | |
| email && contact.vCard.add("email", email), name && contact.vCard.add("fn", name), contactModal.activate({ | |
| params: { | |
| contact: contact, | |
| close: function() { | |
| contactModal.deactivate() | |
| } | |
| } | |
| }) | |
| } | |
| return $rootScope.$on("contacts", function(event, _ref7) { | |
| var type = _ref7.type, | |
| _ref7$data = _ref7.data, | |
| data = void 0 === _ref7$data ? {} : _ref7$data; | |
| "deleteContacts" === type && remove(data), "updateContact" === type && update(data), "createContact" === type && create(data), "addContact" === type && add(data) | |
| }), { | |
| init: angular.noop, | |
| create: create, | |
| update: update, | |
| remove: remove | |
| } | |
| }), angular.module("proton.contact").factory("contactEmails", function($rootScope, Contact, networkActivityTracker) { | |
| var emails = [], | |
| set = function(data) { | |
| return emails.push.apply(emails, _toConsumableArray(data)) | |
| }, | |
| fetch = function() { | |
| return emails | |
| }, | |
| clear = function() { | |
| return emails.length = 0 | |
| }, | |
| findIndex = function(ID) { | |
| return _.findIndex(emails, { | |
| ID: ID | |
| }) | |
| }, | |
| emit = function(contact) { | |
| $rootScope.$emit("contacts", { | |
| type: "refreshContactEmails", | |
| data: { | |
| ID: contact.ContactID | |
| } | |
| }) | |
| }, | |
| loadCache = function() { | |
| var _ref = _asyncToGenerator(regeneratorRuntime.mark(function _callee() { | |
| var list; | |
| return regeneratorRuntime.wrap(function(_context) { | |
| for (;;) switch (_context.prev = _context.next) { | |
| case 0: | |
| return _context.next = 2, Contact.hydrate(); | |
| case 2: | |
| return list = _context.sent, set(list), _context.abrupt("return", fetch()); | |
| case 5: | |
| case "end": | |
| return _context.stop() | |
| } | |
| }, _callee, void 0) | |
| })); | |
| return function() { | |
| return _ref.apply(this, arguments) | |
| } | |
| }(), | |
| load = function() { | |
| var promise = loadCache(); | |
| return networkActivityTracker.track(promise), promise | |
| }; | |
| return $rootScope.$on("createContactEmail", function(event, contactEmail) { | |
| emails.push(contactEmail), emit(contactEmail) | |
| }), $rootScope.$on("updateContactEmail", function(event, ID, contactEmail) { | |
| var index = findIndex(ID); - 1 !== index ? emails[index] = contactEmail : emails.push(contactEmail), emit(contactEmail) | |
| }), $rootScope.$on("deleteContactEmail", function(event, ID) { | |
| var index = findIndex(ID); - 1 !== index && (emails.splice(index, 1), $rootScope.$emit("contacts", { | |
| type: "deletedContactEmail", | |
| data: { | |
| ID: ID | |
| } | |
| })) | |
| }), { | |
| set: set, | |
| fetch: fetch, | |
| clear: clear, | |
| findIndex: findIndex, | |
| load: load | |
| } | |
| }), angular.module("proton.contact").factory("contactImporter", function($rootScope, contactSchema, importContactModal, notification, vcard, csv, gettextCatalog, networkActivityTracker) { | |
| var I18N = { | |
| noFiles: gettextCatalog.getString("No files were selected", null, "Error"), | |
| invalid: gettextCatalog.getString("Invalid file type", null, "Error"), | |
| parsingCSV: gettextCatalog.getString("Cannot convert the file", null, "Error") | |
| }, | |
| dispatch = function() { | |
| var data = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : []; | |
| return $rootScope.$emit("contacts", { | |
| type: "createContact", | |
| data: { | |
| contacts: contactSchema.prepare(data), | |
| mode: "import" | |
| } | |
| }) | |
| }, | |
| importVCF = function() { | |
| var _ref = _asyncToGenerator(regeneratorRuntime.mark(function _callee(reader) { | |
| return regeneratorRuntime.wrap(function(_context) { | |
| for (;;) switch (_context.prev = _context.next) { | |
| case 0: | |
| return _context.abrupt("return", dispatch(vcard.from(reader.result))); | |
| case 1: | |
| case "end": | |
| return _context.stop() | |
| } | |
| }, _callee, void 0) | |
| })); | |
| return function(_x2) { | |
| return _ref.apply(this, arguments) | |
| } | |
| }(), | |
| importVCard = function(file) { | |
| return csv.csvToVCard(file).then(function() { | |
| var parsed = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : []; | |
| return parsed.length && dispatch(parsed) | |
| }).catch(function(e) { | |
| throw console.error(e), new Error(I18N.parsingCSV) | |
| }) | |
| }, | |
| MAP_SRC = { | |
| ".vcf": importVCF, | |
| ".csv": importVCard | |
| }, | |
| importFiles = function() { | |
| var files = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : []; | |
| if (!files.length) return notification.error(I18N.noFiles); | |
| var reader = new FileReader, | |
| file = files[0], | |
| extension = file.name.slice(-4); | |
| reader.onload = function(e) { | |
| return notification.error(e) | |
| }, reader.onload = function() { | |
| if (!MAP_SRC[extension]) return notification.error(I18N.invalid), importContactModal.deactivate(); | |
| var parameter = ".vcf" === extension ? reader : file, | |
| promise = MAP_SRC[extension](parameter).then(function() { | |
| return importContactModal.deactivate() | |
| }); | |
| networkActivityTracker.track(promise) | |
| }, reader.readAsText(file, "utf-8") | |
| }; | |
| return function() { | |
| importContactModal.activate({ | |
| params: { | |
| import: importFiles, | |
| cancel: function() { | |
| importContactModal.deactivate() | |
| } | |
| } | |
| }) | |
| } | |
| }), angular.module("proton.contact").factory("contactMerger", function($rootScope, contactMergerModal, contactEditor, contactSchema, Contact, gettextCatalog, networkActivityTracker, notification, vcard) { | |
| function getEmails(_ref) { | |
| var Emails = _ref.Emails, | |
| vCard = _ref.vCard; | |
| return Array.isArray(Emails) ? _.map(Emails, function(_ref2) { | |
| var _ref2$Email = _ref2.Email; | |
| return void 0 === _ref2$Email ? "" : _ref2$Email | |
| }) : _.reduce(vcard.extractProperties(vCard), function(acc, property) { | |
| return "email" === property.getField() && acc.push(property.valueOf()), acc | |
| }, []) | |
| } | |
| function extractDuplicates() { | |
| var contacts = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : [], | |
| _$reduce = _.reduce(contacts, function(acc, contact, index) { | |
| var emails = getEmails(contact); | |
| return _.each(emails, function() { | |
| var email = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : ""; | |
| acc.map[email] = acc.map[email] || [], acc.map[email].push(index), acc.map[email].length > 1 && acc.duplicate.push(email) | |
| }), acc | |
| }, { | |
| map: {}, | |
| duplicate: [] | |
| }), | |
| _$reduce$map = _$reduce.map, | |
| map = void 0 === _$reduce$map ? {} : _$reduce$map, | |
| _$reduce$duplicate = _$reduce.duplicate, | |
| duplicate = void 0 === _$reduce$duplicate ? [] : _$reduce$duplicate; | |
| return _.chain(duplicate).uniq().reduce(function(acc, email) { | |
| return acc[email] = [], _.each(map[email], function(index) { | |
| var contact = contacts[index]; | |
| contact.selected = !0, acc[email].push(contact) | |
| }), acc | |
| }, {}).value() | |
| } | |
| function confirm(emails) { | |
| contactMergerModal.activate({ | |
| params: { | |
| emails: emails, | |
| merge: function() { | |
| _merge(arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {}), contactMergerModal.deactivate() | |
| }, | |
| close: function() { | |
| contactMergerModal.deactivate() | |
| } | |
| } | |
| }) | |
| } | |
| function _merge() { | |
| var emails = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {}, | |
| _$chain$reduce$value = _.chain(Object.keys(emails)).reduce(function(acc, key) { | |
| var contacts = emails[key], | |
| properties = _.chain(contacts).filter(function(_ref3) { | |
| return _ref3.selected | |
| }).reduce(function(acc2, contact) { | |
| return contact.selected && (acc.toDelete.push(contact.ID), acc2.push(vcard.extractProperties(contact.vCard))), acc2 | |
| }, []).value(); | |
| if (properties.length) { | |
| var newCard = new vCard; | |
| _.each(properties, function(property) { | |
| return newCard.addProperty(property) | |
| }), acc.toCreate.push(newCard) | |
| } | |
| return acc | |
| }, { | |
| toDelete: [], | |
| toCreate: [] | |
| }).value(), | |
| toDelete = _$chain$reduce$value.toDelete, | |
| toCreate = _$chain$reduce$value.toCreate; | |
| contactEditor.remove({ | |
| contactIDs: toDelete, | |
| confirm: !1 | |
| }), contactEditor.create({ | |
| contacts: contactSchema.prepare(toCreate) | |
| }) | |
| } | |
| function mergeContacts() { | |
| var promise = Contact.exportAll().then(function(contacts) { | |
| var emails = extractDuplicates(contacts); | |
| Object.keys(emails).length ? confirm(emails) : notification.info(I18N.noDuplicate) | |
| }); | |
| return networkActivityTracker.track(promise), promise | |
| } | |
| var I18N = { | |
| mergeContacts: gettextCatalog.getString("Merge contacts", null, "Title"), | |
| noDuplicate: gettextCatalog.getString("You have no duplicate contacts", null, "Info") | |
| }; | |
| return $rootScope.$on("contacts", function(event, _ref4) { | |
| "mergeContacts" === _ref4.type && mergeContacts() | |
| }), { | |
| init: angular.noop, | |
| extractDuplicates: extractDuplicates | |
| } | |
| }), angular.module("proton.contact").factory("contactSchema", function(gettextCatalog) { | |
| function getType(property) { | |
| var type = property.getType(); | |
| return Array.isArray(type) ? type : [type] | |
| } | |
| var contactAPI = { | |
| vCard: new vCard | |
| }, | |
| group = ["Tel", "Adr", "Note"], | |
| personnal = ["Bday", "Title", "Org", "Nickname"], | |
| I18N = { | |
| UNKNOWN: gettextCatalog.getString("Unknown", null, "Default display name vcard") | |
| }, | |
| all = group.concat(personnal), | |
| buildEmailProperty = function() { | |
| var property = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {}; | |
| return { | |
| Email: property.valueOf(), | |
| Type: getType(property) | |
| } | |
| }, | |
| formatEmails = function() { | |
| var property = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {}; | |
| return Array.isArray(property) ? _.map(property, buildEmailProperty) : [buildEmailProperty(property)] | |
| }, | |
| checkProperty = function(property) { | |
| return !!Array.isArray(property) || property && !property.isEmpty() && property.valueOf().trim() | |
| }; | |
| return { | |
| contactAPI: contactAPI, | |
| group: group, | |
| personnal: personnal, | |
| custom: function(key) { | |
| return -1 === all.indexOf(key) | |
| }, | |
| prepare: function() { | |
| var contacts = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : []; | |
| return _.reduce(contacts, function(acc, contact) { | |
| var prepared = { | |
| Emails: [], | |
| vCard: contact | |
| }, | |
| nameProperty = contact.get("fn"), | |
| emailProperty = contact.get("email"); | |
| if (checkProperty(emailProperty) && (prepared.Emails = formatEmails(emailProperty)), checkProperty(nameProperty)) prepared.Name = nameProperty.valueOf().trim(); | |
| else { | |
| var nameValue = prepared.Emails.length ? prepared.Emails[0].Email : I18N.UNKNOWN; | |
| prepared.Name = nameValue, prepared.vCard.set("fn", nameValue) | |
| } | |
| return acc.push(prepared), acc | |
| }, []) | |
| } | |
| } | |
| }), angular.module("proton.contact").factory("contactTransformLabel", function(gettextCatalog) { | |
| var MAP = { | |
| adr: gettextCatalog.getString("Address", null, "VCard key name"), | |
| anniversary: gettextCatalog.getString("Anniversary", null, "VCard key name"), | |
| caladruri: gettextCatalog.getString("Calendar user address", null, "VCard key name"), | |
| caluri: gettextCatalog.getString("URI for a calendar", null, "VCard key name"), | |
| bday: gettextCatalog.getString("Birthday", null, "VCard key name"), | |
| categories: gettextCatalog.getString("Categories", null, "VCard key name"), | |
| cell: gettextCatalog.getString("Cell", null, "VCard key name"), | |
| custom: gettextCatalog.getString("Custom", null, "VCard key name"), | |
| email: gettextCatalog.getString("Email", null, "VCard key name"), | |
| fax: gettextCatalog.getString("Fax", null, "VCard key name"), | |
| fburl: gettextCatalog.getString("Free or busy URL", null, "VCard key name"), | |
| fn: gettextCatalog.getString("Name", null, "VCard key name"), | |
| gender: gettextCatalog.getString("Gender", null, "VCard key name"), | |
| geo: gettextCatalog.getString("Geolocation", null, "VCard key name"), | |
| home: gettextCatalog.getString("Personal", null, "VCard key name"), | |
| impp: gettextCatalog.getString("Impp", null, "VCard key name"), | |
| key: gettextCatalog.getString("Key", null, "VCard key name"), | |
| lang: gettextCatalog.getString("Language", null, "VCard key name"), | |
| logo: gettextCatalog.getString("Logo", null, "VCard key name"), | |
| member: gettextCatalog.getString("Member", null, "VCard key name"), | |
| nickname: gettextCatalog.getString("Nickname", null, "VCard key name"), | |
| note: gettextCatalog.getString("Note", null, "VCard key name"), | |
| office: gettextCatalog.getString("Office", null, "VCard key name"), | |
| org: gettextCatalog.getString("Organization", null, "VCard key name"), | |
| photo: gettextCatalog.getString("Photo", null, "VCard key name"), | |
| private: gettextCatalog.getString("Private", null, "VCard key name"), | |
| prodid: gettextCatalog.getString("Software", null, "VCard key name"), | |
| related: gettextCatalog.getString("Related", null, "VCard key name"), | |
| rev: gettextCatalog.getString("Revision", null, "VCard key name"), | |
| role: gettextCatalog.getString("Role", null, "VCard key name"), | |
| sound: gettextCatalog.getString("Sound", null, "VCard key name"), | |
| tel: gettextCatalog.getString("Phone", null, "VCard key name"), | |
| title: gettextCatalog.getString("Title", null, "VCard key name"), | |
| tz: gettextCatalog.getString("Timezone", null, "VCard key name"), | |
| uid: "UID", | |
| url: "URL", | |
| work: gettextCatalog.getString("Work", null, "VCard key name") | |
| }; | |
| return { | |
| toLang: function() { | |
| var label = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : ""; | |
| return MAP[label.toLowerCase()] || "" + label.charAt(0).toUpperCase() + label.slice(1) | |
| }, | |
| toVCard: function() { | |
| var label = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : ""; | |
| return Object.keys(MAP).find(function(key) { | |
| return label === MAP[key] | |
| }) || label | |
| } | |
| } | |
| }), angular.module("proton.contact").factory("contactUI", function(gettextCatalog, tools, contactTransformLabel) { | |
| function removeX() { | |
| var value = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : ""; | |
| return value.toLowerCase().startsWith("x-") ? value.substring(2) : value.toLowerCase().startsWith("x") ? value.substring(1) : value | |
| } | |
| function initialize() { | |
| var datas = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : [], | |
| type = arguments[1], | |
| UI = { | |
| allowCustom: !1, | |
| allowMultiple: !1, | |
| mode: "singleLine", | |
| infinite: !1, | |
| unique: !1, | |
| sortable: !1, | |
| sortableState: !1, | |
| placeholder: "", | |
| iconClass: "", | |
| labels: [], | |
| items: [], | |
| hide: ["version", "n", "prodid", "abuid", "uid"], | |
| inputType: "text" | |
| }; | |
| switch (type) { | |
| case "Name": | |
| UI.unique = !0, UI.placeholder = I18N.name, UI.iconClass = "fa-user"; | |
| break; | |
| case "Emails": | |
| UI.infinite = !0, UI.sortable = !0, UI.inputType = "email", UI.placeholder = I18N.emailAddress, UI.iconClass = "fa-envelope", UI.labels = EMAIL_TYPE.map(function(label) { | |
| return contactTransformLabel.toLang(label) | |
| }); | |
| break; | |
| case "Tels": | |
| UI.inputType = "tel", UI.placeholder = I18N.phoneNumber, UI.iconClass = "fa-phone", UI.labels = TEL_TYPE.map(function(label) { | |
| return contactTransformLabel.toLang(label) | |
| }); | |
| break; | |
| case "Adrs": | |
| UI.placeholder = I18N.address, UI.iconClass = "fa-home", UI.mode = "address", UI.labels = ADR_TYPE.map(function(label) { | |
| return contactTransformLabel.toLang(label) | |
| }); | |
| break; | |
| case "Personals": | |
| UI.placeholder = I18N.information, UI.iconClass = "fa-address-card", UI.labels = PERSONAL_TYPE.map(function(label) { | |
| return contactTransformLabel.toLang(label) | |
| }); | |
| break; | |
| case "Notes": | |
| UI.placeholder = I18N.note, UI.iconClass = "fa-sticky-note", UI.mode = "multiLine", UI.unique = !0; | |
| break; | |
| case "Customs": | |
| UI.infinite = !0, UI.placeholder = I18N.customField, UI.iconClass = "fa-asterisk", UI.labels = [I18N.custom], UI.allowCustom = !0 | |
| } | |
| if (UI.selectable = UI.labels.length > 1, datas.length && (UI.allowMultiple = !0, datas.forEach(function(data) { | |
| (data.value || UI.unique) && add(UI, data.key, removeX(data.type) || removeX(data.key), data.value) | |
| })), !datas.length || 1 === datas.length && _.contains(UI.hide, datas[0].key)) { | |
| var populated = populate(UI, type); | |
| add(UI, populated.key, populated.type, "") | |
| } | |
| return UI.inputName = "name_" + UI.placeholder.replace(/\W+|_/g, ""), UI | |
| } | |
| function populate(UI, type) { | |
| switch (type) { | |
| case "Name": | |
| return { | |
| key: "fn", | |
| type: "fn" | |
| }; | |
| case "Emails": | |
| return { | |
| key: "email", | |
| type: "email" | |
| }; | |
| case "Tels": | |
| return { | |
| key: "tel", | |
| type: "tel" | |
| }; | |
| case "Adrs": | |
| return { | |
| key: "adr", | |
| type: "adr" | |
| }; | |
| case "Personals": | |
| var key = findKey(UI); | |
| return { | |
| key: key, | |
| type: key | |
| }; | |
| case "Customs": | |
| return { | |
| key: "x-custom", | |
| type: "custom" | |
| }; | |
| case "Notes": | |
| return { | |
| key: "note", | |
| type: "note" | |
| } | |
| } | |
| } | |
| function findKey(_ref) { | |
| var _ref$items = _ref.items, | |
| items = void 0 === _ref$items ? [] : _ref$items, | |
| types = _.pluck(items, "type"); | |
| return _.find(PERSONAL_TYPE, function(type) { | |
| return -1 === types.indexOf(type) | |
| }) || PERSONAL_TYPE[_.random(PERSONAL_TYPE.length - 1)] | |
| } | |
| function add(UI, type, label) { | |
| var value = arguments.length > 3 && void 0 !== arguments[3] ? arguments[3] : "", | |
| params = arguments[4], | |
| hide = _.contains(UI.hide, type); | |
| UI.items.push({ | |
| type: type, | |
| label: contactTransformLabel.toLang(label), | |
| value: value, | |
| hide: hide, | |
| params: params | |
| }) | |
| } | |
| var EMAIL_TYPE = ["email", "home", "work", "other"], | |
| TEL_TYPE = ["tel", "mobile", "work", "fax", "other"], | |
| ADR_TYPE = ["adr", "home", "work", "other"], | |
| PERSONAL_TYPE = ["org", "anniversary", "bday", "gender", "nickname", "role", "title", "url"], | |
| I18N = { | |
| name: gettextCatalog.getString("Name", null, "Placeholder"), | |
| emailAddress: gettextCatalog.getString("Email address", null, "Placeholder"), | |
| phoneNumber: gettextCatalog.getString("Phone number", null, "Placeholder"), | |
| information: gettextCatalog.getString("Information", null, "Placeholder"), | |
| note: gettextCatalog.getString("A note", null, "Placeholder"), | |
| address: gettextCatalog.getString("Address", null, "Placeholder"), | |
| custom: gettextCatalog.getString("Custom", null), | |
| customField: gettextCatalog.getString("Custom field", null, "Placeholder") | |
| }; | |
| return { | |
| remove: function(UI, item) { | |
| return UI.items.splice(UI.items.indexOf(item), 1) | |
| }, | |
| add: add, | |
| initialize: initialize, | |
| populate: populate | |
| } | |
| }), angular.module("proton.contact").filter("contact", function(gettextCatalog, authentication) { | |
| var getContact = function(Email) { | |
| return _.findWhere(authentication.user.Contacts, { | |
| Email: Email | |
| }) || {} | |
| }, | |
| getContactFromUser = function(nameContact, Address) { | |
| var _getContact = getContact(Address), | |
| _getContact$Name = _getContact.Name, | |
| Name = void 0 === _getContact$Name ? "" : _getContact$Name, | |
| Email = _getContact.Email; | |
| return Name && Name !== Email ? Name : nameContact || Address | |
| }, | |
| fillContact = function(Name, Address) { | |
| var contact = getContact(Address); | |
| return Address !== Name && Name ? angular.isString(contact.Name) && contact.Name ? contact.Name + " <" + Address + ">" : void 0 : Address | |
| }; | |
| return function(sender, parameter) { | |
| var _ref = sender || {}, | |
| _ref$Name = _ref.Name, | |
| Name = void 0 === _ref$Name ? "" : _ref$Name, | |
| _ref$Address = _ref.Address, | |
| Address = void 0 === _ref$Address ? "" : _ref$Address; | |
| return "Address" === parameter ? "<" + Address + ">" : "Name" === parameter ? getContactFromUser(Name, Address) : fillContact(Name, Address) || Name + " <" + Address + ">" | |
| } | |
| }), angular.module("proton.contact").filter("spam", function() { | |
| return function() { | |
| var contacts = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : [], | |
| input = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : ""; | |
| return input ? _.filter(contacts, function(contact) { | |
| return contact.Email.indexOf(input) > -1 | |
| }) : contacts | |
| } | |
| }), angular.module("proton.contact").factory("contactBeforeToLeaveModal", function(pmModal) { | |
| return pmModal({ | |
| controllerAs: "ctrl", | |
| templateUrl: "templates/contact/contactBeforeToLeaveModal.tpl.html", | |
| controller: function(params) { | |
| this.save = params.save, this.discard = params.discard, this.cancel = params.cancel | |
| } | |
| }) | |
| }); | |
| var _slicedToArray = function() { | |
| function sliceIterator(arr, i) { | |
| var _arr = [], | |
| _n = !0, | |
| _d = !1, | |
| _e = void 0; | |
| try { | |
| for (var _s, _i = arr[Symbol.iterator](); !(_n = (_s = _i.next()).done) && (_arr.push(_s.value), !i || _arr.length !== i); _n = !0); | |
| } catch (err) { | |
| _d = !0, _e = err | |
| } finally { | |
| try { | |
| !_n && _i.return && _i.return() | |
| } finally { | |
| if (_d) throw _e | |
| } | |
| } | |
| return _arr | |
| } | |
| return function(arr, i) { | |
| if (Array.isArray(arr)) return arr; | |
| if (Symbol.iterator in Object(arr)) return sliceIterator(arr, i); | |
| throw new TypeError("Invalid attempt to destructure non-iterable instance") | |
| } | |
| }(); | |
| angular.module("proton.contact").factory("contactLoaderModal", function($rootScope, gettextCatalog, pmModal) { | |
| var I18N = { | |
| encrypting: function(progress) { | |
| return gettextCatalog.getString("Encrypting contacts: {{progress}}%", { | |
| progress: progress | |
| }, "Label for the progress bar displayed during the contact import") | |
| }, | |
| decrypting: function(progress) { | |
| return gettextCatalog.getString("Decrypting contacts: {{progress}}%", { | |
| progress: progress | |
| }, "Label for the progress bar displayed during the contact export") | |
| }, | |
| upload: function(progress) { | |
| return gettextCatalog.getString("Upload: {{progress}}%", { | |
| progress: progress | |
| }, "Label for the progress bar displayed during the contact import") | |
| }, | |
| importComplete: gettextCatalog.getString("Importing contacts complete!", null, "Import complete"), | |
| contactImported: gettextCatalog.getString("contacts successfully imported.", null, "1 of 2 contacts successfully imported."), | |
| exportTitle: gettextCatalog.getString("Exporting Contacts", null, "Title for the contacts exporter modal"), | |
| importTitle: gettextCatalog.getString("Importing Contacts", null, "Title for the contacts exporter modal"), | |
| exportInfo: gettextCatalog.getString("Exporting contacts, this may take a few minutes. When the progress is completed, this modal will close and let you download the file.", null, "Information for the contacts exporter modal"), | |
| importInfo: gettextCatalog.getString("Importing contacts, this may take a few minutes.", null, "Information for the contacts importer modal"), | |
| importFail: function(number) { | |
| return gettextCatalog.getString("{{number}} failed to import.", { | |
| number: number | |
| }, "Number of failed contact during the contact import") | |
| }, | |
| totalFailure: gettextCatalog.getString("Import failed. Please check the import file or try again.", null, "Error during importation") | |
| }, | |
| getTitle = function(mode) { | |
| return "export" === mode ? I18N.exportTitle : I18N.importTitle | |
| }, | |
| getInfo = function(mode) { | |
| return "export" === mode ? I18N.exportInfo : I18N.importInfo | |
| }, | |
| getLabel = function() { | |
| var mode = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : "", | |
| progress = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : 0; | |
| return "export" === mode ? I18N.decrypting(progress) : "import" === mode ? progress > 50 ? I18N.upload(progress) : I18N.encrypting(progress) : "" | |
| }, | |
| getRows = function() { | |
| return (arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : []).map(function(_ref) { | |
| return '<li class="contactLoaderModal-log">- ' + _ref.error + "</li>" | |
| }).join("") | |
| }, | |
| getSuccess = function(_ref2) { | |
| var _ref2$created = _ref2.created, | |
| created = void 0 === _ref2$created ? [] : _ref2$created, | |
| _ref2$total = _ref2.total, | |
| total = void 0 === _ref2$total ? 0 : _ref2$total, | |
| _ref2$errors = _ref2.errors, | |
| errors = void 0 === _ref2$errors ? [] : _ref2$errors; | |
| if (!created.length) { | |
| var _errors = _slicedToArray(errors, 1), | |
| _errors$ = _errors[0]; | |
| _errors$ = void 0 === _errors$ ? {} : _errors$; | |
| var _errors$$error = _errors$.error; | |
| return '<p class="alert alert-danger">' + (void 0 === _errors$$error ? I18N.totalFailure : _errors$$error) + "</p>" | |
| } | |
| var failure = errors.length ? "<p>" + I18N.importFail(errors.length) + "</p>" : "", | |
| logs = errors.length ? '<ul class="contactLoaderModal-logs">' + getRows(errors) + "</ul>" : ""; | |
| return "\n <p>" + I18N.importComplete + '</p>\n <div class="contactLoaderModal-frame">\n <h1>' + created.length + " of " + total + "</h1>\n <strong>" + I18N.contactImported + "</strong>\n </div>\n " + failure + "\n " + logs + "\n " | |
| }; | |
| return pmModal({ | |
| controllerAs: "ctrl", | |
| templateUrl: "templates/contact/contactLoaderModal.tpl.html", | |
| controller: function(params) { | |
| var unsubscribe = []; | |
| unsubscribe.push($rootScope.$on("contacts", function(event, _ref3) { | |
| var _ref3$type = _ref3.type, | |
| type = void 0 === _ref3$type ? "" : _ref3$type, | |
| _ref3$data = _ref3.data, | |
| data = void 0 === _ref3$data ? {} : _ref3$data; | |
| "contactCreated" === type && (document.querySelector(".contactLoaderModal-container").classList.add("contactLoaderModal-imported"), document.querySelector(".contactLoaderModal-success").innerHTML = getSuccess(data)) | |
| })), unsubscribe.push($rootScope.$on("progressBar", function(event, _ref4) { | |
| var _ref4$type = _ref4.type, | |
| type = void 0 === _ref4$type ? "" : _ref4$type, | |
| _ref4$data = _ref4.data, | |
| data = void 0 === _ref4$data ? {} : _ref4$data, | |
| $label = document.querySelector(".contactLoaderModal-label"); | |
| $label && "contactsProgressBar" === type && ($label.textContent = getLabel(params.mode, data.progress)) | |
| })), this.title = getTitle(params.mode), this.info = getInfo(params.mode), this.close = params.close, this.$onDestroy = function() { | |
| _.each(unsubscribe, function(cb) { | |
| return cb() | |
| }), unsubscribe.length = 0 | |
| } | |
| } | |
| }) | |
| }), angular.module("proton.contact").factory("contactMergerModal", function(gettextCatalog, pmModal) { | |
| return pmModal({ | |
| controllerAs: "ctrl", | |
| templateUrl: "templates/contact/contactMergerModal.tpl.html", | |
| controller: function(params) { | |
| var _this = this; | |
| this.title = gettextCatalog.getPlural(Object.keys(params.emails).length, "1 Duplicate found", "{{$count}} Duplicates found", {}), this.emails = params.emails, this.cancel = function() { | |
| return params.close() | |
| }, this.merge = function() { | |
| return params.merge(_this.emails) | |
| } | |
| } | |
| }) | |
| }), angular.module("proton.contact").factory("contactModal", function($rootScope, $state, gettextCatalog, notification, pmModal) { | |
| var I18N = { | |
| contactAdded: gettextCatalog.getString("Contact added", null, "Success message for the contact modal"), | |
| contactError: gettextCatalog.getString("Error with the request", null, "Default error for the contact modal") | |
| }; | |
| return pmModal({ | |
| controllerAs: "ctrl", | |
| templateUrl: "templates/contact/contactModal.tpl.html", | |
| controller: function(params) { | |
| var processing = !1, | |
| unsubscribe = $rootScope.$on("contacts", function(event, _ref) { | |
| var _ref$type = _ref.type, | |
| type = void 0 === _ref$type ? "" : _ref$type, | |
| _ref$data = _ref.data, | |
| data = void 0 === _ref$data ? {} : _ref$data; | |
| if ("contactCreated" === type) { | |
| var _data$created = data.created, | |
| created = void 0 === _data$created ? [] : _data$created, | |
| _data$errors = data.errors, | |
| errors = void 0 === _data$errors ? [] : _data$errors; | |
| processing = !1, errors.length && errors.forEach(function(_ref2) { | |
| var _ref2$error = _ref2.error, | |
| error = void 0 === _ref2$error ? I18N.contactError : _ref2$error; | |
| return notification.error(error) | |
| }), created.length && (notification.success(I18N.contactAdded), $state.go("secured.contacts.details", { | |
| id: created[0].ID | |
| }), params.close()) | |
| } | |
| }); | |
| this.contact = params.contact, this.cancel = params.close, this.$onDestroy = function() { | |
| return unsubscribe() | |
| }, this.submit = function() { | |
| processing || (processing = !0, $rootScope.$emit("contacts", { | |
| type: "submitContactForm" | |
| })) | |
| } | |
| } | |
| }) | |
| }), angular.module("proton.contact").factory("importContactModal", function(pmModal, notification, gettextCatalog) { | |
| var I18N = { | |
| invalidType: gettextCatalog.getString("Invalid file type") | |
| }; | |
| return pmModal({ | |
| controllerAs: "ctrl", | |
| templateUrl: "templates/contact/importContactModal.tpl.html", | |
| controller: function(params, notify, $timeout, $scope) { | |
| var _this = this, | |
| files = [], | |
| extension = void 0; | |
| this.import = function() { | |
| return params.import(files) | |
| }, this.cancel = params.cancel; | |
| var initialization = function() { | |
| var drop = document.getElementById("dropzone"), | |
| $selectFile = $("#selectedFile"); | |
| drop.ondrop = function(e) { | |
| e.preventDefault(); | |
| var file = e.dataTransfer.files[0]; | |
| if (".csv" !== (extension = file.name.substr(file.name.length - 4)) && ".vcf" !== extension) return _this.hover = !1, notification.error(I18N.invalidType); | |
| files = e.dataTransfer.files, $scope.$applyAsync(function() { | |
| _this.fileDropped = files[0].name, _this.hover = !1 | |
| }) | |
| }, drop.ondragover = function(event) { | |
| event.preventDefault(), _this.hover = !0 | |
| }, drop.ondragleave = function(event) { | |
| event.preventDefault(), _this.hover = !1 | |
| }, $("#dropzone").on("click", function() { | |
| $selectFile.trigger("click") | |
| }), $selectFile.change(function() { | |
| var listFiles = $selectFile[0].files, | |
| file = listFiles[0].name; | |
| if (".csv" !== (extension = file.substr(file.length - 4)) && ".vcf" !== extension) return notification.error(I18N.invalidType); | |
| files = listFiles, $scope.$applyAsync(function() { | |
| _this.fileDropped = file, _this.hover = !1 | |
| }) | |
| }) | |
| }; | |
| _.defer(initialization, 100) | |
| } | |
| }) | |
| }), angular.module("proton.conversation").directive("conversation", function($filter, $rootScope, $state, $stateParams, actionConversation, conversationListeners, messageActions, authentication, messageScroll, cache, CONSTANTS, tools, hotkeys, labelsModel, findExpendableMessage, dispatchers) { | |
| var getScrollToPosition = function() { | |
| var container = document.getElementById("pm_thread"), | |
| getDelta = function(node, type) { | |
| if ("UP" === type) { | |
| if (!node.previousElementSibling) return 0; | |
| return node.previousElementSibling.classList.contains("open") ? node.previousElementSibling.offsetHeight + 42 : 42 | |
| } | |
| return node.nextElementSibling && node.nextElementSibling.classList.contains("open") ? node.nextElementSibling.offsetHeight + 42 : 42 | |
| }; | |
| return function(index, max) { | |
| var type = arguments.length > 2 && void 0 !== arguments[2] ? arguments[2] : "UP", | |
| $item = container.querySelector(".message.marked"); | |
| if ($item) { | |
| var delta = getDelta($item, type); | |
| if (0 === index) return container.scrollTop = 0; | |
| "UP" === type && (container.scrollTop -= delta), "DOWN" === type && (container.scrollTop = $item.offsetTop + delta - container.offsetHeight / 2) | |
| } | |
| } | |
| }; | |
| return { | |
| restrict: "E", | |
| replace: !0, | |
| scope: { | |
| conversation: "=" | |
| }, | |
| templateUrl: "templates/partials/conversation.tpl.html", | |
| link: function(scope) { | |
| function back() { | |
| var route = $state.$current.name.replace(".element", ""); | |
| $state.go(route, { | |
| id: null | |
| }) | |
| } | |
| function expandMessage() { | |
| var messages = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : [], | |
| message = findExpendableMessage.find(messages); | |
| return messages.length && (message.openMe = !0), messages | |
| } | |
| function refreshConversation() { | |
| var conversation = cache.getConversationCached($stateParams.id), | |
| messages = cache.queryMessagesCached($stateParams.id), | |
| labelID = tools.currentLocation(); | |
| return messagesCached = messages, scope.trashed = messagesCached.some(function(_ref4) { | |
| var _ref4$LabelIDs = _ref4.LabelIDs, | |
| LabelIDs = void 0 === _ref4$LabelIDs ? [] : _ref4$LabelIDs; | |
| return _.contains(LabelIDs, CONSTANTS.MAILBOX_IDENTIFIERS.trash) | |
| }), scope.nonTrashed = messagesCached.some(function(_ref5) { | |
| var _ref5$LabelIDs = _ref5.LabelIDs, | |
| LabelIDs = void 0 === _ref5$LabelIDs ? [] : _ref5$LabelIDs; | |
| return !_.contains(LabelIDs, CONSTANTS.MAILBOX_IDENTIFIERS.trash) | |
| }), conversation && (_.findWhere(conversation.Labels, { | |
| ID: labelID | |
| }) || $state.includes("secured.search.**")) ? (_.extend(scope.conversation, conversation), void(Array.isArray(messages) && messages.length > 0 ? function() { | |
| for (var toAdd = [], toRemove = [], list = cache.orderMessage($filter("filterMessages")(messages, scope.showTrashed, scope.showNonTrashed), !1), index = 0; index < list.length; index++) ! function(index) { | |
| scope.messages.some(function(_ref6) { | |
| return _ref6.ID === list[index].ID | |
| }) || toAdd.push({ | |
| index: index, | |
| message: list[index] | |
| }) | |
| }(index); | |
| for (var index = 0; index < toAdd.length; index++) { | |
| var ref = toAdd[index]; | |
| scope.messages.splice(ref.index, 0, ref.message) | |
| } | |
| for (var _index = 0; _index < scope.messages.length; _index++) ! function(_index) { | |
| list.some(function(_ref7) { | |
| return _ref7.ID === scope.messages[_index].ID | |
| }) || toRemove.push({ | |
| index: _index | |
| }) | |
| }(_index); | |
| for (var _index2 = toRemove.length - 1; _index2 >= 0; _index2--) scope.messages.splice(toRemove[_index2].index, 1) | |
| }() : back())) : back() | |
| } | |
| var messagesCached = [], | |
| _dispatchers = dispatchers(["message.open", "refreshConversation", "message.expiration", "unmarkMessages", "toggleStar", "elements"]), | |
| on = _dispatchers.on, | |
| unsubscribe = _dispatchers.unsubscribe, | |
| dispatcher = _dispatchers.dispatcher, | |
| scrollToPosition = getScrollToPosition(), | |
| unsubscribeActions = angular.noop; | |
| scope.messages = [], scope.mailbox = tools.currentMailbox(), scope.labels = labelsModel.get(), scope.showTrashed = !1, scope.showNonTrashed = !1, $rootScope.numberElementSelected = 1, $rootScope.showWelcome = !1, scope.inTrash = $state.includes("secured.trash.**"), scope.inSpam = $state.includes("secured.spam.**"), scope.getElements = function() { | |
| return [scope.conversation] | |
| }; | |
| var openMarked = function(message) { | |
| return function() { | |
| var msg = message || scope.markedMessage; | |
| if (msg) return msg.Type === CONSTANTS.DRAFT ? $rootScope.$emit("composer.load", msg) : void dispatcher["message.open"]("toggle", { | |
| action: "openMarked", | |
| message: msg | |
| }) | |
| } | |
| }; | |
| on("refreshConversation", function(event, conversationIDs) { | |
| conversationIDs.indexOf(scope.conversation.ID) > -1 && refreshConversation() | |
| }), on("message.expiration", function() { | |
| scope.$applyAsync(function() { | |
| return refreshConversation() | |
| }) | |
| }), on("message.open", function(event, _ref) { | |
| var type = _ref.type, | |
| data = _ref.data; | |
| if ("toggle" === type && (unsubscribeActions(), unsubscribeActions = conversationListeners(data.message), hotkeys.unbind(["down", "up"]), scope.markedMessage = void 0), "render" === type) return messageScroll.to(data) | |
| }), on("unmarkMessages", function() { | |
| scope.markedMessage = void 0, unsubscribeActions() | |
| }), scope.$on("move", function(e, mailbox) { | |
| unsubscribeActions(); | |
| var labelID = CONSTANTS.MAILBOX_IDENTIFIERS[mailbox]; | |
| if (scope.markedMessage) return $rootScope.$emit("messageActions", { | |
| action: "move", | |
| data: { | |
| ids: [scope.markedMessage.ID], | |
| labelID: labelID | |
| } | |
| }); | |
| actionConversation.move([scope.conversation.ID], labelID) | |
| }); | |
| var onNextPrevElement = function(type) { | |
| return function() { | |
| var index = _.findIndex(scope.messages, { | |
| expand: !0 | |
| }), | |
| pos = "DOWN" === type ? index + 1 : index - 1, | |
| message = scope.messages[pos]; | |
| "DOWN" === type && pos === scope.messages.length || ("UP" !== type || index) && scope.$applyAsync(function() { | |
| scope.messages[index].expand = !1, scrollToPosition(pos, scope.messages.length, type), unsubscribeActions = conversationListeners(message), openMarked(message)() | |
| }) | |
| } | |
| }; | |
| scope.$on("nextElement", onNextPrevElement("DOWN")), scope.$on("previousElement", onNextPrevElement("UP")), scope.$on("markPrevious", function() { | |
| if (unsubscribeActions(), scope.markedMessage) { | |
| var index = scope.messages.indexOf(scope.markedMessage); | |
| if (index > 0) { | |
| var pos = index - 1; | |
| scope.$applyAsync(function() { | |
| scope.markedMessage = scope.messages[pos], scrollToPosition(pos, scope.messages.length, "UP"), unsubscribeActions = conversationListeners(scope.markedMessage) | |
| }) | |
| } | |
| } | |
| }), scope.$on("markNext", function() { | |
| if (unsubscribeActions(), scope.markedMessage) { | |
| var index = scope.messages.indexOf(scope.markedMessage); | |
| if (index < scope.messages.length - 1) { | |
| var pos = index + 1; | |
| scope.$applyAsync(function() { | |
| scope.markedMessage = scope.messages[pos], scrollToPosition(pos, scope.messages.length, "DOWN"), unsubscribeActions = conversationListeners(scope.markedMessage) | |
| }) | |
| } | |
| } | |
| }), on("toggleStar", function() { | |
| var data = { | |
| model: scope.conversation, | |
| type: "conversation" | |
| }; | |
| scope.markedMessage && (data.model = scope.markedMessage, data.type = "message"), dispatcher.elements("toggleStar", data) | |
| }), hotkeys.unbind(["down", "up"]), scope.$on("left", function() { | |
| return hotkeys.bind(["down", "up"]) | |
| }), scope.$on("openMarked", openMarked()), scope.$on("right", function() { | |
| unsubscribeActions(), !scope.markedMessage && scope.$applyAsync(function() { | |
| scope.markedMessage = _.last(scope.messages), unsubscribeActions = conversationListeners(scope.markedMessage), messageScroll.toID(scope.markedMessage.ID, scope.messages), hotkeys.bind(["down", "up"]) | |
| }) | |
| }), scope.$on("escape", function() { | |
| back() | |
| }), scope.toggleOption = function(option) { | |
| scope[option] = !scope[option], refreshConversation() | |
| }, scope.showNotifier = function(folder) { | |
| var filtered = _.filter(messagesCached, function(message) { | |
| return _.contains(message.LabelIDs, CONSTANTS.MAILBOX_IDENTIFIERS[folder]) | |
| }); | |
| return filtered.length < messagesCached.length && filtered.length > 0 | |
| }, scope.getMessages = function() { | |
| return scope.messages | |
| }, scope.read = function() { | |
| return actionConversation.read([scope.conversation.ID]) | |
| }, scope.unread = function() { | |
| actionConversation.unread([scope.conversation.ID]), back() | |
| }, scope.delete = function() { | |
| return actionConversation.remove([scope.conversation.ID]) | |
| }, scope.saveLabels = function(labels, alsoArchive) { | |
| actionConversation.label([scope.conversation.ID], labels, alsoArchive) | |
| }, | |
| function() { | |
| var messages = []; | |
| if (messagesCached = cache.queryMessagesCached($stateParams.id), scope.trashed = _.some(messagesCached, function(_ref2) { | |
| var LabelIDs = _ref2.LabelIDs; | |
| return _.contains(LabelIDs, CONSTANTS.MAILBOX_IDENTIFIERS.trash) | |
| }), scope.nonTrashed = _.some(messagesCached, function(_ref3) { | |
| var LabelIDs = _ref3.LabelIDs; | |
| return !_.contains(LabelIDs, CONSTANTS.MAILBOX_IDENTIFIERS.trash) | |
| }), messages = $filter("filterMessages")(messagesCached, scope.showTrashed, scope.showNonTrashed), messages.length > 0) { | |
| var list = _.map(cache.orderMessage(messages, !1), function(msg) { | |
| return delete msg.expand, delete msg.openMe, msg | |
| }); | |
| scope.messages = expandMessage(list), unsubscribeActions = conversationListeners(_.last(scope.messages)), authentication.user.ViewLayout === CONSTANTS.ROW_MODE && (scope.markedMessage = $rootScope.expandMessage), dispatcher.elements("mark", { | |
| id: $stateParams.id | |
| }) | |
| } else back() | |
| }(), scope.$on("$destroy", function() { | |
| unsubscribe(), unsubscribeActions(), hotkeys.unbind(["down", "up"]), hotkeys.bind(["down", "up"]), dispatcher.elements("close", { | |
| element: scope.conversation | |
| }) | |
| }) | |
| } | |
| } | |
| }), angular.module("proton.conversation").directive("conversationPlaceholder", function() { | |
| return { | |
| replace: !0, | |
| templateUrl: "templates/partials/conversation-placeholder.tpl.html" | |
| } | |
| }), angular.module("proton.conversation").directive("conversationView", function($state, $stateParams, cache, tools) { | |
| return { | |
| restrict: "E", | |
| replace: !0, | |
| template: '<div class="conversationView-container"><conversation ng-if="conversation" data-conversation="conversation"></conversation></div>', | |
| link: function(scope) { | |
| function back() { | |
| var route = $state.$current.name.replace(".element", ""); | |
| $state.go(route, { | |
| id: null | |
| }) | |
| } | |
| var conversationID = $stateParams.id, | |
| ID = tools.currentLocation(); | |
| cache.getConversation(conversationID).then(function(conversation) { | |
| return _.findWhere(conversation.Labels, { | |
| ID: ID | |
| }) || $state.includes("secured.search.**") ? scope.conversation = conversation : back() | |
| }) | |
| } | |
| } | |
| }), angular.module("proton.conversation").directive("listColumns", function() { | |
| return { | |
| replace: !0, | |
| templateUrl: "templates/partials/conversation-list-columns.tpl.html" | |
| } | |
| }), angular.module("proton.conversation").directive("listMobile", function() { | |
| return { | |
| replace: !0, | |
| templateUrl: "templates/partials/conversation-list-mobile.tpl.html" | |
| } | |
| }), angular.module("proton.conversation").directive("listRows", function() { | |
| return { | |
| replace: !0, | |
| templateUrl: "templates/partials/conversation-list-rows.tpl.html" | |
| } | |
| }), angular.module("proton.conversation").directive("statesConversation", function() { | |
| return { | |
| restrict: "E", | |
| replace: !0, | |
| template: "\n <i class=\"fa\" ng-class=\"{\n 'fa-mail-reply': conversation.IsReplied,\n 'fa-mail-reply-all': conversation.IsRepliedAll,\n 'fa-mail-forward': conversation.IsForwarded\n }\"></i>\n " | |
| } | |
| }), angular.module("proton.conversation").factory("actionConversation", function($rootScope, authentication, cache, CONSTANTS, conversationApi, eventManager, gettextCatalog, networkActivityTracker, notification, tools, labelsModel, $filter) { | |
| function getFolderNameTranslated() { | |
| var labelID = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : "", | |
| _ref = labelsModel.read(labelID, "folders") || {}, | |
| Name = _ref.Name; | |
| return mailboxes[labelID] || Name | |
| } | |
| function remove() { | |
| var ids = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : [], | |
| labelID = arguments[1], | |
| promise = conversationApi.delete(ids, labelID); | |
| if (cache.addToDispatcher(promise), !tools.cacheContext()) return promise.then(function() { | |
| return eventManager.call() | |
| }), networkActivityTracker.track(promise); | |
| var events = ids.reduce(function(acc, ID) { | |
| var messages = cache.queryMessagesCached(ID); | |
| return $rootScope.$broadcast("deleteConversation", ID), _.each(messages, function(_ref2) { | |
| var ID = _ref2.ID; | |
| return acc.push({ | |
| Action: 0, | |
| ID: ID | |
| }) | |
| }), acc.push({ | |
| Action: 0, | |
| ID: ID | |
| }), acc | |
| }, []); | |
| return cache.events(events), promise | |
| } | |
| function unread() { | |
| var ids = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : [], | |
| currentLocation = tools.currentLocation(), | |
| promise = conversationApi.unread(ids, currentLocation); | |
| cache.addToDispatcher(promise), tools.cacheContext() || (promise.then(function() { | |
| return eventManager.call() | |
| }), networkActivityTracker.track(promise)); | |
| var events = ids.reduce(function(acc, ID) { | |
| var messages = cache.queryMessagesCached(ID), | |
| _ref3 = cache.getConversationCached(ID) || {}, | |
| _ref3$Labels = _ref3.Labels, | |
| Labels = void 0 === _ref3$Labels ? [] : _ref3$Labels; | |
| if (messages.length) { | |
| var _$chain$filter$sortBy = _.chain(messages).filter(function(_ref4) { | |
| var _ref4$LabelIDs = _ref4.LabelIDs, | |
| LabelIDs = void 0 === _ref4$LabelIDs ? [] : _ref4$LabelIDs; | |
| return _.contains(LabelIDs, currentLocation) | |
| }).sortBy(function(_ref5) { | |
| return _ref5.Time | |
| }).last().value(), | |
| _ID = _$chain$filter$sortBy.ID; | |
| acc.push({ | |
| ID: _ID, | |
| Action: 3, | |
| Message: { | |
| ID: _ID, | |
| IsRead: 0 | |
| } | |
| }) | |
| } | |
| return acc.push({ | |
| Action: 3, | |
| ID: ID, | |
| Conversation: { | |
| ID: ID, | |
| Labels: _.map(Labels, function(label) { | |
| return label.ID === currentLocation && label.ContextNumUnread++, label | |
| }) | |
| } | |
| }), acc | |
| }, []); | |
| cache.events(events) | |
| } | |
| function read() { | |
| var ids = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : [], | |
| currentLocation = tools.currentLocation(), | |
| promise = conversationApi.read(ids); | |
| cache.addToDispatcher(promise), tools.cacheContext() || (promise.then(function() { | |
| return eventManager.call() | |
| }), networkActivityTracker.track(promise)); | |
| var events = ids.reduce(function(acc, ID) { | |
| var _ref6 = cache.getConversationCached(ID) || {}, | |
| _ref6$Labels = _ref6.Labels, | |
| Labels = void 0 === _ref6$Labels ? [] : _ref6$Labels; | |
| return _.each(cache.queryMessagesCached(ID), function(_ref7) { | |
| var ID = _ref7.ID; | |
| acc.push({ | |
| ID: ID, | |
| Action: 3, | |
| Message: { | |
| ID: ID, | |
| IsRead: 1 | |
| } | |
| }) | |
| }), acc.push({ | |
| Action: 3, | |
| ID: ID, | |
| Conversation: { | |
| ID: ID, | |
| Labels: _.map(Labels, function(label) { | |
| return label.ID === currentLocation && (label.ContextNumUnread = 0), label | |
| }) | |
| } | |
| }), acc | |
| }, []); | |
| cache.events(events) | |
| } | |
| function unstar() { | |
| var ids = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : [], | |
| promise = conversationApi.unstar(ids), | |
| LabelIDsRemoved = [MAILBOX_IDENTIFIERS.starred]; | |
| if (cache.addToDispatcher(promise), !tools.cacheContext()) return promise.then(function() { | |
| return eventManager.call() | |
| }), networkActivityTracker.track(promise); | |
| var events = _.chain(ids).map(function(id) { | |
| return cache.getConversationCached(id) | |
| }).filter(Boolean).reduce(function(acc, _ref8) { | |
| var ID = _ref8.ID, | |
| ContextNumUnread = _ref8.ContextNumUnread, | |
| messages = cache.queryMessagesCached(ID); | |
| return _.each(messages, function(message) { | |
| acc.push({ | |
| Action: 3, | |
| ID: message.ID, | |
| Message: { | |
| ID: message.ID, | |
| IsRead: message.IsRead, | |
| LabelIDsRemoved: LabelIDsRemoved | |
| } | |
| }) | |
| }), acc.push({ | |
| Action: 3, | |
| ID: ID, | |
| Conversation: { | |
| ID: ID, | |
| ContextNumUnread: ContextNumUnread, | |
| LabelIDsRemoved: LabelIDsRemoved | |
| } | |
| }), acc | |
| }, []).value(); | |
| cache.events(events) | |
| } | |
| function star() { | |
| var ids = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : [], | |
| promise = conversationApi.star(ids), | |
| LabelIDsAdded = [MAILBOX_IDENTIFIERS.starred]; | |
| if (cache.addToDispatcher(promise), !tools.cacheContext()) return promise.then(function() { | |
| return eventManager.call() | |
| }), networkActivityTracker.track(promise); | |
| var events = _.chain(ids).map(function(id) { | |
| return cache.getConversationCached(id) | |
| }).filter(Boolean).reduce(function(acc, _ref9) { | |
| var ID = _ref9.ID, | |
| ContextNumUnread = _ref9.ContextNumUnread, | |
| messages = cache.queryMessagesCached(ID); | |
| return _.each(messages, function(message) { | |
| acc.push({ | |
| Action: 3, | |
| ID: message.ID, | |
| Message: { | |
| ID: message.ID, | |
| IsRead: message.IsRead, | |
| LabelIDsAdded: LabelIDsAdded | |
| } | |
| }) | |
| }), acc.push({ | |
| Action: 3, | |
| ID: ID, | |
| Conversation: { | |
| ID: ID, | |
| ContextNumUnread: ContextNumUnread, | |
| LabelIDsAdded: LabelIDsAdded | |
| } | |
| }), acc | |
| }, []).value(); | |
| cache.events(events) | |
| } | |
| function label(ids, labels, alsoArchive) { | |
| var currentLocation = tools.currentLocation(), | |
| isStateAllowedRemove = _.contains(basicFolders, currentLocation) || labelsModel.contains(currentLocation, "folders"), | |
| current = tools.currentLocation(), | |
| process = function(events) { | |
| cache.events(events), !0 === alsoArchive && conversationApi.archive(ids) | |
| }, | |
| getLabelsId = function() { | |
| var list = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : [], | |
| cb = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : angular.noop; | |
| return _.chain(list).filter(cb).map(function(_ref10) { | |
| return _ref10.ID | |
| }).value() || [] | |
| }, | |
| toApplyLabels = getLabelsId(labels, function(_ref11) { | |
| return !0 === _ref11.Selected | |
| }), | |
| toRemoveLabels = getLabelsId(labels, function(_ref12) { | |
| return !1 === _ref12.Selected | |
| }), | |
| toApply = [].concat(toApplyLabels), | |
| toRemove = [].concat(toRemoveLabels); | |
| !0 === alsoArchive && (toApply.push(MAILBOX_IDENTIFIERS.archive), isStateAllowedRemove && toRemove.push(current)); | |
| var events = _.chain(ids).map(function(id) { | |
| return cache.getConversationCached(id) | |
| }).filter(Boolean).reduce(function(acc, _ref13) { | |
| var ID = _ref13.ID, | |
| ContextNumUnread = _ref13.ContextNumUnread, | |
| messages = cache.queryMessagesCached(ID); | |
| return _.each(messages, function(message) { | |
| var toApply = [].concat(toApplyLabels), | |
| toRemove = [].concat(toRemoveLabels); | |
| !0 === alsoArchive && (toApply.push(MAILBOX_IDENTIFIERS.archive), isStateAllowedRemove && toRemove.push(current)), acc.push({ | |
| Action: 3, | |
| ID: message.ID, | |
| Message: { | |
| ID: message.ID, | |
| IsRead: message.IsRead, | |
| LabelIDsAdded: toApply, | |
| LabelIDsRemoved: toRemove | |
| } | |
| }) | |
| }), acc.push({ | |
| Action: 3, | |
| ID: ID, | |
| Conversation: { | |
| ID: ID, | |
| ContextNumUnread: ContextNumUnread, | |
| Selected: !1, | |
| LabelIDsAdded: toApply, | |
| LabelIDsRemoved: toRemove | |
| } | |
| }), acc | |
| }, []).value(), | |
| getPromises = function(list) { | |
| var starter = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : [], | |
| flag = arguments.length > 2 && void 0 !== arguments[2] ? arguments[2] : 1; | |
| return _.reduce(list, function(acc, id) { | |
| return acc.push(conversationApi.labels(id, flag, ids)), acc | |
| }, starter) | |
| }, | |
| promise = Promise.all(getPromises(toRemove, getPromises(toApply), 0)); | |
| if (cache.addToDispatcher(promise), tools.cacheContext()) return process(events); | |
| promise.then(function() { | |
| return process(events) | |
| }), networkActivityTracker.track(promise) | |
| } | |
| function move() { | |
| var conversationIDs = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : [], | |
| labelID = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : "", | |
| folders = labelsModel.ids("folders"), | |
| labels = labelsModel.ids("labels"), | |
| toTrash = labelID === MAILBOX_IDENTIFIERS.trash, | |
| toSpam = labelID === MAILBOX_IDENTIFIERS.spam, | |
| toInbox = labelID === MAILBOX_IDENTIFIERS.inbox, | |
| promise = conversationApi.labels(labelID, 1, conversationIDs), | |
| folderName = getFolderNameTranslated(labelID), | |
| successMessage = gettextCatalog.getPlural(conversationIDs.length, "Conversation moved to", "Conversations moved to", {}), | |
| displaySuccess = function() { | |
| return notification.success(successMessage + " " + unicodeTagView(folderName)) | |
| }, | |
| folderIDs = basicFolders.concat(folders).concat(toSpam || toTrash ? labels : []); | |
| if (cache.addToDispatcher(promise), !tools.cacheContext()) return promise.then(function() { | |
| return eventManager.call() | |
| }).then(function() { | |
| return displaySuccess() | |
| }), networkActivityTracker.track(promise); | |
| var labelIDsAdded = [labelID], | |
| events = _.reduce(conversationIDs, function(acc, ID) { | |
| var messages = cache.queryMessagesCached(ID); | |
| _.each(messages, function(_ref14) { | |
| var Type = _ref14.Type, | |
| _ref14$LabelIDs = _ref14.LabelIDs, | |
| LabelIDs = void 0 === _ref14$LabelIDs ? [] : _ref14$LabelIDs, | |
| ID = _ref14.ID, | |
| IsRead = _ref14.IsRead, | |
| copyLabelIDsAdded = labelIDsAdded.slice(), | |
| copyLabelIDsRemoved = _.filter(LabelIDs, function(labelID) { | |
| return _.contains(folderIDs, labelID) | |
| }); | |
| if (toInbox) switch (Type) { | |
| case 1: | |
| var index = copyLabelIDsAdded.indexOf(MAILBOX_IDENTIFIERS.inbox); | |
| copyLabelIDsAdded.splice(index, 1), copyLabelIDsAdded.push(MAILBOX_IDENTIFIERS.allDrafts); | |
| break; | |
| case 2: | |
| var _index = copyLabelIDsAdded.indexOf(MAILBOX_IDENTIFIERS.inbox); | |
| copyLabelIDsAdded.splice(_index, 1), copyLabelIDsAdded.push(MAILBOX_IDENTIFIERS.allSent); | |
| break; | |
| case 3: | |
| copyLabelIDsAdded.push(MAILBOX_IDENTIFIERS.allSent) | |
| } | |
| acc.push({ | |
| ID: ID, | |
| Action: 3, | |
| Message: { | |
| ID: ID, | |
| IsRead: toTrash ? 1 : IsRead, | |
| LabelIDsRemoved: copyLabelIDsRemoved, | |
| LabelIDsAdded: copyLabelIDsAdded | |
| } | |
| }) | |
| }); | |
| var conversation = cache.getConversationCached(ID); | |
| if (conversation) { | |
| var labelIDsRemoved = _.chain(conversation.Labels).filter(function(_ref15) { | |
| var ID = _ref15.ID; | |
| return _.contains(folderIDs, ID) | |
| }).map(function(_ref16) { | |
| return _ref16.ID | |
| }).value(); | |
| acc.push({ | |
| Action: 3, | |
| ID: ID, | |
| Conversation: { | |
| ID: ID, | |
| Selected: !1, | |
| ContextNumUnread: toTrash ? 0 : conversation.ContextNumUnread, | |
| LabelIDsRemoved: labelIDsRemoved, | |
| LabelIDsAdded: labelIDsAdded | |
| } | |
| }) | |
| } | |
| return acc | |
| }, []); | |
| cache.events(events), displaySuccess() | |
| } | |
| var _mailboxes, unicodeTagView = $filter("unicodeTagView"), | |
| MAILBOX_IDENTIFIERS = CONSTANTS.MAILBOX_IDENTIFIERS, | |
| basicFolders = [MAILBOX_IDENTIFIERS.inbox, MAILBOX_IDENTIFIERS.trash, MAILBOX_IDENTIFIERS.spam, MAILBOX_IDENTIFIERS.archive, MAILBOX_IDENTIFIERS.sent, MAILBOX_IDENTIFIERS.drafts], | |
| mailboxes = (_mailboxes = {}, _defineProperty(_mailboxes, MAILBOX_IDENTIFIERS.inbox, gettextCatalog.getString("Inbox", null)), _defineProperty(_mailboxes, MAILBOX_IDENTIFIERS.spam, gettextCatalog.getString("Spam", null)), _defineProperty(_mailboxes, MAILBOX_IDENTIFIERS.drafts, gettextCatalog.getString("Drafts", null)), _defineProperty(_mailboxes, MAILBOX_IDENTIFIERS.allDrafts, gettextCatalog.getString("Drafts", null)), _defineProperty(_mailboxes, MAILBOX_IDENTIFIERS.sent, gettextCatalog.getString("Sent", null)), _defineProperty(_mailboxes, MAILBOX_IDENTIFIERS.allSent, gettextCatalog.getString("Sent", null)), _defineProperty(_mailboxes, MAILBOX_IDENTIFIERS.trash, gettextCatalog.getString("Trash", null)), _defineProperty(_mailboxes, MAILBOX_IDENTIFIERS.archive, gettextCatalog.getString("Archive", null)), _mailboxes); | |
| return { | |
| remove: remove, | |
| unread: unread, | |
| read: read, | |
| unstar: unstar, | |
| star: star, | |
| label: label, | |
| move: move | |
| } | |
| }), angular.module("proton.conversation").factory("conversationApi", function($http, url) { | |
| var requestURL = url.build("conversations"); | |
| return { | |
| query: function() { | |
| var params = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {}; | |
| return $http({ | |
| url: requestURL(), | |
| method: "GET", | |
| params: params | |
| }) | |
| }, | |
| get: function() { | |
| var ConversationID = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : ""; | |
| return $http.get(requestURL(ConversationID)) | |
| }, | |
| count: function() { | |
| return $http.get(requestURL("count")) | |
| }, | |
| star: function() { | |
| var IDs = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : []; | |
| return $http.put(requestURL("star"), { | |
| IDs: IDs | |
| }) | |
| }, | |
| unstar: function() { | |
| var IDs = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : []; | |
| return $http.put(requestURL("unstar"), { | |
| IDs: IDs | |
| }) | |
| }, | |
| read: function() { | |
| var IDs = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : []; | |
| return $http.put(requestURL("read"), { | |
| IDs: IDs | |
| }) | |
| }, | |
| unread: function() { | |
| var IDs = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : [], | |
| LabelID = arguments[1]; | |
| return $http.put(requestURL("unread"), { | |
| IDs: IDs, | |
| LabelID: LabelID | |
| }) | |
| }, | |
| trash: function() { | |
| var IDs = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : []; | |
| return $http.put(requestURL("trash"), { | |
| IDs: IDs | |
| }) | |
| }, | |
| inbox: function() { | |
| var IDs = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : []; | |
| return $http.put(requestURL("inbox"), { | |
| IDs: IDs | |
| }) | |
| }, | |
| spam: function() { | |
| var IDs = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : []; | |
| return $http.put(requestURL("spam"), { | |
| IDs: IDs | |
| }) | |
| }, | |
| archive: function() { | |
| var IDs = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : []; | |
| return $http.put(requestURL("archive"), { | |
| IDs: IDs | |
| }) | |
| }, | |
| delete: function() { | |
| var IDs = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : [], | |
| LabelID = arguments[1]; | |
| return $http.put(requestURL("delete"), { | |
| IDs: IDs, | |
| LabelID: LabelID | |
| }) | |
| }, | |
| labels: function() { | |
| var LabelID = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : "", | |
| Action = arguments[1], | |
| ConversationIDs = arguments.length > 2 && void 0 !== arguments[2] ? arguments[2] : []; | |
| return $http.put(requestURL("label"), { | |
| LabelID: LabelID, | |
| Action: Action, | |
| ConversationIDs: ConversationIDs | |
| }) | |
| } | |
| } | |
| }), angular.module("proton.conversation").factory("conversationListeners", function($rootScope, CONSTANTS) { | |
| function watch(message) { | |
| var listeners = Object.keys(composerMapActions).map(function(key) { | |
| return $rootScope.$on(key, openComposer(key, message)) | |
| }); | |
| return function() { | |
| listeners.forEach(function(cb) { | |
| return cb() | |
| }), listeners.length = 0 | |
| } | |
| } | |
| var composerMapActions = { | |
| replyConversation: "reply", | |
| replyAllConversation: "replyall", | |
| forwardConversation: "forward" | |
| }, | |
| isDraft = function(_ref) { | |
| return _ref.Type === CONSTANTS.DRAFT | |
| }, | |
| isDecrypted = function(_ref2) { | |
| return !_ref2.failedDecryption | |
| }, | |
| openComposer = function(key) { | |
| var message = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : {}; | |
| return function() { | |
| if (!isDraft(message) && isDecrypted(message)) { | |
| var type = composerMapActions[key]; | |
| $rootScope.$emit("composer.new", { | |
| type: type, | |
| data: { | |
| message: message | |
| } | |
| }) | |
| } | |
| } | |
| }; | |
| return watch | |
| }), angular.module("proton.conversation").factory("mailboxIdentifersTemplate", function($rootScope, CONSTANTS, labelsModel) { | |
| var CLEANER = document.createElement("div"), | |
| contains = function(key, labels) { | |
| return _.contains(labels, CONSTANTS.MAILBOX_IDENTIFIERS[key]) | |
| }, | |
| stripHTML = function(s) { | |
| return CLEANER.innerText = s || "", CLEANER.innerHTML | |
| }, | |
| templateTag = function(className, tooltip) { | |
| return '<i class="' + className + '" translate>' + tooltip + "</i>" | |
| }, | |
| templateLabel = function() { | |
| var className = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : "", | |
| tooltip = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : "", | |
| color = arguments.length > 2 && void 0 !== arguments[2] ? arguments[2] : "", | |
| ptTooltip = stripHTML(tooltip).replace(/"|'/g, ""); | |
| return color ? '<i class="fa ' + className + '" pt-tooltip="' + ptTooltip + '" style="color: ' + color + '"></i>' : '<i class="fa ' + className + '" pt-tooltip="' + ptTooltip + '"></i>' | |
| }, | |
| getFolder = function() { | |
| var labelIDs = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : [], | |
| id = _.find(labelIDs, function(id) { | |
| return labelsModel.contains(id, "folders") | |
| }); | |
| return labelsModel.read(id, "folders") || {} | |
| }, | |
| icon = function(_ref, templateMaker) { | |
| var _ref$className = _ref.className, | |
| className = void 0 === _ref$className ? "" : _ref$className, | |
| _ref$tooltip = _ref.tooltip, | |
| tooltip = void 0 === _ref$tooltip ? "" : _ref$tooltip, | |
| _ref$color = _ref.color, | |
| color = void 0 === _ref$color ? "" : _ref$color; | |
| return className && tooltip ? templateMaker ? templateMaker(className, tooltip, color) : templateLabel(className, tooltip, color) : "" | |
| }, | |
| escapeTooltip = function() { | |
| return (arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : "").replace(/^{{/g, "{​{") | |
| }; | |
| return function(_ref2) { | |
| var MAP_LABELS = _ref2.MAP_LABELS, | |
| MAP_TYPES = _ref2.MAP_TYPES; | |
| return { | |
| getTemplateLabels: function(labels) { | |
| return Object.keys(MAP_LABELS).reduce(function(acc, key) { | |
| if ("folder" === key) { | |
| var _getFolder = getFolder(labels), | |
| color = _getFolder.Color, | |
| tooltip = _getFolder.Name; | |
| return acc + icon(_.extend({}, MAP_LABELS[key], { | |
| tooltip: escapeTooltip(tooltip), | |
| color: color | |
| })) | |
| } | |
| return contains(key, labels) ? acc + icon(MAP_LABELS[key]) : acc | |
| }, "") | |
| }, | |
| getTemplateType: function(type) { | |
| return 2 === type || 3 === type ? icon(MAP_TYPES.sent, templateTag) : 1 === type ? icon(MAP_TYPES.drafts, templateTag) : "" | |
| } | |
| } | |
| } | |
| }), angular.module("proton.conversation").factory("conversationsInterceptor", function($q, $injector) { | |
| return { | |
| responseError: function() { | |
| var rep = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {}; | |
| if (/\/conversations\//.test((rep.config || {}).url)) { | |
| var cache = $injector.get("cache"), | |
| cacheCounters = $injector.get("cacheCounters"), | |
| eventManager = $injector.get("eventManager"); | |
| cache.reset(), cacheCounters.reset(), eventManager.call() | |
| } | |
| return $q.reject(rep) | |
| } | |
| } | |
| }), angular.module("proton.conversation").factory("markedScroll", function() { | |
| var CACHE = {}, | |
| getMarked = function() { | |
| return CACHE.wrapper.querySelector(".conversation.marked") | |
| }; | |
| return { | |
| follow: function() { | |
| CACHE.wrapper || (CACHE.wrapper = document.body.querySelector(".conversation-wrapper")), _rAF(function() { | |
| var $marked = getMarked(); | |
| CACHE.wrapper.scrollTop = $marked.offsetTop - CACHE.wrapper.offsetHeight / 2 | |
| }) | |
| }, | |
| clear: function() { | |
| return CACHE.wrapper = null | |
| } | |
| } | |
| }), angular.module("proton.conversation").factory("messageScroll", function() { | |
| function scroll(index, nodeMessage) { | |
| var $header = document.getElementById("conversationHeader"), | |
| $thread = document.getElementById("pm_thread"); | |
| if (0 === index) return $($thread).animate({ | |
| scrollTop: 0 | |
| }, 200); | |
| var node = nodeMessage || document.getElementById("message" + index), | |
| previous = document.getElementById("message" + (index - 1)), | |
| headerOffset = $header ? $header.getBoundingClientRect().top + $header.offsetHeight : 0, | |
| amountScrolled = $thread ? $thread.scrollTop : 0, | |
| paddingTop = ~~$thread.style.paddingTop.replace("px", ""), | |
| summaryHeight = document.getElementsByClassName("summary")[0].getBoundingClientRect().height, | |
| scrollTop = node ? node.getBoundingClientRect().top + amountScrolled - headerOffset - paddingTop : 0; | |
| scrollTop -= 1 === index || previous.classList.contains("open") ? summaryHeight / 2 + 10 : 1.5 * summaryHeight + 20, $($thread).animate({ | |
| scrollTop: scrollTop | |
| }, 200) | |
| } | |
| var toID = function(ID) { | |
| var list = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : []; | |
| return scroll(_.findIndex(list, { | |
| ID: ID | |
| })) | |
| }; | |
| return { | |
| to: function(_ref) { | |
| scroll(_ref.index, _ref.node) | |
| }, | |
| toID: toID | |
| } | |
| }), angular.module("proton.core").controller("HeaderController", function($rootScope, $scope, $state, authentication, organizationModel, CONSTANTS) { | |
| var unsubscribes = []; | |
| $scope.params = {}, $scope.user = authentication.user, $scope.organization = organizationModel.get(), $scope.wizardEnabled = CONSTANTS.WIZARD_ENABLED, $scope.isAdmin = authentication.user.Role === CONSTANTS.PAID_ADMIN_ROLE, $scope.isFree = authentication.user.Role === CONSTANTS.FREE_USER_ROLE, $scope.ctrl = {}, $scope.starred = 2, unsubscribes.push($rootScope.$on("organizationChange", function(event, newOrganization) { | |
| $scope.organization = newOrganization | |
| })), unsubscribes.push($rootScope.$on("updateUser", function() { | |
| $scope.isAdmin = authentication.user.Role === CONSTANTS.PAID_ADMIN_ROLE, $scope.isFree = authentication.user.Role === CONSTANTS.FREE_USER_ROLE | |
| })), $scope.$on("$destroy", function() { | |
| unsubscribes.forEach(function(cb) { | |
| return cb() | |
| }), unsubscribes.length = 0 | |
| }), $scope.cancel = function() { | |
| angular.isDefined($scope.params.cancel) && angular.isFunction($scope.params.cancel) && $scope.params.cancel() | |
| }, $scope.activeSettings = function() { | |
| return -1 !== ["dashboard", "account", "labels", "filters", "security", "appearance", "domains", "bridge", "signatures", "members", "payments", "keys", "vpn"].indexOf($state.$current.name.replace("secured.", "")) | |
| } | |
| }), angular.module("proton.core").controller("ResetController", function($scope, $rootScope, $state, $log, gettextCatalog, $q, $http, CONSTANTS, authentication, networkActivityTracker, User, Reset, Key, passwords, pmcw, tempStorage, tools, notification) { | |
| $scope.generateKeys = function(mbpw) { | |
| var promises = [], | |
| keySalt = CONSTANTS.KEY_PHASE > 1 ? passwords.generateKeySalt() : null; | |
| return $scope.process.genNewKeys = !0, passwords.computeKeyPassword(mbpw, keySalt).then(function(newMailboxPwd) { | |
| return _.each($scope.addresses, function(address) { | |
| promises.push(pmcw.generateKey({ | |
| userIds: [{ | |
| name: address.Email, | |
| email: address.Email | |
| }], | |
| passphrase: newMailboxPwd | |
| }).then(function(response) { | |
| return { | |
| AddressID: address.ID, | |
| PrivateKey: response.privateKeyArmored | |
| } | |
| }, function(err) { | |
| return $scope.process.genNewKeys = !1, $log.error(err), $scope.error = err, Promise.reject(err) | |
| })) | |
| }), $q.all(promises).then(function(keys) { | |
| return $scope.process.generatingKeys = !0, { | |
| KeySalt: keySalt, | |
| PrimaryKey: keys[0].PrivateKey, | |
| AddressKeys: keys | |
| } | |
| }) | |
| }) | |
| }, $scope.resetMailbox = function() { | |
| if (void 0 === $scope.resetMailboxToken) return void notification.error("Missing reset token"); | |
| networkActivityTracker.track($scope.generateKeys($scope.account.mailboxPassword).then($scope.newMailbox).then($scope.resetMailboxTokenResponse).then($scope.doLogUserIn).then($scope.doMailboxLogin)) | |
| }, $scope.doLogUserIn = function() { | |
| return authentication.loginWithCredentials({ | |
| Username: $scope.creds.username, | |
| Password: $scope.creds.password | |
| }) | |
| }, $scope.doMailboxLogin = function(_ref) { | |
| var data = _ref.data; | |
| return $scope.creds.authResponse = data, authentication.unlockWithPassword($scope.account.mailboxPassword, $scope.creds.authResponse).then(function() { | |
| return authentication.setAuthCookie($scope.creds.authResponse).then(function() { | |
| $scope.process.redirecting = !0, $rootScope.isLoggedIn = authentication.isLoggedIn(), $rootScope.isLocked = authentication.isLocked(), $rootScope.isSecure = authentication.isSecured(), $state.go("secured.inbox") | |
| }, function() { | |
| notification.error("doMailboxLogin: Unable to set authCookie.") | |
| }) | |
| }, function() { | |
| notification.error("doMailboxLogin: Unable to unlock mailbox.") | |
| }) | |
| }, $scope.verifyResetCode = function() { | |
| angular.isUndefined($scope.account.resetMbCode) || 0 === $scope.account.resetMbCode.length ? notification.info("Verification Code required") : Reset.validateResetToken({ | |
| Username: $scope.creds.username, | |
| Token: $scope.account.resetMbCode | |
| }).then(function(response) { | |
| 1e3 !== response.data.Code ? notification.error("Invalid Verification Code.") : ($scope.addresses = response.data.Addresses, $scope.resetMailboxToken = $scope.account.resetMbCode, $scope.showForm = !0, $scope.showEmailMessage = !1) | |
| }, function(err) { | |
| $log.error(err), notification.error("Unable to verify Reset Token.") | |
| }) | |
| }, $scope.resetMailboxInit = function() { | |
| if ("DANGER" !== $scope.process.danger) return notification.error("Invalid value"), !1; | |
| angular.isDefined($scope.creds) && angular.isDefined($scope.creds.authResponse) && ($http.defaults.headers.common.Authorization = "Bearer " + $scope.creds.authResponse.ResetToken, $http.defaults.headers.common["x-pm-uid"] = $scope.creds.authResponse.Uid); | |
| var tokenResponse = function(response) { | |
| var deferred = $q.defer(); | |
| return response.data.Error || 1e3 !== response.data.Code ? (notification.info(response), $log.error(response), deferred.reject(response.data.Error)) : response.data.Token ? ($scope.resetMailboxToken = response.data.Token, Reset.validateResetToken({ | |
| Username: $scope.creds.username, | |
| Token: response.data.Token | |
| }).then(function(response) { | |
| 1e3 !== response.data.Code ? notification.error("Invalid Verification Code.") : ($scope.addresses = response.data.Addresses, $scope.showForm = !0, $scope.showEmailMessage = !1, deferred.resolve(200)) | |
| }, function(err) { | |
| $log.error(err), notification.error("Unable to verify Reset Token.") | |
| })) : ($scope.showEmailMessage = !0, deferred.resolve(200)), deferred.promise | |
| }; | |
| networkActivityTracker.track(function() { | |
| return Reset.getMailboxResetToken({}) | |
| }().then(tokenResponse)) | |
| }, $scope.cancelReset = function() { | |
| tempStorage.setItem("creds", $scope.creds), $state.go("login.unlock") | |
| }, $scope.newMailbox = function(params) { | |
| var resetMBtoken = void 0; | |
| return void 0 !== $scope.resetMailboxToken && (resetMBtoken = $scope.resetMailboxToken), params.Token = resetMBtoken, Key.reset(params) | |
| }, $scope.resetMailboxTokenResponse = function(response) { | |
| var promise = $q.defer(); | |
| return response || promise.reject(new Error("Connection error: Unable to save new keys.")), 200 !== response.status ? (notification.error("Error, try again in a few minutes."), $scope.process.savingKeys = !1, promise.reject(new Error("Status Error: Unable to save new keys."))) : response.data.Error ? "" !== response.data.ErrorDescription ? (notification.error(response.data.ErrorDescription), $log.error(response), $scope.process.savingKeys = !1, promise.reject(new Error(response.data.ErrorDescription))) : (notification.error(response.data.Error), $log.error(response), $scope.process.savingKeys = !1, promise.reject(new Error(response.data.Error))) : ($scope.process.savingKeys = !0, promise.resolve(200)), promise | |
| }, | |
| function() { | |
| $scope.creds = tempStorage.getItem("creds"), $scope.creds && $scope.creds.authResponse || $state.go("login"), $scope.tools = tools, $scope.resetMailboxToken = void 0, $scope.account = [], $scope.addresses = [], $scope.process = {}, $scope.process.danger = "", $scope.process.generatingKeys = !1, $scope.process.savingKeys = !1, $scope.process.redirecting = !1, $scope.showForm = !1 | |
| }() | |
| }), angular.module("proton.core").controller("SecuredController", function($rootScope, $scope, $state, authentication, cacheCounters, contactCache, CONSTANTS, eventManager, hotkeys, AppModel, desktopNotifications, attachSignupSubscription, addressWithoutKeysManager) { | |
| $scope.inboxSidebar = AppModel.is("inboxSidebar"), $scope.showSidebar = AppModel.is("showSidebar"), $scope.settingsSidebar = AppModel.is("settingsSidebar"), $scope.contactSidebar = AppModel.is("contactSidebar"), $scope.mobileMode = AppModel.is("mobile"), $scope.tabletMode = AppModel.is("tablet"), $scope.user = authentication.user, $scope.isAdmin = authentication.user.Role === CONSTANTS.PAID_ADMIN_ROLE, $scope.isFree = authentication.user.Role === CONSTANTS.FREE_USER_ROLE, $scope.keyPhase = CONSTANTS.KEY_PHASE, $rootScope.isLoggedIn = !0, $rootScope.isLocked = !1; | |
| var bindAppValue = function(key, _ref) { | |
| var value = _ref.value; | |
| return $scope.$applyAsync(function() { | |
| return $scope[key] = value | |
| }) | |
| }, | |
| unsubscribe = $rootScope.$on("AppModel", function(e, _ref2) { | |
| var type = _ref2.type, | |
| _ref2$data = _ref2.data, | |
| data = void 0 === _ref2$data ? {} : _ref2$data; | |
| "inboxSidebar" === type && bindAppValue(type, data), "mobile" === type && bindAppValue("mobileMode", data), "tablet" === type && bindAppValue("tabletMode", data), "showSidebar" === type && bindAppValue(type, data), "settingsSidebar" === type && bindAppValue(type, data), "contactSidebar" === type && bindAppValue(type, data) | |
| }); | |
| desktopNotifications.request(), 1 === authentication.user.Hotkeys ? hotkeys.bind() : hotkeys.unbind(), attachSignupSubscription(), eventManager.start(authentication.user.EventID), cacheCounters.query(), !$state.includes("secured.contacts") && contactCache.load(), addressWithoutKeysManager.manage().catch(_.noop), $scope.$on("updateUser", function() { | |
| $scope.$applyAsync(function() { | |
| $scope.user = authentication.user, $scope.isAdmin = authentication.user.Role === CONSTANTS.PAID_ADMIN_ROLE, $scope.isFree = authentication.user.Role === CONSTANTS.FREE_USER_ROLE | |
| }) | |
| }), $scope.idDefined = function() { | |
| return $state.params.id && $state.params.id.length > 0 | |
| }, $scope.isMobile = function() { | |
| return AppModel.is("mobile") | |
| }, $scope.$on("$destroy", function() { | |
| hotkeys.unbind(), unsubscribe() | |
| }) | |
| }), angular.module("proton.core").controller("SetupController", function($http, $location, $log, $q, $rootScope, $scope, $state, Address, authentication, CONSTANTS, confirmModal, domains, gettextCatalog, Key, networkActivityTracker, Payment, passwords, pmcw, Reset, secureSessionStorage, setupKeys, tools, user) { | |
| function setupAddress() { | |
| return $log.debug("setupAddress"), $scope.filling = !1, 0 === user.Addresses.length ? Address.setup({ | |
| Domain: $scope.domain.value | |
| }).then(function(result) { | |
| return result.data && 1e3 === result.data.Code ? (user.Addresses = [result.data.Address], user) : result.data && result.data.Error ? $q.reject({ | |
| message: result.data.Error | |
| }) : $q.reject({ | |
| message: "Something went wrong during address creation" | |
| }) | |
| }) : $q.resolve(user) | |
| } | |
| function generateKeys() { | |
| return $log.debug("generateKeys"), $scope.genKeys = !0, setupKeys.generate(user.Addresses, passwordCopy) | |
| } | |
| function installKeys() { | |
| var data = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {}; | |
| return $log.debug("installKeys"), $scope.genKeys = !1, $scope.creating = !0, $scope.setupAccount = !0, setupKeys.setup(data, passwordCopy).then(function() { | |
| authentication.savePassword(data.mailboxPassword), $rootScope.isLoggedIn = authentication.isLoggedIn(), $rootScope.isLocked = authentication.isLocked(), $rootScope.isSecure = authentication.isSecured() | |
| }) | |
| } | |
| function doGetUserInfo() { | |
| return $log.debug("getUserInfo"), $scope.getUserInfo = !0, authentication.fetchUserInfo() | |
| } | |
| function finishRedirect() { | |
| if ($log.debug("finishRedirect"), $scope.finishCreation = !0, authentication.user.Delinquent < UNPAID_STATE.DELINQUENT) return $state.go("secured.inbox", { | |
| welcome: WIZARD_ENABLED | |
| }); | |
| $state.go("secured.dashboard") | |
| } | |
| var passwordCopy = void 0, | |
| WIZARD_ENABLED = CONSTANTS.WIZARD_ENABLED, | |
| KEY_PHASE = CONSTANTS.KEY_PHASE, | |
| UNPAID_STATE = CONSTANTS.UNPAID_STATE; | |
| $scope.submit = function() { | |
| return passwordCopy = $scope.password, networkActivityTracker.track(setupAddress().then(generateKeys).then(installKeys).then(doGetUserInfo).then(finishRedirect)).catch(function() { | |
| $scope.setupError = !0 | |
| }) | |
| }, | |
| function() { | |
| $scope.keyPhase = KEY_PHASE, $scope.tools = tools, $scope.filling = !0, $scope.creating = !1, $scope.genKeys = !1, $scope.setupAccount = !1, $scope.getUserInfo = !1, $scope.finishCreation = !1, $scope.generating = !1, $scope.domains = [], _.each(domains, function(domain) { | |
| $scope.domains.push({ | |
| label: domain, | |
| value: domain | |
| }) | |
| }), $scope.username = user.Name, $scope.domain = $scope.domains[0], $scope.chooseDomain = 0 === user.Addresses.length, $scope.password = "", $scope.passwordConfirm = "" | |
| }() | |
| }), angular.module("proton.core").controller("SignupController", function($location, $rootScope, $scope, $state, $stateParams, authentication, domains, gettextCatalog, networkActivityTracker, notification, plans, AppModel, signupModel, signupUserProcess) { | |
| function generateUserKeys() { | |
| $scope.step = 2; | |
| var promise = signupUserProcess.generateNewKeys().then(function() { | |
| if (AppModel.is("preInvited")) return createAccount(); | |
| if (plans.length) { | |
| if (signupModel.optionsHumanCheck("payment")) return $scope.step = 4; | |
| $scope.step = 3; | |
| var message = gettextCatalog.getString("It currently isn't possible to subscribe to a Paid ProtonMail plan.", null); | |
| return notification.info(message) | |
| } | |
| $scope.step = 3 | |
| }); | |
| networkActivityTracker.track(promise) | |
| } | |
| function verify(_ref) { | |
| var Payment = _ref.Payment, | |
| Amount = _ref.Amount, | |
| Currency = _ref.Currency, | |
| GiftCode = _ref.GiftCode, | |
| Credit = _ref.Credit; | |
| signupModel.verify({ | |
| Payment: Payment, | |
| Amount: Amount, | |
| Currency: Currency, | |
| GiftCode: GiftCode, | |
| Credit: Credit | |
| }, $scope.plan).then(createAccount) | |
| } | |
| function applyGift(opt) { | |
| signupModel.applyGiftCode(opt).then(function(data) { | |
| return notification.success(I18N.success), data | |
| }) | |
| } | |
| var unsubscribe = [], | |
| I18N = { | |
| success: gettextCatalog.getString("Gift code applied", null, "Success") | |
| }; | |
| $scope.step = 1, $scope.plans = plans, $scope.domains = _.map(domains, function(value) { | |
| return { | |
| label: value, | |
| value: value | |
| } | |
| }), $scope.isFromInvitation = AppModel.is("preInvited"), $scope.account = { | |
| username: function() { | |
| return $location.search().u || $stateParams.username || "" | |
| }(), | |
| domain: $scope.domains[0], | |
| codeVerification: "", | |
| captcha_token: !1, | |
| smsCodeVerification: "", | |
| emailVerification: "" | |
| }, authentication.logout(!1, authentication.isLoggedIn()), plans.length && ($scope.plan = _.findWhere(plans, { | |
| Name: $stateParams.plan, | |
| Cycle: parseInt($stateParams.billing, 10), | |
| Currency: $stateParams.currency | |
| })); | |
| var createAccount = function() { | |
| return $scope.step = 5, signupUserProcess.createAccount($scope.account) | |
| }; | |
| unsubscribe.push($rootScope.$on("payments", function(e, _ref2) { | |
| var type = _ref2.type, | |
| _ref2$data = _ref2.data, | |
| data = void 0 === _ref2$data ? {} : _ref2$data; | |
| if ("create.account" === type && ("humanVerification" !== data.action && createAccount(), "humanVerification" === data.action)) { | |
| var _data$options = data.options; | |
| verify({ | |
| Payment: _data$options.Payment, | |
| Amount: _data$options.Amount, | |
| Currency: _data$options.Currency | |
| }) | |
| } | |
| })); | |
| var bindStep = function(key, value) { | |
| return $scope.$applyAsync(function() { | |
| return $scope[key] = value | |
| }) | |
| }; | |
| unsubscribe.push($rootScope.$on("signup", function(e, _ref3) { | |
| var type = _ref3.type, | |
| data = _ref3.data; | |
| if ("chech.humanity" === type && bindStep("step", 3), "creating" === type && bindStep("step", 5), "signup.error" === type && bindStep("signupError", data.value), "goto.step" === type && bindStep("step", data.value), "userform.submit" === type && generateUserKeys(), "humanform.submit" === type && createAccount(), "apply.gift" === type && applyGift(data), "payform.submit" === type) { | |
| var _data$payment = data.payment; | |
| verify({ | |
| Payment: _data$payment.method, | |
| Amount: _data$payment.Amount, | |
| Currency: _data$payment.Currency, | |
| GiftCode: _data$payment.GiftCode, | |
| Credit: _data$payment.Credit | |
| }) | |
| } | |
| })), $scope.$on("$destroy", function() { | |
| unsubscribe.forEach(function(cb) { | |
| return cb() | |
| }), unsubscribe.length = 0 | |
| }) | |
| }), angular.module("proton.core").controller("SupportController", function($rootScope, $scope, $state, $log, authentication, CONSTANTS, tempStorage, User, tools, notification, gettextCatalog, confirmModal, Reset, setupKeys, Key, networkActivityTracker) { | |
| function resetState() { | |
| $scope.params.resetToken = "", $scope.params.danger = "", $scope.params.password = "", $scope.params.passwordConfirm = "", $scope.resetState = $scope.states.RECOVERY | |
| } | |
| function resetLostPassword() { | |
| $scope.params.username = $scope.params.username; | |
| var promise = Reset.requestResetToken({ | |
| Username: $scope.params.username, | |
| NotificationEmail: $scope.params.recoveryEmail | |
| }).then(function(_ref) { | |
| var _ref$data = _ref.data, | |
| data = void 0 === _ref$data ? {} : _ref$data; | |
| if (1e3 === data.Code) $scope.resetState = $scope.states.CODE; | |
| else if (data.Error) return Promise.reject(data.Error) | |
| }); | |
| networkActivityTracker.track(promise) | |
| } | |
| function doReset() { | |
| return 2 === $scope.passwordMode && $scope.keyPhase < 3 ? Reset.resetPassword($scope.tokenParams, $scope.params.password).then(function() { | |
| var response = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {}, | |
| _response$data = response.data, | |
| data = void 0 === _response$data ? {} : _response$data; | |
| return 1e3 === data.Code ? response : Promise.reject({ | |
| message: data.Error || "Unable to update password. Please try again" | |
| }) | |
| }) : generateKeys().then(installKeys) | |
| } | |
| function generateKeys() { | |
| return $log.debug("generateKeys"), $scope.resetState = $scope.states.GENERATE, setupKeys.generate($scope.addresses, $scope.params.password) | |
| } | |
| function installKeys() { | |
| var data = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {}; | |
| return $log.debug("installKeys"), $scope.resetState = $scope.states.INSTALL, $scope.resetAccount = !0, setupKeys.reset(data, $scope.params.password, $scope.tokenParams) | |
| } | |
| function doLogUserIn() { | |
| return $scope.logUserIn = !0, authentication.loginWithCredentials({ | |
| Username: $scope.params.username, | |
| Password: $scope.params.password | |
| }).then(function(_ref3) { | |
| var data = _ref3.data; | |
| return $rootScope.isLoggedIn = !0, data | |
| }) | |
| } | |
| function finishRedirect(authResponse) { | |
| $log.debug("finishRedirect"), $scope.finishInstall = !0; | |
| var creds = { | |
| username: $scope.params.username, | |
| password: $scope.params.password, | |
| authResponse: authResponse | |
| }; | |
| tempStorage.setItem("creds", creds), $state.go("login.unlock") | |
| } | |
| var GENERIC_MESSAGE = { | |
| title: gettextCatalog.getString("Problem loading your account", null, "Title"), | |
| content: gettextCatalog.getString("ProtonMail encountered a problem loading your account. Please refresh the page and try again later.", null, "Info"), | |
| type: "alert-danger" | |
| }; | |
| $scope.keyPhase = CONSTANTS.KEY_PHASE, $scope.states = { | |
| RECOVERY: 1, | |
| CODE: 2, | |
| CHECKING: 3, | |
| DANGER: 4, | |
| PASSWORD: 5, | |
| GENERATE: 6, | |
| INSTALL: 7 | |
| }, $scope.tools = tools, $scope.params = {}, $scope.params.recoveryEmail = "", $scope.params.username = "", $scope.passwordMode = 0, resetState(), $scope.resetAccount = !1, $scope.logUserIn = !1, $scope.finishInstall = !1, $scope.getMessageTitle = function() { | |
| return $state.params.data.title || GENERIC_MESSAGE.title | |
| }, $scope.getMessageContent = function() { | |
| return $state.params.data.content || GENERIC_MESSAGE.content | |
| }, $scope.getMessageType = function() { | |
| return $state.params.data.type || GENERIC_MESSAGE.type | |
| }, $scope.confirmResetLostPassword = function() { | |
| var title = gettextCatalog.getString("Confirm Reset Password", null, "Title"), | |
| message = gettextCatalog.getString('Resetting your password means you will no longer be able to read your old emails. <a href="https://protonmail.com/support/knowledge-base/updating-your-login-password/" target="_blank">Click here to learn more</a>. If you have further questions, please email [email protected]. Are you sure you want to reset your password?', null, "Title"); | |
| confirmModal.activate({ | |
| params: { | |
| title: title, | |
| message: message, | |
| confirm: function() { | |
| confirmModal.deactivate(), resetLostPassword() | |
| }, | |
| cancel: function() { | |
| confirmModal.deactivate() | |
| } | |
| } | |
| }) | |
| }, $scope.validateToken = function() { | |
| $scope.resetState = $scope.states.CHECKING, $scope.tokenParams = { | |
| Username: $scope.params.username, | |
| Token: $scope.params.resetToken | |
| }, Reset.validateResetToken($scope.tokenParams).then(function(_ref2) { | |
| var _ref2$data = _ref2.data, | |
| data = void 0 === _ref2$data ? {} : _ref2$data; | |
| if (1e3 !== data.Code) return Promise.reject({ | |
| message: data.Error || "Unable to verify reset token" | |
| }); | |
| $scope.passwordMode = data.PasswordMode, $scope.addresses = data.Addresses, $scope.resetState = $scope.states.DANGER, 2 === $scope.passwordMode && $scope.keyPhase < 3 && ($scope.resetState = $scope.states.PASSWORD) | |
| }).catch(function(error) { | |
| resetState(), $log.error(error), notification.error(error.message) | |
| }) | |
| }, $scope.confirmReset = function() { | |
| $scope.resetState = $scope.states.PASSWORD | |
| }, $scope.resetPassword = function() { | |
| networkActivityTracker.track(doReset().then(doLogUserIn).then(finishRedirect).catch(function(error) { | |
| $log.error(error), resetState(), notification.error(error.message) | |
| })) | |
| }, $state.is("support.reset-password") && $state.params.username && $state.params.token && ($scope.resetState = $scope.states.CHECKING, $scope.params.username = $state.params.username, | |
| $scope.params.resetToken = $state.params.token, $scope.validateToken()) | |
| }), angular.module("proton.core").directive("cardPanel", function() { | |
| return { | |
| replace: !0, | |
| restrict: "E", | |
| templateUrl: "templates/directives/core/cardPanel.tpl.html", | |
| scope: { | |
| card: "=" | |
| } | |
| } | |
| }), angular.module("proton.core").directive("hideUpgrade", function(organizationModel, $rootScope) { | |
| var HIDE_UPGRADE_CLASS = "hideUpgrade"; | |
| return { | |
| restrict: "A", | |
| link: function(scope, element) { | |
| function update(_ref) { | |
| return "visionary" === _ref.PlanName ? element[0].classList.add(HIDE_UPGRADE_CLASS) : element[0].classList.remove(HIDE_UPGRADE_CLASS) | |
| } | |
| var unsubscribe = $rootScope.$on("organizationChange", function(event, newOrganization) { | |
| return update(newOrganization) | |
| }); | |
| update(organizationModel.get()), scope.$on("$destroy", function() { | |
| return unsubscribe() | |
| }) | |
| } | |
| } | |
| }), angular.module("proton.core").directive("paginator", function($rootScope, $stateParams, paginationModel, CONSTANTS) { | |
| var ELEMENTS_PER_PAGE = CONSTANTS.ELEMENTS_PER_PAGE, | |
| buildClassNames = function(scope) { | |
| var className = [], | |
| maxPageNumber = paginationModel.getMaxPage(); | |
| return 1 === (~~$stateParams.page || 1) && className.push("paginator-disabled-previous"), (paginationModel.isMax() || 0 === scope.totalItems) && className.push("paginator-disabled-next"), 0 !== maxPageNumber && 1 !== maxPageNumber && 0 !== scope.totalItems || className.push("paginator-disabled-main"), className.join(" ") | |
| }, | |
| buildPageList = function() { | |
| var size = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : 1; | |
| return _.range(1, size + 1) | |
| }, | |
| buildPages = function() { | |
| var size = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : ELEMENTS_PER_PAGE, | |
| total = Math.ceil(size / ELEMENTS_PER_PAGE), | |
| value = ~~$stateParams.page > total ? ~~$stateParams.page : total; | |
| return buildPageList(value) | |
| }, | |
| onAction = function(key) { | |
| return function(e) { | |
| return e.preventDefault(), paginationModel[key]() | |
| } | |
| }; | |
| return { | |
| restrict: "E", | |
| replace: !0, | |
| templateUrl: "templates/directives/paginator.tpl.html", | |
| scope: { | |
| totalItems: "=" | |
| }, | |
| link: function(scope, el) { | |
| scope.pages = buildPageList(paginationModel.getMaxPage()), scope.page = ~~$stateParams.page || 1; | |
| var rawClassNames = el[0].className; | |
| el[0].className += " " + buildClassNames(scope); | |
| var $next = el[0].querySelector(".paginator-btn-next"), | |
| $previous = el[0].querySelector(".paginator-btn-previous"), | |
| $dropdown = el[0].querySelector(".paginator-dropdown-list"), | |
| onNext = onAction("next"), | |
| onPrevious = onAction("previous"), | |
| onSelect = function(e) { | |
| e.preventDefault(); | |
| var target = e.target; | |
| target.classList.contains("paginator-dropdown-item") && paginationModel.to({ | |
| page: +target.getAttribute("data-value") | |
| }) | |
| }; | |
| $next.addEventListener("click", onNext, !1), $previous.addEventListener("click", onPrevious, !1), $dropdown.addEventListener("click", onSelect, !1); | |
| var unsubscribe = $rootScope.$on("app.cacheCounters", function(event, _ref) { | |
| var type = _ref.type, | |
| data = _ref.data; | |
| "refresh.currentState" === type && scope.$applyAsync(function() { | |
| scope.pages = buildPages(data.value), el[0].className = rawClassNames + " " + buildClassNames(scope) | |
| }) | |
| }); | |
| scope.$on("$destroy", function() { | |
| $next.removeEventListener("click", onNext), $previous.removeEventListener("click", onPrevious), $dropdown.removeEventListener("click", onSelect, !1), unsubscribe() | |
| }) | |
| } | |
| } | |
| }), angular.module("proton.core").directive("paginatorScope", function($rootScope) { | |
| return { | |
| restrict: "E", | |
| replace: !0, | |
| templateUrl: "templates/directives/paginatorScope.tpl.html", | |
| scope: { | |
| page: "=", | |
| totalItems: "=", | |
| itemsPerPage: "=", | |
| change: "=" | |
| }, | |
| link: function(scope, el, attribute) { | |
| scope.pages = []; | |
| var disable = function() { | |
| scope.disableMain = 1 === Math.ceil(scope.totalItems / scope.itemsPerPage) || 0 === scope.totalItems, scope.disableP = 1 === scope.page || 0 === scope.totalItems, scope.disableN = Math.ceil(scope.totalItems / scope.itemsPerPage) === scope.page || 0 === scope.totalItems | |
| }, | |
| buildPages = function() { | |
| var pages = void 0, | |
| temp = []; | |
| pages = scope.totalItems % scope.itemsPerPage == 0 ? scope.totalItems / scope.itemsPerPage : Math.floor(scope.totalItems / scope.itemsPerPage) + 1; | |
| for (var i = 1; i <= pages; ++i) temp.push(i); | |
| scope.pages = temp | |
| }; | |
| scope.select = function(p) { | |
| scope.change(p), scope.$applyAsync(function() { | |
| return disable() | |
| }) | |
| }, scope.next = function() { | |
| return scope.change(scope.page + 1) | |
| }, scope.previous = function() { | |
| return scope.change(scope.page - 1) | |
| }, scope.$watch("totalItems", function() { | |
| disable(), buildPages() | |
| }); | |
| var unsubscribe = $rootScope.$on("paginatorScope", function(e, _ref) { | |
| var type = _ref.type, | |
| page = _ref.page; | |
| type === attribute.type && (scope.page = page, disable()) | |
| }); | |
| scope.$on("$destroy", function() { | |
| return unsubscribe() | |
| }) | |
| } | |
| } | |
| }), angular.module("proton.core").directive("placeholderProgress", function(authentication, $filter) { | |
| var humanSize = $filter("humanSize"), | |
| percentage = $filter("percentage"), | |
| percentageValue = function() { | |
| return percentage(authentication.user.UsedSpace, authentication.user.MaxSpace) | |
| }; | |
| return { | |
| templateUrl: "templates/directives/core/placeholderProgress.tpl.html", | |
| replace: !0, | |
| link: function(scope) { | |
| scope.storageStyle = function() { | |
| return { | |
| width: percentageValue() + "%" | |
| } | |
| }, scope.usedSpace = humanSize(authentication.user.UsedSpace), scope.maxSpace = humanSize(authentication.user.MaxSpace) | |
| } | |
| } | |
| }), angular.module("proton.core").factory("alertModal", function(pmModal) { | |
| return pmModal({ | |
| controller: function(params) { | |
| this.title = params.title, this.message = params.message, this.alert = params.alert || "alert-info", this.ok = function() { | |
| params.ok() | |
| } | |
| }, | |
| controllerAs: "ctrl", | |
| templateUrl: "templates/modals/alert.tpl.html" | |
| }) | |
| }), angular.module("proton.core").factory("browserFingerprint", function() { | |
| function get() { | |
| return new Promise(function(resolve, reject) { | |
| try { | |
| (new window.Fingerprint2).get(function(fingerprint, components) { | |
| resolve({ | |
| fingerprint: fingerprint, | |
| components: components | |
| }) | |
| }) | |
| } catch (error) { | |
| reject(error) | |
| } | |
| }) | |
| } | |
| return { | |
| get: get | |
| } | |
| }), angular.module("proton.core").factory("bugModal", function(pmModal) { | |
| return pmModal({ | |
| controllerAs: "ctrl", | |
| templateUrl: "templates/modals/bug.tpl.html", | |
| controller: function(params) { | |
| var _this = this; | |
| this.form = params.form, this.form.attachScreenshot = !1, this.submit = function() { | |
| params.submit && params.submit(_this.form) | |
| }, this.cancel = function() { | |
| params.cancel && params.cancel() | |
| } | |
| } | |
| }) | |
| }), angular.module("proton.core").factory("cardModal", function(pmModal, Payment, gettextCatalog, cardModel, networkActivityTracker, paymentModel) { | |
| return pmModal({ | |
| controllerAs: "ctrl", | |
| templateUrl: "templates/modals/card.tpl.html", | |
| controller: function(params) { | |
| var self = this; | |
| self.card = {}, params.method ? (self.text = gettextCatalog.getString("Update your credit card information.", null, "Credit card modal"), self.mode = "display", self.panel = { | |
| fullname: params.method.Details.Name, | |
| number: "•••• •••• •••• " + params.method.Details.Last4, | |
| month: params.method.Details.ExpMonth, | |
| year: params.method.Details.ExpYear, | |
| cvc: "•••", | |
| zip: params.method.Details.ZIP, | |
| country: params.method.Details.Country | |
| }) : (self.text = gettextCatalog.getString("Add a credit card.", null, "Credit card modal"), self.mode = "edition"); | |
| var method = function() { | |
| if ("edition" === self.mode) { | |
| var card = cardModel(self.card); | |
| return Payment.updateMethod({ | |
| Type: "card", | |
| Details: card.details() | |
| }).then(function() { | |
| var _ref = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {}, | |
| _ref$data = _ref.data, | |
| data = void 0 === _ref$data ? {} : _ref$data; | |
| if (1e3 === data.Code) return data.PaymentMethod | |
| }).catch(function(_ref2) { | |
| var _ref2$data = _ref2.data, | |
| data = void 0 === _ref2$data ? {} : _ref2$data; | |
| throw Error(data.Error) | |
| }) | |
| } | |
| return Promise.resolve() | |
| }; | |
| self.edit = function() { | |
| self.card.fullname = self.panel.fullname, self.mode = "edition" | |
| }, self.submit = function() { | |
| var promise = method().then(function(method) { | |
| return paymentModel.getMethods(!0).then(function(methods) { | |
| return { | |
| method: method, | |
| methods: methods | |
| } | |
| }) | |
| }).then(params.close); | |
| networkActivityTracker.track(promise) | |
| }, self.cancel = params.close | |
| } | |
| }) | |
| }), angular.module("proton.core").factory("checkTypoEmails", function() { | |
| var addresses = ["prontonmail.", "prtonmail.", "protomail.", "protonmai.", "protonmsil.", "ptotonmail."].reduce(function(previousValue, currentValue) { | |
| return previousValue.concat([currentValue + "ch", currentValue + "com"]) | |
| }, []).concat(["gmail.co", "yahoo.co"]); | |
| return function() { | |
| var email = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : "", | |
| splitter = email.split("@"); | |
| if (splitter.length) { | |
| var domain = splitter[1]; | |
| return addresses.indexOf(domain) > -1 | |
| } | |
| return !1 | |
| } | |
| }), angular.module("proton.core").factory("confirmModal", function(pmModal, gettextCatalog) { | |
| var I18N = { | |
| confirm: gettextCatalog.getString("Confirm", null, "Default text for the confirm button in the confirm modal"), | |
| cancel: gettextCatalog.getString("Cancel", null, "Default text for the cancel button in the confirm modal") | |
| }; | |
| return pmModal({ | |
| controllerAs: "ctrl", | |
| templateUrl: "templates/modals/confirm.tpl.html", | |
| controller: function(params, hotkeys) { | |
| hotkeys.unbind(["enter"]), this.title = params.title, this.message = params.message, this.confirmText = params.confirmText || I18N.confirm, this.cancelText = params.cancelText || I18N.cancel, this.confirm = function() { | |
| return hotkeys.bind(["enter"]), params.confirm() | |
| }, this.cancel = function() { | |
| return hotkeys.bind(["enter"]), params.cancel() | |
| }, setTimeout(function() { | |
| return angular.element("#confirmModalBtn").focus() | |
| }, 100) | |
| } | |
| }) | |
| }), angular.module("proton.core").factory("consoleMessage", function($log) { | |
| var styles = { | |
| span: "color: #505061; font-size: 14px;", | |
| strong: "color: #505061; font-size: 14px; font-weight: bold;", | |
| alert: "color: #FF5956; font-size: 18px; font-weight: bold;", | |
| alertSpan: "color: #FF5956; font-size: 14px;", | |
| link: "color: #9397cd; font-size: 14px;" | |
| }; | |
| return function() { | |
| $log.info("%cFind a %csecurity bug?%c🛠[email protected]", styles.span, styles.strong, styles.link), $log.info("%cWe're %chiring!⛰ %chttps://protonmail.com/careers", styles.span, styles.strong, styles.link) | |
| } | |
| }), angular.module("proton.core").factory("csv", function(csvFormat) { | |
| var properties = csvFormat.getAllProperties(), | |
| toVCard = function(contact) { | |
| return _.reduce(properties, function(acc) { | |
| var key = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : "", | |
| props = csvFormat[key](contact); | |
| return props.length && _.each(props, function(_ref) { | |
| var _ref$value = _ref.value, | |
| value = void 0 === _ref$value ? "" : _ref$value, | |
| _ref$parameter = _ref.parameter, | |
| parameter = void 0 === _ref$parameter ? "" : _ref$parameter, | |
| params = {}; | |
| parameter && (params.type = parameter), acc.add(key, value, params) | |
| }), acc | |
| }, new vCard) | |
| }; | |
| return { | |
| csvToVCard: function(file) { | |
| return new Promise(function(resolve, reject) { | |
| var onComplete = function() { | |
| var _ref2 = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {}, | |
| _ref2$data = _ref2.data; | |
| return resolve((void 0 === _ref2$data ? [] : _ref2$data).map(toVCard)) | |
| }; | |
| Papa.parse(file, { | |
| header: !0, | |
| dynamicTyping: !0, | |
| complete: onComplete, | |
| error: reject, | |
| skipEmptyLines: !0 | |
| }) | |
| }) | |
| } | |
| } | |
| }), angular.module("proton.core").factory("csvFormat", function() { | |
| var PROPERTIES = { | |
| adr: [], | |
| anniversary: ["Anniversary"], | |
| bday: ["Birthday"], | |
| email: ["E-mail Address", "E-mail 2 Address", "E-mail 3 Address", "Email", "Alternate Email 1", "Alternate Email 2", "Primary Email", "Secondary Email"], | |
| fn: [], | |
| gender: ["Gender"], | |
| geo: ["Geolocation", "Location"], | |
| impp: ["Impp"], | |
| lang: ["Language"], | |
| logo: ["Logo"], | |
| member: ["Membmer", "Group Membership"], | |
| nickname: ["Nickname", "Display Name", "Screen Name"], | |
| note: ["Notes", "Note"], | |
| org: ["Company", "Organization", "Department"], | |
| photo: ["Photo", "Avatar"], | |
| prodid: ["Software"], | |
| rev: ["Revision"], | |
| role: ["Role"], | |
| sound: ["Sound"], | |
| tel: ["Primary Phone", "Other Phone", "Radio Phone", "Other", "Yahoo Phone"], | |
| title: ["Title", "Job Title", "JobTitle"], | |
| tz: ["Timezone", "TimeZone"], | |
| uid: ["UID"], | |
| url: ["URL", "Web Page", "Personal Website", "Business Website", "Website", "Web Page 1", "Web Page 2", "Personal Web Page"] | |
| }, | |
| PHONES = { | |
| Home: ["Home Phone", "Home Phone 2"], | |
| Work: ["Work Phone", "Company Main Phone", "Business Phone", "Business Phone 2"], | |
| Mobile: ["Mobile", "Mobile Number", "Mobile Phone"], | |
| Fax: ["Fax", "Fax Number", "Home Fax", "Business Fax", "Other Fax", "Telex"], | |
| Pager: ["Pager", "Pager Number"], | |
| Car: ["Car Phone"] | |
| }, | |
| parameters = { | |
| Fax: ["Fax"], | |
| Home: ["Home"], | |
| Work: ["Work", "Business"], | |
| Mobile: ["Mobile"], | |
| Personal: ["Personal", "Perso", "Main", "Primary"] | |
| }, | |
| getParameter = function() { | |
| var key = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : ""; | |
| return _.chain(Object.keys(parameters)).filter(function(param) { | |
| return parameters[param].filter(function(value) { | |
| return key.indexOf(value) > -1 | |
| }).length > 0 | |
| }).first().value() | |
| }, | |
| extractKeys = function() { | |
| var keys = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : [], | |
| contact = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : {}; | |
| return keys.reduce(function(acc, key) { | |
| var value = contact[key]; | |
| if (value) { | |
| var property = { | |
| value: value.toString() | |
| }, | |
| parameter = getParameter(key); | |
| parameter && (property.parameter = parameter), acc.push(property) | |
| } | |
| return acc | |
| }, []) | |
| }, | |
| extractAddress = function(contact, type) { | |
| var address = contact[type + " Address"] || contact[type + " Street"] || "", | |
| address2 = contact[type + " Address 2"] || contact[type + " Street 2"] || "", | |
| city = contact[type + " City"] || "", | |
| state = contact[type + " State"] || "", | |
| zipCode = contact[type + " ZipCode"] || contact[type + " Postal Code"] || contact[type + " ZIP"] || "", | |
| country = contact[type + " Country"] || contact[type + " Country/Region"] || "", | |
| value = ["", address2, address, city, state, zipCode, country]; | |
| return value.join("").trim().length ? value.join(";").trim() : "" | |
| }, | |
| getAllProperties = function() { | |
| return Object.keys(PROPERTIES) | |
| }, | |
| anniversary = function(contact) { | |
| return extractKeys(PROPERTIES.anniversary, contact) | |
| }, | |
| gender = function(contact) { | |
| return extractKeys(PROPERTIES.gender, contact) | |
| }, | |
| geo = function(contact) { | |
| return extractKeys(PROPERTIES.geo, contact) | |
| }, | |
| impp = function(contact) { | |
| return extractKeys(PROPERTIES.impp, contact) | |
| }, | |
| lang = function(contact) { | |
| return extractKeys(PROPERTIES.lang, contact) | |
| }, | |
| logo = function(contact) { | |
| return extractKeys(PROPERTIES.logo, contact) | |
| }, | |
| member = function(contact) { | |
| return extractKeys(PROPERTIES.member, contact) | |
| }, | |
| nickname = function(contact) { | |
| return extractKeys(PROPERTIES.nickname, contact) | |
| }, | |
| note = function(contact) { | |
| return extractKeys(PROPERTIES.note, contact) | |
| }, | |
| org = function(contact) { | |
| return extractKeys(PROPERTIES.org, contact) | |
| }, | |
| photo = function(contact) { | |
| return extractKeys(PROPERTIES.photo, contact) | |
| }, | |
| prodid = function(contact) { | |
| return extractKeys(PROPERTIES.prodid, contact) | |
| }, | |
| rev = function(contact) { | |
| return extractKeys(PROPERTIES.csv, contact) | |
| }, | |
| role = function(contact) { | |
| return extractKeys(PROPERTIES.role, contact) | |
| }, | |
| sound = function(contact) { | |
| return extractKeys(PROPERTIES.sound, contact) | |
| }, | |
| title = function(contact) { | |
| return extractKeys(PROPERTIES.title, contact) | |
| }, | |
| tz = function(contact) { | |
| return extractKeys(PROPERTIES.tz, contact) | |
| }, | |
| uid = function(contact) { | |
| return extractKeys(PROPERTIES.uid, contact) | |
| }, | |
| url = function(contact) { | |
| return extractKeys(PROPERTIES.url, contact) | |
| }; | |
| return { | |
| getAllProperties: getAllProperties, | |
| adr: function(contact) { | |
| var addresses = []; | |
| if (_.each(["Home", "Work", "Business", "Other"], function(type) { | |
| var value = extractAddress(contact, type); | |
| value && addresses.push({ | |
| value: value, | |
| type: type | |
| }) | |
| }), contact["Address 1 - Formatted"]) { | |
| var address = { | |
| value: contact["Address 1 - Formatted"] | |
| }; | |
| contact["Address 2 - Type"] && (address.parameter = contact["Address 1 - Type"]), addresses.push(address) | |
| } | |
| if (contact["Address 2 - Formatted"]) { | |
| var _address = { | |
| value: contact["Address 2 - Formatted"] | |
| }; | |
| contact["Address 2 - Type"] && (_address.parameter = contact["Address 2 - Type"]), addresses.push(_address) | |
| } | |
| if (contact["Address 3 - Formatted"]) { | |
| var _address2 = { | |
| value: contact["Address 3 - Formatted"] | |
| }; | |
| contact["Address 3 - Type"] && (_address2.parameter = contact["Address 3 - Type"]), addresses.push(_address2) | |
| } | |
| return addresses | |
| }, | |
| anniversary: anniversary, | |
| bday: function(contact) { | |
| var bdays = extractKeys(PROPERTIES.bday, contact), | |
| year = contact["Birth Year"], | |
| month = contact["Birth Month"], | |
| day = contact["Birth Day"]; | |
| return year && month && day && bdays.push(year + "-" + month + "-" + day), bdays | |
| }, | |
| email: function(contact) { | |
| var emails = extractKeys(PROPERTIES.email, contact); | |
| if (contact["E-mail 1 - Value"]) { | |
| var _email = { | |
| value: contact["E-mail 1 - Value"] | |
| }; | |
| contact["E-mail 1 - Type"] && (_email.parameter = contact["E-mail 1 - Type"]), emails.push(_email) | |
| } | |
| if (contact["E-mail 2 - Value"]) { | |
| var _email2 = { | |
| value: contact["E-mail 2 - Value"] | |
| }; | |
| contact["E-mail 2 - Type"] && (_email2.parameter = contact["E-mail 2 - Type"]), emails.push(_email2) | |
| } | |
| if (contact["E-mail 3 - Value"]) { | |
| var _email3 = { | |
| value: contact["E-mail 3 - Value"] | |
| }; | |
| contact["E-mail 3 - Type"] && (_email3.parameter = contact["E-mail 3 - Type"]), emails.push(_email3) | |
| } | |
| return emails | |
| }, | |
| fn: function(contact) { | |
| var fullnames = [], | |
| name = []; | |
| return contact.First && name.push(contact.First), contact.Name && name.push(contact.Name), contact.Middle && name.push(contact.Middle), contact.Last && name.push(contact.Last), contact["First Name"] && name.push(contact["First Name"]), contact["Middle Name"] && name.push(contact["Middle Name"]), contact["Last Name"] && name.push(contact["Last Name"]), name.length && fullnames.push({ | |
| value: name.join(" ") | |
| }), fullnames | |
| }, | |
| gender: gender, | |
| geo: geo, | |
| impp: impp, | |
| lang: lang, | |
| logo: logo, | |
| member: member, | |
| nickname: nickname, | |
| note: note, | |
| org: org, | |
| photo: photo, | |
| prodid: prodid, | |
| rev: rev, | |
| role: role, | |
| sound: sound, | |
| tel: function(contact) { | |
| var tels = extractKeys(PROPERTIES.tel, contact); | |
| if (Object.keys(PHONES).forEach(function(parameter) { | |
| PHONES[parameter].forEach(function(key) { | |
| var value = contact[key]; | |
| value && tels.push({ | |
| value: value, | |
| parameter: parameter | |
| }) | |
| }) | |
| }), contact["Phone 1 - Value"]) { | |
| var _tel = { | |
| value: contact["Phone 1 - Value"] | |
| }; | |
| contact["Phone 1 - Type"] && (_tel.parameter = contact["Phone 1 - Type"]), tels.push(_tel) | |
| } | |
| if (contact["Phone 2 - Value"]) { | |
| var _tel2 = { | |
| value: contact["Phone 2 - Value"] | |
| }; | |
| contact["Phone 2 - Type"] && (_tel2.parameter = contact["Phone 2 - Type"]), tels.push(_tel2) | |
| } | |
| if (contact["Phone 3 - Value"]) { | |
| var _tel3 = { | |
| value: contact["Phone 3 - Value"] | |
| }; | |
| contact["Phone 3 - Type"] && (_tel3.parameter = contact["Phone 3 - Type"]), tels.push(_tel3) | |
| } | |
| return tels | |
| }, | |
| title: title, | |
| tz: tz, | |
| uid: uid, | |
| url: url | |
| } | |
| }), angular.module("proton.core").factory("customizeInvoiceModal", function(eventManager, pmModal, settingsApi, notification, authentication, networkActivityTracker) { | |
| return pmModal({ | |
| controllerAs: "ctrl", | |
| templateUrl: "templates/modals/customizeInvoice.tpl.html", | |
| controller: function(params) { | |
| var self = this; | |
| self.text = authentication.user.InvoiceText || "", self.cancel = function() { | |
| return params.cancel() | |
| }, self.submit = function() { | |
| var promise = settingsApi.invoiceText({ | |
| InvoiceText: self.text | |
| }).then(function() { | |
| var _ref = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {}, | |
| _ref$data = _ref.data, | |
| data = void 0 === _ref$data ? {} : _ref$data; | |
| if (data.Error) throw new Error(data.Error); | |
| return data | |
| }).then(function() { | |
| return eventManager.call() | |
| }).then(function() { | |
| notification.success("Invoice customized"), params.cancel() | |
| }); | |
| networkActivityTracker.track(promise) | |
| } | |
| } | |
| }) | |
| }), angular.module("proton.core").factory("deleteAccountModal", function(pmModal, Bug, User, networkActivityTracker, authentication, $state, CONSTANTS, gettextCatalog, notification) { | |
| function report(params, isAdmin) { | |
| return isAdmin ? Bug.report(params) : Promise.resolve() | |
| } | |
| function deleteUser(params) { | |
| return User.delete(params).then(function(_ref) { | |
| var _ref$data = _ref.data, | |
| data = void 0 === _ref$data ? {} : _ref$data; | |
| if (1e3 === data.Code) return data; | |
| throw new Error(data.Error) | |
| }) | |
| } | |
| var I18N = { | |
| invalidForm: gettextCatalog.getString("Invalid email address or password", null, "Error reported when the delete account form is invalid") | |
| }; | |
| return pmModal({ | |
| controllerAs: "ctrl", | |
| templateUrl: "templates/modals/deleteAccount.tpl.html", | |
| controller: function(params, $scope) { | |
| var self = this; | |
| self.hasTwoFactor = authentication.user.TwoFactor, self.isAdmin = authentication.user.Role === CONSTANTS.PAID_ADMIN_ROLE, self.email = "", self.feedback = "", self.password = "", self.twoFactorCode = "", self.submit = function() { | |
| if ($scope.deleteForm.$invalid) return void notification.error(I18N.invalidForm); | |
| var username = authentication.user.Name, | |
| params = { | |
| OS: "--", | |
| OSVersion: "--", | |
| Browser: "--", | |
| BrowserVersion: "--", | |
| BrowserExtensions: "--", | |
| Client: "--", | |
| ClientVersion: "--", | |
| Title: "[DELETION FEEDBACK] " + username, | |
| Username: username, | |
| Email: self.email || authentication.user.Addresses[0].Email, | |
| Description: self.feedback | |
| }, | |
| promise = report(params, self.isAdmin).then(function() { | |
| return deleteUser({ | |
| Password: self.password, | |
| TwoFactorCode: self.twoFactorCode | |
| }) | |
| }).then(function() { | |
| return $state.go("login") | |
| }); | |
| networkActivityTracker.track(promise) | |
| }, self.cancel = function() { | |
| params.close() | |
| } | |
| } | |
| }) | |
| }), angular.module("proton.core").factory("dkimModal", function(pmModal, $rootScope) { | |
| return pmModal({ | |
| controllerAs: "ctrl", | |
| templateUrl: "templates/modals/domain/dkim.tpl.html", | |
| controller: function(params) { | |
| this.domain = params.domain, this.step = params.step, this.open = function(name) { | |
| $rootScope.$broadcast(name, params.domain) | |
| }, this.next = function() { | |
| params.next() | |
| }, this.close = function() { | |
| params.close() | |
| } | |
| } | |
| }) | |
| }), angular.module("proton.core").factory("dmarcModal", function(pmModal, $rootScope) { | |
| return pmModal({ | |
| controllerAs: "ctrl", | |
| templateUrl: "templates/modals/domain/dmarc.tpl.html", | |
| controller: function(params) { | |
| this.domain = params.domain, this.step = params.step, this.open = function(name) { | |
| $rootScope.$broadcast(name, params.domain) | |
| }, this.verify = function() { | |
| params.verify() | |
| }, this.close = function() { | |
| params.close() | |
| } | |
| } | |
| }) | |
| }), angular.module("proton.core").factory("domainModal", function(pmModal, $rootScope) { | |
| return pmModal({ | |
| controllerAs: "ctrl", | |
| templateUrl: "templates/modals/domain/domain.tpl.html", | |
| controller: function(params) { | |
| var self = this; | |
| self.step = params.step, self.domain = params.domain, self.name = "", self.open = function(name) { | |
| $rootScope.$broadcast(name, params.domain) | |
| }, self.submit = function() { | |
| angular.isDefined(params.submit) && angular.isFunction(params.submit) && params.submit(self.name) | |
| }, self.next = function() { | |
| angular.isDefined(params.next) && angular.isFunction(params.next) && params.next() | |
| }, self.cancel = function() { | |
| angular.isDefined(params.cancel) && angular.isFunction(params.cancel) && params.cancel() | |
| }, self.beginsWith = function() { | |
| var value = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : "", | |
| _self$name = self.name; | |
| return (void 0 === _self$name ? "" : _self$name).substring(0, value.length) === value | |
| } | |
| } | |
| }) | |
| }), angular.module("proton.core").factory("donateModal", function($rootScope, pmModal) { | |
| return pmModal({ | |
| controllerAs: "ctrl", | |
| templateUrl: "templates/modals/donate.tpl.html", | |
| controller: function(params) { | |
| this.typeOfModal = params.type, this.close = params.close; | |
| var unsubscribe = $rootScope.$on("payments", function(e, _ref) { | |
| /^(donation|topUp)\.request\.success/.test(_ref.type) && params.close() | |
| }); | |
| this.$onDestroy = function() { | |
| return unsubscribe() | |
| } | |
| } | |
| }) | |
| }), angular.module("proton.core").factory("downloadFile", function(gettextCatalog, notification, aboutClient) { | |
| var newerBrowser = gettextCatalog.getString("Download requires a newer browser.", null, "Error"), | |
| learnMore = gettextCatalog.getString("Learn more.", null, "Info"); | |
| return function(blob, filename) { | |
| try { | |
| if (!aboutClient.isFileSaverSupported()) throw new Error(newerBrowser); | |
| window.saveAs(blob, filename) | |
| } catch (error) { | |
| notification.error(newerBrowser + ' <a href="https://protonmail.com/support/knowledge-base/problems-with-attachments/" target="_blank">' + learnMore + "</a>"), console.error(error) | |
| } | |
| } | |
| }), angular.module("proton.core").factory("$exceptionHandler", function($injector) { | |
| var nReports = 0, | |
| MAP_ERROR_SILENT = { | |
| "loginPassword:cancel": !0 | |
| }, | |
| getError = function(exception) { | |
| if (exception instanceof Error) return { | |
| message: exception.message, | |
| stack: exception.stack | |
| }; | |
| if (angular.isString(exception)) return exception; | |
| try { | |
| var json = angular.toJson(exception); | |
| return $.isEmptyObject(json) ? exception.toString() : exception | |
| } catch (err) { | |
| return err.message | |
| } | |
| }, | |
| isLoggable = function(err) { | |
| return !(MAP_ERROR_SILENT[err] || MAP_ERROR_SILENT[(err || {}).message]) | |
| }; | |
| return function(exception) { | |
| if (nReports++, console.error(exception), nReports < 6) { | |
| var error = getError(exception); | |
| if (!isLoggable(error)) return Promise.resolve(); | |
| try { | |
| return $injector.get("bugReportApi").crash(error) | |
| } catch (e) { | |
| console.error(e) | |
| } | |
| } | |
| return Promise.resolve() | |
| } | |
| }), angular.module("proton.core").factory("feedbackModal", function(pmModal, Bug, notification, networkActivityTracker, gettextCatalog) { | |
| return pmModal({ | |
| controllerAs: "ctrl", | |
| templateUrl: "templates/modals/feedback.tpl.html", | |
| controller: function(params) { | |
| var _this = this; | |
| this.fdbckTxt = "", this.submit = function() { | |
| var description = _this.fdbckTxt, | |
| data = { | |
| OS: "--", | |
| OSVersion: "--", | |
| Browser: "--", | |
| BrowserVersion: "--", | |
| BrowserExtensions: "--", | |
| Client: "--", | |
| ClientVersion: "--", | |
| Title: "[FEEDBACK v3]", | |
| Username: "--", | |
| Email: "--", | |
| Description: description | |
| }, | |
| feedbackPromise = Bug.report(data); | |
| feedbackPromise.then(function() { | |
| notification.success(gettextCatalog.getString("Thanks for your feedback!", null, "Success message when sending feedback")), params.close() | |
| }), networkActivityTracker.track(feedbackPromise) | |
| }, this.close = function() { | |
| params.close() | |
| } | |
| } | |
| }) | |
| }), angular.module("proton.core").factory("hotkeyModal", function(pmModal, authentication, CONSTANTS) { | |
| return pmModal({ | |
| controllerAs: "ctrl", | |
| templateUrl: "templates/modals/hotkey.tpl.html", | |
| controller: function(params) { | |
| this.isMac = -1 !== navigator.userAgent.indexOf("Mac OS X"), authentication.user.ViewLayout === CONSTANTS.ROW_MODE ? this.mode = "row" : authentication.user.ViewLayout === CONSTANTS.COLUMN_MODE && (this.mode = "column"), this.close = function() { | |
| params.close() | |
| } | |
| } | |
| }) | |
| }), angular.module("proton.core").factory("humanVerificationModal", function($http, $rootScope, pmModal, User, networkActivityTracker) { | |
| function handleResult(_ref) { | |
| var _ref$data = _ref.data, | |
| data = void 0 === _ref$data ? {} : _ref$data; | |
| return 1e3 === data.Code ? Promise.resolve(data) : data.Error ? Promise.reject(data.Error) : Promise.reject("Error") | |
| } | |
| return pmModal({ | |
| controllerAs: "ctrl", | |
| templateUrl: "templates/modals/humanVerification.tpl.html", | |
| controller: function(params, $scope) { | |
| var self = this, | |
| unsubscribe = []; | |
| self.tokens = { | |
| captcha: "" | |
| }; | |
| var promise = User.human().then(handleResult).then(function(_ref2) { | |
| var VerifyMethods = _ref2.VerifyMethods, | |
| Token = _ref2.Token; | |
| self.token = Token, self.methods = VerifyMethods, self.showCaptcha = _.contains(VerifyMethods, "captcha"), self.verificator = "captcha" | |
| }); | |
| networkActivityTracker.track(promise), self.submit = function() { | |
| var promise = User.check({ | |
| Token: self.tokens[self.verificator], | |
| TokenType: self.verificator | |
| }).then(handleResult).then(function() { | |
| params.close(!0) | |
| }).catch(function() { | |
| params.close(!0) | |
| }); | |
| networkActivityTracker.track(promise) | |
| }, self.cancel = function() { | |
| return params.close(!1) | |
| }, unsubscribe.push($rootScope.$on("captcha.token", function(event, token) { | |
| $scope.$applyAsync(function() { | |
| self.tokens.captcha = token | |
| }) | |
| })), self.$onDestroy = function() { | |
| unsubscribe.forEach(function(cb) { | |
| return cb() | |
| }), unsubscribe.length = 0 | |
| } | |
| } | |
| }) | |
| }), angular.module("proton.core").factory("logoutManager", function($rootScope, authentication, eventManager, cache, cacheCounters, contactCache, paymentModel) { | |
| return $rootScope.$on("$stateChangeSuccess", function(e, state) { | |
| var currentState = state.name, | |
| specialStates = ["login.setup"]; - 1 === currentState.indexOf("secured") && -1 === specialStates.indexOf(currentState) && (eventManager.stop(), cache.reset(), cacheCounters.reset(), contactCache.clear(), paymentModel.clear(), authentication.isLoggedIn() && authentication.logout(), $rootScope.$emit("logout")) | |
| }), {} | |
| }), angular.module("proton.core").factory("mxModal", function(pmModal, $rootScope) { | |
| return pmModal({ | |
| controllerAs: "ctrl", | |
| templateUrl: "templates/modals/domain/mx.tpl.html", | |
| controller: function(params) { | |
| this.domain = params.domain, this.step = params.step, this.open = function(name) { | |
| $rootScope.$broadcast(name, params.domain) | |
| }, this.next = function() { | |
| params.next() | |
| }, this.close = function() { | |
| params.close() | |
| } | |
| } | |
| }) | |
| }), angular.module("proton.core").factory("reactivateModal", function(pmModal) { | |
| return pmModal({ | |
| controllerAs: "ctrl", | |
| templateUrl: "templates/modals/reactivate.tpl.html", | |
| controller: function(params) { | |
| this.loginPassword = "", this.keyPassword = "", this.submit = function() { | |
| params.submit && params.submit(this.loginPassword, this.keyPassword) | |
| }.bind(this), this.cancel = function() { | |
| params.cancel && params.cancel() | |
| } | |
| } | |
| }) | |
| }), angular.module("proton.core").factory("recoveryCodeModal", function(pmModal, downloadFile) { | |
| return pmModal({ | |
| controllerAs: "ctrl", | |
| templateUrl: "templates/modals/twofactor/recoveryCode.tpl.html", | |
| controller: function(params) { | |
| this.recoveryCodesFirstHalf = params.recoveryCodes.slice(0, 8), this.recoveryCodesSecondHalf = params.recoveryCodes.slice(8, 16), this.download = function() { | |
| var blob = new Blob([params.recoveryCodes.join("\r\n")], { | |
| type: "text/plain;charset=utf-8;" | |
| }); | |
| downloadFile(blob, "protonmail_recovery_codes.txt") | |
| }, this.done = function() { | |
| params.close() | |
| }, this.cancel = function() { | |
| params.close() | |
| } | |
| } | |
| }) | |
| }), angular.module("proton.core").factory("sharedSecretModal", function(authentication, pmModal, $timeout, webcrypto) { | |
| return pmModal({ | |
| controllerAs: "ctrl", | |
| templateUrl: "templates/modals/twofactor/sharedSecret.tpl.html", | |
| controller: function(params) { | |
| var self = this, | |
| randomBytes = webcrypto.getRandomValues(new Uint8Array(20)), | |
| sharedSecret = base32.encode(randomBytes), | |
| primaryAddress = _.find(authentication.user.Addresses, function(_ref) { | |
| return _ref.Keys | |
| }), | |
| identifier = primaryAddress ? primaryAddress.Email : authentication.user.Name + "@protonmail", | |
| qrURI = "otpauth://totp/" + identifier + "?secret=" + sharedSecret + "&issuer=ProtonMail&algorithm=SHA1&digits=6&period=30"; | |
| self.sharedSecret = params.sharedSecret || sharedSecret, self.qrURI = params.qrURI || qrURI, self.manual = !1, self.next = function() { | |
| return params.next(self.sharedSecret, self.qrURI) | |
| }, self.cancel = function() { | |
| return params.cancel() | |
| }, self.displayManual = function() { | |
| self.manual = !self.manual | |
| }, self.makeCode = function() { | |
| new QRCode(document.getElementById("qrcode"), self.qrURI) | |
| } | |
| } | |
| }) | |
| }), angular.module("proton.core").factory("signatureModal", function(pmModal, authentication) { | |
| return pmModal({ | |
| controllerAs: "ctrl", | |
| templateUrl: "templates/modals/signature.tpl.html", | |
| controller: function(params) { | |
| this.defaultDisplayName = authentication.user.DisplayName, this.defaultSignature = authentication.user.Signature, this.address = params.address, this.address.DisplayName = this.address.DisplayName || authentication.user.DisplayName, this.address.Signature = this.address.Signature || authentication.user.Signature, this.address.custom = !0, this.confirm = function() { | |
| params.confirm(this.address) | |
| }, this.cancel = function() { | |
| params.cancel() | |
| } | |
| } | |
| }) | |
| }), angular.module("proton.core").factory("spfModal", function(pmModal, $rootScope) { | |
| return pmModal({ | |
| controllerAs: "ctrl", | |
| templateUrl: "templates/modals/domain/spf.tpl.html", | |
| controller: function(params) { | |
| this.domain = params.domain, this.step = params.step, this.open = function(name) { | |
| $rootScope.$broadcast(name, params.domain) | |
| }, this.next = function() { | |
| params.next() | |
| }, this.close = function() { | |
| params.close() | |
| } | |
| } | |
| }) | |
| }), angular.module("proton.core").factory("supportModal", function(pmModal) { | |
| return pmModal({ | |
| controllerAs: "ctrl", | |
| templateUrl: "templates/modals/support.tpl.html", | |
| controller: function(params) { | |
| this.cancel = function() { | |
| params.cancel && params.cancel() | |
| } | |
| } | |
| }) | |
| }), angular.module("proton.core").factory("switchPasswordModeModal", function(authentication, pmModal) { | |
| return pmModal({ | |
| controllerAs: "ctrl", | |
| templateUrl: "templates/modals/switchPasswordMode.tpl.html", | |
| controller: function(params) { | |
| var self = this; | |
| self.currentPasswordMode = authentication.user.PasswordMode, self.save = function() {}, self.cancel = params.cancel | |
| } | |
| }) | |
| }), angular.module("proton.core").factory("twoFAIntroModal", function(pmModal) { | |
| return pmModal({ | |
| controllerAs: "ctrl", | |
| templateUrl: "templates/modals/twofactor/twoFAIntroModal.tpl.html", | |
| controller: function(params) { | |
| var self = this; | |
| self.next = function() { | |
| return params.next() | |
| }, self.cancel = function() { | |
| return params.cancel() | |
| } | |
| } | |
| }) | |
| }), angular.module("proton.core").factory("vcard", function(CONSTANTS, notification, sanitize) { | |
| function isValidType() { | |
| var type = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : ""; | |
| return !type.length || _.contains(VCARD_TYPES, type.toLowerCase()) | |
| } | |
| function clean() { | |
| var vcard = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : new vCard, | |
| properties = extractProperties(vcard); | |
| return _.reduce(properties, function(acc, property) { | |
| var type = property.getType(), | |
| typeValue = type && (Array.isArray(type) ? type.map(function(t) { | |
| return cleanType(t) | |
| }).filter(function(t) { | |
| return t | |
| }) : cleanType(type)), | |
| key = property.getField(), | |
| value = property.valueOf(), | |
| params = property.getParams(); | |
| return delete params.type, typeValue && typeValue.length && (params.type = typeValue), acc.add(key, sanitize.input(cleanValue(value)), params), acc | |
| }, new vCard) | |
| } | |
| function cleanType() { | |
| var type = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : ""; | |
| return "x-INTERNET" === type ? "" : isValidType(type) ? type : type.toLowerCase().startsWith("x") ? type : "x-" + type | |
| } | |
| function cleanValue() { | |
| var value = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : "", | |
| matches = value.match(/_\$!<(.*)>!\$_/); | |
| return Array.isArray(matches) ? matches[1] : value | |
| } | |
| function extractProperties() { | |
| var vcard = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : new vCard; | |
| return _.reduce(Object.keys(vcard.data), function(acc, key) { | |
| var value = vcard.get(key), | |
| props = Array.isArray(value) ? value : [value]; | |
| return acc.concat(props) | |
| }, []) | |
| } | |
| function build() { | |
| var properties = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : [], | |
| target = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : new vCard; | |
| return _.each(properties, function(property) { | |
| return target.addProperty(property) | |
| }), target | |
| } | |
| var VCARD_VERSION = CONSTANTS.VCARD_VERSION, | |
| VCARD_TYPES = CONSTANTS.VCARD_TYPES, | |
| merge = function() { | |
| var vcards = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : []; | |
| return _.reduce(vcards, function(acc) { | |
| return build(extractProperties(arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : {}), acc) | |
| }, new vCard) | |
| }, | |
| to = function() { | |
| var vcards = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : []; | |
| return _.reduce(vcards, function(acc, vCard) { | |
| return acc + clean(vCard).toString(VCARD_VERSION) + "\r\n" | |
| }, "") | |
| }; | |
| return { | |
| from: function() { | |
| var vcfString = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : ""; | |
| try { | |
| return vCard.parse(vcfString).map(function(vcard) { | |
| return clean(vcard) | |
| }) | |
| } catch (e) { | |
| notification.error(e) | |
| } | |
| }, | |
| to: to, | |
| extractProperties: extractProperties, | |
| merge: merge, | |
| build: build, | |
| isValidType: isValidType | |
| } | |
| }), angular.module("proton.core").factory("verificationModal", function(pmModal, $rootScope) { | |
| return pmModal({ | |
| controllerAs: "ctrl", | |
| templateUrl: "templates/modals/domain/verification.tpl.html", | |
| controller: function(params) { | |
| this.domain = params.domain, this.step = params.step, this.open = function(name) { | |
| $rootScope.$broadcast(name, params.domain) | |
| }, this.submit = function() { | |
| angular.isDefined(params.close) && angular.isFunction(params.close) && params.submit() | |
| }, this.next = function() { | |
| angular.isDefined(params.close) && angular.isFunction(params.close) && (params.close(), params.next()) | |
| }, this.close = function() { | |
| angular.isDefined(params.close) && angular.isFunction(params.close) && params.close() | |
| } | |
| } | |
| }) | |
| }), angular.module("proton.core").factory("welcomeModal", function(pmModal, settingsApi, authentication, networkActivityTracker) { | |
| function saveDisplayName(DisplayName) { | |
| var promise = settingsApi.display({ | |
| DisplayName: DisplayName | |
| }); | |
| authentication.user.DisplayName = DisplayName, networkActivityTracker.track(promise) | |
| } | |
| return pmModal({ | |
| controllerAs: "ctrl", | |
| templateUrl: "templates/modals/welcome.tpl.html", | |
| controller: function(params) { | |
| var _this = this; | |
| this.displayName = authentication.user.DisplayName, this.cancel = params.cancel, this.next = function() { | |
| _this.displayName.length && saveDisplayName(_this.displayName), params.next() | |
| } | |
| } | |
| }) | |
| }), angular.module("proton.core").factory("formatResponseInterceptor", function($q) { | |
| return { | |
| responseError: function(rejection) { | |
| return rejection.data = rejection.data || {}, $q.reject(rejection) | |
| } | |
| } | |
| }), angular.module("proton.core").service("cache", function($interval, $q, $rootScope, $state, $stateParams, CONSTANTS, conversationApi, firstLoad, gettextCatalog, messageModel, messageApi, cacheCounters, networkActivityTracker, tools, labelsModel, cachePages) { | |
| function storeConversations() { | |
| (arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : []).forEach(updateConversation) | |
| } | |
| function getPages(_ref) { | |
| var _ref$Page = _ref.Page, | |
| Page = void 0 === _ref$Page ? 0 : _ref$Page, | |
| _ref$Limit = _ref.Limit, | |
| Limit = void 0 === _ref$Limit ? CONSTANTS.CONVERSATION_LIMIT : _ref$Limit; | |
| return _.range(Page, Page + Limit / CONSTANTS.ELEMENTS_PER_PAGE, 1) | |
| } | |
| function storeMessages() { | |
| (arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : []).forEach(updateMessage) | |
| } | |
| function storeTime(conversationId, loc, time) { | |
| timeCached[conversationId] = timeCached[conversationId] || {}, timeCached[conversationId][loc] = time | |
| } | |
| function updateMessage(message, isSend) { | |
| _.findWhere(messagesCached, { | |
| ID: message.ID | |
| }) ? messagesCached = _.map(messagesCached, function(msg) { | |
| if (isSend && msg.ID === message.ID) return message; | |
| if (msg.ID === message.ID) { | |
| var m = _.extend({}, msg, message); | |
| return m.Type = message.Type, m | |
| } | |
| return msg | |
| }) : messagesCached.push(message), manageTimes(message.ConversationID), $rootScope.$emit("labelsElement." + message.ID, message), $rootScope.$emit("foldersMessage." + message.ID, message), $rootScope.$emit("foldersElement." + message.ID, message) | |
| } | |
| function extractContextDatas(oldElement, newElement) { | |
| var _newElement$Labels = newElement.Labels, | |
| Labels = void 0 === _newElement$Labels ? [] : _newElement$Labels, | |
| ID = tools.currentLocation(), | |
| _ref2 = Labels.length ? _.findWhere(Labels, { | |
| ID: ID | |
| }) || {} : newElement, | |
| _ref2$ContextNumUnrea = _ref2.ContextNumUnread, | |
| ContextNumUnread = void 0 === _ref2$ContextNumUnrea ? oldElement.ContextNumUnread : _ref2$ContextNumUnrea, | |
| _ref2$ContextNumAttac = _ref2.ContextNumAttachments, | |
| ContextNumAttachments = void 0 === _ref2$ContextNumAttac ? oldElement.ContextNumAttachments : _ref2$ContextNumAttac, | |
| _ref2$ContextSize = _ref2.ContextSize, | |
| ContextSize = void 0 === _ref2$ContextSize ? oldElement.ContextSize : _ref2$ContextSize, | |
| _ref2$ContextTime = _ref2.ContextTime; | |
| return { | |
| ContextNumUnread: ContextNumUnread, | |
| ContextNumAttachments: ContextNumAttachments, | |
| ContextSize: ContextSize, | |
| ContextTime: void 0 === _ref2$ContextTime ? oldElement.ContextTime : _ref2$ContextTime | |
| } | |
| } | |
| function updateConversation(conversation) { | |
| var current = _.findWhere(conversationsCached, { | |
| ID: conversation.ID | |
| }); | |
| if (current) return _.extend(current, conversation, { | |
| Labels: getLabels(current, conversation), | |
| Senders: filterSenderConversation(current.Senders, conversation.Senders) | |
| }, extractContextDatas(current, conversation)), delete current.LabelIDsAdded, delete current.LabelIDsRemoved, manageTimes(current.ID), $rootScope.$emit("labelsElement." + current.ID, current), void $rootScope.$emit("foldersElement." + current.ID, current); | |
| _.extend(conversation, extractContextDatas(conversation, conversation)), conversationsCached.push(conversation), manageTimes(conversation.ID), $rootScope.$emit("labelsElement." + conversation.ID, conversation), $rootScope.$emit("foldersElement." + conversation.ID, conversation) | |
| } | |
| function vector(_ref3, unread, type) { | |
| var _ref3$LabelIDs = _ref3.LabelIDs, | |
| LabelIDs = void 0 === _ref3$LabelIDs ? [] : _ref3$LabelIDs, | |
| _ref3$Labels = _ref3.Labels, | |
| Labels = void 0 === _ref3$Labels ? [] : _ref3$Labels, | |
| IsRead = _ref3.IsRead, | |
| toInt = function(value) { | |
| return +!!value | |
| }, | |
| locs = [inbox, allDrafts, drafts, allSent, sent, trash, spam, allmail, archive, starred].concat(labelsModel.ids()); | |
| return _.reduce(locs, function(acc, loc) { | |
| if ("message" === type) { | |
| var test = _.contains(LabelIDs, loc); | |
| acc[loc] = toInt(unread ? test && 0 === IsRead : test) | |
| } | |
| if ("conversation" === type) { | |
| var label = _.findWhere(Labels, { | |
| ID: loc | |
| }); | |
| acc[loc] = toInt(unread ? label && label.ContextNumUnread > 0 : label) | |
| } | |
| return acc | |
| }, {}) | |
| } | |
| function manageTimes(conversationID) { | |
| if (conversationID) { | |
| var _ref4 = api.getConversationCached(conversationID) || {}, | |
| _ref4$Labels = _ref4.Labels, | |
| Labels = void 0 === _ref4$Labels ? [] : _ref4$Labels, | |
| messages = api.queryMessagesCached(conversationID); | |
| messages.length && Labels.forEach(function(_ref5) { | |
| var ID = _ref5.ID, | |
| _ref6 = _.chain(messages).filter(function(_ref7) { | |
| var _ref7$LabelIDs = _ref7.LabelIDs, | |
| LabelIDs = void 0 === _ref7$LabelIDs ? [] : _ref7$LabelIDs; | |
| return _.contains(LabelIDs, ID) | |
| }).first().value() || {}, | |
| Time = _ref6.Time; | |
| Time && storeTime(conversationID, ID, Time) | |
| }) | |
| } | |
| } | |
| function manageCounters(oldElement, newElement, type) { | |
| var oldUnreadVector = vector(oldElement, !0, type), | |
| newUnreadVector = vector(newElement, !0, type), | |
| newTotalVector = vector(newElement, !1, type), | |
| oldTotalVector = vector(oldElement, !1, type), | |
| locs = [inbox, allDrafts, drafts, allSent, sent, trash, spam, allmail, archive, starred].concat(labelsModel.ids()); | |
| _.each(locs, function(loc) { | |
| var deltaUnread = newUnreadVector[loc] - oldUnreadVector[loc], | |
| deltaTotal = newTotalVector[loc] - oldTotalVector[loc], | |
| currentUnread = void 0, | |
| currentTotal = void 0; | |
| "message" === type ? (currentUnread = cacheCounters.unreadMessage(loc), currentTotal = cacheCounters.totalMessage(loc), cacheCounters.updateMessage(loc, currentTotal + deltaTotal, currentUnread + deltaUnread)) : "conversation" === type && (currentUnread = cacheCounters.unreadConversation(loc), currentTotal = cacheCounters.totalConversation(loc), cacheCounters.updateConversation(loc, currentTotal + deltaTotal, currentUnread + deltaUnread)) | |
| }) | |
| } | |
| function queryConversations(request) { | |
| var loc = getLocation(request), | |
| context = tools.cacheContext(); | |
| request.Limit = request.Limit || CONSTANTS.CONVERSATION_LIMIT; | |
| var promise = api.getDispatcher().then(function() { | |
| return conversationApi.query(request) | |
| }).then(function() { | |
| var _ref9 = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {}, | |
| _ref9$data = _ref9.data, | |
| data = void 0 === _ref9$data ? {} : _ref9$data; | |
| if (1e3 === data.Code) { | |
| if (cacheCounters.currentState(data.Limit), $rootScope.$emit("elements", { | |
| type: "setLimit", | |
| data: { | |
| limit: data.Limit, | |
| total: data.Total | |
| } | |
| }), _.each(data.Conversations, function(conversation) { | |
| conversation.loaded = !0, storeTime(conversation.ID, loc, conversation.ContextTime) | |
| }), context) { | |
| var total = data.Limit, | |
| unread = 0 === total ? 0 : data.Unread, | |
| pages = getPages(request); | |
| return cacheCounters.updateConversation(loc, total, unread), storeConversations(data.Conversations), pages.forEach(function(page) { | |
| return !cachePages.inside(page) && cachePages.add(page) | |
| }), api.clearDispatcher(), api.orderConversation(data.Conversations.slice(0, CONSTANTS.ELEMENTS_PER_PAGE), loc) | |
| } | |
| return api.clearDispatcher(), data.Conversations.slice(0, CONSTANTS.ELEMENTS_PER_PAGE) | |
| } | |
| if (api.clearDispatcher(), $rootScope.$emit("elements", { | |
| type: "error", | |
| data: { | |
| code: data.Code, | |
| error: data.Error | |
| } | |
| }), data.Code === INVALID_SEARCH_ERROR_CODE) return []; | |
| throw new Error(data.Error || I18N.errorConversations) | |
| }); | |
| return networkActivityTracker.track(promise), promise | |
| } | |
| function queryMessages(request) { | |
| var loc = getLocation(request), | |
| context = tools.cacheContext(); | |
| request.Limit = request.Limit || CONSTANTS.MESSAGE_LIMIT; | |
| var promise = api.getDispatcher().then(function() { | |
| return messageApi.query(request) | |
| }).then(function() { | |
| var _ref10 = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {}, | |
| _ref10$data = _ref10.data, | |
| data = void 0 === _ref10$data ? {} : _ref10$data; | |
| if (1e3 === data.Code) { | |
| var _data$Messages = data.Messages, | |
| Messages = void 0 === _data$Messages ? [] : _data$Messages, | |
| _data$Total = data.Total, | |
| Total = void 0 === _data$Total ? 0 : _data$Total, | |
| _data$Limit = data.Limit, | |
| Limit = void 0 === _data$Limit ? 0 : _data$Limit; | |
| if (cacheCounters.currentState(Limit), $rootScope.$emit("elements", { | |
| type: "setLimit", | |
| data: { | |
| limit: Limit, | |
| total: Total | |
| } | |
| }), _.each(Messages, function(message) { | |
| var _message$ToList = message.ToList, | |
| ToList = void 0 === _message$ToList ? [] : _message$ToList, | |
| _message$CCList = message.CCList, | |
| CCList = void 0 === _message$CCList ? [] : _message$CCList, | |
| _message$BCCList = message.BCCList, | |
| BCCList = void 0 === _message$BCCList ? [] : _message$BCCList; | |
| message.loaded = !0, message.Senders = [message.Sender], message.Recipients = _.uniq([].concat(ToList, CCList, BCCList)) | |
| }), storeMessages(Messages), context) { | |
| var pages = getPages(request); | |
| return cacheCounters.updateMessage(loc, Limit), pages.forEach(function(page) { | |
| return !cachePages.inside(page) && cachePages.add(page) | |
| }), api.clearDispatcher(), api.orderMessage(Messages.slice(0, CONSTANTS.ELEMENTS_PER_PAGE)) | |
| } | |
| return api.clearDispatcher(), Messages.slice(0, CONSTANTS.ELEMENTS_PER_PAGE) | |
| } | |
| if (api.clearDispatcher(), $rootScope.$emit("elements", { | |
| type: "error", | |
| data: { | |
| code: data.Code, | |
| error: data.Error | |
| } | |
| }), data.Code === INVALID_SEARCH_ERROR_CODE) return []; | |
| throw new Error(data.Error || I18N.errorMessages) | |
| }); | |
| return networkActivityTracker.track(promise), promise | |
| } | |
| function getConversation() { | |
| var conversationID = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : "", | |
| promise = conversationApi.get(conversationID).then(function() { | |
| var _ref11 = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {}, | |
| _ref11$data = _ref11.data, | |
| data = void 0 === _ref11$data ? {} : _ref11$data, | |
| Code = data.Code, | |
| Conversation = data.Conversation, | |
| Messages = data.Messages; | |
| if (1e3 === Code) { | |
| var conversation = Conversation, | |
| messages = Messages, | |
| message = _.max(messages, function(_ref12) { | |
| return _ref12.Time | |
| }); | |
| return messages.forEach(function(message) { | |
| return message.loaded = !0 | |
| }), conversation.loaded = !0, conversation.Time = message.Time, storeConversations([conversation]), storeMessages(messages), angular.copy(conversation) | |
| } | |
| throw new Error(data.Error) | |
| }); | |
| return networkActivityTracker.track(promise), promise | |
| } | |
| function getMessage() { | |
| var messageID = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : "", | |
| promise = messageApi.get(messageID).then(function() { | |
| var _ref13 = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {}, | |
| _ref13$data = _ref13.data, | |
| data = void 0 === _ref13$data ? {} : _ref13$data; | |
| if (1e3 === data.Code) { | |
| var message = data.Message; | |
| return message.loaded = !0, storeMessages([message]), messageModel(message) | |
| } | |
| throw new Error(data.Error) | |
| }); | |
| return networkActivityTracker.track(promise), promise | |
| } | |
| function reverse() { | |
| return (arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : []).reduce(function(acc, item) { | |
| return acc.unshift(item), acc | |
| }, []) | |
| } | |
| function getLabelsId() { | |
| var oldElement = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {}, | |
| newElement = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : {}, | |
| labelIDs = newElement.LabelIDs || oldElement.LabelIDs || []; | |
| return Array.isArray(newElement.LabelIDsRemoved) && (labelIDs = _.difference(labelIDs, newElement.LabelIDsRemoved)), Array.isArray(newElement.LabelIDsAdded) && (labelIDs = _.uniq(labelIDs.concat(newElement.LabelIDsAdded))), labelIDs | |
| } | |
| function getLabels(old, _ref22) { | |
| var _ref22$Labels = _ref22.Labels, | |
| Labels = void 0 === _ref22$Labels ? [] : _ref22$Labels, | |
| _ref22$LabelIDsRemove = _ref22.LabelIDsRemoved, | |
| LabelIDsRemoved = void 0 === _ref22$LabelIDsRemove ? [] : _ref22$LabelIDsRemove, | |
| _ref22$LabelIDsAdded = _ref22.LabelIDsAdded, | |
| LabelIDsAdded = void 0 === _ref22$LabelIDsAdded ? [] : _ref22$LabelIDsAdded, | |
| _ref22$ContextNumUnre = _ref22.ContextNumUnread, | |
| ContextNumUnread = void 0 === _ref22$ContextNumUnre ? 0 : _ref22$ContextNumUnre; | |
| if (LabelIDsAdded.length || LabelIDsRemoved.length) { | |
| var toAdd = _.map(LabelIDsAdded, function(ID) { | |
| return { | |
| ID: ID, | |
| ContextNumUnread: ContextNumUnread | |
| } | |
| }), | |
| filtered = _.filter(old.Labels, function(_ref23) { | |
| var ID = _ref23.ID; | |
| return !_.contains(LabelIDsRemoved, ID) | |
| }); | |
| return _.uniq(filtered.concat(toAdd), function(_ref24) { | |
| return _ref24.ID | |
| }) | |
| } | |
| return Labels.length ? _.map(Labels, function(label) { | |
| var oldLabel = _.findWhere(old.Labels || [], { | |
| ID: label.ID | |
| }); | |
| return oldLabel ? _.extend({}, oldLabel, label) : label | |
| }) : old.Labels || [] | |
| } | |
| function handleCounters() { | |
| var events = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : []; | |
| _.chain(events).filter(function(event) { | |
| return event.Message | |
| }).map(function(event) { | |
| return angular.copy(event.Message) | |
| }).each(function(newMessage) { | |
| var oldMessage = _.findWhere(messagesCached, { | |
| ID: newMessage.ID | |
| }); | |
| oldMessage && (newMessage.LabelIDs = getLabelsId(oldMessage, newMessage), manageCounters(oldMessage, newMessage, "message")) | |
| }), _.chain(events).filter(function(event) { | |
| return event.Conversation | |
| }).map(function(event) { | |
| return angular.copy(event.Conversation) | |
| }).each(function(newConversation) { | |
| var oldConversation = _.findWhere(conversationsCached, { | |
| ID: newConversation.ID | |
| }); | |
| oldConversation && (newConversation.Labels = getLabels(oldConversation, newConversation), manageCounters(oldConversation, newConversation, "conversation")) | |
| }), cacheCounters.status() | |
| } | |
| function expiration() { | |
| var now = moment().unix(), | |
| _messagesCached$reduc = messagesCached.reduce(function(acc) { | |
| var message = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : {}, | |
| ExpirationTime = message.ExpirationTime; | |
| return acc[0 !== ExpirationTime && ExpirationTime < now ? "removeList" : "list"].push(message), acc | |
| }, { | |
| list: [], | |
| removeList: [] | |
| }), | |
| list = _messagesCached$reduc.list, | |
| removeList = _messagesCached$reduc.removeList; | |
| messagesCached = list, removeList.length && $rootScope.$emit("message.expiration", removeList) | |
| } | |
| var api = {}, | |
| messagesCached = [], | |
| conversationsCached = [], | |
| dispatcher = [], | |
| timeCached = {}, | |
| INVALID_SEARCH_ERROR_CODE = 15225, | |
| _CONSTANTS$STATUS = CONSTANTS.STATUS, | |
| DELETE = _CONSTANTS$STATUS.DELETE, | |
| CREATE = _CONSTANTS$STATUS.CREATE, | |
| UPDATE_DRAFT = _CONSTANTS$STATUS.UPDATE_DRAFT, | |
| UPDATE_FLAGS = _CONSTANTS$STATUS.UPDATE_FLAGS, | |
| _CONSTANTS$MAILBOX_ID = CONSTANTS.MAILBOX_IDENTIFIERS, | |
| inbox = _CONSTANTS$MAILBOX_ID.inbox, | |
| allDrafts = _CONSTANTS$MAILBOX_ID.allDrafts, | |
| drafts = _CONSTANTS$MAILBOX_ID.drafts, | |
| allSent = _CONSTANTS$MAILBOX_ID.allSent, | |
| sent = _CONSTANTS$MAILBOX_ID.sent, | |
| trash = _CONSTANTS$MAILBOX_ID.trash, | |
| spam = _CONSTANTS$MAILBOX_ID.spam, | |
| allmail = _CONSTANTS$MAILBOX_ID.allmail, | |
| archive = _CONSTANTS$MAILBOX_ID.archive, | |
| starred = _CONSTANTS$MAILBOX_ID.starred, | |
| I18N = { | |
| errorMessages: gettextCatalog.getString("No messages available", null, "Error"), | |
| errorConversations: gettextCatalog.getString("No conversations available", null, "Error") | |
| }, | |
| dispatchElements = function(type) { | |
| var data = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : {}; | |
| return $rootScope.$emit("elements", { | |
| type: type, | |
| data: data | |
| }) | |
| }; | |
| api.addToDispatcher = function(action) { | |
| return dispatcher.push(action) | |
| }, api.clearDispatcher = function() { | |
| return dispatcher.length = 0 | |
| }, api.getDispatcher = function() { | |
| return Promise.all(dispatcher) | |
| }, $interval(expiration, 1e3, 0, !1); | |
| var filterSenderConversation = function() { | |
| var previous = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : []; | |
| return (arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : []).concat(previous).reduce(function(acc, sender) { | |
| return acc.map[sender.Address] || (acc.list.push(sender), acc.map[sender.Address] = !0), acc | |
| }, { | |
| list: [], | |
| map: {} | |
| }).list | |
| }, | |
| getLocation = function() { | |
| return (arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {}).Label | |
| }; | |
| api.empty = function(labelID) { | |
| messagesCached = _.filter(messagesCached, function(_ref14) { | |
| var _ref14$LabelIDs = _ref14.LabelIDs; | |
| return -1 === (void 0 === _ref14$LabelIDs ? [] : _ref14$LabelIDs).indexOf(labelID) | |
| }), cacheCounters.updateMessage(labelID, 0), _.each(conversationsCached, function(conversation) { | |
| conversation.Labels = _.filter(conversation.Labels, function(_ref15) { | |
| return _ref15.ID !== labelID | |
| }) | |
| }), cacheCounters.updateConversation(labelID, 0), dispatchElements("refresh") | |
| }, api.orderConversation = function() { | |
| var conversations = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : [], | |
| loc = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : ""; | |
| return reverse(conversations.sort(function(a, b) { | |
| return api.getTime(a.ID, loc) < api.getTime(b.ID, loc) ? -1 : api.getTime(a.ID, loc) > api.getTime(b.ID, loc) ? 1 : a.Order < b.Order ? -1 : a.Order > b.Order ? 1 : 0 | |
| })) | |
| }, api.orderMessage = function() { | |
| var messages = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : [], | |
| doReverse = !(arguments.length > 1 && void 0 !== arguments[1]) || arguments[1], | |
| list = messages.sort(function(a, b) { | |
| return a.Time < b.Time ? -1 : a.Time > b.Time ? 1 : a.Order < b.Order ? -1 : a.Order > b.Order ? 1 : 0 | |
| }); | |
| return doReverse ? reverse(list) : list | |
| }, api.orderElements = function() { | |
| var elements = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : [], | |
| type = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : "message", | |
| doReverse = !(arguments.length > 2 && void 0 !== arguments[2]) || arguments[2], | |
| loc = arguments.length > 3 && void 0 !== arguments[3] ? arguments[3] : "", | |
| list = elements.sort(function(a, b) { | |
| var timeA = "message" === type ? a.Time : api.getTime(a.ID, loc), | |
| timeB = "message" === type ? b.Time : api.getTime(b.ID, loc); | |
| return timeA < timeB ? -1 : timeA > timeB ? 1 : a.Order < b.Order ? -1 : a.Order > b.Order ? 1 : 0 | |
| }); | |
| return doReverse ? reverse(list) : list | |
| }, api.getTime = function(conversationId, loc) { | |
| return timeCached[conversationId] && angular.isNumber(timeCached[conversationId][loc]) ? timeCached[conversationId][loc] : (api.getConversationCached(conversationId) || {}).ContextTime || "" | |
| }, api.queryMessages = function(request) { | |
| var loc = getLocation(request), | |
| context = tools.cacheContext(), | |
| page = request.Page || 0; | |
| if (context && !firstLoad.get() && cachePages.consecutive(page)) { | |
| var start = page * CONSTANTS.ELEMENTS_PER_PAGE, | |
| end = start + CONSTANTS.ELEMENTS_PER_PAGE, | |
| total = void 0, | |
| number = void 0, | |
| mailbox = tools.currentMailbox(), | |
| messages = _.chain(messagesCached).filter(function(_ref16) { | |
| var _ref16$LabelIDs = _ref16.LabelIDs; | |
| return -1 !== (void 0 === _ref16$LabelIDs ? [] : _ref16$LabelIDs).indexOf(loc) | |
| }).map(function(message) { | |
| return messageModel(message) | |
| }).value(); | |
| switch (messages = api.orderMessage(messages), mailbox) { | |
| case "label": | |
| total = cacheCounters.totalMessage($stateParams.label); | |
| break; | |
| default: | |
| total = cacheCounters.totalMessage(CONSTANTS.MAILBOX_IDENTIFIERS[mailbox]) | |
| } | |
| if (angular.isDefined(total) && (number = 0 === total ? 0 : total % CONSTANTS.ELEMENTS_PER_PAGE == 0 ? CONSTANTS.ELEMENTS_PER_PAGE : Math.ceil(total / CONSTANTS.ELEMENTS_PER_PAGE) - 1 === page ? total % CONSTANTS.ELEMENTS_PER_PAGE : CONSTANTS.ELEMENTS_PER_PAGE, cacheCounters.currentState(total), messages = messages.slice(start, end), messages.length === number)) return Promise.resolve(messages) | |
| } | |
| return queryMessages(request) | |
| }, api.queryConversations = function(request) { | |
| var loc = getLocation(request), | |
| context = tools.cacheContext(), | |
| page = request.Page || 0; | |
| if (context && !firstLoad.get() && cachePages.consecutive(page)) { | |
| var start = page * CONSTANTS.ELEMENTS_PER_PAGE, | |
| end = start + CONSTANTS.ELEMENTS_PER_PAGE, | |
| total = void 0, | |
| number = void 0, | |
| mailbox = tools.currentMailbox(), | |
| conversations = _.filter(conversationsCached, function(_ref17) { | |
| var _ref17$Labels = _ref17.Labels, | |
| Labels = void 0 === _ref17$Labels ? [] : _ref17$Labels, | |
| ID = _ref17.ID; | |
| return _.findWhere(Labels, { | |
| ID: loc | |
| }) && api.getTime(ID, loc) | |
| }); | |
| switch (conversations = api.orderConversation(conversations, loc), mailbox) { | |
| case "label": | |
| total = cacheCounters.totalConversation($stateParams.label); | |
| break; | |
| default: | |
| total = cacheCounters.totalConversation(CONSTANTS.MAILBOX_IDENTIFIERS[mailbox]) | |
| } | |
| if (angular.isDefined(total) && (number = 0 === total ? 0 : total % CONSTANTS.ELEMENTS_PER_PAGE == 0 ? CONSTANTS.ELEMENTS_PER_PAGE : Math.ceil(total / CONSTANTS.ELEMENTS_PER_PAGE) - 1 === page ? total % CONSTANTS.ELEMENTS_PER_PAGE : CONSTANTS.ELEMENTS_PER_PAGE, cacheCounters.currentState(total), conversations = conversations.slice(start, end), conversations.length === number)) return Promise.resolve(conversations) | |
| } | |
| return queryConversations(request) | |
| }, api.queryMessagesCached = function() { | |
| var ConversationID = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : ""; | |
| return api.orderMessage(_.where(messagesCached, { | |
| ConversationID: ConversationID | |
| })).map(messageModel) | |
| }, api.getConversationCached = function(ID) { | |
| return angular.copy(_.findWhere(conversationsCached, { | |
| ID: ID | |
| })) | |
| }, api.getMessageCached = function(ID) { | |
| return messageModel(_.findWhere(messagesCached, { | |
| ID: ID | |
| })) | |
| }, api.getConversation = function(ID) { | |
| var conversation = _.findWhere(conversationsCached, { | |
| ID: ID | |
| }) || {}, | |
| messages = api.queryMessagesCached(ID); | |
| return !0 === conversation.loaded && messages.length === conversation.NumMessages ? Promise.resolve(angular.copy(conversation)) : getConversation(ID) | |
| }, api.getMessage = function() { | |
| var ID = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : "", | |
| message = _.findWhere(messagesCached, { | |
| ID: ID | |
| }) || {}; | |
| return new Promise(function(resolve) { | |
| resolve(message.Body ? messageModel(message) : api.queryMessage(ID)) | |
| }) | |
| }, api.queryMessage = getMessage, api.delete = function(event) { | |
| return messagesCached = messagesCached.filter(function(_ref18) { | |
| return _ref18.ID !== event.ID | |
| }), conversationsCached = conversationsCached.filter(function(_ref19) { | |
| return _ref19.ID !== event.ID | |
| }), Promise.resolve() | |
| }, api.createMessage = function(event) { | |
| return updateMessage(event.Message), Promise.resolve() | |
| }, api.updateMessage = updateMessage, api.createConversation = function(_ref20) { | |
| var Conversation = _ref20.Conversation; | |
| return Conversation.loaded = !0, updateConversation(Conversation), Promise.resolve() | |
| }, api.updateDraftConversation = function(event) { | |
| return updateConversation(event.Conversation), Promise.resolve() | |
| }, api.updateFlagMessage = function(event, isSend) { | |
| var current = _.findWhere(messagesCached, { | |
| ID: event.ID | |
| }); | |
| if (!current) return Promise.resolve(); | |
| var message = _.extend({}, current, event.Message); | |
| return message.LabelIDs = getLabelsId(current, event.Message), delete message.LabelIDsRemoved, delete message.LabelIDsAdded, Promise.resolve(updateMessage(message, isSend)) | |
| }, api.updateFlagConversation = function() { | |
| var event = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {}; | |
| return (_.findWhere(conversationsCached, { | |
| ID: event.ID | |
| }) || {}).loaded ? (updateConversation(event.Conversation), Promise.resolve()) : getConversation(event.ID).then(function(conversation) { | |
| conversation.LabelIDsAdded = event.Conversation.LabelIDsAdded, conversation.LabelIDsRemoved = event.Conversation.LabelIDsRemoved, updateConversation(conversation) | |
| }) | |
| }; | |
| var formatCreate = function() { | |
| var list = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : []; | |
| return Promise.all(list.map(function(_ref25) { | |
| var event = _ref25.event, | |
| type = _ref25.type; | |
| return api["create" + type](event) | |
| })) | |
| }, | |
| formatUpdate = function() { | |
| var list = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : [], | |
| promise = list.map(function(_ref26) { | |
| var event = _ref26.event, | |
| type = _ref26.type, | |
| isSend = _ref26.isSend, | |
| item = _ref26.item; | |
| return api["Message" === type ? "updateFlagMessage" : "update" + item + type](event, isSend) | |
| }); | |
| return Promise.all(promise) | |
| }, | |
| formatDelete = function() { | |
| var list = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : []; | |
| return Promise.all(list.map(api.delete)) | |
| }, | |
| eventProcess = function() { | |
| var events = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : [], | |
| fromBackend = arguments.length > 1 && void 0 !== arguments[1] && arguments[1], | |
| isSend = arguments[2]; | |
| console.log("[events] from the " + (fromBackend ? "back" : "front") + "-end", events), !fromBackend && handleCounters(events); | |
| var _$chain$reduce$value = _.chain(events).reduce(function(acc, event) { | |
| var hasType = event.Message || event.Conversation, | |
| type = event.Message ? "Message" : "Conversation"; | |
| return hasType && (event[type].ID = event.ID, fromBackend && event.Action === UPDATE_DRAFT && (event[type].loaded = !1), acc[type + "IDs"].push(event.ID), event.Action === CREATE && acc.flow[type].create.push({ | |
| event: event, | |
| type: type | |
| }), event.Action === UPDATE_DRAFT && acc.flow[type].update.push({ | |
| event: event, | |
| type: type, | |
| isSend: isSend, | |
| item: "Draft" | |
| }), event.Action === UPDATE_FLAGS && acc.flow[type].update.push({ | |
| event: event, | |
| type: type, | |
| isSend: isSend, | |
| item: "Flag" | |
| })), event.Action === DELETE && acc.flow.delete.push(event), acc | |
| }, { | |
| flow: { | |
| Message: { | |
| create: [], | |
| update: [] | |
| }, | |
| Conversation: { | |
| create: [], | |
| update: [] | |
| }, | |
| delete: [] | |
| }, | |
| MessageIDs: [], | |
| ConversationIDs: [] | |
| }).value(), | |
| flow = _$chain$reduce$value.flow, | |
| MessageIDs = _$chain$reduce$value.MessageIDs, | |
| ConversationIDs = _$chain$reduce$value.ConversationIDs; | |
| return formatCreate(flow.Message.create).then(function() { | |
| return formatUpdate(flow.Message.update) | |
| }).then(function() { | |
| return formatCreate(flow.Conversation.create) | |
| }).then(function() { | |
| return formatUpdate(flow.Conversation.update) | |
| }).then(function() { | |
| return formatDelete(flow.delete) | |
| }).then(function() { | |
| return api.callRefresh(MessageIDs, ConversationIDs) | |
| }) | |
| }; | |
| return api.events = eventProcess, api.callRefresh = function() { | |
| var messageIDs = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : [], | |
| conversationIDs = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : []; | |
| dispatchElements("refresh"), $rootScope.$emit("updatePageName"), $rootScope.$emit("refreshConversation", conversationIDs), $rootScope.$emit("message.refresh", messageIDs), dispatchElements("refresh.time") | |
| }, api.reset = function() { | |
| conversationsCached.length = 0, messagesCached.length = 0 | |
| }, api.more = function(elementID, elementTime, action) { | |
| var type = tools.getTypeList(), | |
| elementsCached = "conversation" === type ? conversationsCached : messagesCached, | |
| loc = tools.currentLocation(), | |
| elements = elementsCached.filter(function(_ref27) { | |
| var _ref27$LabelIDs = _ref27.LabelIDs; | |
| return (void 0 === _ref27$LabelIDs ? [] : _ref27$LabelIDs).indexOf(loc) > -1 | |
| }), | |
| elementsOrdered = api.orderElements(elements, type, !0, loc); | |
| if (_.findWhere(elementsOrdered, { | |
| ID: elementID | |
| })) { | |
| var currentIndex = _.findIndex(elementsOrdered, { | |
| ID: elementID | |
| }); | |
| if ("previous" === action && elementsOrdered[currentIndex + 1]) return Promise.resolve(elementsOrdered[currentIndex + 1]); | |
| if ("next" === action && elementsOrdered[currentIndex - 1]) return Promise.resolve(elementsOrdered[currentIndex - 1]) | |
| } | |
| return function() { | |
| var Label = loc, | |
| request = { | |
| Label: Label | |
| }; | |
| return "next" === action ? (request.BeginID = elementID, request.Begin = elementTime) : "previous" === action && (request.EndID = elementID, request.End = elementTime), ("conversation" === type ? queryConversations(request) : queryMessages(request)).then(function() { | |
| var elements = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : []; | |
| if (elements.length) return elements["next" === action ? elements.length - 1 : 0]; | |
| throw new Error("No elements found") | |
| }) | |
| }() | |
| }, api | |
| }), angular.module("proton.core").service("cacheCounters", function(messageApi, CONSTANTS, conversationApi, $q, $rootScope, authentication, labelsModel) { | |
| var api = {}, | |
| counters = {}, | |
| _CONSTANTS$MAILBOX_ID = CONSTANTS.MAILBOX_IDENTIFIERS, | |
| inbox = _CONSTANTS$MAILBOX_ID.inbox, | |
| allDrafts = _CONSTANTS$MAILBOX_ID.allDrafts, | |
| drafts = _CONSTANTS$MAILBOX_ID.drafts, | |
| allSent = _CONSTANTS$MAILBOX_ID.allSent, | |
| sent = _CONSTANTS$MAILBOX_ID.sent, | |
| trash = _CONSTANTS$MAILBOX_ID.trash, | |
| spam = _CONSTANTS$MAILBOX_ID.spam, | |
| allmail = _CONSTANTS$MAILBOX_ID.allmail, | |
| archive = _CONSTANTS$MAILBOX_ID.archive, | |
| starred = _CONSTANTS$MAILBOX_ID.starred, | |
| dispatch = function(type) { | |
| var data = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : {}; | |
| return $rootScope.$emit("app.cacheCounters", { | |
| type: type, | |
| data: data | |
| }) | |
| }, | |
| exist = function(loc) { | |
| angular.isUndefined(counters[loc]) && (counters[loc] = { | |
| message: { | |
| total: 0, | |
| unread: 0 | |
| }, | |
| conversation: { | |
| total: 0, | |
| unread: 0 | |
| } | |
| }) | |
| }; | |
| return $rootScope.$on("labelsModel", function(e, _ref) { | |
| var type = _ref.type, | |
| data = _ref.data; | |
| "cache.update" === type && (data.create.forEach(function(_ref2) { | |
| var ID = _ref2.ID; | |
| return exist(ID) | |
| }), Object.keys(data.remove).forEach(function(ID) { | |
| delete counters[ID] | |
| })) | |
| }), api.query = function() { | |
| var locs = [inbox, allDrafts, drafts, allSent, sent, trash, spam, allmail, archive, starred].concat(labelsModel.ids()); | |
| return $q.all({ | |
| message: messageApi.count(), | |
| conversation: conversationApi.count() | |
| }).then(function() { | |
| var _ref3 = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {}, | |
| _ref3$message = _ref3.message, | |
| message = void 0 === _ref3$message ? {} : _ref3$message, | |
| _ref3$conversation = _ref3.conversation, | |
| conversation = void 0 === _ref3$conversation ? {} : _ref3$conversation; | |
| return locs.forEach(exist), _.chain(message.data.Counts).filter(function(_ref4) { | |
| var LabelID = _ref4.LabelID; | |
| return counters[LabelID] | |
| }).each(function(_ref5) { | |
| var LabelID = _ref5.LabelID, | |
| _ref5$Total = _ref5.Total, | |
| Total = void 0 === _ref5$Total ? 0 : _ref5$Total, | |
| _ref5$Unread = _ref5.Unread, | |
| Unread = void 0 === _ref5$Unread ? 0 : _ref5$Unread; | |
| counters[LabelID].message.total = Total, counters[LabelID].message.unread = Unread | |
| }), _.chain(conversation.data.Counts).filter(function(_ref6) { | |
| var LabelID = _ref6.LabelID; | |
| return counters[LabelID] | |
| }).each(function(_ref7) { | |
| var LabelID = _ref7.LabelID, | |
| _ref7$Total = _ref7.Total, | |
| Total = void 0 === _ref7$Total ? 0 : _ref7$Total, | |
| _ref7$Unread = _ref7.Unread, | |
| Unread = void 0 === _ref7$Unread ? 0 : _ref7$Unread; | |
| counters[LabelID].conversation.total = Total, counters[LabelID].conversation.unread = Unread | |
| }), dispatch("load"), Promise.resolve() | |
| }, Promise.reject) | |
| }, api.add = function() { | |
| var loc = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : ""; | |
| return exist(loc) | |
| }, api.status = function() { | |
| return dispatch("update.counters", { | |
| counters: counters | |
| }) | |
| }, api.updateMessage = function() { | |
| var loc = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : "", | |
| total = arguments[1], | |
| unread = arguments[2]; | |
| exist(loc), angular.isDefined(total) && (counters[loc].message.total = total), angular.isDefined(unread) && (counters[loc].message.unread = unread) | |
| }, api.updateConversation = function() { | |
| var loc = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : "", | |
| total = arguments[1], | |
| unread = arguments[2]; | |
| exist(loc), angular.isDefined(total) && (counters[loc].conversation.total = total), angular.isDefined(unread) && (counters[loc].conversation.unread = unread) | |
| }, api.totalMessage = function() { | |
| var loc = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : ""; | |
| return counters[loc] && counters[loc].message && counters[loc].message.total | |
| }, api.totalConversation = function() { | |
| var loc = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : ""; | |
| return counters[loc] && counters[loc].conversation && counters[loc].conversation.total | |
| }, api.unreadMessage = function() { | |
| var loc = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : ""; | |
| return counters[loc] && counters[loc].message && counters[loc].message.unread | |
| }, api.unreadConversation = function() { | |
| var loc = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : ""; | |
| return counters[loc] && counters[loc].conversation && counters[loc].conversation.unread | |
| }, api.reset = function() { | |
| counters = {} | |
| }, api.currentState = function() { | |
| var value = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : 0; | |
| counters.CURRENT_STATE_VALUE = value, dispatch("refresh.currentState", { | |
| value: value | |
| }) | |
| }, api.getCurrentState = function() { | |
| return counters.CURRENT_STATE_VALUE || 0 | |
| }, api.getCounter = function(location) { | |
| return counters[location] | |
| }, api | |
| }), angular.module("proton.core").factory("cachePages", function($rootScope, tools) { | |
| var pages = [], | |
| inside = function(page) { | |
| return pages.indexOf(page) > -1 | |
| }, | |
| add = function(page) { | |
| return pages.push(page) | |
| }, | |
| clear = function() { | |
| return pages.length = 0 | |
| }, | |
| consecutive = function(page) { | |
| for (var i = page; i >= 0; i--) | |
| if (-1 === pages.indexOf(i)) return !1; | |
| return !0 | |
| }; | |
| return $rootScope.$on("$stateChangeStart", function(event, toState, toParams, fromState) { | |
| tools.filteredState(fromState.name) !== tools.filteredState(toState.name) && clear() | |
| }), { | |
| init: angular.noop, | |
| add: add, | |
| inside: inside, | |
| clear: clear, | |
| consecutive: consecutive | |
| } | |
| }), angular.module("proton.core").factory("paginationModel", function(CONSTANTS, cacheCounters, $rootScope, $state, $stateParams, authentication, tools) { | |
| var ELEMENTS_PER_PAGE = CONSTANTS.ELEMENTS_PER_PAGE, | |
| MESSAGE_VIEW_MODE = CONSTANTS.MESSAGE_VIEW_MODE, | |
| currentState = ""; | |
| $rootScope.$on("$stateChangeSuccess", function(e, state) { | |
| currentState = state.name.replace(".element", "") | |
| }); | |
| var getLayout = function() { | |
| return authentication.user.ViewMode === MESSAGE_VIEW_MODE ? "message" : "conversation" | |
| }, | |
| getMaxPage = function() { | |
| var counter = cacheCounters.getCounter(tools.currentLocation()); | |
| if (tools.cacheContext() && counter) { | |
| var key = "unread" === $stateParams.filter ? "unread" : "total"; | |
| return Math.ceil(counter[getLayout()][key] / ELEMENTS_PER_PAGE) | |
| } | |
| return Math.ceil(cacheCounters.getCurrentState() / ELEMENTS_PER_PAGE) | |
| }, | |
| switchPage = function() { | |
| var opts = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {}; | |
| $state.go(currentState, _.extend({ | |
| id: null | |
| }, opts)) | |
| }, | |
| previous = function() { | |
| var pos = ~~$stateParams.page || 0; | |
| if (pos) { | |
| var page = pos - 1; | |
| switchPage({ | |
| page: page <= 1 ? void 0 : page | |
| }) | |
| } | |
| }, | |
| next = function() { | |
| var pos = ~~$stateParams.page || 1, | |
| page = pos + 1; | |
| page <= getMaxPage() && switchPage({ | |
| page: page | |
| }) | |
| }, | |
| isMax = function() { | |
| return (~~$stateParams.page || 1) >= getMaxPage() | |
| }; | |
| return { | |
| init: angular.noop, | |
| next: next, | |
| previous: previous, | |
| getMaxPage: getMaxPage, | |
| isMax: isMax, | |
| to: switchPage | |
| } | |
| }), angular.module("proton.dashboard").directive("activePlan", function($rootScope, CONSTANTS, subscriptionModel) { | |
| var _CONSTANTS$PLANS$PLAN = CONSTANTS.PLANS.PLAN, | |
| PLUS = _CONSTANTS$PLANS$PLAN.PLUS, | |
| PROFESSIONAL = _CONSTANTS$PLANS$PLAN.PROFESSIONAL, | |
| VISIONARY = _CONSTANTS$PLANS$PLAN.VISIONARY, | |
| PLANS = _.reduce(["free", PLUS, PROFESSIONAL, VISIONARY], function(acc, plan) { | |
| return acc + " " + plan + "-active" | |
| }, ""); | |
| return { | |
| restrict: "A", | |
| link: function(scope, element) { | |
| var update = function() { | |
| return element.removeClass(PLANS).addClass(subscriptionModel.name() + "-active") | |
| }, | |
| unsubscribe = $rootScope.$on("subscription", function(event, _ref) { | |
| "update" === _ref.type && update() | |
| }); | |
| update(), scope.$on("$destroy", function() { | |
| return unsubscribe() | |
| }) | |
| } | |
| } | |
| }), angular.module("proton.dashboard").directive("addVpn", function($rootScope, gettextCatalog) { | |
| return { | |
| restrict: "E", | |
| replace: !0, | |
| scope: {}, | |
| template: '<button class="addVpn-button" type="button">\n <div class="addVpn-button-wrapper">\n <i class="addVpn-button-sign"></i>\n <span class="addVpn-button-txt">' + gettextCatalog.getString("+ Add ProtonVPN", null, "Button") + "</span>\n </div>\n </button>", | |
| link: function(scope, element, _ref) { | |
| var plan = _ref.plan, | |
| value = "free" === plan ? "vpnbasic" : "vpnplus", | |
| onClick = function() { | |
| $rootScope.$emit("dashboard", { | |
| type: "change.addon", | |
| data: { | |
| addon: "vpn", | |
| plan: "free", | |
| value: value | |
| } | |
| }), $rootScope.$emit("dashboard", { | |
| type: "change.addon", | |
| data: { | |
| addon: "vpn", | |
| plan: "plus", | |
| value: value | |
| } | |
| }), $rootScope.$emit("dashboard", { | |
| type: "change.addon", | |
| data: { | |
| addon: "vpn", | |
| plan: "professional", | |
| value: value | |
| } | |
| }) | |
| }; | |
| element.on("click", onClick), scope.$on("$destroy", function() { | |
| return element.off("click", onClick) | |
| }) | |
| } | |
| } | |
| }), angular.module("proton.dashboard").directive("addonRow", function($filter, $rootScope, CONSTANTS, dashboardConfiguration, dashboardModel, dashboardOptions, gettextCatalog, subscriptionModel, customProPlanModel) { | |
| customProPlanModel.init(); | |
| var _CONSTANTS$PLANS$ADDO = CONSTANTS.PLANS.ADDON, | |
| MEMBER = _CONSTANTS$PLANS$ADDO.MEMBER, | |
| ADDRESS = _CONSTANTS$PLANS$ADDO.ADDRESS, | |
| DOMAIN = _CONSTANTS$PLANS$ADDO.DOMAIN, | |
| SPACE = _CONSTANTS$PLANS$ADDO.SPACE, | |
| MAP_ADDONS = { | |
| member: MEMBER, | |
| address: ADDRESS, | |
| domain: DOMAIN, | |
| space: SPACE | |
| }, | |
| filter = function(amount) { | |
| return $filter("currency")(amount / 100 / dashboardConfiguration.cycle(), dashboardConfiguration.currency()) | |
| }, | |
| initValue = function(addon) { | |
| return "" + subscriptionModel.count(addon) | |
| }, | |
| getPrice = function(_ref) { | |
| var addon = _ref.addon, | |
| value = _ref.value; | |
| if (!value || "none" === value) return ""; | |
| var amounts = dashboardModel.amounts(); | |
| return "+ " + filter(amounts[MAP_ADDONS[addon]] * value) + "/mo" | |
| }; | |
| return { | |
| restrict: "E", | |
| replace: !0, | |
| scope: {}, | |
| templateUrl: "templates/dashboard/addonRow.tpl.html", | |
| compile: function(element, _ref2) { | |
| function buildOptions() { | |
| var options = _.reduce(dashboardOptions.get(plan, addon), function(acc, _ref3) { | |
| var label = _ref3.label, | |
| value = _ref3.value; | |
| return acc + '<option value="' + value + '">' + label + " " + getPrice({ | |
| addon: addon, | |
| value: value | |
| }) + "</option>" | |
| }, ""); | |
| $select.html(options) | |
| } | |
| var addon = _ref2.addon, | |
| plan = _ref2.plan, | |
| $select = element.find(".addonRow-select"), | |
| set = function() { | |
| var value = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : initValue(addon); | |
| return $select.val(value) | |
| }; | |
| return buildOptions(), | |
| function(scope) { | |
| var onChange = function() { | |
| return $rootScope.$emit("dashboard", { | |
| type: "change.addon", | |
| data: { | |
| addon: addon, | |
| plan: plan, | |
| value: +$select.val() | |
| } | |
| }) | |
| }, | |
| unsubscribe = $rootScope.$on("dashboard", function(event, _ref4) { | |
| var type = _ref4.type, | |
| _ref4$data = _ref4.data, | |
| data = void 0 === _ref4$data ? {} : _ref4$data; | |
| if ("addon.updated" === type && data.addon === addon && data.plan === plan && (buildOptions(), set(data.value)), "currency.updated" === type || "cycle.updated" === type) { | |
| var value = $select.val(); | |
| buildOptions(), set(value) | |
| } | |
| }); | |
| $select.on("change", onChange), set(), onChange(), scope.$on("$destroy", function() { | |
| unsubscribe(), $select.off("change", onChange) | |
| }) | |
| } | |
| } | |
| } | |
| }), angular.module("proton.dashboard").directive("currencySelector", function($rootScope, dashboardConfiguration) { | |
| var ACTIVE_BUTTON_CLASS = "active"; | |
| return { | |
| restrict: "E", | |
| replace: !0, | |
| templateUrl: "templates/dashboard/currencySelector.tpl.html", | |
| link: function(scope, element) { | |
| function onClick(event) { | |
| var currency = event.target.getAttribute("value"); | |
| $rootScope.$emit("dashboard", { | |
| type: "change.currency", | |
| data: { | |
| currency: currency | |
| } | |
| }), active(currency) | |
| } | |
| function active(currency) { | |
| _.each($buttons, function(button) { | |
| button.value === currency ? button.classList.add(ACTIVE_BUTTON_CLASS) : button.classList.remove(ACTIVE_BUTTON_CLASS) | |
| }) | |
| } | |
| var currency = dashboardConfiguration.currency(), | |
| $buttons = element.find(".currencySelector-button"); | |
| element.on("click", onClick); | |
| var unsubscribe = $rootScope.$on("subscription", function(event, _ref) { | |
| var type = _ref.type, | |
| data = _ref.data; | |
| "update" === type && active(data.subscription.Currency) | |
| }); | |
| active(currency), scope.$on("$destroy", function() { | |
| unsubscribe(), element.off("click", onClick) | |
| }) | |
| } | |
| } | |
| }), angular.module("proton.dashboard").directive("freeColumn", function($rootScope, dashboardConfiguration) { | |
| return { | |
| restrict: "E", | |
| replace: !0, | |
| scope: {}, | |
| templateUrl: "templates/dashboard/freeColumn.tpl.html", | |
| link: function(scope, element) { | |
| var update = function() { | |
| var _dashboardConfigurati = dashboardConfiguration.get(), | |
| free = _dashboardConfigurati.free, | |
| action = free.vpnplus || free.vpnbasic ? "add" : "remove"; | |
| element[0].classList[action]("freeColumn-show-vpn") | |
| }, | |
| unsubscribe = $rootScope.$on("dashboard", function(event, _ref) { | |
| "vpn.updated" === _ref.type && update() | |
| }); | |
| update(), scope.$on("$destroy", function() { | |
| return unsubscribe() | |
| }) | |
| } | |
| } | |
| }), angular.module("proton.dashboard").directive("overviewSection", function($rootScope, authentication, organizationModel, subscriptionModel) { | |
| return { | |
| replace: !0, | |
| restrict: "E", | |
| scope: {}, | |
| templateUrl: "templates/dashboard/overviewSection.tpl.html", | |
| link: function(scope, element) { | |
| function updateUser() { | |
| scope.$applyAsync(function() { | |
| scope.user = angular.copy(authentication.user) | |
| }) | |
| } | |
| function updateOrganization(organization) { | |
| scope.$applyAsync(function() { | |
| scope.organization = angular.copy(organization) | |
| }) | |
| } | |
| function updateSubscription(subscription) { | |
| scope.$applyAsync(function() { | |
| scope.subscription = angular.copy(subscription) | |
| }) | |
| } | |
| function onClick() { | |
| $(".settings").animate({ | |
| scrollTop: $("#plans").offset().top | |
| }, 1e3) | |
| } | |
| var unsubscribe = [], | |
| $buttons = element.find(".scroll"); | |
| $buttons.on("click", onClick); | |
| var refreshUser = function() { | |
| authentication.fetchUserInfo().then(function(data) { | |
| return scope.user = data | |
| }) | |
| }; | |
| unsubscribe.push($rootScope.$on("updateUser", function() { | |
| updateUser() | |
| })), unsubscribe.push($rootScope.$on("organizationChange", function(e, organization) { | |
| updateOrganization(organization) | |
| })), unsubscribe.push($rootScope.$on("subscription", function(e, _ref) { | |
| var type = _ref.type, | |
| _ref$data = _ref.data, | |
| data = void 0 === _ref$data ? {} : _ref$data; | |
| "update" === type && updateSubscription(data.subscription) | |
| })), unsubscribe.push($rootScope.$on("payments", function(e, _ref2) { | |
| "topUp.request.success" === _ref2.type && refreshUser() | |
| })), updateUser(), updateOrganization(organizationModel.get()), updateSubscription(subscriptionModel.get()), scope.$on("$destroy", function() { | |
| $buttons.off("click", onClick), _.each(unsubscribe, function(cb) { | |
| return cb() | |
| }), unsubscribe.length = 0 | |
| }) | |
| } | |
| } | |
| }), angular.module("proton.dashboard").directive("planPrice", function($filter, $rootScope, dashboardConfiguration, dashboardModel, gettextCatalog) { | |
| var types = ["cycle.updated", "currency.updated"], | |
| I18N = { | |
| user: gettextCatalog.getString("user", null, "Label"), | |
| month: gettextCatalog.getString("month", null, "Delay") | |
| }, | |
| amount = function(plan, cycle, currency) { | |
| var amounts = dashboardModel.amounts(cycle), | |
| month = "/" + I18N.month, | |
| user = "professional" === plan ? "/" + I18N.user : ""; | |
| return "" + $filter("currency")(amounts[plan] / 100 / cycle, currency) + month + user | |
| }; | |
| return { | |
| restrict: "E", | |
| replace: !0, | |
| scope: {}, | |
| template: '<strong class="planPrice"></strong>', | |
| link: function(scope, element, _ref) { | |
| function update() { | |
| scope.$applyAsync(function() { | |
| element.text(amount(plan, dashboardConfiguration.cycle(), dashboardConfiguration.currency())) | |
| }) | |
| } | |
| var plan = _ref.plan, | |
| unsubscribe = $rootScope.$on("dashboard", function(event, _ref2) { | |
| var type = _ref2.type; | |
| types.indexOf(type) > -1 && update() | |
| }); | |
| update(), scope.$on("$destroy", function() { | |
| return unsubscribe() | |
| }) | |
| } | |
| } | |
| }), angular.module("proton.dashboard").directive("plusColumn", function() { | |
| return { | |
| restrict: "E", | |
| replace: !0, | |
| scope: {}, | |
| templateUrl: "templates/dashboard/plusColumn.tpl.html" | |
| } | |
| }), angular.module("proton.dashboard").directive("professionalColumn", function(customProPlanModal) { | |
| return { | |
| restrict: "E", | |
| replace: !0, | |
| scope: {}, | |
| templateUrl: "templates/dashboard/professionalColumn.tpl.html", | |
| link: function(scope, element) { | |
| function onClick() { | |
| customProPlanModal.activate({ | |
| params: { | |
| close: function() { | |
| customProPlanModal.deactivate() | |
| } | |
| } | |
| }) | |
| } | |
| var $buttons = element.find(".professionalColumn-customize"); | |
| $buttons.on("click", onClick), scope.$on("$destroy", function() { | |
| $buttons.off("click", onClick) | |
| }) | |
| } | |
| } | |
| }), angular.module("proton.dashboard").directive("selectPlan", function($rootScope, gettextCatalog, subscriptionModel) { | |
| var ACTIVE_BUTTON_CLASS = "primary", | |
| I18N = { | |
| downgradeToFree: gettextCatalog.getString("Downgrade to Free", null, "Button to select plan on the dashboard"), | |
| downgradeToPlus: gettextCatalog.getString("Downgrade to Plus", null, "Button to select plan on the dashboard"), | |
| downgradeToProfessional: gettextCatalog.getString("Switch to Professional", null, "Button to select plan on the dashboard"), | |
| updateFree: gettextCatalog.getString("Update Free", null, "Button to select plan on the dashboard"), | |
| updatePlus: gettextCatalog.getString("Update Plus", null, "Button to select plan on the dashboard"), | |
| updateProfessional: gettextCatalog.getString("Update Professional", null, "Button to select plan on the dashboard"), | |
| updateVisionary: gettextCatalog.getString("Update Visionary", null, "Button to select plan on the dashboard"), | |
| upgradeToPlus: gettextCatalog.getString("Upgrade to Plus", null, "Button to select plan on the dashboard"), | |
| upgradeToProfessional: gettextCatalog.getString("Upgrade to Professional", null, "Button to select plan on the dashboard"), | |
| upgradeToVisionary: gettextCatalog.getString("Switch to Visionary", null, "Button to select plan on the dashboard") | |
| }, | |
| MAP = { | |
| free: { | |
| free: I18N.updateFree, | |
| plus: I18N.upgradeToPlus, | |
| professional: I18N.upgradeToProfessional, | |
| visionary: I18N.upgradeToVisionary | |
| }, | |
| plus: { | |
| free: I18N.downgradeToFree, | |
| plus: I18N.updatePlus, | |
| professional: I18N.upgradeToProfessional, | |
| visionary: I18N.upgradeToVisionary | |
| }, | |
| professional: { | |
| free: I18N.downgradeToFree, | |
| plus: I18N.downgradeToPlus, | |
| professional: I18N.updateProfessional, | |
| visionary: I18N.upgradeToVisionary | |
| }, | |
| visionary: { | |
| free: I18N.downgradeToFree, | |
| plus: I18N.downgradeToPlus, | |
| professional: I18N.downgradeToProfessional, | |
| visionary: I18N.updateVisionary | |
| } | |
| }; | |
| return { | |
| restrict: "E", | |
| replace: !0, | |
| scope: {}, | |
| template: '<button class="selectPlan-button pm_button large" type="button"></button>', | |
| link: function(scope, element, _ref) { | |
| function update() { | |
| var currentPlanName = subscriptionModel.name(); | |
| element.text(MAP[currentPlanName][plan]), element.addClass(ACTIVE_BUTTON_CLASS), currentPlanName === plan && element.removeClass(ACTIVE_BUTTON_CLASS) | |
| } | |
| var plan = _ref.plan, | |
| onClick = function() { | |
| return $rootScope.$emit("dashboard", { | |
| type: "select.plan", | |
| data: { | |
| plan: plan | |
| } | |
| }) | |
| }, | |
| unsubscribe = $rootScope.$on("subscription", function(event, _ref2) { | |
| "update" === _ref2.type && update() | |
| }); | |
| element.on("click", onClick), update(), scope.$on("$destroy", function() { | |
| element.off("click", onClick), unsubscribe() | |
| }) | |
| } | |
| } | |
| }), angular.module("proton.dashboard").directive("subscriptionSection", function($rootScope, CONSTANTS, subscriptionModel, gettextCatalog) { | |
| function formatTitle() { | |
| var plan = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {}; | |
| switch (plan.Name) { | |
| case "1vpn": | |
| plan.Title = "+ " + plan.time * plan.MaxVPN + " " + I18N.vpn; | |
| break; | |
| case "1gb": | |
| plan.Title = "+ " + plan.time * fromBase(plan.MaxSpace) + " GB"; | |
| break; | |
| case "5address": | |
| plan.Title = "+ " + plan.time * plan.MaxAddresses + " " + I18N.addresses; | |
| break; | |
| case "1domain": | |
| plan.Title = "+ " + plan.time * plan.MaxDomains + " " + (plan.time > 1 ? I18N.domains : I18N.domain); | |
| break; | |
| case "1member": | |
| plan.Title = "+ " + plan.time * plan.MaxMembers + " " + (plan.time > 1 ? I18N.members : I18N.member) | |
| } | |
| } | |
| function extractAddons() { | |
| var plans = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : [], | |
| vpn = arguments.length > 1 && void 0 !== arguments[1] && arguments[1]; | |
| return _.chain(plans).where({ | |
| Type: 0 | |
| }).reduce(function(acc, plan) { | |
| return vpn === plan.Name.indexOf("vpn") > -1 && (acc[plan.Name] ? (acc[plan.Name].Amount += plan.Amount, acc[plan.Name].time++) : (acc[plan.Name] = plan, acc[plan.Name].time = 1)), acc | |
| }, {}).each(function(plan) { | |
| return formatTitle(plan) | |
| }).value() | |
| } | |
| var _cycles, _CONSTANTS$CYCLE = CONSTANTS.CYCLE, | |
| MONTHLY = _CONSTANTS$CYCLE.MONTHLY, | |
| YEARLY = _CONSTANTS$CYCLE.YEARLY, | |
| TWO_YEARS = _CONSTANTS$CYCLE.TWO_YEARS, | |
| I18N = { | |
| vpn: gettextCatalog.getString("VPN connections", null), | |
| addresses: gettextCatalog.getString("addresses", null), | |
| domain: gettextCatalog.getString("domain", null), | |
| domains: gettextCatalog.getString("domains", null), | |
| member: gettextCatalog.getString("user", null), | |
| members: gettextCatalog.getString("users", null), | |
| cycles: (_cycles = {}, _defineProperty(_cycles, MONTHLY, gettextCatalog.getString("Monthly", null)), _defineProperty(_cycles, YEARLY, gettextCatalog.getString("Annually", null)), _defineProperty(_cycles, TWO_YEARS, gettextCatalog.getString("2-years", null)), _cycles), | |
| methods: { | |
| card: gettextCatalog.getString("Credit card", null), | |
| paypal: "Paypal" | |
| } | |
| }, | |
| formatSubscription = function() { | |
| var sub = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {}; | |
| return sub.cycle = I18N.cycles[sub.Cycle], sub.plans = _.reduce(sub.Plans, function(acc, plan) { | |
| return plan.Type === CONSTANTS.PLANS_TYPE.PLAN && (plan.addons = extractAddons(sub.Plans, plan.Name.indexOf("vpn") > -1), acc.push(plan)), acc | |
| }, []), sub | |
| }, | |
| getFirstMethodType = function() { | |
| var methods = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : []; | |
| return methods.length ? I18N.methods[methods[0].Type] : "None" | |
| }, | |
| fromBase = function(value) { | |
| return value / Math.pow(CONSTANTS.BASE_SIZE, 3) | |
| }; | |
| return { | |
| scope: { | |
| methods: "=" | |
| }, | |
| restrict: "E", | |
| replace: !0, | |
| templateUrl: "templates/dashboard/subscriptionSection.tpl.html", | |
| link: function(scope) { | |
| var subscription = subscriptionModel.get(), | |
| unsubscribe = $rootScope.$on("subscription", function(event, _ref) { | |
| var type = _ref.type, | |
| _ref$data = _ref.data, | |
| data = void 0 === _ref$data ? {} : _ref$data; | |
| "update" === type && scope.$applyAsync(function() { | |
| scope.subscription = formatSubscription(data.subscription) | |
| }) | |
| }); | |
| scope.subscription = formatSubscription(subscription), scope.method = getFirstMethodType(scope.methods), scope.$on("$destroy", function() { | |
| return unsubscribe() | |
| }) | |
| } | |
| } | |
| }), angular.module("proton.dashboard").directive("totalPlan", function($filter, $rootScope, dashboardConfiguration, dashboardModel, gettextCatalog) { | |
| var amount = function(plan, cycle, currency) { | |
| return $filter("currency")(dashboardModel.total(plan, cycle) / 100 / cycle, currency) | |
| }, | |
| types = ["addon.updated", "cycle.updated", "currency.updated", "vpn.updated"], | |
| month = gettextCatalog.getString("month", null); | |
| return { | |
| restrict: "E", | |
| replace: !0, | |
| scope: {}, | |
| template: '<strong class="totalPlan"></strong>', | |
| link: function(scope, element, _ref) { | |
| function update() { | |
| scope.$applyAsync(function() { | |
| element.text(amount(plan, dashboardConfiguration.cycle(), dashboardConfiguration.currency()) + "/" + month) | |
| }) | |
| } | |
| var plan = _ref.plan, | |
| unsubscribe = $rootScope.$on("dashboard", function(event, _ref2) { | |
| var type = _ref2.type; | |
| types.indexOf(type) > -1 && update() | |
| }); | |
| update(), scope.$on("$destroy", function() { | |
| return unsubscribe() | |
| }) | |
| } | |
| } | |
| }), angular.module("proton.dashboard").directive("totalRows", function($filter, $rootScope, blackFridayModel, CONSTANTS, dashboardConfiguration, dashboardModel, gettextCatalog, subscriptionModel) { | |
| var _CONSTANTS$CYCLE = CONSTANTS.CYCLE, | |
| MONTHLY = _CONSTANTS$CYCLE.MONTHLY, | |
| YEARLY = _CONSTANTS$CYCLE.YEARLY, | |
| TWO_YEARS = _CONSTANTS$CYCLE.TWO_YEARS, | |
| I18N = { | |
| billedAs: function(amount, cycle) { | |
| return cycle === YEARLY ? gettextCatalog.getString("Billed as {{amount}} /yr", { | |
| amount: amount | |
| }, "Info") : cycle === TWO_YEARS ? gettextCatalog.getString("Billed as {{amount}} /2-yr", { | |
| amount: amount | |
| }, "Info") : "" | |
| } | |
| }, | |
| types = ["addon.updated", "cycle.updated", "currency.updated", "vpn.updated"], | |
| amount = function(plan, cycle, currency, division) { | |
| return $filter("currency")(dashboardModel.total(plan, cycle) / 100 / division, currency) | |
| }; | |
| return { | |
| restrict: "E", | |
| replace: !0, | |
| scope: {}, | |
| templateUrl: "templates/dashboard/totalRows.tpl.html", | |
| link: function(scope, element, _ref) { | |
| function bindClass() { | |
| var action = subscriptionModel.cycle() === TWO_YEARS || blackFridayModel.isBlackFridayPeriod(!0) ? "add" : "remove"; | |
| element[0].classList[action]("totalRows-has-2-years") | |
| } | |
| function update() { | |
| scope.$applyAsync(function() { | |
| monthly.text(amount(plan, MONTHLY, dashboardConfiguration.currency(), MONTHLY)), yearly.text(amount(plan, YEARLY, dashboardConfiguration.currency(), YEARLY)), twoYears.text(amount(plan, TWO_YEARS, dashboardConfiguration.currency(), TWO_YEARS)), yearlyBilled.text(I18N.billedAs(amount(plan, YEARLY, dashboardConfiguration.currency(), MONTHLY), YEARLY)), twoYearsBilled.text(I18N.billedAs(amount(plan, TWO_YEARS, dashboardConfiguration.currency(), MONTHLY), TWO_YEARS)), scope.cycle = dashboardConfiguration.cycle() | |
| }) | |
| } | |
| var plan = _ref.plan, | |
| unsubscribe = [], | |
| monthly = element.find(".totalRows-monthly-price"), | |
| yearly = element.find(".totalRows-yearly-price"), | |
| yearlyBilled = element.find(".totalRows-yearly-billed-price"), | |
| twoYears = element.find(".totalRows-2-years-price"), | |
| twoYearsBilled = element.find(".totalRows-2-years-billed-price"); | |
| scope.onChange = function() { | |
| return $rootScope.$emit("dashboard", { | |
| type: "change.cycle", | |
| data: { | |
| cycle: scope.cycle | |
| } | |
| }) | |
| }, unsubscribe.push($rootScope.$on("dashboard", function(event, _ref2) { | |
| var _ref2$type = _ref2.type, | |
| type = void 0 === _ref2$type ? "" : _ref2$type; | |
| types.indexOf(type) > -1 && update() | |
| })), unsubscribe.push($rootScope.$on("blackFriday", function(event, _ref3) { | |
| var _ref3$type = _ref3.type; | |
| "tictac" === (void 0 === _ref3$type ? "" : _ref3$type) && bindClass() | |
| })), update(), bindClass(), scope.$on("$destroy", function() { | |
| unsubscribe.forEach(function(cb) { | |
| return cb() | |
| }), unsubscribe.length = 0 | |
| }) | |
| } | |
| } | |
| }), angular.module("proton.dashboard").directive("visionaryColumn", function() { | |
| return { | |
| restrict: "E", | |
| replace: !0, | |
| scope: {}, | |
| templateUrl: "templates/dashboard/visionaryColumn.tpl.html" | |
| } | |
| }), angular.module("proton.dashboard").directive("vpnColumns", function($rootScope, CONSTANTS, dashboardConfiguration, dashboardModel, customVpnModel) { | |
| function onClick(event) { | |
| switch (event.target.getAttribute("data-action")) { | |
| case "vpnbasic": | |
| customVpnModel.set("vpnbasic", 1), customVpnModel.set("vpnplus", 0), customVpnModel.set("vpn", 0); | |
| break; | |
| case "vpnplus": | |
| customVpnModel.set("vpnbasic", 0), customVpnModel.set("vpnplus", 1) | |
| } | |
| } | |
| var _CONSTANTS$PLANS$PLAN = CONSTANTS.PLANS.PLAN, | |
| VPN_BASIC = _CONSTANTS$PLANS$PLAN.VPN_BASIC, | |
| VPN_PLUS = _CONSTANTS$PLANS$PLAN.VPN_PLUS; | |
| return { | |
| restrict: "E", | |
| replace: !0, | |
| scope: {}, | |
| templateUrl: "templates/dashboard/vpnColumns.tpl.html", | |
| link: function(scope, element) { | |
| var amounts = dashboardModel.amounts(), | |
| update = function() { | |
| element.removeClass("vpnColumns-vpnbasic-selected vpnColumns-vpnplus-selected"), customVpnModel.get("vpnbasic") && element.addClass("vpnColumns-vpnbasic-selected"), customVpnModel.get("vpnplus") && element.addClass("vpnColumns-vpnplus-selected") | |
| }, | |
| unsubscribe = $rootScope.$on("dashboard", function(event, _ref) { | |
| "vpn.modal.updated" === _ref.type && update() | |
| }); | |
| scope.vpnbasicAmount = dashboardModel.filter(amounts[VPN_BASIC]) + "/mo", scope.vpnplusAmount = dashboardModel.filter(amounts[VPN_PLUS]) + "/mo", element.on("click", onClick), scope.$on("$destroy", function() { | |
| element.off("click", onClick), unsubscribe() | |
| }) | |
| } | |
| } | |
| }), angular.module("proton.dashboard").directive("vpnDiscountPanel", function() { | |
| return { | |
| restrict: "E", | |
| replace: !0, | |
| scope: {}, | |
| templateUrl: "templates/dashboard/vpnDiscountPanel.tpl.html" | |
| } | |
| }), angular.module("proton.dashboard").directive("vpnRow", function($rootScope, CONSTANTS, dashboardConfiguration, dashboardModel, gettextCatalog, subscriptionModel, customVpnModal) { | |
| var _CONSTANTS$PLANS$PLAN = CONSTANTS.PLANS.PLAN, | |
| VPN_BASIC = _CONSTANTS$PLANS$PLAN.VPN_BASIC, | |
| VPN_PLUS = _CONSTANTS$PLANS$PLAN.VPN_PLUS, | |
| VPN = CONSTANTS.PLANS.ADDON.VPN, | |
| getName = function() { | |
| return (arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {}).vpnplus ? "ProtonVPN Plus" : "ProtonVPN Basic" | |
| }, | |
| getClass = function() { | |
| return (arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {}).vpnplus ? "vpnRow-vpnplus" : "vpnRow-vpnbasic" | |
| }, | |
| initVpn = function(plan) { | |
| return $rootScope.$emit("dashboard", { | |
| type: "init.vpn", | |
| data: { | |
| plan: plan | |
| } | |
| }) | |
| }, | |
| I18N = { | |
| with: gettextCatalog.getString("with", null, "ProtonVPN with X connections"), | |
| connections: gettextCatalog.getString("connections", null, "ProtonVPN with X connections") | |
| }, | |
| openModal = function(plan) { | |
| customVpnModal.activate({ | |
| params: { | |
| plan: plan, | |
| close: function() { | |
| customVpnModal.deactivate() | |
| } | |
| } | |
| }) | |
| }; | |
| return { | |
| restrict: "E", | |
| replace: !0, | |
| scope: {}, | |
| templateUrl: "templates/dashboard/vpnRow.tpl.html", | |
| link: function(scope, element, _ref) { | |
| var plan = _ref.plan, | |
| getAmount = function() { | |
| var vpnbasic = dashboardModel.amount({ | |
| plan: plan, | |
| addon: "vpnbasic" | |
| }), | |
| vpnplus = dashboardModel.amount({ | |
| plan: plan, | |
| addon: "vpnplus" | |
| }), | |
| vpn = dashboardModel.amount({ | |
| plan: plan, | |
| addon: "vpn" | |
| }), | |
| amount = vpnbasic + vpnplus + ("professional" === plan ? vpn : 0); | |
| return "+ " + dashboardModel.filter(amount) + "/mo" | |
| }, | |
| getConnections = function(config) { | |
| var _dashboardModel$get = dashboardModel.get(dashboardConfiguration.cycle()), | |
| addons = _dashboardModel$get.addons, | |
| connections = function(key) { | |
| return addons[key].MaxVPN | |
| }, | |
| vpnbasic = config.vpnbasic * connections(VPN_BASIC), | |
| vpnplus = config.vpnplus * connections(VPN_PLUS), | |
| vpn = config.vpn * connections(VPN); | |
| return vpnbasic + vpnplus + ("professional" === plan ? vpn : 0) + " " + I18N.connections | |
| }, | |
| $info = element.find(".vpnRow-info"), | |
| buildString = function(config) { | |
| return $info.html('\n <div class="vpnRow-left">\n <b class="' + getClass(config) + '">' + getName(config) + "</b> " + I18N.with + ' <button type="button" class="vpnRow-edit" data-action="open-vpn-modal">' + getConnections(config) + '</button>\n </div>\n <div class="vpnRow-right">\n <strong>' + getAmount() + "</strong>\n </div>\n ") | |
| }, | |
| update = function() { | |
| var config = dashboardConfiguration.get()[plan]; | |
| config.vpnplus || config.vpnbasic ? (element.addClass("vpnRow-has-vpn"), buildString(config)) : element.removeClass("vpnRow-has-vpn") | |
| }, | |
| onClick = function(event) { | |
| "open-vpn-modal" === event.target.getAttribute("data-action") && openModal(plan) | |
| }, | |
| unsubscribe = $rootScope.$on("dashboard", function(event, _ref2) { | |
| var type = _ref2.type; | |
| "currency.updated" !== type && "cycle.updated" !== type || update(), "vpn.updated" === type && update() | |
| }); | |
| element.on("click", onClick), initVpn(plan), scope.$on("$destroy", function() { | |
| unsubscribe(), element.off("click", onClick) | |
| }) | |
| } | |
| } | |
| }), angular.module("proton.dashboard").directive("vpnSlider", function($rootScope, CONSTANTS, customVpnModel, dashboardConfiguration, dashboardModel) { | |
| var _CONSTANTS$PLANS$PLAN = CONSTANTS.PLANS.PLAN, | |
| VPN_PLUS = _CONSTANTS$PLANS$PLAN.VPN_PLUS, | |
| VPN_BASIC = _CONSTANTS$PLANS$PLAN.VPN_BASIC, | |
| onClick = function(event) { | |
| switch (event.target.getAttribute("data-action")) { | |
| case "vpnplus": | |
| customVpnModel.set("vpnbasic", 0), customVpnModel.set("vpnplus", 1) | |
| } | |
| }; | |
| return { | |
| replace: !0, | |
| restrict: "E", | |
| scope: {}, | |
| templateUrl: "templates/dashboard/vpnSlider.tpl.html", | |
| link: function(scope, element) { | |
| var $count = element.find(".vpnSlider-count"), | |
| _dashboardModel$get = dashboardModel.get(dashboardConfiguration.cycle()), | |
| addons = _dashboardModel$get.addons, | |
| vpnbasic = addons[VPN_BASIC], | |
| vpnplus = addons[VPN_PLUS], | |
| _customVpnModel$param = customVpnModel.parameters(), | |
| value = _customVpnModel$param.value, | |
| options = _customVpnModel$param.options, | |
| updateCount = function() { | |
| customVpnModel.get("vpnbasic") && $count.text("" + vpnbasic.MaxVPN), customVpnModel.get("vpnplus") && $count.text("" + (vpnplus.MaxVPN + customVpnModel.get("vpn"))) | |
| }, | |
| updateSlider = function() { | |
| customVpnModel.get("vpnplus") && scope.$applyAsync(function() { | |
| return scope.value = customVpnModel.get("vpnplus") * vpnplus.MaxVPN + customVpnModel.get("vpn") | |
| }) | |
| }, | |
| updateClass = function() { | |
| element[0].classList.toggle("vpnSlider-vpnplus-selected", customVpnModel.get("vpnplus")), element[0].classList.toggle("vpnSlider-vpnbasic-selected", customVpnModel.get("vpnbasic")) | |
| }, | |
| unsubscribe = $rootScope.$on("dashboard", function(event, _ref) { | |
| var _ref$type = _ref.type; | |
| "vpn.modal.updated" === (void 0 === _ref$type ? "" : _ref$type) && (updateCount(), updateSlider(), updateClass()) | |
| }); | |
| scope.value = value, scope.options = options, element.on("click", onClick), scope.$on("$destroy", function() { | |
| element.off("click", onClick), unsubscribe() | |
| }) | |
| } | |
| } | |
| }), angular.module("proton.dashboard").directive("vpnTotal", function($rootScope, CONSTANTS, customVpnModel, dashboardConfiguration, dashboardModel) { | |
| return { | |
| replace: !0, | |
| restrict: "E", | |
| scope: {}, | |
| templateUrl: "templates/dashboard/vpnTotal.tpl.html", | |
| link: function(scope, element) { | |
| var $amount = element.find(".vpnTotal-amount"), | |
| updateAmount = function() { | |
| var amount = customVpnModel.amount(); | |
| $amount.text(dashboardModel.filter(amount) + "/mo") | |
| }, | |
| unsubscribe = $rootScope.$on("dashboard", function(event, _ref) { | |
| var _ref$type = _ref.type; | |
| "vpn.modal.updated" === (void 0 === _ref$type ? "" : _ref$type) && updateAmount() | |
| }); | |
| scope.$on("$destroy", function() { | |
| unsubscribe() | |
| }) | |
| } | |
| } | |
| }), angular.module("proton.dashboard").factory("customProPlanModel", function($rootScope, CONSTANTS, dashboardConfiguration, dashboardModel) { | |
| function getSliders() { | |
| return _.reduce(["members", "storage", "addresses"], function(acc, type) { | |
| return acc[type] = getSliderParameters(type), acc | |
| }, {}) | |
| } | |
| function getEquivalentOptions() { | |
| var _dashboardModel$get2 = dashboardModel.get(dashboardConfiguration.cycle()), | |
| plan = _dashboardModel$get2.plan, | |
| addons = _dashboardModel$get2.addons, | |
| professionalPlan = plan[PROFESSIONAL], | |
| memberAddon = addons[MEMBER]; | |
| return _.range(0, MAX_MEMBER).map(function(value) { | |
| return { | |
| members: value * memberAddon.MaxMembers + professionalPlan.MaxMembers, | |
| storage: value * fromBase(memberAddon.MaxSpace) + fromBase(professionalPlan.MaxSpace), | |
| addresses: value * memberAddon.MaxAddresses + professionalPlan.MaxAddresses | |
| } | |
| }) | |
| } | |
| function getSliderParameters(type) { | |
| var _dashboardModel$get3 = dashboardModel.get(dashboardConfiguration.cycle()), | |
| addons = _dashboardModel$get3.addons, | |
| plan = _dashboardModel$get3.plan, | |
| memberAddon = addons[MEMBER], | |
| professionalPlan = plan[PROFESSIONAL], | |
| _dashboardConfigurati = dashboardConfiguration.get(), | |
| professional = _dashboardConfigurati.professional, | |
| options = getEquivalentOptions(), | |
| option = _.findWhere(options, { | |
| members: Number(professional.member) + professionalPlan.MaxMembers | |
| }), | |
| step = void 0, | |
| start = void 0, | |
| min = void 0, | |
| max = void 0; | |
| switch (type) { | |
| case "members": | |
| step = memberAddon.MaxMembers, start = option.members, min = _.first(options).members, max = _.last(options).members; | |
| break; | |
| case "storage": | |
| step = fromBase(memberAddon.MaxSpace), start = option.storage, min = _.first(options).storage, max = _.last(options).storage; | |
| break; | |
| case "addresses": | |
| step = memberAddon.MaxAddresses, start = option.addresses, min = _.first(options).addresses, max = _.last(options).addresses | |
| } | |
| return { | |
| value: start, | |
| options: { | |
| type: type, | |
| animate: !1, | |
| tooltips: !0, | |
| connect: [!0, !1], | |
| start: start, | |
| step: step, | |
| range: { | |
| min: min, | |
| max: max | |
| }, | |
| pips: { | |
| mode: "values", | |
| values: [min, max], | |
| density: 4 | |
| }, | |
| format: { | |
| to: function(value) { | |
| return "" + Number(value).toFixed() | |
| }, | |
| from: function(value) { | |
| return value | |
| } | |
| } | |
| } | |
| } | |
| } | |
| var PLANS = CONSTANTS.PLANS, | |
| BASE_SIZE = CONSTANTS.BASE_SIZE, | |
| MAX_MEMBER = CONSTANTS.MAX_MEMBER, | |
| PLAN = PLANS.PLAN, | |
| ADDON = PLANS.ADDON, | |
| MEMBER = ADDON.MEMBER, | |
| PROFESSIONAL = PLAN.PROFESSIONAL, | |
| fromBase = function(value) { | |
| return value / Math.pow(BASE_SIZE, 3) | |
| }, | |
| CACHE = {}, | |
| refreshSlider = function(type) { | |
| return $rootScope.$emit("refresh.slider", { | |
| type: type, | |
| data: { | |
| value: CACHE[type] | |
| } | |
| }) | |
| }, | |
| send = function() { | |
| var _dashboardModel$get = dashboardModel.get(dashboardConfiguration.cycle()), | |
| plan = _dashboardModel$get.plan, | |
| professionalPlan = plan[PROFESSIONAL]; | |
| $rootScope.$emit("dashboard", { | |
| type: "change.addon", | |
| data: { | |
| plan: "professional", | |
| addon: "member", | |
| value: CACHE.members - professionalPlan.MaxMembers | |
| } | |
| }) | |
| }; | |
| return $rootScope.$on("slider.updated", function(event, _ref) { | |
| var type = _ref.type, | |
| _ref$data = _ref.data, | |
| data = void 0 === _ref$data ? {} : _ref$data; | |
| if (_.contains(["members", "storage", "addresses"], type)) { | |
| var options = getEquivalentOptions(), | |
| _$findWhere = _.findWhere(options, _defineProperty({}, type, data.value)), | |
| members = _$findWhere.members, | |
| storage = _$findWhere.storage, | |
| addresses = _$findWhere.addresses; | |
| CACHE.members = members, CACHE.storage = storage, CACHE.addresses = addresses, refreshSlider("members"), refreshSlider("storage"), refreshSlider("addresses") | |
| } | |
| }), { | |
| init: angular.noop, | |
| getSliders: getSliders, | |
| send: send | |
| } | |
| }), angular.module("proton.dashboard").factory("customVpnModel", function($rootScope, CONSTANTS, dashboardConfiguration, dashboardModel) { | |
| var MAX_VPN = CONSTANTS.MAX_VPN, | |
| PLANS = CONSTANTS.PLANS, | |
| PLAN = PLANS.PLAN, | |
| ADDON = PLANS.ADDON, | |
| VPN = ADDON.VPN, | |
| VPN_BASIC = PLAN.VPN_BASIC, | |
| VPN_PLUS = PLAN.VPN_PLUS, | |
| CACHE = {}, | |
| dispatch = function() { | |
| return $rootScope.$emit("dashboard", { | |
| type: "vpn.modal.updated" | |
| }) | |
| }, | |
| set = function(key, value) { | |
| CACHE[key] = value, dispatch() | |
| }, | |
| get = function(key) { | |
| return key ? CACHE[key] : angular.copy(CACHE) | |
| }, | |
| parameters = function() { | |
| var _dashboardModel$get = dashboardModel.get(dashboardConfiguration.cycle()), | |
| addons = _dashboardModel$get.addons, | |
| vpn = addons[VPN], | |
| vpnplus = addons[VPN_PLUS], | |
| step = vpn.MaxVPN, | |
| min = vpnplus.MaxVPN, | |
| start = CACHE.vpn + vpnplus.MaxVPN, | |
| max = MAX_VPN; | |
| return { | |
| value: start, | |
| options: { | |
| type: "vpn", | |
| animate: !1, | |
| tooltips: !0, | |
| connect: [!0, !1], | |
| start: start, | |
| step: step, | |
| range: { | |
| min: min, | |
| max: max | |
| }, | |
| pips: { | |
| mode: "values", | |
| values: [min, max], | |
| density: 4 | |
| }, | |
| format: { | |
| to: function(value) { | |
| return "" + Number(value).toFixed() | |
| }, | |
| from: function(value) { | |
| return value | |
| } | |
| } | |
| } | |
| } | |
| }, | |
| init = function(plan) { | |
| var config = dashboardConfiguration.get(), | |
| _config$plan = config[plan], | |
| _config$plan$vpnbasic = _config$plan.vpnbasic, | |
| vpnbasic = void 0 === _config$plan$vpnbasic ? 0 : _config$plan$vpnbasic, | |
| _config$plan$vpnplus = _config$plan.vpnplus, | |
| vpnplus = void 0 === _config$plan$vpnplus ? 0 : _config$plan$vpnplus, | |
| _config$plan$vpn = _config$plan.vpn, | |
| vpn = void 0 === _config$plan$vpn ? 0 : _config$plan$vpn; | |
| CACHE.vpnbasic = vpnbasic, CACHE.vpnplus = vpnbasic || vpnplus ? vpnplus : 1, CACHE.vpn = vpn, dispatch() | |
| }, | |
| amount = function() { | |
| var amounts = dashboardModel.amounts(), | |
| result = 0; | |
| return CACHE.vpnbasic && (result += amounts[VPN_BASIC]), CACHE.vpnplus && (result += amounts[VPN_PLUS]), CACHE.vpn && (result += CACHE.vpn * amounts[VPN]), result | |
| }; | |
| return $rootScope.$on("slider.updated", function(event, _ref) { | |
| var _ref$type = _ref.type, | |
| type = void 0 === _ref$type ? "" : _ref$type, | |
| _ref$data = _ref.data, | |
| data = void 0 === _ref$data ? {} : _ref$data; | |
| if ("vpn" === type) { | |
| var _dashboardModel$get2 = dashboardModel.get(dashboardConfiguration.cycle()), | |
| addons = _dashboardModel$get2.addons, | |
| vpnplus = addons[VPN_PLUS]; | |
| CACHE.vpn = data.value - vpnplus.MaxVPN, dispatch() | |
| } | |
| }), { | |
| init: init, | |
| set: set, | |
| get: get, | |
| parameters: parameters, | |
| amount: amount | |
| } | |
| }), angular.module("proton.dashboard").factory("dashboardConfiguration", function() { | |
| var CONFIGURATION = { | |
| free: {}, | |
| plus: {}, | |
| professional: {} | |
| }; | |
| return { | |
| cycle: function() { | |
| return CONFIGURATION.cycle | |
| }, | |
| currency: function() { | |
| return CONFIGURATION.currency | |
| }, | |
| get: function() { | |
| return angular.copy(CONFIGURATION) | |
| }, | |
| set: function(key, value) { | |
| return CONFIGURATION[key] = value | |
| }, | |
| addon: function(plan, _addon, value) { | |
| return CONFIGURATION[plan][_addon] = value | |
| } | |
| } | |
| }); | |
| var _slicedToArray = function() { | |
| function sliceIterator(arr, i) { | |
| var _arr = [], | |
| _n = !0, | |
| _d = !1, | |
| _e = void 0; | |
| try { | |
| for (var _s, _i = arr[Symbol.iterator](); !(_n = (_s = _i.next()).done) && (_arr.push(_s.value), !i || _arr.length !== i); _n = !0); | |
| } catch (err) { | |
| _d = !0, _e = err | |
| } finally { | |
| try { | |
| !_n && _i.return && _i.return() | |
| } finally { | |
| if (_d) throw _e | |
| } | |
| } | |
| return _arr | |
| } | |
| return function(arr, i) { | |
| if (Array.isArray(arr)) return arr; | |
| if (Symbol.iterator in Object(arr)) return sliceIterator(arr, i); | |
| throw new TypeError("Invalid attempt to destructure non-iterable instance") | |
| } | |
| }(); | |
| angular.module("proton.dashboard").factory("dashboardModel", function($filter, $rootScope, confirmModal, CONSTANTS, dashboardConfiguration, downgrade, gettextCatalog, Payment, paymentModal, subscriptionModel, networkActivityTracker, paymentModel) { | |
| var _CONSTANTS$PLANS$PLAN = CONSTANTS.PLANS.PLAN, | |
| PLUS = _CONSTANTS$PLANS$PLAN.PLUS, | |
| PROFESSIONAL = _CONSTANTS$PLANS$PLAN.PROFESSIONAL, | |
| VISIONARY = _CONSTANTS$PLANS$PLAN.VISIONARY, | |
| VPN_BASIC = _CONSTANTS$PLANS$PLAN.VPN_BASIC, | |
| VPN_PLUS = _CONSTANTS$PLANS$PLAN.VPN_PLUS, | |
| MAIL_PLANS = ["free", PLUS, PROFESSIONAL, VISIONARY], | |
| _CONSTANTS$PLANS$ADDO = CONSTANTS.PLANS.ADDON, | |
| ADDRESS = _CONSTANTS$PLANS$ADDO.ADDRESS, | |
| MEMBER = _CONSTANTS$PLANS$ADDO.MEMBER, | |
| DOMAIN = _CONSTANTS$PLANS$ADDO.DOMAIN, | |
| SPACE = _CONSTANTS$PLANS$ADDO.SPACE, | |
| VPN = _CONSTANTS$PLANS$ADDO.VPN, | |
| _CONSTANTS$CYCLE = CONSTANTS.CYCLE, | |
| MONTHLY = _CONSTANTS$CYCLE.MONTHLY, | |
| YEARLY = _CONSTANTS$CYCLE.YEARLY, | |
| TWO_YEARS = _CONSTANTS$CYCLE.TWO_YEARS, | |
| CACHE_PLAN = {}, | |
| CACHE_API = {}, | |
| filter = function(amount) { | |
| return $filter("currency")(amount / 100 / dashboardConfiguration.cycle(), dashboardConfiguration.currency()) | |
| }, | |
| get = function(key) { | |
| var cache = angular.copy(CACHE_PLAN); | |
| return key ? cache[key] : cache | |
| }, | |
| changeAddon = function(plan, addon, value) { | |
| dashboardConfiguration.addon(plan, addon, value), $rootScope.$emit("dashboard", { | |
| type: "addon.updated", | |
| data: { | |
| plan: plan, | |
| addon: addon, | |
| value: value | |
| } | |
| }) | |
| }, | |
| selectVpn = function() { | |
| var plan = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : "", | |
| vpn = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : 0; | |
| dashboardConfiguration.addon("free", "vpnbasic", +("vpnbasic" === plan)), dashboardConfiguration.addon("free", "vpnplus", +("vpnplus" === plan)), dashboardConfiguration.addon("plus", "vpnbasic", +("vpnbasic" === plan)), dashboardConfiguration.addon("plus", "vpnplus", +("vpnplus" === plan)), dashboardConfiguration.addon("professional", "vpnbasic", +("vpnbasic" === plan)), dashboardConfiguration.addon("professional", "vpnplus", +("vpnplus" === plan)), dashboardConfiguration.addon("professional", "vpn", vpn), $rootScope.$emit("dashboard", { | |
| type: "vpn.updated" | |
| }) | |
| }, | |
| removeVpn = function() { | |
| dashboardConfiguration.addon("free", "vpnbasic", 0), dashboardConfiguration.addon("free", "vpnplus", 0), dashboardConfiguration.addon("plus", "vpnbasic", 0), dashboardConfiguration.addon("plus", "vpnplus", 0), dashboardConfiguration.addon("professional", "vpnbasic", 0), dashboardConfiguration.addon("professional", "vpnplus", 0), dashboardConfiguration.addon("professional", "vpn", 0), $rootScope.$emit("dashboard", { | |
| type: "vpn.updated" | |
| }) | |
| }, | |
| updateVpn = function() { | |
| var vpnbasic = +subscriptionModel.hasPaid("vpnbasic"), | |
| vpnplus = +subscriptionModel.hasPaid("vpnplus"), | |
| vpn = subscriptionModel.count("vpn"); | |
| dashboardConfiguration.addon("free", "vpnbasic", vpnbasic), dashboardConfiguration.addon("free", "vpnplus", vpnplus), dashboardConfiguration.addon("plus", "vpnbasic", vpnbasic), dashboardConfiguration.addon("plus", "vpnplus", vpnplus), dashboardConfiguration.addon("professional", "vpnbasic", vpnbasic), dashboardConfiguration.addon("professional", "vpnplus", vpnplus), dashboardConfiguration.addon("professional", "vpn", vpn), $rootScope.$emit("dashboard", { | |
| type: "vpn.updated" | |
| }) | |
| }, | |
| initVpn = function() { | |
| var plan = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : ""; | |
| dashboardConfiguration.addon(plan, "vpnbasic", +subscriptionModel.hasPaid("vpnbasic")), dashboardConfiguration.addon(plan, "vpnplus", +subscriptionModel.hasPaid("vpnplus")), "professional" === plan && dashboardConfiguration.addon(plan, "vpn", subscriptionModel.count("vpn")), $rootScope.$emit("dashboard", { | |
| type: "vpn.updated", | |
| data: { | |
| plan: plan | |
| } | |
| }) | |
| }, | |
| query = function() { | |
| var currency = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : "USD", | |
| cycle = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : YEARLY, | |
| key = "plans-" + currency + "-" + cycle, | |
| _ref = CACHE_API[key] || {}, | |
| _ref$Plans = _ref.Plans; | |
| return void 0 === _ref$Plans ? [] : _ref$Plans | |
| }, | |
| collectPlans = function(plan) { | |
| var plans = [], | |
| cache = CACHE_PLAN[dashboardConfiguration.cycle()], | |
| config = dashboardConfiguration.get(); | |
| switch (plan) { | |
| case "free": | |
| config.free.vpnbasic && plans.push(cache.addons[VPN_BASIC]), config.free.vpnplus && plans.push(cache.addons[VPN_PLUS]); | |
| break; | |
| case "plus": | |
| plans.push(cache.plan[PLUS]), config.plus.vpnbasic && plans.push(cache.addons[VPN_BASIC]), config.plus.vpnplus && plans.push(cache.addons[VPN_PLUS]), _.times(config.plus.space, function() { | |
| return plans.push(cache.addons[SPACE]) | |
| }), _.times(config.plus.address, function() { | |
| return plans.push(cache.addons[ADDRESS]) | |
| }), _.times(config.plus.domain, function() { | |
| return plans.push(cache.addons[DOMAIN]) | |
| }); | |
| break; | |
| case "professional": | |
| plans.push(cache.plan[PROFESSIONAL]), config.professional.vpnbasic && plans.push(cache.addons[VPN_BASIC]), config.professional.vpnplus && plans.push(cache.addons[VPN_PLUS]), _.times(config.professional.member, function() { | |
| return plans.push(cache.addons[MEMBER]) | |
| }), _.times(config.professional.domain, function() { | |
| return plans.push(cache.addons[DOMAIN]) | |
| }), _.times(config.professional.vpn, function() { | |
| return plans.push(cache.addons[VPN]) | |
| }); | |
| break; | |
| case "visionary": | |
| plans.push(cache.plan[VISIONARY]) | |
| } | |
| return plans | |
| }, | |
| selectPlan = function(plan, choice) { | |
| var plans = collectPlans(plan); | |
| if ("free" === plan && !plans.length) return downgrade(); | |
| var PlanIDs = _.pluck(plans, "ID"), | |
| promise = Payment.valid({ | |
| Cycle: dashboardConfiguration.cycle(), | |
| Currency: dashboardConfiguration.currency(), | |
| PlanIDs: PlanIDs, | |
| Coupon: subscriptionModel.coupon() | |
| }).then(function() { | |
| var _ref2 = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {}, | |
| _ref2$data = _ref2.data, | |
| valid = void 0 === _ref2$data ? {} : _ref2$data; | |
| paymentModal.activate({ | |
| params: { | |
| planIDs: PlanIDs, | |
| valid: valid, | |
| choice: choice, | |
| plan: plan, | |
| cancel: function() { | |
| paymentModal.deactivate() | |
| } | |
| } | |
| }) | |
| }).catch(function() { | |
| var _ref3 = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {}, | |
| _ref3$data = _ref3.data, | |
| data = void 0 === _ref3$data ? {} : _ref3$data; | |
| throw Error(data.Error) | |
| }); | |
| networkActivityTracker.track(promise) | |
| }, | |
| fetchPlans = function() { | |
| var currency = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : "USD", | |
| cycle = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : YEARLY, | |
| key = "plans-" + currency + "-" + cycle; | |
| return CACHE_API[key] ? Promise.resolve(CACHE_API[key]) : Payment.plans(currency, cycle).then(function(_ref4) { | |
| var _ref4$data = _ref4.data, | |
| data = void 0 === _ref4$data ? {} : _ref4$data; | |
| return CACHE_API[key] = data, data | |
| }).catch(function() { | |
| var _ref5 = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {}, | |
| _ref5$data = _ref5.data; | |
| throw (void 0 === _ref5$data ? {} : _ref5$data).Error | |
| }) | |
| }, | |
| loadPlanCycle = function(currency) { | |
| var cycle = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : YEARLY; | |
| return fetchPlans(currency, cycle).then(function() { | |
| var data = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {}, | |
| _reduce = (data.Plans || []).reduce(function(acc, plan) { | |
| return acc.amounts[plan.Name] = plan.Amount, _.contains(MAIL_PLANS, plan.Name) ? (acc.plan[plan.Name] = plan, acc.list.push(plan), acc) : (acc.addons[plan.Name] = plan, acc) | |
| }, { | |
| addons: {}, | |
| plan: {}, | |
| list: [], | |
| amounts: {} | |
| }); | |
| return { | |
| list: _reduce.list, | |
| addons: _reduce.addons, | |
| plan: _reduce.plan, | |
| amounts: _reduce.amounts | |
| } | |
| }) | |
| }, | |
| loadPlans = function() { | |
| var Currency = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : dashboardConfiguration.currency(), | |
| promise = Promise.all([loadPlanCycle(Currency), loadPlanCycle(Currency, MONTHLY), loadPlanCycle(Currency, TWO_YEARS)]).then(function(_ref6) { | |
| var _ref7 = _slicedToArray(_ref6, 3), | |
| yearly = _ref7[0], | |
| monthly = _ref7[1], | |
| twoYears = _ref7[2]; | |
| return CACHE_PLAN[YEARLY] = angular.copy(yearly), CACHE_PLAN[MONTHLY] = angular.copy(monthly), CACHE_PLAN[TWO_YEARS] = angular.copy(twoYears), angular.copy(CACHE_PLAN) | |
| }); | |
| return networkActivityTracker.track(promise), promise | |
| }, | |
| changeCurrency = function(currency) { | |
| loadPlans(currency).then(function(data) { | |
| dashboardConfiguration.set("currency", currency), $rootScope.$emit("dashboard", { | |
| type: "currency.updated", | |
| data: _.extend(data, { | |
| currency: currency | |
| }) | |
| }) | |
| }) | |
| }, | |
| amounts = function() { | |
| var cycle = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : dashboardConfiguration.cycle(); | |
| return angular.copy(CACHE_PLAN[cycle].amounts) | |
| }, | |
| amount = function(_ref8) { | |
| var _ref8$config = _ref8.config, | |
| config = void 0 === _ref8$config ? dashboardConfiguration.get() : _ref8$config, | |
| plan = _ref8.plan, | |
| addon = _ref8.addon, | |
| _ref8$cycle = _ref8.cycle, | |
| cycle = void 0 === _ref8$cycle ? dashboardConfiguration.cycle() : _ref8$cycle; | |
| switch (addon) { | |
| case "vpn": | |
| return CACHE_PLAN[cycle].amounts[VPN] * config[plan].vpn; | |
| case "address": | |
| return CACHE_PLAN[cycle].amounts[ADDRESS] * config[plan].address; | |
| case "space": | |
| return CACHE_PLAN[cycle].amounts[SPACE] * config[plan].space; | |
| case "domain": | |
| return CACHE_PLAN[cycle].amounts[DOMAIN] * config[plan].domain; | |
| case "member": | |
| return CACHE_PLAN[cycle].amounts[MEMBER] * config[plan].member; | |
| case "vpnbasic": | |
| return CACHE_PLAN[cycle].amounts[VPN_BASIC] * config[plan].vpnbasic; | |
| case "vpnplus": | |
| return CACHE_PLAN[cycle].amounts[VPN_PLUS] * config[plan].vpnplus | |
| } | |
| switch (plan) { | |
| case "plus": | |
| case "professional": | |
| case "visionary": | |
| return CACHE_PLAN[cycle].amounts[plan]; | |
| default: | |
| return 0 | |
| } | |
| }, | |
| total = function(plan, cycle) { | |
| var config = dashboardConfiguration.get(), | |
| result = 0; | |
| switch (plan) { | |
| case "free": | |
| result += amount({ | |
| config: config, | |
| plan: plan, | |
| cycle: cycle, | |
| addon: VPN_BASIC | |
| }), result += amount({ | |
| config: config, | |
| plan: plan, | |
| cycle: cycle, | |
| addon: VPN_PLUS | |
| }); | |
| break; | |
| case "plus": | |
| result += amount({ | |
| config: config, | |
| plan: plan, | |
| cycle: cycle | |
| }), result += amount({ | |
| config: config, | |
| plan: plan, | |
| cycle: cycle, | |
| addon: "address" | |
| }), result += amount({ | |
| config: config, | |
| plan: plan, | |
| cycle: cycle, | |
| addon: "space" | |
| }), result += amount({ | |
| config: config, | |
| plan: plan, | |
| cycle: cycle, | |
| addon: "domain" | |
| }), result += amount({ | |
| config: config, | |
| plan: plan, | |
| cycle: cycle, | |
| addon: VPN_BASIC | |
| }), result += amount({ | |
| config: config, | |
| plan: plan, | |
| cycle: cycle, | |
| addon: VPN_PLUS | |
| }), result *= config[plan].vpnbasic || config[plan].vpnplus ? .8 : 1; | |
| break; | |
| case "professional": | |
| result += amount({ | |
| config: config, | |
| plan: plan, | |
| cycle: cycle | |
| }), result += amount({ | |
| config: config, | |
| plan: plan, | |
| cycle: cycle, | |
| addon: "member" | |
| }), result += amount({ | |
| config: config, | |
| plan: plan, | |
| cycle: cycle, | |
| addon: "domain" | |
| }), result += amount({ | |
| config: config, | |
| plan: plan, | |
| cycle: cycle, | |
| addon: VPN_BASIC | |
| }), result += amount({ | |
| config: config, | |
| plan: plan, | |
| cycle: cycle, | |
| addon: VPN_PLUS | |
| }), result += amount({ | |
| config: config, | |
| plan: plan, | |
| cycle: cycle, | |
| addon: "vpn" | |
| }), result *= config[plan].vpnbasic || config[plan].vpnplus ? .8 : 1; | |
| break; | |
| case "visionary": | |
| result += amount({ | |
| config: config, | |
| plan: plan, | |
| cycle: cycle | |
| }) | |
| } | |
| return result | |
| }, | |
| changeCycle = function(cycle) { | |
| dashboardConfiguration.set("cycle", cycle), $rootScope.$emit("dashboard", { | |
| type: "cycle.updated", | |
| data: { | |
| cycle: cycle | |
| } | |
| }) | |
| }; | |
| return $rootScope.$on("subscription", function(event, _ref9) { | |
| var _ref9$type = _ref9.type; | |
| "update" === (void 0 === _ref9$type ? "" : _ref9$type) && (updateVpn(), changeCycle(subscriptionModel.cycle()), changeCurrency(subscriptionModel.currency())) | |
| }), $rootScope.$on("dashboard", function(event, _ref10) { | |
| var type = _ref10.type, | |
| _ref10$data = _ref10.data, | |
| data = void 0 === _ref10$data ? {} : _ref10$data; | |
| "change.cycle" === type && changeCycle(data.cycle), "change.currency" === type && changeCurrency(data.currency), "change.addon" === type && changeAddon(data.plan, data.addon, data.value), "select.plan" === type && selectPlan(data.plan), "select.vpn" === type && selectVpn(data.plan, data.vpn), "remove.vpn" === type && removeVpn(), "init.vpn" === type && initVpn(data.plan) | |
| }), $rootScope.$on("modal.payment", function(e, _ref11) { | |
| var type = _ref11.type, | |
| data = _ref11.data; | |
| if ("process.success" === type) { | |
| var promise = Promise.all([subscriptionModel.fetch(), paymentModel.getMethods(!0)]); | |
| networkActivityTracker.track(promise) | |
| } | |
| if ("switch" === type) { | |
| var Cycle = data.Cycle, | |
| Currency = data.Currency, | |
| plan = data.plan; | |
| paymentModal.deactivate(), dashboardConfiguration.set("currency", Currency), dashboardConfiguration.set("cycle", Cycle), loadPlanCycle(Currency, Cycle).then(function() { | |
| selectPlan(plan, "paypal") | |
| }) | |
| } | |
| }), { | |
| init: angular.noop, | |
| loadPlans: loadPlans, | |
| fetchPlans: fetchPlans, | |
| get: get, | |
| query: query, | |
| amount: amount, | |
| amounts: amounts, | |
| total: total, | |
| filter: filter | |
| } | |
| }), angular.module("proton.dashboard").factory("dashboardOptions", function(gettextCatalog, CONSTANTS) { | |
| var MAX_MEMBER = CONSTANTS.MAX_MEMBER, | |
| ADDRESS_OPTIONS = _.range(5, 51, 5).map(function(value, index) { | |
| return { | |
| label: gettextCatalog.getString("{{value}} Addresses", { | |
| value: value | |
| }, "dashboard options select"), | |
| value: index | |
| } | |
| }), | |
| SPACE_OPTIONS = _.range(5, 21).map(function(value, index) { | |
| return { | |
| label: gettextCatalog.getPlural(value, "1 GB Storage", "{{$count}} GB Storage", {}, "dashboard options select"), | |
| value: index | |
| } | |
| }), | |
| MEMBER_OPTIONS = _.range(1, MAX_MEMBER + 1).map(function(value, index) { | |
| return { | |
| label: gettextCatalog.getPlural(value, "1 User", "{{$count}} Users", {}, "dashboard options select"), | |
| value: index | |
| } | |
| }), | |
| generateDomains = function(start, end) { | |
| return _.range(start, end).map(function(value, index) { | |
| return { | |
| label: gettextCatalog.getPlural(value, "1 Custom Domain", "{{$count}} Custom Domains", {}, "dashboard options select"), | |
| value: index | |
| } | |
| }) | |
| }, | |
| VPN_OPTIONS = [{ | |
| label: "----------", | |
| value: "none" | |
| }, { | |
| label: "Basic", | |
| value: "vpnbasic" | |
| }, { | |
| label: "Plus", | |
| value: "vpnplus" | |
| }], | |
| options = { | |
| free: { | |
| vpn: VPN_OPTIONS | |
| }, | |
| plus: { | |
| vpn: VPN_OPTIONS, | |
| address: ADDRESS_OPTIONS, | |
| space: SPACE_OPTIONS, | |
| domain: generateDomains(1, 11) | |
| }, | |
| professional: { | |
| vpn: VPN_OPTIONS, | |
| member: MEMBER_OPTIONS, | |
| domain: generateDomains(2, 11) | |
| } | |
| }; | |
| return { | |
| get: function(plan, addon) { | |
| return angular.copy(options[plan][addon]) | |
| } | |
| } | |
| }), angular.module("proton.dashboard").factory("downgrade", function($rootScope, confirmModal, eventManager, gettextCatalog, networkActivityTracker, notification, Payment, subscriptionModel) { | |
| function unsubscribe() { | |
| return Payment.delete().then(function() { | |
| var _ref = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {}, | |
| _ref$data = _ref.data, | |
| data = void 0 === _ref$data ? {} : _ref$data; | |
| if (1e3 === data.Code) return data | |
| }).then(function() { | |
| return eventManager.call() | |
| }).then(function() { | |
| return subscriptionModel.set(FREE_PLAN) | |
| }).catch(function() { | |
| var _ref2 = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {}, | |
| _ref2$data = _ref2.data, | |
| data = void 0 === _ref2$data ? {} : _ref2$data; | |
| throw Error(data.Error) | |
| }) | |
| } | |
| var FREE_PLAN = { | |
| Type: 1, | |
| Name: "free" | |
| }, | |
| I18N = { | |
| downgradeTitle: gettextCatalog.getString("Confirm downgrade", null, "Title"), | |
| downgradeMessage: gettextCatalog.getString("This will downgrade your account to a free account. ProtonMail is free software that is supported by donations and paid accounts. Please consider making a donation so we can continue to offer the service for free.<br /><br />Note: Additional addresses, custom domains, and users must be removed/disabled before performing this action.", null, "Info"), | |
| successMessage: gettextCatalog.getString("You have successfully unsubscribed", null, "Downgrade account") | |
| }; | |
| return function() { | |
| confirmModal.activate({ | |
| params: { | |
| title: I18N.downgradeTitle, | |
| message: I18N.downgradeMessage, | |
| confirm: function() { | |
| var promise = unsubscribe().then(function() { | |
| confirmModal.deactivate(), notification.success(I18N.successMessage) | |
| }); | |
| networkActivityTracker.track(promise) | |
| }, | |
| cancel: function() { | |
| confirmModal.deactivate() | |
| } | |
| } | |
| }) | |
| } | |
| }), angular.module("proton.dashboard").factory("customProPlanModal", function(customProPlanModel, gettextCatalog, pmModal) { | |
| var I18N = { | |
| members: function(value) { | |
| return gettextCatalog.getPlural(value, "1 user", "{{$count}} users", {}, "Custom pro plan dashboard") | |
| }, | |
| storage: function(value) { | |
| return gettextCatalog.getString("{{value}} GB storage", { | |
| value: value | |
| }, "Custom pro plan dashboard") | |
| }, | |
| addresses: function(value) { | |
| return gettextCatalog.getString("{{value}} addresses", { | |
| value: value | |
| }, "Custom pro plan dashboard") | |
| } | |
| }; | |
| return pmModal({ | |
| controllerAs: "ctrl", | |
| templateUrl: "templates/dashboard/customProPlanModal.tpl.html", | |
| controller: function(params) { | |
| var _this = this; | |
| this.sliders = customProPlanModel.getSliders(), this.format = function(type) { | |
| return I18N[type](_this.sliders[type].value) | |
| }, this.close = function() { | |
| return params.close() | |
| }, this.submit = function() { | |
| customProPlanModel.send(), params.close() | |
| } | |
| } | |
| }) | |
| }), angular.module("proton.dashboard").factory("customVpnModal", function($rootScope, dashboardConfiguration, pmModal, customVpnModel) { | |
| return pmModal({ | |
| controllerAs: "ctrl", | |
| templateUrl: "templates/dashboard/customVpnModal.tpl.html", | |
| controller: function(params) { | |
| var config = dashboardConfiguration.get(), | |
| plan = params.plan; | |
| customVpnModel.init(plan), this.fromPlan = "customVpnModal-from-" + plan, this.hasVpn = config[plan].vpnbasic || config[plan].vpnplus, this.close = function() { | |
| return params.close() | |
| }, this.remove = function() { | |
| return $rootScope.$emit("dashboard", { | |
| type: "remove.vpn" | |
| }), params.close() | |
| }, this.submit = function() { | |
| var vpnplus = customVpnModel.get("vpnplus"), | |
| vpn = customVpnModel.get("vpn"); | |
| $rootScope.$emit("dashboard", { | |
| type: "select.vpn", | |
| data: { | |
| plan: vpnplus ? "vpnplus" : "vpnbasic", | |
| vpn: vpn | |
| } | |
| }), params.close() | |
| } | |
| } | |
| }) | |
| }), angular.module("proton.dnd").constant("PTDNDCONSTANTS", { | |
| CLASSNAME: { | |
| BODY: "ptdnd-dragstart", | |
| DRAG_HOVER: "ptdnd-drag-hover", | |
| DROPZONE: "ptDnd-dropzone-container", | |
| DROPZONE_HOVER: "ptdnd-dropzone-hover", | |
| NOTIF: "ptdnd-notification", | |
| NOTIF_ACTIVE: "ptdnd-notification-active", | |
| NOTIF_FIREFOX: "ptdnd-notification-firefox", | |
| DRAG_IMAGE: "ptdnd-dragimage" | |
| }, | |
| DROPZONE_ATTR_ID: "data-pt-drop-id" | |
| }), angular.module("proton.dnd").directive("ptDraggable", function($rootScope, ptDndModel, ptDndUtils, PTDNDCONSTANTS, ptDndNotification) { | |
| var CLASSNAME = PTDNDCONSTANTS.CLASSNAME, | |
| DROPZONE_ATTR_ID = PTDNDCONSTANTS.DROPZONE_ATTR_ID, | |
| getSelected = angular.noop; | |
| return document.addEventListener("dragstart", function(event) { | |
| var target = ptDndUtils.getDragInitiatorNode(event.target); | |
| if (!target) return ptDndModel.draggable.set("currentId", null); | |
| var eventData = event.dataTransfer || event.originalEvent.dataTransfer; | |
| if (document.body.classList.add(CLASSNAME.BODY), eventData.effectAllowed = "move", eventData.setData("Text", JSON.stringify({ | |
| id: target.dataset.ptId | |
| })), ptDndModel.draggable.set("currentId", target.dataset.ptId), ptDndModel.draggable.has(target.dataset.ptId)) { | |
| var item = ptDndModel.draggable.get(target.dataset.ptId); | |
| item.hookDragStart(target, event), ptDndNotification.onDragStart(event, eventData, item.type) | |
| } | |
| return !1 | |
| }), document.addEventListener("dragenter", function(_ref) { | |
| var target = _ref.target; | |
| 1 === target.nodeType && !target.classList.contains(CLASSNAME.DRAG_HOVER) && target.hasAttribute(DROPZONE_ATTR_ID) && (angular.element(document.querySelectorAll("." + CLASSNAME.DRAG_HOVER)).removeClass(CLASSNAME.DRAG_HOVER), target.classList.add(CLASSNAME.DRAG_HOVER)) | |
| }), document.addEventListener("dragleave", function(_ref2) { | |
| var target = _ref2.target; | |
| 1 === target.nodeType && target.classList.contains(CLASSNAME.DRAG_HOVER) && target.classList.remove(CLASSNAME.DRAG_HOVER) | |
| }), document.addEventListener("dragend", function() { | |
| document.body.classList.remove(CLASSNAME.BODY), angular.element(document.querySelectorAll("." + CLASSNAME.DROPZONE_HOVER)).removeClass(CLASSNAME.DROPZONE_HOVER), angular.element(document.querySelectorAll("." + CLASSNAME.DRAG_HOVER)).removeClass(CLASSNAME.DRAG_HOVER), ptDndModel.draggable.set("currentId", null) | |
| }), { | |
| link: function(scope, el) { | |
| getSelected = scope.getElements; | |
| var id = ptDndUtils.generateUniqId(); | |
| el[0].setAttribute("draggable", !0), el[0].setAttribute("data-pt-id", id), ptDndModel.draggable.set(id, { | |
| model: scope.conversation, | |
| type: scope.conversation.ConversationID ? "message" : "conversation", | |
| hookDragStart: function(target, event) { | |
| var _this = this, | |
| value = $rootScope.numberElementChecked; | |
| if (scope.conversation.Selected) return scope.$applyAsync(function() { | |
| scope.conversation.Selected = !0, $rootScope.numberElementChecked = value, _this.onDragStart(target, event, getSelected()) | |
| }); | |
| $rootScope.$emit("dnd", { | |
| type: "hook.dragstart", | |
| data: { | |
| before: { | |
| number: value, | |
| ids: _.pluck(getSelected(), "ID") | |
| } | |
| } | |
| }), scope.$applyAsync(function() { | |
| scope.conversation.Selected = !0, $rootScope.numberElementChecked = 1, _this.onDragStart(target, event, [scope.conversation]) | |
| }) | |
| } | |
| }) | |
| } | |
| } | |
| }), angular.module("proton.dnd").directive("ptDropzone", function($rootScope, ptDndUtils, ptDndModel, PTDNDCONSTANTS) { | |
| var CLASSNAME = PTDNDCONSTANTS.CLASSNAME, | |
| DROPZONE_ATTR_ID = PTDNDCONSTANTS.DROPZONE_ATTR_ID; | |
| return document.addEventListener("dragenter", function(_ref) { | |
| var target = _ref.target; | |
| 1 === target.nodeType && target.hasAttribute(DROPZONE_ATTR_ID) && (angular.element(document.querySelectorAll("." + CLASSNAME.DROPZONE_HOVER)).removeClass(CLASSNAME.DROPZONE_HOVER), target.classList.add(CLASSNAME.DROPZONE_HOVER)) | |
| }), document.addEventListener("dragover", function(e) { | |
| if (e.preventDefault(), e.target.hasAttribute(DROPZONE_ATTR_ID)) { | |
| var dragItemId = e.target.getAttribute(DROPZONE_ATTR_ID); | |
| return ptDndModel.dropzone.get(dragItemId).onDragOver(e.target, e), (e.dataTransfer || e.originalEvent.dataTransfer).dropEffect = "move", !1 | |
| } | |
| }), document.addEventListener("drop", function(e) { | |
| if (e.preventDefault(), document.body.classList.remove(CLASSNAME.BODY), e.target.hasAttribute(DROPZONE_ATTR_ID) && ptDndModel.draggable.has("currentId")) { | |
| var dragElmId = e.target.getAttribute(DROPZONE_ATTR_ID), | |
| _JSON$parse = JSON.parse((e.dataTransfer || e.originalEvent.dataTransfer).getData("Text")), | |
| id = _JSON$parse.id; | |
| ptDndModel.dropzone.get(dragElmId).onDropSuccess(e, id), ptDndModel.draggable.get(id).onDropItem(e), angular.element(document.querySelectorAll("." + CLASSNAME.DROPZONE_HOVER)).removeClass(CLASSNAME.DROPZONE_HOVER), angular.element(document.querySelectorAll("." + CLASSNAME.DRAG_HOVER)).removeClass(CLASSNAME.DRAG_HOVER) | |
| } | |
| }), { | |
| type: "A", | |
| link: function(scope, el) { | |
| var unsubscribe = [], | |
| refresh = function() { | |
| ptDndModel.dropzone.reset(), [].slice.call(el[0].querySelectorAll("[data-pt-dropzone-item]")).forEach(function(node) { | |
| var id = ptDndUtils.generateUniqId("drop"); | |
| node.classList.add("ptDnd-dropzone-container"), node.setAttribute(DROPZONE_ATTR_ID, id), ptDndModel.dropzone.set(id, { | |
| value: node.dataset.ptDropzoneItem, | |
| type: node.dataset.ptDropzoneItemType | |
| }) | |
| }) | |
| }, | |
| id = setTimeout(function() { | |
| return refresh(), clearTimeout(id) | |
| }, 1e3); | |
| unsubscribe.push($rootScope.$on("labelsModel", function(e, _ref2) { | |
| var type = _ref2.type; | |
| "cache.refesh" !== type && "cache.update" !== type || refresh() | |
| })), unsubscribe.push($rootScope.$on("$stateChangeSuccess", function() { | |
| _rAF(refresh) | |
| })), scope.$on("$destroy", function() { | |
| unsubscribe.forEach(function(cb) { | |
| return cb() | |
| }), unsubscribe.length = 0 | |
| }) | |
| } | |
| } | |
| }), angular.module("proton.dnd").factory("ptDndModel", function($rootScope) { | |
| var CACHE = {}, | |
| reset = function(type) { | |
| return function() { | |
| return CACHE[type] = {} | |
| } | |
| }, | |
| dispatch = function(type) { | |
| var data = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : {}; | |
| return $rootScope.$emit("ptDnd", { | |
| type: type, | |
| data: data | |
| }) | |
| }; | |
| $rootScope.$on("$stateChangeStart", function() { | |
| reset("draggable") | |
| }); | |
| var make = function(type) { | |
| var has = function(id) { | |
| return !!(CACHE[type] || {})[id] | |
| }, | |
| get = function(id) { | |
| return (CACHE[type] || {})[id] | |
| }; | |
| return { | |
| has: has, | |
| set: function(id, value) { | |
| CACHE[type] = CACHE[type] || {}, "draggable" === type && "currentId" !== id && (CACHE[type][id] = _.extend({ | |
| selectedList: [], | |
| onDragStart: function(target, event) { | |
| var selectedList = arguments.length > 2 && void 0 !== arguments[2] ? arguments[2] : []; | |
| CACHE[type][id].selectedList = selectedList, dispatch("dragstart", { | |
| id: id, | |
| target: target, | |
| event: event, | |
| selectedList: selectedList, | |
| model: CACHE[type][id].model, | |
| type: CACHE[type][id].type | |
| }) | |
| }, | |
| onDropItem: function(event) { | |
| dispatch("drop", { | |
| event: event, | |
| selectedList: CACHE[type][id].selectedList, | |
| model: CACHE[type][id].model, | |
| type: CACHE[type][id].type | |
| }) | |
| } | |
| }, value)), "draggable" === type && "currentId" === id && (CACHE[type][id] = value), "dropzone" === type && (CACHE[type][id] = _.extend({ | |
| onDragOver: function(target, event) { | |
| dispatch("dragover", { | |
| id: id, | |
| target: target, | |
| event: event, | |
| value: CACHE[type][id].value, | |
| type: CACHE[type][id].type | |
| }) | |
| }, | |
| onDropSuccess: function(event, itemId) { | |
| _rAF(function() { | |
| dispatch("dropsuccess", { | |
| itemId: itemId, | |
| event: event, | |
| value: CACHE[type][id].value, | |
| type: CACHE[type][id].type | |
| }) | |
| }) | |
| } | |
| }, value)) | |
| }, | |
| get: get, | |
| reset: reset(type) | |
| } | |
| }; | |
| return { | |
| draggable: make("draggable"), | |
| dropzone: make("dropzone") | |
| } | |
| }), angular.module("proton.dnd").factory("ptDndNotification", function(PTDNDCONSTANTS, gettextCatalog, $rootScope, aboutClient) { | |
| var CLASSNAME = PTDNDCONSTANTS.CLASSNAME, | |
| getMessage = function(total, item) { | |
| var message = gettextCatalog.getPlural(total, "message", "messages", {}), | |
| conversation = gettextCatalog.getPlural(total, "conversation", "conversations", {}); | |
| return gettextCatalog.getString("Move {{total}} {{type}}", { | |
| type: "conversation" === item ? conversation : message, | |
| total: total | |
| }, "notification drag and drop") | |
| }, | |
| isIE11 = aboutClient.isIE11(), | |
| isEdge = aboutClient.isEdge(), | |
| isFirefox = aboutClient.isFirefox(), | |
| suffix = isEdge ? "!important" : "", | |
| $notif = function() { | |
| var $notif = document.createElement("SPAN"); | |
| return $notif.className = CLASSNAME.NOTIF, document.body.appendChild($notif), $notif | |
| }(); | |
| isFirefox && $notif.classList.add(CLASSNAME.NOTIF_FIREFOX); | |
| var show = function() { | |
| return (arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : $notif).classList.add(CLASSNAME.NOTIF_ACTIVE) | |
| }, | |
| hide = function() { | |
| return $notif.classList.remove(CLASSNAME.NOTIF_ACTIVE) | |
| }; | |
| !isFirefox && document.addEventListener("drag", function(e) { | |
| _rAF(function() { | |
| $notif.style.transform = ("translate(" + e.clientX + "px, " + e.clientY + "px) " + suffix).trim() | |
| }) | |
| }), document.addEventListener("dragend", function() { | |
| hide() | |
| }); | |
| var onDragStart = function(e, eventData, type) { | |
| if ($notif.textContent = getMessage($rootScope.numberElementChecked || 1, type), !isIE11 && !isEdge && !isFirefox) { | |
| var img = new Image; | |
| img.src = "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7", eventData.setDragImage(img, 0, 0) | |
| } | |
| isFirefox && eventData.setDragImage($notif, 0, 0), !isIE11 && !isEdge && show() | |
| }; | |
| return { | |
| init: angular.noop, | |
| show: show, | |
| hide: hide, | |
| onDragStart: onDragStart | |
| } | |
| }), angular.module("proton.dnd").factory("actionDnd", function($rootScope, $state, CONSTANTS, ptDndModel, actionConversation, labelsModel, gettextCatalog, notification, ptDndNotification, authentication) { | |
| var NOTIFS = { | |
| APPLY_LABEL: gettextCatalog.getString("Apply label", null, "notification drag and drop"), | |
| star: function(total, type) { | |
| var message = gettextCatalog.getPlural(total, "message", "messages", {}), | |
| conversation = gettextCatalog.getPlural(total, "conversation", "conversations", {}); | |
| return gettextCatalog.getString("Star {{total}} {{type}}", { | |
| type: "conversation" === type ? conversation : message, | |
| total: total | |
| }, "notification drag and drop") | |
| } | |
| }; | |
| ptDndNotification.init(); | |
| var move = function(ids, type, labelID) { | |
| if ("conversation" === type) return actionConversation.move(ids, labelID); | |
| $rootScope.$emit("messageActions", { | |
| action: "move", | |
| data: { | |
| ids: ids, | |
| labelID: labelID | |
| } | |
| }) | |
| }, | |
| label = function(list, type, labelID) { | |
| var ids = _.pluck(list, "ID"), | |
| label = labelsModel.read(labelID), | |
| labels = [(label.Selected = !0, label)]; | |
| if (labelsModel.read(labelID, "folders")) return move(ids, type, labelID); | |
| authentication.user.AlsoArchive && move(ids, type, CONSTANTS.MAILBOX_IDENTIFIERS.archive), "conversation" === type ? actionConversation.label(ids, labels) : $rootScope.$emit("messageActions", { | |
| action: "label", | |
| data: { | |
| messages: list, | |
| labels: labels | |
| } | |
| }), notification.success(NOTIFS.APPLY_LABEL + " " + label.Name) | |
| }, | |
| star = function() { | |
| var list = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : [], | |
| type = arguments[1]; | |
| list.forEach(function(model) { | |
| $rootScope.$emit("elements", { | |
| type: "toggleStar", | |
| data: { | |
| model: model, | |
| type: type | |
| } | |
| }) | |
| }), notification.success(NOTIFS.star(list.length, type)) | |
| }, | |
| selectedList = void 0; | |
| return $rootScope.$on("ptDnd", function(e, _ref) { | |
| var type = _ref.type, | |
| data = _ref.data; | |
| if ("drop" === type && (selectedList = data.selectedList), "dropsuccess" === type) { | |
| var _ptDndModel$draggable = ptDndModel.draggable.get(data.itemId), | |
| model = _ptDndModel$draggable.model, | |
| _type = _ptDndModel$draggable.type, | |
| list = $rootScope.numberElementChecked && selectedList ? selectedList : [model], | |
| ids = _.pluck(list, "ID"); | |
| if (selectedList = void 0, "label" === data.type) return label(list, _type, data.value); | |
| if ("starred" === data.value) return star(list, _type); | |
| move(ids, _type, CONSTANTS.MAILBOX_IDENTIFIERS[data.value]) | |
| } | |
| }), { | |
| init: angular.noop | |
| } | |
| }), angular.module("proton.dnd").factory("ptDndUtils", function() { | |
| function generateUniqId() { | |
| return "" + (arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : "drag-") + Math.random().toString(36).substring(7) | |
| } | |
| function getDragInitiatorNode(node) { | |
| for (var currentNode = node; currentNode.parentNode;) { | |
| if ("true" === currentNode.getAttribute("draggable")) return currentNode; | |
| currentNode = currentNode.parentNode | |
| } | |
| return null | |
| } | |
| return { | |
| generateUniqId: generateUniqId, | |
| getDragInitiatorNode: getDragInitiatorNode | |
| } | |
| }), angular.module("proton.domains").directive("domainsMenuStep", function() { | |
| return { | |
| replace: !0, | |
| templateUrl: "templates/domains/domainsMenuStep.tpl.html" | |
| } | |
| }), angular.module("proton.domains").factory("domainApi", function($http, url) { | |
| var requestURL = url.build("domains"), | |
| create = function(params) { | |
| return $http.post(requestURL(), params) | |
| }, | |
| query = function() { | |
| return $http.get(requestURL()) | |
| }, | |
| available = function() { | |
| return $http.get(requestURL("available")) | |
| }, | |
| catchall = function(domainID, params) { | |
| return $http.put(requestURL(domainID, "catchall"), params) | |
| }, | |
| get = function(id) { | |
| return $http.get(requestURL(id)) | |
| }; | |
| return { | |
| delete: function(id) { | |
| return $http.delete(requestURL(id)) | |
| }, | |
| create: create, | |
| query: query, | |
| available: available, | |
| get: get, | |
| catchall: catchall | |
| } | |
| }), angular.module("proton.domains").factory("domainModel", function($rootScope, domainApi, gettextCatalog) { | |
| function set(newDomains) { | |
| domains = newDomains | |
| } | |
| function catchall(ID, AddressID) { | |
| return domainApi.catchall(ID, { | |
| AddressID: AddressID | |
| }).then(function() { | |
| var _ref = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {}, | |
| _ref$data = _ref.data, | |
| data = void 0 === _ref$data ? {} : _ref$data; | |
| if (1e3 === data.Code) { | |
| return _.findWhere(domains, { | |
| ID: ID | |
| }).CatchAll = AddressID, data | |
| } | |
| throw new Error(data.Error || errorMessage) | |
| }) | |
| } | |
| function fetch() { | |
| return domainApi.query().then(function() { | |
| var _ref2 = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {}, | |
| _ref2$data = _ref2.data, | |
| data = void 0 === _ref2$data ? {} : _ref2$data; | |
| if (1e3 === data.Code) return domains = data.Domains, data.Domains; | |
| throw new Error(data.Error || errorMessage) | |
| }) | |
| } | |
| function clear() { | |
| domains.length = 0 | |
| } | |
| var domains = [], | |
| errorMessage = gettextCatalog.getString("Domain request failed", null, "Error"), | |
| query = function() { | |
| return angular.copy(domains) | |
| }, | |
| get = function(ID) { | |
| return _.findWhere(query(), { | |
| ID: ID | |
| }) | |
| }; | |
| return $rootScope.$on("deleteDomain", function(event, ID) { | |
| var index = _.findIndex(domains, { | |
| ID: ID | |
| }); | |
| index > -1 && (domains.splice(index, 1), $rootScope.$emit("domainsChange", domains)) | |
| }), $rootScope.$on("createDomain", function(event, ID, member) { | |
| var index = _.findIndex(domains, { | |
| ID: ID | |
| }); - 1 === index ? domains.push(member) : _.extend(domains[index], member), $rootScope.$emit("domainsChange", domains) | |
| }), $rootScope.$on("updateDomain", function(event, ID, member) { | |
| var index = _.findIndex(domains, { | |
| ID: ID | |
| }); - 1 === index ? domains.push(member) : _.extend(domains[index], member), $rootScope.$emit("domainsChange", domains) | |
| }), { | |
| query: query, | |
| get: get, | |
| set: set, | |
| fetch: fetch, | |
| clear: clear, | |
| catchall: catchall | |
| } | |
| }), angular.module("proton.domains").factory("pmDomainModel", function(domainApi, gettextCatalog) { | |
| function get() { | |
| return domains | |
| } | |
| function fetch() { | |
| return domainApi.available().then(function() { | |
| var _ref = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {}, | |
| _ref$data = _ref.data, | |
| data = void 0 === _ref$data ? {} : _ref$data; | |
| if (1e3 === data.Code) return clear(), domains.push.apply(domains, _toConsumableArray(data.Domains)), domains; | |
| throw new Error(data.Error || errorMessage) | |
| }) | |
| } | |
| function clear() { | |
| domains.length = 0 | |
| } | |
| var errorMessage = gettextCatalog.getString("Domain request failed", null, "Error"), | |
| domains = []; | |
| return { | |
| get: get, | |
| fetch: fetch, | |
| clear: clear | |
| } | |
| }), angular.module("proton.elements").controller("ElementsController", function($filter, $log, $q, $rootScope, $scope, $state, $stateParams, $window, actionConversation, AttachmentLoader, authentication, labelsModel, limitElementsModel, cache, cacheCounters, confirmModal, CONSTANTS, embedded, eventManager, firstLoad, gettextCatalog, Label, networkActivityTracker, paginationModel, messageActions, settingsApi, AppModel, markedScroll, removeElement, tools) { | |
| function watchElements() { | |
| angular.isDefined(unbindWatcherElements) && unbindWatcherElements(), unbindWatcherElements = $scope.$watch("conversations", function() { | |
| $rootScope.numberElementSelected = getElementsSelected().length, $rootScope.numberElementUnread = cacheCounters.unreadConversation(tools.currentLocation()) | |
| }, !0) | |
| } | |
| function getWildCard() { | |
| return angular.isDefined($stateParams.wildcard) ? $stateParams.wildcard : authentication.user.AutoWildcardSearch | |
| } | |
| function forgeRequestParameters(mailbox) { | |
| var params = { | |
| Page: (~~$stateParams.page || 1) - 1 | |
| }; | |
| if (angular.isDefined($stateParams.filter) && (params.Unread = +("unread" === $stateParams.filter)), angular.isDefined($stateParams.sort)) { | |
| var sort = $stateParams.sort, | |
| desc = "-" === sort.charAt(0); | |
| !0 === desc && (sort = sort.slice(1)), params.Sort = $filter("capitalize")(sort), params.Desc = +desc | |
| } | |
| return "search" === mailbox ? (params.Address = $stateParams.address, params.Label = $stateParams.label, params.Keyword = $stateParams.keyword, params.To = $stateParams.to, params.From = $stateParams.from, params.Subject = $stateParams.subject, params.Begin = $stateParams.begin, params.End = $stateParams.end, params.Attachments = $stateParams.attachments, params.AutoWildcard = getWildCard()) : params.Label = "label" === mailbox ? $stateParams.label : CONSTANTS.MAILBOX_IDENTIFIERS[mailbox], params | |
| } | |
| function isStarred(_ref5) { | |
| var _ref5$LabelIDs = _ref5.LabelIDs, | |
| LabelIDs = void 0 === _ref5$LabelIDs ? [] : _ref5$LabelIDs, | |
| _ref5$Labels = _ref5.Labels, | |
| Labels = void 0 === _ref5$Labels ? [] : _ref5$Labels; | |
| return Labels.length ? _.contains(LabelIDs, CONSTANTS.MAILBOX_IDENTIFIERS.starred) : !!_.findWhere(Labels, { | |
| ID: CONSTANTS.MAILBOX_IDENTIFIERS.starred | |
| }) | |
| } | |
| function getElementsSelected() { | |
| var includeMarked = !(arguments.length > 0 && void 0 !== arguments[0]) || arguments[0], | |
| _$scope$conversations = $scope.conversations, | |
| conversations = void 0 === _$scope$conversations ? [] : _$scope$conversations, | |
| elements = _.where(conversations, { | |
| Selected: !0 | |
| }); | |
| return $state.params.id && authentication.user.ViewLayout === CONSTANTS.ROW_MODE ? _.filter(conversations, function(_ref6) { | |
| var ID = _ref6.ID, | |
| ConversationID = _ref6.ConversationID; | |
| return ID === $state.params.id || ConversationID === $state.params.id | |
| }) : !elements.length && $scope.markedElement && includeMarked ? _.filter(conversations, function(_ref7) { | |
| var ID = _ref7.ID, | |
| ConversationID = _ref7.ConversationID; | |
| return ID === $scope.markedElement.ID || ConversationID === $scope.markedElement.ID | |
| }) : elements | |
| } | |
| function idsSelected() { | |
| return _.pluck(getElementsSelected(), "ID") | |
| } | |
| function getTypeSelected() { | |
| var elementsSelected = getElementsSelected(); | |
| return elementsSelected.length ? elementsSelected[0].ConversationID ? "message" : "conversation" : tools.getTypeList() | |
| } | |
| function redirectUser() { | |
| var name = $state.$current.name, | |
| route = name.replace(".element", ""); | |
| $state.go(route, { | |
| id: "" | |
| }) | |
| } | |
| function goToPage() { | |
| var type = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : "to"; | |
| $stateParams.page && $scope.selectElements("all", !1), $scope.page = ~~$stateParams.page || 1, paginationModel[type]() | |
| } | |
| function openElement(element) { | |
| if (element) { | |
| var params = {}, | |
| sameView = $state.params.id && $state.params.id === element.ConversationID; | |
| if ("conversation" === tools.typeView() && "message" === tools.getTypeList() ? (params.id = element.ConversationID, params.messageID = element.ID) : (params.id = element.ID, params.messageID = null), $scope.selectElements("all", !1), embedded.deallocator(element), AttachmentLoader.flushCache(), $scope.markedElement = element, sameView) return $rootScope.$emit("message.open", { | |
| type: "toggle", | |
| data: { | |
| message: element, | |
| action: "openElement" | |
| } | |
| }); | |
| var route = $state.$current.name.replace(".element", ""); | |
| $state.go(route + ".element", params) | |
| } | |
| } | |
| var unsubscribes = [], | |
| unbindWatcherElements = void 0, | |
| id = setInterval(function() { | |
| $rootScope.$emit("elements", { | |
| type: "refresh.time" | |
| }) | |
| }, 6e4); | |
| $scope.elementsLoaded = !1, $scope.limitReached = !1, $scope.conversations = [], $scope.$on("$stateChangeSuccess", function() { | |
| $scope.elementsLoaded = !1, $scope.limitReached = !1 | |
| }), $scope.senders = function(element) { | |
| return angular.isDefined(element.Senders) ? element.Senders : [element.Sender] | |
| }, $scope.recipients = function(element) { | |
| if (angular.isDefined(element.Recipients)) return element.Recipients; | |
| var recipients = []; | |
| return element.ToList && (recipients = recipients.concat(element.ToList)), element.CCList && (recipients = recipients.concat(element.CCList)), element.BCCList && (recipients = recipients.concat(element.BCCList)), recipients | |
| }; | |
| var displayType = function(type) { | |
| var test = !1, | |
| isColumnsMode = authentication.user.ViewLayout === CONSTANTS.COLUMN_MODE, | |
| isRowsMode = authentication.user.ViewLayout === CONSTANTS.ROW_MODE; | |
| switch (type) { | |
| case "rows": | |
| test = !AppModel.is("mobile") && isRowsMode && !$scope.idDefined(); | |
| break; | |
| case "columns": | |
| test = isColumnsMode && !AppModel.is("mobile"); | |
| break; | |
| case "placeholder": | |
| var idDefined = $scope.idDefined(); | |
| test = isColumnsMode && (!idDefined || idDefined && $rootScope.numberElementChecked > 0) && !AppModel.is("mobile"); | |
| break; | |
| case "mobile": | |
| test = !$scope.idDefined() && AppModel.is("mobile") | |
| } | |
| return test | |
| }; | |
| $scope.displayType = displayType, $scope.startWatchingEvent = function() { | |
| function toggleStar() { | |
| var type = getTypeSelected(); | |
| getElementsSelected().forEach(function(model) { | |
| $rootScope.$emit("elements", { | |
| type: "toggleStar", | |
| data: { | |
| type: type, | |
| model: model | |
| } | |
| }) | |
| }) | |
| } | |
| function nextElement() { | |
| var elementID = $state.params.id; | |
| if (!elementID) return markNext(); | |
| var isRowMode = authentication.user.ViewLayout === CONSTANTS.ROW_MODE, | |
| current = $state.$current.name, | |
| elementTime = $scope.markedElement.Time, | |
| conversationMode = authentication.user.ViewMode === CONSTANTS.CONVERSATION_VIEW_MODE; | |
| cache.more(elementID, elementTime, "previous").then(function(element) { | |
| var id = conversationMode ? element.ConversationID || element.ID : element.ID; | |
| $state.go(current, { | |
| id: id | |
| }), $scope.markedElement = element, $rootScope.$emit("elements", { | |
| type: "switchTo.next.success", | |
| data: element | |
| }), !isRowMode && markedScroll.follow() | |
| }).catch(function(data) { | |
| $rootScope.$emit("elements", { | |
| type: "switchTo.next.error", | |
| data: data | |
| }) | |
| }) | |
| } | |
| function previousElement() { | |
| var elementID = $state.params.id; | |
| if (!elementID) return markPrevious(); | |
| var isRowMode = authentication.user.ViewLayout === CONSTANTS.ROW_MODE, | |
| current = $state.$current.name, | |
| elementTime = $scope.markedElement.Time, | |
| conversationMode = authentication.user.ViewMode === CONSTANTS.CONVERSATION_VIEW_MODE; | |
| cache.more(elementID, elementTime, "next").then(function(element) { | |
| var id = conversationMode ? element.ConversationID || element.ID : element.ID; | |
| $state.go(current, { | |
| id: id | |
| }), $scope.markedElement = element, $rootScope.$emit("elements", { | |
| type: "switchTo.previous.success", | |
| data: element | |
| }), !isRowMode && markedScroll.follow() | |
| }).catch(function(data) { | |
| $rootScope.$emit("elements", { | |
| type: "switchTo.previous.error", | |
| data: data | |
| }) | |
| }) | |
| } | |
| var isOpened = !!$state.params.id, | |
| onElement = function(cb) { | |
| var value = !(arguments.length > 1 && void 0 !== arguments[1]) || arguments[1]; | |
| return function() { | |
| isOpened || (cb.apply(void 0, arguments), "conversation" === tools.typeView() && (isOpened = value)) | |
| } | |
| }; | |
| unsubscribes.push($rootScope.$on("elements", function(e, _ref) { | |
| var type = _ref.type, | |
| _ref$data = _ref.data, | |
| data = void 0 === _ref$data ? {} : _ref$data; | |
| switch (type) { | |
| case "mark": | |
| var thisElement = _.findWhere($scope.conversations, { | |
| ID: data.id | |
| }); | |
| thisElement && $scope.markedElement !== thisElement && $scope.$applyAsync(function() { | |
| $scope.markedElement = thisElement | |
| }); | |
| break; | |
| case "open": | |
| isOpened = !0, $scope.$applyAsync(function() { | |
| return openElement(data.element) | |
| }); | |
| break; | |
| case "close": | |
| isOpened = !1; | |
| break; | |
| case "refresh": | |
| $scope.refreshElements(); | |
| break; | |
| case "switchTo.next": | |
| nextElement(); | |
| break; | |
| case "switchTo.previous": | |
| previousElement() | |
| } | |
| })), $scope.$on("openMarked", onElement(function() { | |
| openElement($scope.markedElement) | |
| })), $scope.$on("left", function() { | |
| redirectUser(), isOpened = !1 | |
| }), $scope.$on("right", onElement(function() { | |
| openElement($scope.markedElement) | |
| })), $scope.$on("selectMark", function() { | |
| $scope.markedElement && $scope.$applyAsync(function() { | |
| $scope.markedElement.Selected = !$scope.markedElement.Selected, $rootScope.numberElementChecked = _.where($scope.conversations, { | |
| Selected: !0 | |
| }).length | |
| }) | |
| }), unsubscribes.push($rootScope.$on("selectElements", function(event, _ref2) { | |
| var value = _ref2.value, | |
| isChecked = _ref2.isChecked; | |
| $scope.$applyAsync(function() { | |
| $scope.selectElements(value, isChecked) | |
| }) | |
| })), $scope.$on("applyLabels", function(event, LabelID) { | |
| $scope.applyLabels(LabelID) | |
| }), $scope.$on("move", function(event, mailbox) { | |
| !isOpened && $scope.move(mailbox) | |
| }), $scope.$on("read", function() { | |
| $scope.read() | |
| }), $scope.$on("unread", function() { | |
| $scope.unread() | |
| }), unsubscribes.push($rootScope.$on("toggleStar", function() { | |
| !isOpened && toggleStar() | |
| })); | |
| var markPrevious = onElement(function() { | |
| if ($scope.conversations) { | |
| var index = $scope.conversations.indexOf($scope.markedElement); | |
| if (index > 0) return $scope.$applyAsync(function() { | |
| $scope.markedElement = $scope.conversations[index - 1] | |
| }), markedScroll.follow(!0); | |
| goToPage("previous") | |
| } | |
| }, !1), | |
| markNext = onElement(function() { | |
| if ($scope.conversations) { | |
| var index = $scope.conversations.indexOf($scope.markedElement); | |
| if (index < $scope.conversations.length - 1) return $scope.$applyAsync(function() { | |
| $scope.markedElement = $scope.conversations[index + 1] | |
| }), markedScroll.follow(); | |
| goToPage("next") | |
| } | |
| }, !1); | |
| $scope.$on("markPrevious", markPrevious), $scope.$on("markNext", markNext), $scope.$on("nextElement", function() { | |
| nextElement() | |
| }), $scope.$on("previousElement", function() { | |
| previousElement() | |
| }), $scope.$on("$destroy", function() { | |
| unsubscribes.forEach(function(callback) { | |
| return callback() | |
| }), unsubscribes.length = 0, clearInterval(id), markedScroll.clear() | |
| }) | |
| }, $scope.refreshElements = function() { | |
| var request = forgeRequestParameters($scope.mailbox); | |
| return ("message" === tools.getTypeList() ? cache.queryMessages(request) : cache.queryConversations(request)).then(function(elements) { | |
| firstLoad.set(!1); | |
| var page = ~~$stateParams.page || 0, | |
| selectedMap = $scope.conversations.reduce(function(map, element) { | |
| return element.Selected && (map[element.ID] = element), map | |
| }, {}); | |
| return $scope.$applyAsync(function() { | |
| var previousConversations = angular.copy($scope.conversations); | |
| if ($scope.elementsLoaded = !0, $scope.conversations = elements.map(function(element) { | |
| return element.Selected = void 0 !== selectedMap[element.ID], element | |
| }), watchElements(), $scope.limitReached = limitElementsModel.isReached() && paginationModel.isMax(), 0 === $scope.conversations.length && page > 0) return $scope.back(); | |
| if ($scope.conversations.length > 0) { | |
| var element = void 0; | |
| if ($scope.markedElement) { | |
| var found = _.findWhere($scope.conversations, { | |
| ID: $scope.markedElement.ID | |
| }); | |
| if (found) element = found; | |
| else { | |
| var previousIndexMarked = _.findIndex(previousConversations, { | |
| ID: $scope.markedElement.ID | |
| }) || 0; | |
| element = $scope.conversations[previousIndexMarked] || _.first($scope.conversations) | |
| } | |
| } else element = $state.params.id ? _.find($scope.conversations, function(_ref3) { | |
| var ID = _ref3.ID, | |
| ConversationID = _ref3.ConversationID; | |
| return $state.params.id === ConversationID || $state.params.id === ID | |
| }) : _.first($scope.conversations); | |
| $scope.markedElement = element | |
| } | |
| }), elements | |
| }, function() { | |
| $scope.elementsLoaded = !0, $scope.conversations = [] | |
| }) | |
| }, $scope.active = function(element) { | |
| return !(0 !== $rootScope.numberElementChecked || !angular.isDefined($state.params.id)) && ($state.params.id === element.ConversationID || $state.params.id === element.ID) | |
| }, $scope.hasLabels = function(_ref4) { | |
| var _ref4$LabelIDs = _ref4.LabelIDs, | |
| LabelIDs = void 0 === _ref4$LabelIDs ? [] : _ref4$LabelIDs, | |
| _ref4$Labels = _ref4.Labels, | |
| Labels = void 0 === _ref4$Labels ? [] : _ref4$Labels; | |
| return LabelIDs.length || Labels.length | |
| }, $scope.hasAttachments = function(element) { | |
| return element.ConversationID ? element.NumAttachments > 0 : element.ContextNumAttachments > 0 | |
| }, $scope.isRead = function(element) { | |
| return element.ConversationID ? 1 === element.IsRead : 0 === element.ContextNumUnread | |
| }, $scope.size = function(element) { | |
| return element.ConversationID ? element.Size : element.ContextSize | |
| }, $scope.isDisabled = function() { | |
| return !$scope.markedElement && (!$rootScope.numberElementChecked && !angular.isDefined($state.params.id)) | |
| }, $scope.isCacheContext = function() { | |
| return tools.cacheContext() | |
| }, $scope.selectElements = function(value, isChecked) { | |
| var actions = { | |
| all: function(element) { | |
| element.Selected = isChecked | |
| }, | |
| read: function(element) { | |
| element.Selected = (0 === element.ContextNumUnread || 1 === element.IsRead) && isChecked | |
| }, | |
| unread: function(element) { | |
| element.Selected = (element.ContextNumUnread > 0 || 0 === element.IsRead) && isChecked | |
| }, | |
| starred: function(element) { | |
| element.Selected = isStarred(element) && isChecked | |
| }, | |
| unstarred: function(element) { | |
| element.Selected = !isStarred(element) && isChecked | |
| } | |
| }; | |
| _.each($scope.conversations, function(element) { | |
| return actions[value](element) | |
| }), $rootScope.numberElementChecked = _.where($scope.conversations, { | |
| Selected: !0 | |
| }).length | |
| }, $scope.read = function() { | |
| var type = getTypeSelected(), | |
| ids = idsSelected(); | |
| "conversation" === type ? actionConversation.read(ids) : "message" === type && $rootScope.$emit("messageActions", { | |
| action: "read", | |
| data: { | |
| ids: ids | |
| } | |
| }) | |
| }, $scope.unread = function() { | |
| var type = getTypeSelected(), | |
| ids = idsSelected(); | |
| "conversation" === type ? actionConversation.unread(ids) : "message" === type && $rootScope.$emit("messageActions", { | |
| action: "unread", | |
| data: { | |
| ids: ids | |
| } | |
| }), angular.isDefined($state.params.id) && $scope.back(!0) | |
| }, $scope.delete = function() { | |
| removeElement({ | |
| getElementsSelected: getElementsSelected, | |
| idsSelected: idsSelected, | |
| getTypeSelected: getTypeSelected | |
| }) | |
| }, $scope.move = function(mailbox) { | |
| var type = getTypeSelected(), | |
| ids = idsSelected(), | |
| labelID = CONSTANTS.MAILBOX_IDENTIFIERS[mailbox]; | |
| 0 !== ids.length && ($rootScope.numberElementChecked = 0, "conversation" === type ? actionConversation.move(ids, labelID) : "message" === type && $rootScope.$emit("messageActions", { | |
| action: "move", | |
| data: { | |
| ids: ids, | |
| labelID: labelID | |
| } | |
| })) | |
| }, $scope.getElements = function() { | |
| return getElementsSelected() | |
| }, $scope.saveLabels = function(labels, alsoArchive) { | |
| var type = getTypeSelected(), | |
| ids = idsSelected(); | |
| if ("conversation" === type) actionConversation.label(ids, labels, alsoArchive); | |
| else if ("message" === type) { | |
| var messages = getElementsSelected(); | |
| $rootScope.$emit("messageActions", { | |
| action: "label", | |
| data: { | |
| messages: messages, | |
| labels: labels, | |
| alsoArchive: alsoArchive | |
| } | |
| }) | |
| } | |
| }, $scope.back = function() { | |
| if (arguments.length > 0 && void 0 !== arguments[0] && arguments[0]) { | |
| var opt = _.extend({}, $stateParams, { | |
| id: null | |
| }); | |
| return $state.go($state.$current.name.replace(".element", ""), opt) | |
| } | |
| $state.go($state.$current.name.replace(".element", ""), { | |
| id: null, | |
| page: ~~$stateParams.page || 1, | |
| label: $stateParams.label | |
| }) | |
| }, $scope.closeLabels = function() { | |
| $(".pm_dropdown").removeClass("active") | |
| }, $scope.displayPaginator = function() { | |
| return !$state.params.id || 0 === authentication.user.ViewLayout | |
| }, $scope.applyLabels = function(labelID) { | |
| var labels = []; | |
| _.each($scope.labels, function(label) { | |
| label.ID === labelID && (label.Selected = !0), labels.push(label) | |
| }), $scope.saveLabels(labels, !0) | |
| }, $scope.goToLabel = function(labelID) { | |
| var params = { | |
| page: void 0, | |
| filter: void 0, | |
| sort: void 0, | |
| label: labelID | |
| }; | |
| $state.go("secured.label", params) | |
| }, | |
| function() { | |
| $scope.markedElement = void 0, $scope.mailbox = tools.currentMailbox(), $scope.conversationsPerPage = authentication.user.NumMessagePerPage, $scope.labels = labelsModel.get(), $scope.messageButtons = authentication.user.MessageButtons, $scope.selectedFilter = $stateParams.filter, $scope.selectedOrder = $stateParams.sort || "-date", $scope.page = ~~$stateParams.page || 1, $scope.startWatchingEvent(), $scope.refreshElements().then(function() { | |
| $scope.$applyAsync(function() { | |
| $scope.selectElements("all", !1) | |
| }) | |
| }, $log.error) | |
| }() | |
| }), angular.module("proton.elements").directive("advancedFilterElement", function($rootScope, $stateParams, CONSTANTS, gettextCatalog, messageApi, confirmModal, labelsModel, networkActivityTracker, cache, notification, eventManager, $state) { | |
| var _BUTTONS_CLASS, getClass = function(name) { | |
| return "advancedFilterElement-" + name | |
| }, | |
| MAILBOX_IDENTIFIERS = CONSTANTS.MAILBOX_IDENTIFIERS, | |
| BUTTONS_CLASS = (_BUTTONS_CLASS = {}, _defineProperty(_BUTTONS_CLASS, getClass("btn-small-to-large"), function() { | |
| return "size" === $stateParams.sort | |
| }), _defineProperty(_BUTTONS_CLASS, getClass("btn-large-to-small"), function() { | |
| return "-size" === $stateParams.sort | |
| }), _defineProperty(_BUTTONS_CLASS, getClass("btn-old-to-new"), function() { | |
| return "date" === $stateParams.sort | |
| }), _defineProperty(_BUTTONS_CLASS, getClass("btn-new-to-old"), function() { | |
| return !$stateParams.sort || "-date" === $stateParams.sort | |
| }), _defineProperty(_BUTTONS_CLASS, getClass("btn-show-all"), function() { | |
| return !($stateParams.sort && "-date" !== $stateParams.sort || $stateParams.filter) | |
| }), _defineProperty(_BUTTONS_CLASS, getClass("btn-unread"), function() { | |
| return "unread" === $stateParams.filter | |
| }), _defineProperty(_BUTTONS_CLASS, getClass("btn-read"), function() { | |
| return "read" === $stateParams.filter | |
| }), _BUTTONS_CLASS), | |
| clearState = function(state) { | |
| return state.replace(".element", "") | |
| }, | |
| switchState = function() { | |
| var opt = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {}; | |
| $state.go(clearState($state.$current.name), _.extend({}, $state.params, { | |
| page: void 0, | |
| id: void 0 | |
| }, opt)) | |
| }, | |
| empty = function(mailbox) { | |
| var title = gettextCatalog.getString("Delete all", null, "Title"), | |
| message = gettextCatalog.getString("Are you sure? This cannot be undone.", null, "Info"), | |
| errorMessage = gettextCatalog.getString("Empty request failed", null, "Error shows when the empty folder request failed"); | |
| if (-1 !== ["drafts", "spam", "trash", "folder"].indexOf(mailbox)) { | |
| var labelID = $stateParams.label || MAILBOX_IDENTIFIERS[mailbox], | |
| MAP_ACTIONS = { | |
| drafts: "emptyDraft", | |
| spam: "emptySpam", | |
| trash: "emptyTrash", | |
| folder: "emptyLabel" | |
| }; | |
| confirmModal.activate({ | |
| params: { | |
| title: title, | |
| message: message, | |
| confirm: function() { | |
| var promise = messageApi[MAP_ACTIONS[mailbox]](labelID).then(function() { | |
| var _ref = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {}, | |
| _ref$data = _ref.data, | |
| data = void 0 === _ref$data ? {} : _ref$data; | |
| if (1e3 === data.Code) return cache.empty(labelID), confirmModal.deactivate(), notification.success(gettextCatalog.getString("Folder emptied", null)), eventManager.call(); | |
| throw new Error(data.Error || errorMessage) | |
| }); | |
| networkActivityTracker.track(promise) | |
| }, | |
| cancel: function() { | |
| confirmModal.deactivate() | |
| } | |
| } | |
| }) | |
| } | |
| }, | |
| orderBy = function(sort) { | |
| return switchState({ | |
| sort: "-date" === sort ? void 0 : sort | |
| }) | |
| }, | |
| filterBy = function(filter) { | |
| return switchState({ | |
| filter: filter | |
| }) | |
| }, | |
| clearFilter = function() { | |
| return switchState({ | |
| filter: void 0, | |
| sort: void 0 | |
| }) | |
| }, | |
| toggleTrashSpam = function() { | |
| return switchState({ | |
| trashspam: angular.isDefined($state.params.trashspam) ? void 0 : 0 | |
| }) | |
| }, | |
| ACTIONS = { | |
| empty: empty, | |
| orderBy: orderBy, | |
| filterBy: filterBy, | |
| clearFilter: clearFilter, | |
| toggleTrashSpam: toggleTrashSpam | |
| }; | |
| return { | |
| replace: !0, | |
| templateUrl: "templates/elements/advancedFilterElement.tpl.html", | |
| link: function(scope, el) { | |
| var $btns = el.find("button"), | |
| onClick = function(e) { | |
| e.preventDefault(); | |
| var action = e.target.getAttribute("data-action"); | |
| action && ACTIONS[action](e.target.getAttribute("data-action-arg")) | |
| }; | |
| _.each($btns, function(button) { | |
| var cssClass = button.classList.item(0); | |
| BUTTONS_CLASS[cssClass] && BUTTONS_CLASS[cssClass]() && button.classList.add("active") | |
| }); | |
| var bindClass = function() { | |
| var labelID = $stateParams.label, | |
| action = labelID && labelsModel.read(labelID, "folders") ? "add" : "remove"; | |
| el[0].classList[action]("advancedFilterElement-state-folder") | |
| }, | |
| unsubscribe = $rootScope.$on("$stateChangeSuccess", bindClass); | |
| bindClass(), $btns.on("click", onClick), scope.$on("$destroy", function() { | |
| $btns.off("click", onClick), unsubscribe() | |
| }) | |
| } | |
| } | |
| }), angular.module("proton.elements").directive("countElementsSelected", function($rootScope) { | |
| return { | |
| replace: !0, | |
| templateUrl: "templates/elements/countElementsSelected.tpl.html", | |
| link: function(scope, element) { | |
| var $btn = element.find(".countElementsSelected-btn-unselect"), | |
| onClick = function() { | |
| return $rootScope.$emit("selectElements", { | |
| value: "all", | |
| isChecked: !1 | |
| }) | |
| }; | |
| $btn.on("click", onClick), scope.$on("$destroy", function() { | |
| $btn.off("click", onClick) | |
| }) | |
| } | |
| } | |
| }), angular.module("proton.elements").directive("elementView", function(tools) { | |
| return { | |
| restrict: "E", | |
| template: "\n <conversation-view ng-if=\"type === 'conversation'\"></conversation-view>\n <message-view ng-if=\"type === 'message'\"></message-view>\n ", | |
| link: function(scope) { | |
| scope.type = tools.typeView() | |
| } | |
| } | |
| }), angular.module("proton.elements").directive("elementsContainer", function($rootScope) { | |
| return { | |
| restrict: "A", | |
| link: function(scope, el) { | |
| var onClick = function(_ref) { | |
| var target = _ref.target; | |
| target && !/ptSelectConversation|customMaskInput/.test(target.className) && $rootScope.$emit("elements", { | |
| type: "open", | |
| data: { | |
| element: scope.conversation | |
| } | |
| }) | |
| }; | |
| el.on("click", onClick), scope.$on("$destroy", function() { | |
| el.off("click", onClick) | |
| }) | |
| } | |
| } | |
| }), angular.module("proton.elements").directive("elementsSelector", function($rootScope, authentication, gettextCatalog, dedentTpl) { | |
| var ORDER_FALSY = ["all", "read", "unread", "star", "unstar"], | |
| ORDER_TRUTHY = ["all", "unread", "read", "unstar", "star"], | |
| ACTIONS = { | |
| all: { | |
| label: gettextCatalog.getString("Select All", null, "Action"), | |
| icon: "fa-check-square-o", | |
| action: "all" | |
| }, | |
| unread: { | |
| label: gettextCatalog.getString("All Unread", null, "Action"), | |
| icon: "fa-eye-slash", | |
| action: "unread" | |
| }, | |
| read: { | |
| label: gettextCatalog.getString("All Read", null, "Action"), | |
| icon: "fa-eye", | |
| action: "read" | |
| }, | |
| unstar: { | |
| label: gettextCatalog.getString("All Unstarred", null, "Action"), | |
| icon: "fa-star-o", | |
| action: "unstarred" | |
| }, | |
| star: { | |
| label: gettextCatalog.getString("All Starred", null, "Action"), | |
| icon: "fa-star", | |
| action: "starred" | |
| } | |
| }, | |
| map = function(list) { | |
| return list.map(function(key) { | |
| return ACTIONS[key] | |
| }) | |
| }, | |
| orderActions = function() { | |
| var order = +authentication.user.MessageButtons; | |
| return map(order ? ORDER_TRUTHY : ORDER_FALSY) | |
| }, | |
| getTemplate = function() { | |
| return orderActions().reduce(function(prev, _ref) { | |
| var label = _ref.label, | |
| icon = _ref.icon, | |
| action = _ref.action; | |
| return prev + dedentTpl('\n <button data-action="' + action + '" class="elementsSelector-btn-action">\n <i class="fa ' + icon + '"></i>\n <span>' + label + "</span>\n </button>\n ") | |
| }, "") | |
| }; | |
| return { | |
| replace: !0, | |
| templateUrl: "templates/elements/elementsSelector.tpl.html", | |
| compile: function(element) { | |
| return element[0].querySelector(".pm_dropdown").insertAdjacentHTML("beforeEnd", getTemplate()), | |
| function(scope, el) { | |
| function onClick(_ref2) { | |
| var currentTarget = _ref2.currentTarget, | |
| value = currentTarget.getAttribute("data-action"); | |
| $rootScope.$emit("selectElements", { | |
| value: value, | |
| isChecked: !0 | |
| }), $rootScope.$emit("closeDropdown") | |
| } | |
| var $btn = el.find(".elementsSelector-btn-action"); | |
| $btn.on("click", onClick), scope.checkedSelectorState = function() { | |
| return _.every(scope.conversations, { | |
| Selected: !0 | |
| }) | |
| }, scope.$on("$destroy", function() { | |
| $btn.off("click", onClick) | |
| }) | |
| } | |
| } | |
| } | |
| }), angular.module("proton.elements").directive("foldersElement", function($rootScope, $state, gettextCatalog, $compile, mailboxIdentifersTemplate) { | |
| var allowedStates = ["secured.allSent.**", "secured.sent.**", "secured.allDrafts.**", "secured.drafts.**", "secured.search.**", "secured.starred.**", "secured.allmail.**", "secured.label.**"], | |
| isAllowedState = function() { | |
| return allowedStates.some(function(key) { | |
| return $state.includes(key) | |
| }) | |
| }, | |
| MAP_LABELS = { | |
| inbox: { | |
| className: "fa-inbox", | |
| tooltip: gettextCatalog.getString("In inbox", null, "Type of label for a message/conversation") | |
| }, | |
| sent: { | |
| className: "fa-send", | |
| tooltip: gettextCatalog.getString("In sent", null, "Type of label for a message/conversation") | |
| }, | |
| drafts: { | |
| className: "fa-file-text-o", | |
| tooltip: gettextCatalog.getString("In drafts", null, "Type of label for a message/conversation") | |
| }, | |
| archive: { | |
| className: "fa-archive", | |
| tooltip: gettextCatalog.getString("In archive", null, "Type of label for a message/conversation") | |
| }, | |
| trash: { | |
| className: "fa-trash-o", | |
| tooltip: gettextCatalog.getString("In trash", null, "Type of label for a message/conversation") | |
| }, | |
| spam: { | |
| className: "fa-ban", | |
| tooltip: gettextCatalog.getString("In spam", null, "Type of label for a message/conversation") | |
| }, | |
| folder: { | |
| className: "fa-folder" | |
| } | |
| }, | |
| _mailboxIdentifersTem = mailboxIdentifersTemplate({ | |
| MAP_LABELS: MAP_LABELS | |
| }), | |
| getTemplateLabels = _mailboxIdentifersTem.getTemplateLabels; | |
| return { | |
| templateUrl: "templates/elements/foldersElement.tpl.html", | |
| replace: !0, | |
| scope: { | |
| conversation: "=" | |
| }, | |
| link: function(scope, el) { | |
| var build = function(event, _ref) { | |
| var _ref$LabelIDs = _ref.LabelIDs, | |
| LabelIDs = void 0 === _ref$LabelIDs ? [] : _ref$LabelIDs, | |
| _ref$Labels = _ref.Labels, | |
| Labels = void 0 === _ref$Labels ? [] : _ref$Labels; | |
| if ((LabelIDs.length || Labels.length) && isAllowedState()) { | |
| var labelIDs = Labels.length ? _.map(Labels, function(_ref2) { | |
| return _ref2.ID | |
| }) : LabelIDs, | |
| tpl = $compile(getTemplateLabels(labelIDs))(scope); | |
| el.empty().append(tpl) | |
| } | |
| }, | |
| unsubscribe = $rootScope.$on("foldersElement." + scope.conversation.ID, build); | |
| build(0, scope.conversation), scope.$on("$destroy", unsubscribe) | |
| } | |
| } | |
| }), angular.module("proton.elements").directive("labelsElement", function($rootScope, labelsModel, authentication, $state) { | |
| var toLabels = function() { | |
| return (arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : []).reduce(function(acc, id) { | |
| var item = labelsModel.read(id, "labels"); | |
| return item && acc.push(item), acc | |
| }, []) | |
| }, | |
| moreVisibility = function(node) { | |
| return { | |
| hide: function() { | |
| node.classList.add("labelsElement-hidden") | |
| }, | |
| show: function() { | |
| _rAF(function() { | |
| return node.classList.remove("labelsElement-hidden") | |
| }) | |
| } | |
| } | |
| }; | |
| return { | |
| restrict: "E", | |
| templateUrl: "templates/elements/labelsElement.tpl.html", | |
| replace: !0, | |
| scope: { | |
| element: "=" | |
| }, | |
| link: function(scope, el, _ref) { | |
| var _ref$limit = _ref.limit, | |
| limit = void 0 === _ref$limit ? 4 : _ref$limit, | |
| moreToggle = moreVisibility(el[0].querySelector(".labelsElement-more")), | |
| build = function(e, _ref2) { | |
| var _ref2$LabelIDs = _ref2.LabelIDs, | |
| LabelIDs = void 0 === _ref2$LabelIDs ? [] : _ref2$LabelIDs, | |
| _ref2$Labels = _ref2.Labels, | |
| Labels = void 0 === _ref2$Labels ? [] : _ref2$Labels; | |
| if (moreToggle.hide(), LabelIDs.length || Labels.length) { | |
| var labelIDs = Labels.length ? _.map(Labels, function(_ref3) { | |
| return _ref3.ID | |
| }) : LabelIDs, | |
| labels = toLabels(labelIDs); | |
| if ("none" !== limit) return scope.labels = labels.length ? angular.copy(labels.slice(0, limit)) : [], void(labels.length > limit && moreToggle.show()); | |
| scope.labels = angular.copy(labels) | |
| } | |
| }, | |
| onClick = function(e) { | |
| if (e.stopPropagation(), e.target.classList.contains("labelsElement-label")) { | |
| var label = e.target.getAttribute("data-label-id"); | |
| $state.go("secured.label", { | |
| label: label | |
| }) | |
| } | |
| e.target.classList.contains("labelsElement-btn-remove") && $rootScope.$emit("messageActions", { | |
| action: "unlabel", | |
| data: { | |
| messageID: scope.element.ID, | |
| conversationID: scope.element.ConversationID, | |
| labelID: e.target.getAttribute("data-label-id") | |
| } | |
| }) | |
| }, | |
| unsubscribe = $rootScope.$on("labelsElement." + scope.element.ID, build); | |
| build(0, scope.element), scope.color = function() { | |
| var _ref4 = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {}, | |
| _ref4$Color = _ref4.Color; | |
| return { | |
| color: void 0 === _ref4$Color ? "inherit" : _ref4$Color | |
| } | |
| }, el.on("click", onClick), scope.$on("$destroy", function() { | |
| el.off("click", onClick), unsubscribe() | |
| }) | |
| } | |
| } | |
| }), angular.module("proton.elements").directive("moveElement", function() { | |
| return { | |
| replace: !0, | |
| templateUrl: "templates/elements/moveElement.tpl.html", | |
| link: function(scope, element) { | |
| function onClick(event) { | |
| if ("BUTTON" === event.target.tagName) { | |
| var action = event.target.getAttribute("data-action"); | |
| if ("delete" === action) return scope.delete(); | |
| scope.move(action) | |
| } | |
| } | |
| element.on("click", onClick), scope.$on("$destroy", function() { | |
| element.off("click", onClick) | |
| }) | |
| } | |
| } | |
| }), angular.module("proton.elements").directive("movedButton", function($state, gettextCatalog, tools) { | |
| var MAP = { | |
| sent: "secured.allSent", | |
| allSent: "secured.sent", | |
| drafts: "secured.allDrafts", | |
| allDrafts: "secured.drafts" | |
| }; | |
| return { | |
| restrict: "E", | |
| replace: !0, | |
| scope: {}, | |
| template: '\n <button class="movedButton-container">\n <div>\n <i class="movedButton-icon fa fa-share-square-o"></i>\n <span class="movedButton-text">' + gettextCatalog.getString("Include moved messages", null, "Link") + "</span>\n </div>\n </button>\n ", | |
| link: function(scope, element) { | |
| var current = tools.filteredState(), | |
| onClick = function() { | |
| return $state.go(MAP[current], _.extend({}, $state.params, { | |
| page: void 0, | |
| id: void 0 | |
| })) | |
| }; | |
| "allSent" !== current && "allDrafts" !== current || element.addClass("active"), element.on("click", onClick), scope.$on("$destroy", function() { | |
| return element.off("click", onClick) | |
| }) | |
| } | |
| } | |
| }), angular.module("proton.elements").directive("movedSelect", function($rootScope, authentication, gettextCatalog, networkActivityTracker, settingsApi) { | |
| var I18N = { | |
| includeMoved: gettextCatalog.getString("Include Moved", null, "Option"), | |
| hideMoved: gettextCatalog.getString("Hide Moved", null, "Option") | |
| }; | |
| return { | |
| restrict: "E", | |
| replace: !0, | |
| scope: {}, | |
| template: '\n <span class="movedSelect-container pm_select inline">\n <select class="movedSelect-select">\n <option value="3">' + I18N.includeMoved + '</option>\n <option value="0">' + I18N.hideMoved + '</option>\n </select>\n <i class="fa fa-angle-down"></i>\n </span>\n ', | |
| link: function(scope, element) { | |
| function onChange() { | |
| var Moved = get(), | |
| promise = settingsApi.updateMoved({ | |
| Moved: Moved | |
| }).then(function() { | |
| var _ref = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {}, | |
| _ref$data = _ref.data, | |
| data = void 0 === _ref$data ? {} : _ref$data; | |
| if (1e3 === data.Code) return authentication.user.Moved = Moved, data; | |
| throw new Error(data.Error) | |
| }); | |
| networkActivityTracker.track(promise) | |
| } | |
| var $select = element.find("select"), | |
| set = function(moved) { | |
| return $select.val(+moved) | |
| }, | |
| get = function() { | |
| return ~~$select.val() | |
| }, | |
| unsubscribe = $rootScope.$on("updateUser", function() { | |
| return set(authentication.user.Moved) | |
| }); | |
| set(authentication.user.Moved), $select.on("change", onChange), scope.$on("$destroy", function() { | |
| unsubscribe(), $select.off("change", onChange) | |
| }) | |
| } | |
| } | |
| }); | |
| var _slicedToArray = function() { | |
| function sliceIterator(arr, i) { | |
| var _arr = [], | |
| _n = !0, | |
| _d = !1, | |
| _e = void 0; | |
| try { | |
| for (var _s, _i = arr[Symbol.iterator](); !(_n = (_s = _i.next()).done) && (_arr.push(_s.value), !i || _arr.length !== i); _n = !0); | |
| } catch (err) { | |
| _d = !0, _e = err | |
| } finally { | |
| try { | |
| !_n && _i.return && _i.return() | |
| } finally { | |
| if (_d) throw _e | |
| } | |
| } | |
| return _arr | |
| } | |
| return function(arr, i) { | |
| if (Array.isArray(arr)) return arr; | |
| if (Symbol.iterator in Object(arr)) return sliceIterator(arr, i); | |
| throw new TypeError("Invalid attempt to destructure non-iterable instance") | |
| } | |
| }(); | |
| angular.module("proton.elements").directive("navElements", function($rootScope, $state, authentication, tools, CONSTANTS) { | |
| var SPECIAL_BOXES = ["drafts", "search", "sent", "allDrafts", "allSent"], | |
| dispatch = function(type) { | |
| var data = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : {}; | |
| return $rootScope.$emit("elements", { | |
| type: type, | |
| data: data | |
| }) | |
| }, | |
| showNextPrev = function() { | |
| var box = tools.currentMailbox(), | |
| rowMode = authentication.user.ViewLayout === CONSTANTS.ROW_MODE, | |
| context = tools.cacheContext(), | |
| notSpecial = -1 === SPECIAL_BOXES.indexOf(box); | |
| return $state.params.id && rowMode && context && notSpecial | |
| }; | |
| return { | |
| replace: !0, | |
| templateUrl: "templates/elements/navElements.tpl.html", | |
| link: function(scope, el) { | |
| var unsubscribe = [], | |
| toggleClass = function() { | |
| var action = showNextPrev() ? "add" : "remove"; | |
| el[0].classList[action]("navElements-displayed") | |
| }, | |
| toggleClassError = function(name, type) { | |
| "success" === type && (el[0].classList.remove("navElements-no-previous"), el[0].classList.remove("navElements-no-next")), "error" === type && el[0].classList.add("navElements-no-" + name) | |
| }; | |
| toggleClass(), unsubscribe.push($rootScope.$on("$stateChangeSuccess", toggleClass)), unsubscribe.push($rootScope.$on("settings", function(event, _ref) { | |
| "viewLayout.updated" === _ref.type && toggleClass() | |
| })), unsubscribe.push($rootScope.$on("elements", function(e, _ref2) { | |
| var type = _ref2.type; | |
| if (/(previous|next)\.(error|success)$/.test(type)) { | |
| var _type$split = type.split("."), | |
| _type$split2 = _slicedToArray(_type$split, 3), | |
| name = _type$split2[1], | |
| flag = _type$split2[2]; | |
| toggleClassError(name, flag) | |
| } | |
| })); | |
| var onClick = function(_ref3) { | |
| var target = _ref3.target; | |
| dispatch("switchTo." + target.getAttribute("data-dest"), { | |
| conversation: scope.conversation, | |
| from: "button" | |
| }) | |
| }; | |
| el.on("click", onClick), scope.$on("$destroy", function() { | |
| el.off("click", onClick), unsubscribe.forEach(function(cb) { | |
| return cb() | |
| }), unsubscribe.length = 0 | |
| }) | |
| } | |
| } | |
| }), angular.module("proton.elements").directive("ptSelectElement", function() { | |
| return { | |
| replace: !0, | |
| templateUrl: "templates/elements/ptSelectElement.tpl.html" | |
| } | |
| }), angular.module("proton.elements").directive("ptSelectElements", function($rootScope) { | |
| return { | |
| link: function(scope, el) { | |
| function onChange(_ref) { | |
| var target = _ref.target, | |
| isChecked = target.checked; | |
| $rootScope.$emit("selectElements", { | |
| value: target.value, | |
| isChecked: isChecked | |
| }), _rAF(function() { | |
| return target.blur() | |
| }) | |
| } | |
| el.on("change", onChange), scope.$watch("value", function() { | |
| return el.change() | |
| }), scope.$on("$destroy", function() { | |
| el.off("change", onChange) | |
| }) | |
| } | |
| } | |
| }), angular.module("proton.elements").directive("ptSelectMultipleElements", function($rootScope) { | |
| function selectConversations(scope) { | |
| return function(previous, from, to) { | |
| _.each(scope.conversations, function(conversation, i) { | |
| if (!(i >= from && i <= to)) return !1; | |
| conversation.Selected = previous.conversation.Selected | |
| }), $rootScope.numberElementChecked = countChecked(scope.conversations) | |
| } | |
| } | |
| var CACHE = {}, | |
| countChecked = function(conversations) { | |
| return _.where(conversations, { | |
| Selected: !0 | |
| }).length | |
| }; | |
| return { | |
| link: function(scope, el) { | |
| function onClick(_ref2) { | |
| var target = _ref2.target, | |
| shiftKey = _ref2.shiftKey, | |
| index = +target.getAttribute("data-index"); | |
| if ("INPUT" === target.nodeName && /ptSelectConversation/.test(target.className)) { | |
| var isChecked = target.checked; | |
| scope.$applyAsync(function() { | |
| if (scope.conversations[index].Selected = isChecked, $rootScope.numberElementChecked = countChecked(scope.conversations), shiftKey && previous) { | |
| var from = Math.min(index, previous.index), | |
| to = Math.max(index, previous.index); | |
| conversationsToSelect(previous, from, to), target.checked = previous.conversation.Selected | |
| } | |
| $rootScope.showWelcome = !1, previous = { | |
| index: index, | |
| conversation: scope.conversations[index] | |
| } | |
| }) | |
| } | |
| } | |
| var previous = null, | |
| conversationsToSelect = selectConversations(scope), | |
| unsubscribe = $rootScope.$on("dnd", function(e, _ref) { | |
| var type = _ref.type, | |
| data = _ref.data; | |
| "hook.dragstart" === type && (CACHE.number = data.before.number, CACHE.ids = data.before.ids, $rootScope.numberElementChecked = 1, _.each(scope.conversations, function(item) { | |
| item.Selected = !1 | |
| })) | |
| }), | |
| onDragEnd = function() { | |
| _rAF(function() { | |
| scope.$applyAsync(function() { | |
| _.each(scope.conversations, function(item) { | |
| CACHE.ids && (item.Selected = -1 !== CACHE.ids.indexOf(item.ID)), 1 !== $rootScope.numberElementChecked || CACHE.number || (item.Selected = !1) | |
| }), $rootScope.numberElementChecked = CACHE.number || countChecked(scope.conversations), delete CACHE.number, delete CACHE.ids | |
| }) | |
| }) | |
| }; | |
| el.on("click", onClick), document.addEventListener("dragend", onDragEnd), scope.$on("$destroy", function() { | |
| el.off("click", onClick), document.removeEventListener("dragend", onDragEnd), unsubscribe(), delete CACHE.number, | |
| delete CACHE.ids | |
| }) | |
| } | |
| } | |
| }), angular.module("proton.elements").directive("ptStar", function($rootScope, CONSTANTS, gettextCatalog, tools, actionConversation) { | |
| function isStarred(_ref) { | |
| var _ref$LabelIDs = _ref.LabelIDs, | |
| LabelIDs = void 0 === _ref$LabelIDs ? [] : _ref$LabelIDs, | |
| _ref$Labels = _ref.Labels, | |
| Labels = void 0 === _ref$Labels ? [] : _ref$Labels; | |
| return Labels.length ? _.findWhere(Labels, { | |
| ID: CONSTANTS.MAILBOX_IDENTIFIERS.starred | |
| }) : LabelIDs.some(function(label) { | |
| return label === CONSTANTS.MAILBOX_IDENTIFIERS.starred | |
| }) | |
| } | |
| function toggleStar(_ref2) { | |
| var model = _ref2.model, | |
| type = _ref2.type, | |
| action = isStarred(model) ? "unstar" : "star"; | |
| "conversation" === type && actionConversation[action]([model.ID]), "message" === type && $rootScope.$emit("messageActions", { | |
| action: action, | |
| data: { | |
| ids: [model.ID] | |
| } | |
| }) | |
| } | |
| return $rootScope.$on("elements", function(e, _ref3) { | |
| var type = _ref3.type, | |
| _ref3$data = _ref3.data, | |
| data = void 0 === _ref3$data ? {} : _ref3$data; | |
| "toggleStar" === type && toggleStar(data) | |
| }), { | |
| scope: { | |
| model: "=" | |
| }, | |
| replace: !0, | |
| templateUrl: "templates/elements/ptStar.tpl.html", | |
| link: function(scope, el, attr) { | |
| function onClick(e) { | |
| "A" === e.target.nodeName && (e.preventDefault(), e.stopPropagation(), toggleStar({ | |
| model: scope.model, | |
| type: type | |
| })) | |
| } | |
| var type = attr.ptStarType || tools.getTypeList(); | |
| scope.isStarred = function() { | |
| return isStarred(scope.model) | |
| }, el.on("click", onClick), scope.$on("$destroy", function() { | |
| el.off("click", onClick), $(".tooltip").remove() | |
| }) | |
| } | |
| } | |
| }), angular.module("proton.elements").directive("searchLimitReached", function(gettextCatalog) { | |
| var message = gettextCatalog.getString("Your search matched too many results. Please limit your search and try again.", null, "Inform the user that he reach the search limit"); | |
| return { | |
| replace: !0, | |
| restrict: "E", | |
| template: '<div class="searchLimit-container"></div>', | |
| link: function(scope, element) { | |
| element[0].textContent = message | |
| } | |
| } | |
| }), angular.module("proton.ui").directive("timeElement", function($rootScope, cache, tools) { | |
| function getTime(_ref) { | |
| var ID = _ref.ID, | |
| Time = _ref.Time, | |
| type = tools.getTypeList(), | |
| loc = tools.currentLocation(), | |
| time = "conversation" === type ? cache.getTime(ID, loc) : Time, | |
| m = moment.unix(time), | |
| format = m.isSame(moment(), "day") ? "LT" : "ll"; | |
| return m.format(format) | |
| } | |
| return { | |
| restrict: "E", | |
| replace: !0, | |
| template: '<time class="time"></time>', | |
| link: function(scope, element) { | |
| function displayTime() { | |
| element[0].textContent = getTime(scope.conversation) | |
| } | |
| var unsubscribe = $rootScope.$on("elements", function(e, _ref2) { | |
| "refresh.time" === _ref2.type && displayTime() | |
| }); | |
| displayTime(), scope.$on("$destroy", function() { | |
| return unsubscribe() | |
| }) | |
| } | |
| } | |
| }), angular.module("proton.elements").factory("elementsError", function($rootScope) { | |
| function last() { | |
| return errors.length ? _.last(errors) : {} | |
| } | |
| var errors = []; | |
| return $rootScope.$on("elements", function(event, _ref) { | |
| var type = _ref.type, | |
| _ref$data = _ref.data, | |
| data = void 0 === _ref$data ? {} : _ref$data; | |
| "error" === type && errors.push(data) | |
| }), $rootScope.$on("$stateChangeSuccess", function() { | |
| errors.length = 0 | |
| }), { | |
| init: angular.noop, | |
| last: last | |
| } | |
| }), angular.module("proton.elements").factory("firstLoad", function($rootScope, tools) { | |
| function cleanState(state) { | |
| return tools.filteredState(state) | |
| } | |
| function get() { | |
| return first | |
| } | |
| function set(state) { | |
| first = state | |
| } | |
| var first = !0; | |
| return $rootScope.$on("$stateChangeStart", function(event, toState, toParams, fromState) { | |
| first = cleanState(fromState.name) !== cleanState(toState.name) | |
| }), { | |
| get: get, | |
| set: set | |
| } | |
| }), angular.module("proton.elements").factory("limitElementsModel", function($rootScope) { | |
| function set(_ref) { | |
| var _ref$Limit = _ref.Limit, | |
| Limit = void 0 === _ref$Limit ? 0 : _ref$Limit, | |
| _ref$Total = _ref.Total, | |
| Total = void 0 === _ref$Total ? 0 : _ref$Total; | |
| CACHE.limit = Limit, CACHE.total = Total | |
| } | |
| var CACHE = {}, | |
| isReached = function() { | |
| return CACHE.total !== CACHE.limit | |
| }; | |
| return $rootScope.$on("elements", function(event, _ref2) { | |
| var type = _ref2.type, | |
| _ref2$data = _ref2.data, | |
| data = void 0 === _ref2$data ? {} : _ref2$data; | |
| "setLimit" === type && set(data) | |
| }), { | |
| init: angular.noop, | |
| isReached: isReached | |
| } | |
| }), angular.module("proton.elements").factory("removeElement", function(gettextCatalog, AppModel, actionConversation, messageActions, confirmModal, $state, $rootScope, notification, tools) { | |
| function redirectUser() { | |
| var route = $state.$current.name.replace(".element", ""); | |
| $state.go(route, { | |
| id: "" | |
| }) | |
| } | |
| var I18N = { | |
| TITLE: gettextCatalog.getString("Delete", null, "Title"), | |
| MESSAGE: gettextCatalog.getString("Are you sure? This cannot be undone.", null, "Info"), | |
| DRAFT_INFO: gettextCatalog.getString("A draft selected is open in a composer, this action will close the composer and delete the message.", null, "Info"), | |
| TYPES: { | |
| message: function(n) { | |
| return gettextCatalog.getPlural(n, "message", "messages", {}, "Type element") | |
| }, | |
| conversation: function(n) { | |
| return gettextCatalog.getPlural(n, "conversation", "conversations", {}, "Type element") | |
| } | |
| }, | |
| success: function(total, item) { | |
| return gettextCatalog.getString("{{total}} {{item}} removed", { | |
| total: total, | |
| item: item | |
| }, "Remove element") | |
| } | |
| }, | |
| lookForOpenDraft = function() { | |
| var ids = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : [], | |
| getElementsSelected = arguments[1], | |
| mapComposer = (AppModel.get("composerList") || []).reduce(function(acc, item) { | |
| return acc[item.ID] = "ID", acc[item.ConversationID] = "ConversationID", acc | |
| }, {}), | |
| listOpenedDraft = ids.reduce(function(acc, id) { | |
| return mapComposer[id] && acc.push({ | |
| id: id, | |
| key: mapComposer[id] | |
| }), acc | |
| }, []); | |
| if ($state.includes("secured.drafts.**") && listOpenedDraft.length) { | |
| var selectedMap = getElementsSelected().reduce(function(acc, msg) { | |
| return acc.ConversationID[msg.ConversationID] = msg, acc.ID[msg.ID] = msg, acc | |
| }, { | |
| ConversationID: {}, | |
| ID: {} | |
| }); | |
| return { | |
| isDraftOpen: !0, | |
| drafts: listOpenedDraft.map(function(_ref) { | |
| var id = _ref.id, | |
| key = _ref.key; | |
| return selectedMap[key][id] | |
| }), | |
| message: I18N.MESSAGE + " <br><p><i>" + I18N.DRAFT_INFO + "</i></p>" | |
| } | |
| } | |
| return { | |
| message: I18N.MESSAGE | |
| } | |
| }, | |
| removeList = function() { | |
| var _ref2 = _asyncToGenerator(regeneratorRuntime.mark(function _callee(ids, context, labelID) { | |
| return regeneratorRuntime.wrap(function(_context) { | |
| for (;;) switch (_context.prev = _context.next) { | |
| case 0: | |
| if ("conversation" !== context) { | |
| _context.next = 2; | |
| break | |
| } | |
| return _context.abrupt("return", actionConversation.remove(ids, labelID)); | |
| case 2: | |
| return _context.abrupt("return", messageActions.destroy(ids)); | |
| case 3: | |
| case "end": | |
| return _context.stop() | |
| } | |
| }, _callee, void 0) | |
| })); | |
| return function(_x2, _x3, _x4) { | |
| return _ref2.apply(this, arguments) | |
| } | |
| }(); | |
| return function() { | |
| var _ref3 = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {}, | |
| getElementsSelected = _ref3.getElementsSelected, | |
| idsSelected = _ref3.idsSelected, | |
| getTypeSelected = _ref3.getTypeSelected, | |
| ids = idsSelected(), | |
| context = getTypeSelected(), | |
| _lookForOpenDraft = lookForOpenDraft(ids, getElementsSelected), | |
| message = _lookForOpenDraft.message, | |
| isDraftOpen = _lookForOpenDraft.isDraftOpen, | |
| _lookForOpenDraft$dra = _lookForOpenDraft.drafts, | |
| drafts = void 0 === _lookForOpenDraft$dra ? [] : _lookForOpenDraft$dra, | |
| labelID = tools.currentLocation(); | |
| confirmModal.activate({ | |
| params: { | |
| message: message, | |
| title: I18N.TITLE, | |
| cancel: confirmModal.deactivate, | |
| confirm: function() { | |
| var _ref4 = _asyncToGenerator(regeneratorRuntime.mark(function _callee2() { | |
| return regeneratorRuntime.wrap(function(_context2) { | |
| for (;;) switch (_context2.prev = _context2.next) { | |
| case 0: | |
| return confirmModal.deactivate(), _context2.next = 3, removeList(ids, context, labelID); | |
| case 3: | |
| isDraftOpen && drafts.forEach(function(message) { | |
| $rootScope.$emit("composer.update", { | |
| type: "close.message", | |
| data: { | |
| message: message | |
| } | |
| }) | |
| }), notification.success(I18N.success(ids.length, I18N.TYPES[context](ids.length))), $rootScope.showWelcome = !1, $rootScope.numberElementChecked = 0, redirectUser(); | |
| case 8: | |
| case "end": | |
| return _context2.stop() | |
| } | |
| }, _callee2, void 0) | |
| })); | |
| return function() { | |
| return _ref4.apply(this, arguments) | |
| } | |
| }() | |
| } | |
| }) | |
| } | |
| }), angular.module("proton.filter").directive("customFilterList", function($rootScope, authentication, networkActivityTracker, Filter, gettextCatalog, notification, filterModal, confirmModal, eventManager) { | |
| return { | |
| replace: !0, | |
| restrict: "E", | |
| templateUrl: "templates/filter/customFilterList.tpl.html", | |
| scope: {}, | |
| link: function(scope) { | |
| function changeCustomFilterStatus(filter, status) { | |
| filter.Status = status ? 1 : 0, 0 === filter.Status ? scope.disableCustomFilter(filter) : 1 === filter.Status && scope.enableCustomFilter(filter) | |
| } | |
| var unsubscribe = []; | |
| scope.customFilters = null, networkActivityTracker.track(Filter.query().then(function(_ref) { | |
| var _ref$data = _ref.data, | |
| data = void 0 === _ref$data ? {} : _ref$data; | |
| if (1e3 === data.Code) return data.Filters; | |
| throw new Error(data.Error) | |
| })).then(function(result) { | |
| return scope.customFilters = result | |
| }), unsubscribe.push($rootScope.$on("changeCustomFilterStatus", function(event, _ref2) { | |
| var id = _ref2.id, | |
| status = _ref2.status, | |
| filter = _.findWhere(scope.customFilters, { | |
| ID: id | |
| }); | |
| filter && changeCustomFilterStatus(filter, status) | |
| })), scope.filterDragControlListeners = { | |
| containment: ".pm_sort", | |
| accept: function(sourceItemHandleScope, destSortableScope) { | |
| return sourceItemHandleScope.itemScope.sortableScope.$id === destSortableScope.$id | |
| }, | |
| dragStart: function() { | |
| scope.itemMoved = !0 | |
| }, | |
| dragEnd: function() { | |
| scope.itemMoved = !1 | |
| }, | |
| orderChanged: function() { | |
| var order = []; | |
| _.each(scope.customFilters, function(filter, index) { | |
| order[index] = filter.Priority, filter.Priority = index + 1 | |
| }), networkActivityTracker.track(Filter.order({ | |
| Order: order | |
| }).then(function(_ref3) { | |
| var _ref3$data = _ref3.data, | |
| data = void 0 === _ref3$data ? {} : _ref3$data; | |
| if (1e3 === data.Code) return notification.success(gettextCatalog.getString("Order saved", null, "Info")); | |
| throw new Error(data.Error || gettextCatalog.getString("Unable to save your changes, please try again.", null, "Error")) | |
| })) | |
| } | |
| }, scope.$on("$destroy", function() { | |
| unsubscribe.forEach(function(cb) { | |
| return cb() | |
| }), unsubscribe.length = 0 | |
| }), scope.$on("deleteFilter", function(event, filterId) { | |
| if (!scope.itemMoved) { | |
| var index = _.findIndex(scope.customFilters, { | |
| ID: filterId | |
| }); - 1 !== index && scope.customFilters.splice(index, 1) | |
| } | |
| }), scope.$on("createFilter", function(event, filterId, filter) { | |
| if (!scope.itemMoved) { | |
| var index = _.findIndex(scope.customFilters, { | |
| ID: filterId | |
| }); - 1 === index ? scope.customFilters.push(filter) : scope.customFilters[index] = filter | |
| } | |
| }), scope.$on("updateFilter", function(event, filterId, filter) { | |
| if (!scope.itemMoved) { | |
| var index = _.findIndex(scope.customFilters, { | |
| ID: filterId | |
| }); - 1 === index ? scope.customFilters.push(filter) : scope.customFilters[index] = filter | |
| } | |
| }), scope.addCustomFilter = function() { | |
| var activeCustomFilters = _.where(scope.customFilters, { | |
| Status: 1 | |
| }); | |
| if (!authentication.hasPaidMail() && 1 === activeCustomFilters.length) return notification.info(gettextCatalog.getString('Free ProtonMail accounts are limited to 1 custom filter. Please <a href="/dashboard">upgrade</a> to get unlimited filters.', null, "Info")); | |
| filterModal.activate({ | |
| params: { | |
| mode: "simple", | |
| close: function() { | |
| filterModal.deactivate() | |
| } | |
| } | |
| }) | |
| }, scope.addSieveFilter = function() { | |
| var activeCustomFilters = _.where(scope.customFilters, { | |
| Status: 1 | |
| }); | |
| if (!authentication.hasPaidMail() && 1 === activeCustomFilters.length) return notification.info(gettextCatalog.getString('Free ProtonMail accounts are limited to 1 custom filter. Please <a href="/dashboard">upgrade</a> to get unlimited filters.', null, "Info")); | |
| filterModal.activate({ | |
| params: { | |
| mode: "complex", | |
| close: function() { | |
| filterModal.deactivate() | |
| } | |
| } | |
| }) | |
| }, scope.isSimple = function(filter) { | |
| return filter.Simple && Object.keys(filter.Simple).length | |
| }, scope.editCustomFilter = function(filter) { | |
| var complex = arguments.length > 1 && void 0 !== arguments[1] && arguments[1]; | |
| filterModal.activate({ | |
| params: { | |
| mode: !complex && scope.isSimple(filter) ? "simple" : "complex", | |
| filter: filter, | |
| close: function() { | |
| filterModal.deactivate() | |
| } | |
| } | |
| }) | |
| }, scope.deleteCustomFilter = function(filter) { | |
| var title = gettextCatalog.getString("Delete Filter", null, "Title"), | |
| message = gettextCatalog.getString("Are you sure you want to delete this filter?", null, "Info"); | |
| confirmModal.activate({ | |
| params: { | |
| title: title, | |
| message: message, | |
| confirm: function() { | |
| networkActivityTracker.track(Filter.delete(filter).then(function(_ref4) { | |
| var _ref4$data = _ref4.data, | |
| data = void 0 === _ref4$data ? {} : _ref4$data; | |
| if (1e3 === data.Code) return eventManager.call(), notification.success(gettextCatalog.getString("Custom filter deleted", null, "Info")); | |
| throw new Error(data.Error) | |
| })), confirmModal.deactivate() | |
| }, | |
| cancel: function() { | |
| confirmModal.deactivate() | |
| } | |
| } | |
| }) | |
| }, scope.enableCustomFilter = function(filter) { | |
| return networkActivityTracker.track(Filter.enable(filter).then(function(_ref5) { | |
| var _ref5$data = _ref5.data, | |
| data = void 0 === _ref5$data ? {} : _ref5$data; | |
| if (1e3 === data.Code) return notification.success(gettextCatalog.getString("Status updated", null, "Info")); | |
| throw filter.Status = 0, new Error(data.Error) | |
| })) | |
| }, scope.disableCustomFilter = function(filter) { | |
| return networkActivityTracker.track(Filter.disable(filter).then(function(_ref6) { | |
| var _ref6$data = _ref6.data, | |
| data = void 0 === _ref6$data ? {} : _ref6$data; | |
| if (1e3 === data.Code) return notification.success(gettextCatalog.getString("Status updated", null, "Info")); | |
| throw filter.Status = 1, new Error(data.Error) | |
| })) | |
| } | |
| } | |
| } | |
| }), angular.module("proton.filter").directive("emailBlockButton", function(filterAddressModal) { | |
| return { | |
| replace: !0, | |
| restrict: "E", | |
| templateUrl: "templates/filter/emailBlockButton.tpl.html", | |
| scope: {}, | |
| link: function(scope, elem, _ref) { | |
| var targetList = _ref.targetList, | |
| onClick = function() { | |
| filterAddressModal.activate({ | |
| params: { | |
| type: targetList, | |
| close: function() { | |
| filterAddressModal.deactivate() | |
| } | |
| } | |
| }) | |
| }; | |
| elem.on("click", onClick), scope.$on("$destroy", function() { | |
| elem.off("click", onClick) | |
| }) | |
| } | |
| } | |
| }), angular.module("proton.filter").directive("emailBlockList", function($rootScope, spamListModel, gettextCatalog) { | |
| var I18N = { | |
| whitelist: gettextCatalog.getString("Whitelist", null, "Info"), | |
| blacklist: gettextCatalog.getString("Blacklist", null, "Info") | |
| }, | |
| CLASSNAMES = { | |
| LIST: "emailBlockList-list", | |
| BTN_SWITCH: "emailBlockList-btn-switch", | |
| BTN_DELETE: "emailBlockList-btn-delete" | |
| }, | |
| onEvent = function(element, type, callback) { | |
| return element.addEventListener(type, callback), | |
| function() { | |
| return element.removeEventListener(type, callback) | |
| } | |
| }; | |
| return { | |
| replace: !0, | |
| restrict: "E", | |
| templateUrl: "templates/filter/emailBlockList.tpl.html", | |
| scope: { | |
| listType: "@" | |
| }, | |
| link: function(scope, elem, _ref) { | |
| var switchTo = _ref.switchTo, | |
| unsubscribe = [], | |
| list = spamListModel.list(spamListModel.getType(scope.listType)), | |
| tbody = elem[0].querySelector("." + CLASSNAMES.LIST); | |
| scope.filterName = I18N[scope.listType], list.get().then(function(list) { | |
| scope.$applyAsync(function() { | |
| return scope.entries = list | |
| }) | |
| }), unsubscribe.push($rootScope.$on("filters", function() { | |
| list.get().then(function(list) { | |
| scope.$applyAsync(function() { | |
| scope.entries = _.uniq(list, !1, "ID"), $(".tooltip").hide() | |
| }) | |
| }) | |
| })); | |
| var onScroll = _.throttle(function() { | |
| if (!list.isLoading() && !list.isEnding()) { | |
| var elementCount = scope.entries.length, | |
| triggerFetch = elementCount - 50; | |
| (tbody.scrollTop + tbody.clientHeight) / tbody.scrollHeight > triggerFetch / elementCount && list.get().then(function(list) { | |
| scope.$applyAsync(function() { | |
| scope.entries = _.uniq(scope.entries.concat(list), !1, "ID") | |
| }) | |
| }) | |
| } | |
| }, 100), | |
| onClick = function(_ref2) { | |
| var target = _ref2.target; | |
| "BUTTON" === target.nodeName && (target.classList.contains(CLASSNAMES.BTN_SWITCH) && spamListModel.move(target.dataset.entryId, spamListModel.getType(switchTo)), target.classList.contains(CLASSNAMES.BTN_DELETE) && spamListModel.destroy(target.dataset.entryId)) | |
| }; | |
| unsubscribe.push(onEvent(tbody, "scroll", onScroll)), unsubscribe.push(onEvent(elem[0], "click", onClick)), scope.$on("$destroy", function() { | |
| _.each(unsubscribe, function(cb) { | |
| return cb() | |
| }), unsubscribe.length = 0, spamListModel.clear() | |
| }) | |
| } | |
| } | |
| }), angular.module("proton.filter").directive("filterView", function() { | |
| return { | |
| replace: !0, | |
| restrict: "E", | |
| templateUrl: "templates/filter/filterView.tpl.html", | |
| scope: {} | |
| } | |
| }), angular.module("proton.filter").directive("sieveLabelInput", function() { | |
| return { | |
| replace: !0, | |
| restrict: "E", | |
| templateUrl: "templates/filter/sieveLabelInput.tpl.html", | |
| scope: { | |
| sieve: "=" | |
| }, | |
| link: { | |
| pre: function(scope, elem) { | |
| var unsubscribe = []; | |
| scope.codeMirrorOptions = { | |
| lineWrapping: !0, | |
| lineNumbers: !0, | |
| readOnly: !1, | |
| fixedGutter: !1, | |
| lint: { | |
| delay: 800 | |
| }, | |
| gutters: ["CodeMirror-lint-markers"], | |
| autoRefresh: !0, | |
| mode: "sieve" | |
| }; | |
| var editor = null, | |
| unicodeClassification = { | |
| "'": ["‹", "›", "‚", "‘", "‛", "’", "â›", "âœ", "â®", "â¯"], | |
| '"': ["«", "»", "„", "“", "‟", "â€", "â", "âž", "ã€", "〞", "〟", """] | |
| }, | |
| regexMap = _.mapObject(unicodeClassification, function(value) { | |
| return new RegExp("[" + value.join("") + "]", "g") | |
| }); | |
| scope.codeMirrorLoaded = function(codemirror) { | |
| editor = codemirror, editor.on("change", function() { | |
| var value = editor.getValue(); | |
| if (_.values(regexMap).some(function(regex) { | |
| return regex.exec(value) | |
| })) { | |
| var sanitizedValue = _.reduce(_.keys(regexMap), function(interValue, ascii) { | |
| return interValue.replace(regexMap[ascii], ascii) | |
| }, value), | |
| cursor = editor.getCursor(); | |
| editor.setValue(sanitizedValue), editor.setCursor(cursor) | |
| } | |
| }) | |
| }; | |
| var focusCodeMirror = function() { | |
| null !== editor && editor.focus() | |
| }, | |
| sieveLabel = elem.find("label"); | |
| sieveLabel.on("click.focusSieve", focusCodeMirror), unsubscribe.push(function() { | |
| return sieveLabel.off("click.focusSieve") | |
| }), scope.$on("$destroy", function() { | |
| _.each(unsubscribe, function(cb) { | |
| return cb() | |
| }), unsubscribe.length = 0 | |
| }) | |
| } | |
| } | |
| } | |
| }), angular.module("proton.filter").directive("spamListSearch", function(spamListModel) { | |
| return { | |
| replace: !0, | |
| restrict: "E", | |
| templateUrl: "templates/filter/spamListSearch.tpl.html", | |
| scope: {}, | |
| link: function(scope, el) { | |
| var $input = el.find("input"), | |
| onInput = _.debounce(function(_ref) { | |
| var target = _ref.target; | |
| spamListModel.search(target.value.trim()) | |
| }, 500); | |
| $input.on("input", onInput), scope.$on("$destroy", function() { | |
| $input.off("input", onInput) | |
| }) | |
| } | |
| } | |
| }), angular.module("proton.filter").directive("spamLists", function() { | |
| return { | |
| replace: !0, | |
| restrict: "E", | |
| templateUrl: "templates/filter/spamLists.tpl.html" | |
| } | |
| }), angular.module("proton.filter").factory("filterModal", function($timeout, $rootScope, pmModal, gettextCatalog, Filter, networkActivityTracker, notify, CONSTANTS, eventManager, labelModal, labelsModel, sieveLint) { | |
| var TRANSLATIONS = { | |
| TYPES: [{ | |
| label: gettextCatalog.getString("Select", null, "Filter modal type"), | |
| value: "select" | |
| }, { | |
| label: gettextCatalog.getString("the subject", null, "Filter modal type"), | |
| value: "subject" | |
| }, { | |
| label: gettextCatalog.getString("the sender", null, "Filter modal type"), | |
| value: "sender" | |
| }, { | |
| label: gettextCatalog.getString("the recipient", null, "Filter modal type"), | |
| value: "recipient" | |
| }, { | |
| label: gettextCatalog.getString("the attachments", null, "Filter modal type"), | |
| value: "attachments" | |
| }], | |
| COMPARATORS: [{ | |
| label: gettextCatalog.getString("contains", null, "Condition for custom filter"), | |
| value: "contains" | |
| }, { | |
| label: gettextCatalog.getString("is exactly", null, "Condition for custom filter"), | |
| value: "is" | |
| }, { | |
| label: gettextCatalog.getString("begins with", null, "Condition for custom filter"), | |
| value: "starts" | |
| }, { | |
| label: gettextCatalog.getString("ends with", null, "Condition for custom filter"), | |
| value: "ends" | |
| }, { | |
| label: gettextCatalog.getString("matches", null, "Condition for custom filter"), | |
| value: "matches" | |
| }, { | |
| label: gettextCatalog.getString("does not contain", null, "Condition for custom filter"), | |
| value: "!contains" | |
| }, { | |
| label: gettextCatalog.getString("is not", null, "Condition for custom filter"), | |
| value: "!is" | |
| }, { | |
| label: gettextCatalog.getString("does not begin with", null, "Condition for custom filter"), | |
| value: "!starts" | |
| }, { | |
| label: gettextCatalog.getString("does not end with", null, "Condition for custom filter"), | |
| value: "!ends" | |
| }, { | |
| label: gettextCatalog.getString("does not match", null, "Condition for custom filter"), | |
| value: "!matches" | |
| }], | |
| OPERATORS: [{ | |
| label: gettextCatalog.getString("all", null, "Filter modal operators"), | |
| value: "all" | |
| }, { | |
| label: gettextCatalog.getString("any", null, "Filter modal operators"), | |
| value: "any" | |
| }], | |
| ERROR_PATTERN: gettextCatalog.getString("Text or pattern already included", null, "Error"), | |
| FILTER_UPDATED_SUCCESS: gettextCatalog.getString("Filter updated", null, "Notification"), | |
| FILTER_CREATED_SUCCESS: gettextCatalog.getString("Filter created", null, "Notification") | |
| }, | |
| filterNewLabel = function() { | |
| var _ref = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {}, | |
| _ref$create = _ref.create, | |
| create = void 0 === _ref$create ? [] : _ref$create, | |
| type = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : labelsModel.IS_LABEL; | |
| return angular.copy(create).filter(function(_ref2) { | |
| return _ref2.Exclusive === type | |
| }) | |
| }; | |
| return pmModal({ | |
| controllerAs: "ctrl", | |
| templateUrl: "templates/filter/modal.tpl.html", | |
| controller: function(params, $scope) { | |
| function openLabelModal() { | |
| var Exclusive = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : 0; | |
| labelModal.activate({ | |
| params: { | |
| label: { | |
| Exclusive: Exclusive | |
| }, | |
| close: function() { | |
| labelModal.deactivate() | |
| } | |
| } | |
| }) | |
| } | |
| function prepareConditions() { | |
| var _ref3 = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {}, | |
| _ref3$Simple = _ref3.Simple, | |
| Simple = void 0 === _ref3$Simple ? {} : _ref3$Simple, | |
| _Simple$Conditions = Simple.Conditions, | |
| Conditions = void 0 === _Simple$Conditions ? [] : _Simple$Conditions, | |
| conditions = Conditions.map(function(_ref4) { | |
| var _ref4$Type = _ref4.Type, | |
| Type = void 0 === _ref4$Type ? {} : _ref4$Type, | |
| _ref4$Comparator = _ref4.Comparator, | |
| Comparator = void 0 === _ref4$Comparator ? {} : _ref4$Comparator, | |
| _ref4$Values = _ref4.Values; | |
| return { | |
| Values: void 0 === _ref4$Values ? [] : _ref4$Values, | |
| value: "", | |
| Type: _.findWhere(ctrl.types, { | |
| value: Type.value | |
| }), | |
| Comparator: _.findWhere(ctrl.comparators, { | |
| value: Comparator.value | |
| }) | |
| } | |
| }); | |
| return 0 === conditions.length && conditions.push({ | |
| Values: [], | |
| value: "", | |
| Type: ctrl.types[0], | |
| Comparator: ctrl.comparators[0] | |
| }), conditions | |
| } | |
| function prepareActions() { | |
| var _ref5 = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {}, | |
| _ref5$Simple = _ref5.Simple, | |
| Simple = void 0 === _ref5$Simple ? {} : _ref5$Simple, | |
| _ref6 = Simple.Actions || {}, | |
| _ref6$FileInto = _ref6.FileInto, | |
| FileInto = void 0 === _ref6$FileInto ? [] : _ref6$FileInto, | |
| _ref6$Mark = _ref6.Mark, | |
| Mark = void 0 === _ref6$Mark ? { | |
| Read: !1, | |
| Starred: !1 | |
| } : _ref6$Mark, | |
| move = findCurrentMoveFolder(FileInto); | |
| ctrl.hasMove = !!move, ctrl.hasMark = Mark.Read || Mark.Starred; | |
| var actions = { | |
| Labels: labelsOrdered.map(function(label) { | |
| return label.Selected = -1 !== FileInto.indexOf(label.Name), label | |
| }), | |
| Move: move || "inbox", | |
| Mark: Mark | |
| }; | |
| return ctrl.hasLabels = !!_.where(actions.Labels, { | |
| Selected: !0 | |
| }).length, actions | |
| } | |
| function prepareOperator() { | |
| var _ref7 = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {}, | |
| _ref7$Simple = _ref7.Simple, | |
| Simple = void 0 === _ref7$Simple ? {} : _ref7$Simple, | |
| _ref8 = Simple.Operator || {}, | |
| _ref8$value = _ref8.value, | |
| value = void 0 === _ref8$value ? "all" : _ref8$value; | |
| return _.findWhere(ctrl.operators, { | |
| value: value | |
| }) | |
| } | |
| function prepareID() { | |
| var _ref9 = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {}, | |
| _ref9$ID = _ref9.ID; | |
| return void 0 === _ref9$ID ? "" : _ref9$ID | |
| } | |
| function prepareName() { | |
| var _ref10 = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {}, | |
| _ref10$Name = _ref10.Name; | |
| return void 0 === _ref10$Name ? "" : _ref10$Name | |
| } | |
| function prepareStatus() { | |
| var _ref11 = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {}, | |
| _ref11$Status = _ref11.Status; | |
| return void 0 === _ref11$Status ? 1 : _ref11$Status | |
| } | |
| var labelsOrdered = labelsModel.get("labels"), | |
| foldersOrdered = labelsModel.get("folders"), | |
| ctrl = this, | |
| model = angular.copy(params.filter); | |
| ctrl.hasLabels = !1, ctrl.hasMove = !1, ctrl.hasMark = !1, ctrl.folders = foldersOrdered, ctrl.types = angular.copy(TRANSLATIONS.TYPES), ctrl.comparators = angular.copy(TRANSLATIONS.COMPARATORS), ctrl.operators = angular.copy(TRANSLATIONS.OPERATORS); | |
| var findCurrentMoveFolder = function() { | |
| var list = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : [], | |
| map = labelsModel.get("folders").reduce(function(acc, label) { | |
| return acc[label.Name] = label, acc | |
| }, {}); | |
| return _.find(list, function(key) { | |
| return CONSTANTS.MAILBOX_IDENTIFIERS[key] || map[key] | |
| }) || "" | |
| }; | |
| ctrl.addLabel = function() { | |
| return openLabelModal(0) | |
| }, ctrl.addFolder = function() { | |
| return openLabelModal(1) | |
| }, ctrl.initialization = function() { | |
| ctrl.filter = { | |
| ID: prepareID(model), | |
| Name: prepareName(model), | |
| Status: prepareStatus(model), | |
| Version: CONSTANTS.FILTER_VERSION | |
| }, sieveLint.resetLastCheck(), "simple" === params.mode ? (ctrl.mode = "simple", ctrl.filter.Simple = { | |
| Operator: prepareOperator(model), | |
| Conditions: prepareConditions(model), | |
| Actions: prepareActions(model) | |
| }) : "complex" === params.mode && (ctrl.mode = "complex", ctrl.filter.Sieve = model ? model.Sieve : ""); | |
| var unsubscribe = []; | |
| angular.isObject(ctrl.filter.Simple) && (unsubscribe.push($rootScope.$on("labelsModel", function(e, _ref12) { | |
| var type = _ref12.type, | |
| data = _ref12.data; | |
| "cache.update" === type && $scope.$applyAsync(function() { | |
| ctrl.filter.Simple.Actions.Labels = ctrl.filter.Simple.Actions.Labels.concat(filterNewLabel(data)), ctrl.folders = ctrl.folders.concat(filterNewLabel(data, labelsModel.IS_FOLDER)) | |
| }) | |
| })), unsubscribe.push($rootScope.$on("autocompleteEmail", function(e, _ref13) { | |
| var type = _ref13.type, | |
| data = _ref13.data; | |
| "input.blur" === type && "filter-modal-add-condition-input" === data.type && ctrl.addValue(ctrl.filter.Simple.Conditions[Number(data.eventData)]) | |
| }))), $scope.$on("$destroy", function() { | |
| _.each(unsubscribe, function(cb) { | |
| return cb() | |
| }), unsubscribe.length = 0 | |
| }), $timeout(function() { | |
| angular.element("#filterName").focus() | |
| }, 100, !1) | |
| }, ctrl.onChangeAttachements = function(model, value) { | |
| model.Comparator = _.findWhere(ctrl.comparators, { | |
| value: value | |
| }) | |
| }, ctrl.displaySeparator = function() { | |
| if (ctrl.filter.Simple) { | |
| var conditions = ctrl.filter.Simple.Conditions; | |
| return conditions.length > 0 && "select" !== conditions[0].Type.value | |
| } | |
| return !1 | |
| }, ctrl.valid = function() { | |
| var pass = !0; | |
| if (pass = ctrl.filter.Name.length > 0, Object.keys(ctrl.filter.Simple || {}).length > 0) { | |
| var attachmentsCondition = 0; | |
| return _.each(ctrl.filter.Simple.Conditions, function(condition) { | |
| pass = pass && "select" !== condition.Type.value, "subject" !== condition.Type.value && "sender" !== condition.Type.value && "recipient" !== condition.Type.value || (pass = pass && condition.Values.length > 0), "attachments" === condition.Type.value && attachmentsCondition++ | |
| }), pass = pass && attachmentsCondition <= 1, pass = pass && (ctrl.hasLabels || ctrl.hasMove || ctrl.hasMark), !0 === ctrl.hasLabels && (pass = pass && _.where(ctrl.filter.Simple.Actions.Labels, { | |
| Selected: !0 | |
| }).length > 0), !0 === ctrl.hasMark && (pass = pass && (ctrl.filter.Simple.Actions.Mark.Starred || ctrl.filter.Simple.Actions.Mark.Read)), !0 === ctrl.hasMove && (pass = pass && !!ctrl.filter.Simple.Actions.Move), pass | |
| } | |
| return ctrl.filter.Sieve.length > 0 && sieveLint.lastCheckWasValid() | |
| }, ctrl.addCondition = function() { | |
| ctrl.filter.Simple.Conditions.push({ | |
| Type: _.first(ctrl.types), | |
| Comparator: _.first(ctrl.comparators), | |
| Values: [], | |
| value: "" | |
| }) | |
| }, ctrl.addValue = function(condition) { | |
| -1 === condition.Values.indexOf(condition.value) ? condition.value && (condition.Values.push(condition.value), condition.value = "") : notify({ | |
| message: TRANSLATIONS.ERROR_PATTERN, | |
| classes: "notification-danger" | |
| }) | |
| }, ctrl.removeCondition = function(condition) { | |
| var index = ctrl.filter.Simple.Conditions.indexOf(condition); | |
| ctrl.filter.Simple.Conditions.splice(index, 1) | |
| }; | |
| var bindFileInto = function() { | |
| var _ref14 = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {}, | |
| _ref14$FileInto = _ref14.FileInto, | |
| FileInto = void 0 === _ref14$FileInto ? [] : _ref14$FileInto, | |
| _ref14$Move = _ref14.Move, | |
| Move = void 0 === _ref14$Move ? "" : _ref14$Move, | |
| labels = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : []; | |
| return _.uniq([Move].filter(Boolean).concat(FileInto, labels)) | |
| }, | |
| requestUpdate = function() { | |
| var data = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {}, | |
| onSuccess = function() { | |
| var message = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : ""; | |
| return function(result) { | |
| result.data && 1e3 === result.data.Code ? (notify({ | |
| message: message, | |
| classes: "notification-success" | |
| }), eventManager.call(), params.close()) : result.data && result.data.Error && (notify({ | |
| message: result.data.Error, | |
| classes: "notification-danger" | |
| }), 50016 === result.data.Code && (eventManager.call(), params.close())) | |
| } | |
| }; | |
| return data.ID ? Filter.update(data).then(onSuccess(TRANSLATIONS.FILTER_UPDATED_SUCCESS)) : Filter.create(data).then(onSuccess(TRANSLATIONS.FILTER_CREATED_SUCCESS)) | |
| }; | |
| ctrl.save = function() { | |
| if ("complex" === params.mode) return void $timeout(function() { | |
| var clone = angular.copy(ctrl.filter); | |
| delete clone.Simple, delete clone.Tree, networkActivityTracker.track(requestUpdate(clone)) | |
| }, 100, !1); | |
| var clone = angular.copy(ctrl.filter); | |
| if (Object.keys(ctrl.filter.Simple || {}).length > 0) { | |
| if (!1 === ctrl.hasMove && (clone.Simple.Actions.Move = ""), !1 === ctrl.hasMark && (clone.Simple.Actions.Mark = { | |
| Read: !1, | |
| Starred: !1 | |
| }), !0 === ctrl.hasLabels) { | |
| var labels = _.filter(clone.Simple.Actions.Labels, function(_ref15) { | |
| return !0 === _ref15.Selected | |
| }).map(function(_ref16) { | |
| return _ref16.Name | |
| }), | |
| fileInto = bindFileInto(clone.Simple.Actions, labels); | |
| clone.Simple.Actions.FileInto = fileInto, delete clone.Simple.Actions.Labels | |
| } else delete clone.Simple.Actions.Labels; | |
| clone.Simple.Actions.FileInto = bindFileInto(clone.Simple.Actions), delete clone.Simple.Actions.Move | |
| } | |
| networkActivityTracker.track(requestUpdate(clone)) | |
| }, ctrl.cancel = function() { | |
| params.close() | |
| }, ctrl.initialization() | |
| } | |
| }) | |
| }), angular.module("proton.filter").factory("incomingModel", function(notify, gettextCatalog, IncomingDefault, networkActivityTracker) { | |
| var I18N = { | |
| ADD_SUCCESS: gettextCatalog.getString("Spam Filter Added", null, "Filters"), | |
| UPDATE_SUCCESS: gettextCatalog.getString("Spam Filter Updated", null, "Filters"), | |
| DELETE_SUCCESS: gettextCatalog.getString("Spam Filter Deleted", null, "Filters") | |
| }, | |
| notifySuccess = function(message) { | |
| return notify({ | |
| message: message, | |
| classes: "notification-success" | |
| }) | |
| }; | |
| return { | |
| get: function(config) { | |
| var promise = IncomingDefault.get(config).then(function(_ref) { | |
| var _ref$data = _ref.data, | |
| data = void 0 === _ref$data ? {} : _ref$data; | |
| if (data.Error) throw new Error(data.Error); | |
| return data.IncomingDefaults | |
| }); | |
| return networkActivityTracker.track(promise), promise | |
| }, | |
| update: function(ID, Location) { | |
| var promise = IncomingDefault.update({ | |
| ID: ID, | |
| Location: Location | |
| }).then(function(_ref2) { | |
| var _ref2$data = _ref2.data, | |
| data = void 0 === _ref2$data ? {} : _ref2$data; | |
| if (data.Error) { | |
| var error = new Error(data.Error); | |
| throw error.Code = data.Code, error | |
| } | |
| return notifySuccess(I18N.UPDATE_SUCCESS), data.IncomingDefault | |
| }); | |
| return networkActivityTracker.track(promise), promise | |
| }, | |
| remove: function(ID) { | |
| var promise = IncomingDefault.delete({ | |
| IDs: [ID] | |
| }).then(function(_ref3) { | |
| var _ref3$data = _ref3.data, | |
| data = void 0 === _ref3$data ? {} : _ref3$data; | |
| if (data.Error) throw new Error(data.Error); | |
| return notifySuccess(I18N.DELETE_SUCCESS), data.IncomingDefault | |
| }); | |
| return networkActivityTracker.track(promise), promise | |
| }, | |
| create: function(params) { | |
| var promise = IncomingDefault.add(params).then(function(_ref4) { | |
| var _ref4$data = _ref4.data, | |
| data = void 0 === _ref4$data ? {} : _ref4$data; | |
| if (data.Error) throw new Error(data.Error); | |
| return notifySuccess(I18N.ADD_SUCCESS), data.IncomingDefault | |
| }); | |
| return networkActivityTracker.track(promise), promise | |
| } | |
| } | |
| }), angular.module("proton.filter").factory("spamListModel", function($q, $rootScope, CONSTANTS, incomingModel) { | |
| function getDefault() { | |
| var _ref; | |
| return _ref = { | |
| MAP: Object.create(null) | |
| }, _defineProperty(_ref, BLACKLIST_TYPE, { | |
| list: [], | |
| page: 0 | |
| }), _defineProperty(_ref, WHITELIST_TYPE, { | |
| list: [], | |
| page: 0 | |
| }), _ref | |
| } | |
| function updateCache(reset) { | |
| reset && (MAIN_CACHE.MAP = Object.create(null)); | |
| var map = MAIN_CACHE[BLACKLIST_TYPE].list.concat(MAIN_CACHE[WHITELIST_TYPE].list).reduce(function(acc, item) { | |
| return acc[item.ID] = item, acc | |
| }, Object.create(null)); | |
| _.extend(MAIN_CACHE.MAP, map) | |
| } | |
| function refresh() { | |
| if (MAIN_CACHE.query) return search(MAIN_CACHE.query); | |
| dispatch("change", { | |
| type: "refresh" | |
| }) | |
| } | |
| var load = function() { | |
| var _ref5 = _asyncToGenerator(regeneratorRuntime.mark(function _callee4() { | |
| var config, whitelist, blacklist, params = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {}, | |
| noEvent = arguments[1]; | |
| return regeneratorRuntime.wrap(function(_context4) { | |
| for (;;) switch (_context4.prev = _context4.next) { | |
| case 0: | |
| return config = { | |
| Page: 0, | |
| PageSize: PAGE_SIZE | |
| }, whitelist = list(WHITELIST_TYPE), blacklist = list(BLACKLIST_TYPE), whitelist.setLoader(!0), blacklist.setLoader(!0), _context4.next = 7, Promise.all([whitelist.loadList(_.extend({}, config, params)), blacklist.loadList(_.extend({}, config, params))]); | |
| case 7: | |
| whitelist.setLoader(!1), blacklist.setLoader(!1), updateCache(), !noEvent && resetIndex(), !noEvent && dispatch("change", { | |
| type: "load" | |
| }); | |
| case 12: | |
| case "end": | |
| return _context4.stop() | |
| } | |
| }, _callee4, this) | |
| })); | |
| return function() { | |
| return _ref5.apply(this, arguments) | |
| } | |
| }(), | |
| search = function() { | |
| var _ref8 = _asyncToGenerator(regeneratorRuntime.mark(function _callee7(query) { | |
| return regeneratorRuntime.wrap(function(_context7) { | |
| for (;;) switch (_context7.prev = _context7.next) { | |
| case 0: | |
| return MAIN_CACHE.query = query, resetIndex(), _context7.next = 4, load({ | |
| Keyword: query | |
| }, !0); | |
| case 4: | |
| dispatch("search"); | |
| case 5: | |
| case "end": | |
| return _context7.stop() | |
| } | |
| }, _callee7, this) | |
| })); | |
| return function(_x8) { | |
| return _ref8.apply(this, arguments) | |
| } | |
| }(), | |
| MAILBOX_IDENTIFIERS = CONSTANTS.MAILBOX_IDENTIFIERS, | |
| BLACKLIST_TYPE = +MAILBOX_IDENTIFIERS.spam, | |
| WHITELIST_TYPE = +MAILBOX_IDENTIFIERS.inbox, | |
| PAGE_SIZE = 100, | |
| MAIN_CACHE = getDefault(), | |
| dispatch = function(type) { | |
| var data = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : {}; | |
| return $rootScope.$emit("filters", { | |
| type: type, | |
| data: data | |
| }) | |
| }, | |
| getType = function(type) { | |
| return "whitelist" === type ? WHITELIST_TYPE : BLACKLIST_TYPE | |
| }, | |
| resetIndex = function(type) { | |
| if (type) return MAIN_CACHE[WHITELIST_TYPE].ending && (MAIN_CACHE[WHITELIST_TYPE].page = 0, MAIN_CACHE[WHITELIST_TYPE].ending = !1), MAIN_CACHE[BLACKLIST_TYPE].ending && (MAIN_CACHE[BLACKLIST_TYPE].page = 0, | |
| MAIN_CACHE[BLACKLIST_TYPE].ending = !1), MAIN_CACHE[type].page = 0; | |
| MAIN_CACHE[WHITELIST_TYPE].page = 0, MAIN_CACHE[BLACKLIST_TYPE].page = 0, MAIN_CACHE[WHITELIST_TYPE].ending = !1, MAIN_CACHE[BLACKLIST_TYPE].ending = !1 | |
| }, | |
| list = function(type) { | |
| var CACHE = MAIN_CACHE[type], | |
| extendPage = function(value) { | |
| return CACHE.page += value | |
| }, | |
| setLoader = function(value) { | |
| return CACHE.loading = value | |
| }, | |
| loadList = function() { | |
| var _ref2 = _asyncToGenerator(regeneratorRuntime.mark(function _callee(params) { | |
| var list; | |
| return regeneratorRuntime.wrap(function(_context) { | |
| for (;;) switch (_context.prev = _context.next) { | |
| case 0: | |
| return _context.next = 2, incomingModel.get(_.extend({ | |
| Location: type | |
| }, params)); | |
| case 2: | |
| return list = _context.sent, !CACHE.ending && (CACHE.list = list), _context.abrupt("return", list); | |
| case 5: | |
| case "end": | |
| return _context.stop() | |
| } | |
| }, _callee, void 0) | |
| })); | |
| return function(_x2) { | |
| return _ref2.apply(this, arguments) | |
| } | |
| }(), | |
| get = function() { | |
| var _ref3 = _asyncToGenerator(regeneratorRuntime.mark(function _callee2() { | |
| var pageFrom, list; | |
| return regeneratorRuntime.wrap(function(_context2) { | |
| for (;;) switch (_context2.prev = _context2.next) { | |
| case 0: | |
| if (pageFrom = CACHE.page, !(CACHE.list.length && CACHE.list.length >= (pageFrom + 2) * PAGE_SIZE)) { | |
| _context2.next = 5; | |
| break | |
| } | |
| return CACHE.ending = CACHE.list.length < PAGE_SIZE && !CACHE.invalidate, delete CACHE.invalidate, _context2.abrupt("return", angular.copy(CACHE.list)); | |
| case 5: | |
| return extendPage(1), setLoader(!0), _context2.next = 9, loadList({ | |
| Location: type, | |
| Page: pageFrom, | |
| Keyword: MAIN_CACHE.query, | |
| PageSize: PAGE_SIZE | |
| }); | |
| case 9: | |
| return list = _context2.sent, updateCache(), setLoader(!1), CACHE.ending = list.length < PAGE_SIZE && !CACHE.invalidate, delete CACHE.invalidate, _context2.abrupt("return", list); | |
| case 15: | |
| case "end": | |
| return _context2.stop() | |
| } | |
| }, _callee2, void 0) | |
| })); | |
| return function() { | |
| return _ref3.apply(this, arguments) | |
| } | |
| }(), | |
| add = function() { | |
| var _ref4 = _asyncToGenerator(regeneratorRuntime.mark(function _callee3(Email) { | |
| var item; | |
| return regeneratorRuntime.wrap(function(_context3) { | |
| for (;;) switch (_context3.prev = _context3.next) { | |
| case 0: | |
| return _context3.next = 2, incomingModel.create({ | |
| Email: Email, | |
| Location: type | |
| }); | |
| case 2: | |
| item = _context3.sent, CACHE.list.unshift(item), MAIN_CACHE.MAP[item.ID] = item, resetIndex(item.Location), refresh(); | |
| case 7: | |
| case "end": | |
| return _context3.stop() | |
| } | |
| }, _callee3, void 0) | |
| })); | |
| return function(_x3) { | |
| return _ref4.apply(this, arguments) | |
| } | |
| }(); | |
| return { | |
| extendPage: extendPage, | |
| setLoader: setLoader, | |
| loadList: loadList, | |
| get: get, | |
| add: add, | |
| isLoading: function() { | |
| return !!CACHE.loading | |
| }, | |
| isEnding: function() { | |
| return !!CACHE.ending | |
| } | |
| } | |
| }, | |
| move = function() { | |
| var _ref6 = _asyncToGenerator(regeneratorRuntime.mark(function _callee5(id, location) { | |
| var data, item, index; | |
| return regeneratorRuntime.wrap(function(_context5) { | |
| for (;;) switch (_context5.prev = _context5.next) { | |
| case 0: | |
| return _context5.prev = 0, _context5.next = 3, incomingModel.update(id, location); | |
| case 3: | |
| data = _context5.sent, item = MAIN_CACHE.MAP[id], index = _.findIndex(MAIN_CACHE[item.Location].list, function(o) { | |
| return o.ID === item.ID | |
| }), MAIN_CACHE[item.Location].list.splice(index, 1), MAIN_CACHE[location].list.unshift(data), MAIN_CACHE.MAP[item.ID] = data, MAIN_CACHE[item.Location].invalidate = !MAIN_CACHE[item.Location].ending, resetIndex(), refresh(), _context5.next = 17; | |
| break; | |
| case 14: | |
| _context5.prev = 14, _context5.t0 = _context5.catch(0), 35023 === _context5.t0.Code && (delete MAIN_CACHE.MAP[id], load({ | |
| Search: MAIN_CACHE.query | |
| })); | |
| case 17: | |
| case "end": | |
| return _context5.stop() | |
| } | |
| }, _callee5, void 0, [ | |
| [0, 14] | |
| ]) | |
| })); | |
| return function(_x5, _x6) { | |
| return _ref6.apply(this, arguments) | |
| } | |
| }(), | |
| destroy = function() { | |
| var _ref7 = _asyncToGenerator(regeneratorRuntime.mark(function _callee6(id) { | |
| var item, index; | |
| return regeneratorRuntime.wrap(function(_context6) { | |
| for (;;) switch (_context6.prev = _context6.next) { | |
| case 0: | |
| return _context6.next = 2, incomingModel.remove(id); | |
| case 2: | |
| item = MAIN_CACHE.MAP[id], index = _.findIndex(MAIN_CACHE[item.Location].list, function(o) { | |
| return o.ID === item.ID | |
| }), MAIN_CACHE[item.Location].list.splice(index, 1), MAIN_CACHE[item.Location].invalidate = !MAIN_CACHE[item.Location].ending, delete MAIN_CACHE.MAP[id], resetIndex(item.Location), refresh(); | |
| case 9: | |
| case "end": | |
| return _context6.stop() | |
| } | |
| }, _callee6, void 0) | |
| })); | |
| return function(_x7) { | |
| return _ref7.apply(this, arguments) | |
| } | |
| }(); | |
| return { | |
| list: list, | |
| load: load, | |
| move: move, | |
| destroy: destroy, | |
| search: search, | |
| refresh: refresh, | |
| clear: function() { | |
| return MAIN_CACHE = getDefault() | |
| }, | |
| getType: getType | |
| } | |
| }), angular.module("proton.filter").factory("filterAddressModal", function(pmModal, spamListModel) { | |
| return pmModal({ | |
| controllerAs: "ctrl", | |
| templateUrl: "templates/filter/filterAddressModal.tpl.html", | |
| controller: function(params) { | |
| var _this = this; | |
| this.filter = { | |
| Email: "" | |
| }, this.cancel = params.close, this.type = params.type, this.create = function() { | |
| spamListModel.list(spamListModel.getType(params.type)).add(_this.filter.Email), params.close() | |
| }, setTimeout(function() { | |
| angular.element("#emailAddress").focus() | |
| }, 100) | |
| } | |
| }) | |
| }), angular.module("proton.filter").factory("sieveLint", function(Filter, CONSTANTS) { | |
| function register() { | |
| window.CodeMirror.registerHelper("lint", "sieve", function(text) { | |
| if ("" === text.trim()) { | |
| var line = text.split("\n")[0]; | |
| return [{ | |
| message: "A sieve script cannot be empty", | |
| severity: "error", | |
| from: window.CodeMirror.Pos(0, 0), | |
| to: window.CodeMirror.Pos(0, line.length) | |
| }] | |
| } | |
| return Filter.check({ | |
| Version: CONSTANTS.FILTER_VERSION, | |
| Sieve: text | |
| }).then(function(response) { | |
| return 200 !== response.status ? [] : (wasValid = 0 === response.data.Issues.length, response.data.Issues) | |
| }) | |
| }) | |
| } | |
| function lastCheckWasValid() { | |
| return wasValid | |
| } | |
| function resetLastCheck() { | |
| wasValid = !0 | |
| } | |
| var wasValid = !0; | |
| return { | |
| init: register, | |
| lastCheckWasValid: lastCheckWasValid, | |
| resetLastCheck: resetLastCheck | |
| } | |
| }), angular.module("proton.formUtils").directive("captcha", function($rootScope, CONSTANTS, url, $httpParamSerializer) { | |
| var IFRAME_SECURE_ORIGIN = CONSTANTS.IFRAME_SECURE_ORIGIN, | |
| APP_HOST = url.host(), | |
| captchaMessage = { | |
| type: "pm_captcha", | |
| language: "en", | |
| key: "6LcWsBUTAAAAAOkRfBk-EXkGzOfcSz3CzvYbxfTn" | |
| }, | |
| captchaReceiveMessage = function($iframe) { | |
| return function(event) { | |
| if (void 0 !== event.origin || void 0 !== event.originalEvent.origin) { | |
| if ((event.origin || event.originalEvent.origin) === IFRAME_SECURE_ORIGIN) { | |
| var data = event.data; | |
| "pm_captcha" === data.type && $rootScope.$emit("humanVerification", { | |
| type: "captcha", | |
| data: data | |
| }), "pm_height" === data.type && $iframe.height(event.data.height + 40) | |
| } | |
| } | |
| } | |
| }; | |
| return { | |
| replace: !0, | |
| templateUrl: "templates/formUtils/captcha.tpl.html", | |
| link: function(scope, el, _ref) { | |
| var _ref$token = _ref.token, | |
| token = void 0 === _ref$token ? "signup" : _ref$token, | |
| iframe = el.find("iframe"), | |
| listener = captchaReceiveMessage(iframe), | |
| parameters = $httpParamSerializer({ | |
| token: token, | |
| client: "web", | |
| host: APP_HOST | |
| }); | |
| window.captchaSendMessage = function() { | |
| iframe[0].contentWindow.postMessage(captchaMessage, IFRAME_SECURE_ORIGIN) | |
| }, iframe[0].onload = window.captchaSendMessage, iframe[0].src = "https://secure.protonmail.com/captcha/captcha.html?" + parameters, window.addEventListener("message", listener, !1), scope.$on("$destroy", function() { | |
| window.removeEventListener("message", listener, !1) | |
| }) | |
| } | |
| } | |
| }), angular.module("proton.formUtils").directive("captchaView", function($httpParamSerializer, $rootScope, url) { | |
| return { | |
| restrict: "E", | |
| templateUrl: "templates/formUtils/captchaView.tpl.html", | |
| link: function(scope, element, _ref) { | |
| function receiveMessage(event) { | |
| var origin = event.origin, | |
| originalEvent = event.originalEvent, | |
| data = event.data; | |
| if (void 0 !== origin || void 0 !== originalEvent.origin) { | |
| if ("https://secure.protonmail.com" === (origin || originalEvent.origin) && ("pm_captcha" === data.type && $rootScope.$emit("captcha.token", data.token), "pm_height" === data.type)) { | |
| var height = event.data.height + 40; | |
| iframe.style.height = height + "px" | |
| } | |
| } | |
| } | |
| var token = _ref.token, | |
| iframe = element[0].querySelector("iframe"), | |
| host = url.host(), | |
| parameters = $httpParamSerializer({ | |
| token: token, | |
| client: "web", | |
| host: host | |
| }); | |
| window.addEventListener("message", receiveMessage, !1), iframe.src = "https://secure.protonmail.com/captcha/captcha.html?" + parameters, scope.$on("$destroy", function() { | |
| window.removeEventListener("message", receiveMessage, !1) | |
| }) | |
| } | |
| } | |
| }), angular.module("proton.formUtils").directive("cardCvc", function() { | |
| return { | |
| require: "ngModel", | |
| link: function(scope, element, attributes, ngModel) { | |
| ngModel.$validators.cardCvc = function(modelValue) { | |
| return $.payment.validateCardCVC(modelValue) | |
| } | |
| } | |
| } | |
| }), angular.module("proton.formUtils").directive("cardNumber", function() { | |
| return { | |
| require: "ngModel", | |
| link: function(scope, element, attributes, ngModel) { | |
| ngModel.$validators.cardNumber = function(modelValue) { | |
| return $.payment.validateCardNumber(modelValue) | |
| } | |
| } | |
| } | |
| }), angular.module("proton.formUtils").directive("cardView", function(countriesListModel) { | |
| var countries = countriesListModel(), | |
| currentYear = (new Date).getFullYear(), | |
| months = _.range(1, 13).map(function(i) { | |
| return ("0" + i).slice(-2) | |
| }), | |
| years = _.range(currentYear, currentYear + 12); | |
| return { | |
| replace: !0, | |
| templateUrl: "templates/formUtils/cardView.tpl.html", | |
| scope: { | |
| card: "=", | |
| form: "=" | |
| }, | |
| link: function(scope) { | |
| var country = scope.card.country ? _.findWhere(countries, { | |
| value: scope.card.country.value | |
| }) : countries[0]; | |
| scope.months = months, scope.years = years, scope.countries = countries, scope.card.country = country, scope.card.month = scope.months[0], scope.card.year = scope.years[0] | |
| } | |
| } | |
| }), angular.module("proton.formUtils").directive("compareTo", function() { | |
| return { | |
| require: "ngModel", | |
| scope: { | |
| otherModelValue: "=compareTo" | |
| }, | |
| link: function(scope, element, attributes, ngModel) { | |
| ngModel.$validators.compareTo = function(modelValue) { | |
| return !scope.otherModelValue || modelValue === scope.otherModelValue | |
| }, scope.$watch("otherModelValue", function() { | |
| ngModel.$validate() | |
| }) | |
| } | |
| } | |
| }), angular.module("proton.formUtils").directive("cvcTooltip", function(gettextCatalog) { | |
| var line1 = gettextCatalog.getString("For Visa, MasterCard and Discover, the 3 digits on the back of your card.", null, "Info"), | |
| line2 = gettextCatalog.getString("For American Express, the 4 digits on the front of your card.", null, "Info"), | |
| title = gettextCatalog.getString("Security Code", null, "Credit card CVC"); | |
| return { | |
| restrict: "A", | |
| link: function(scope, element) { | |
| element[0].setAttribute("tabindex", 0), element[0].setAttribute("role", "button"); | |
| var options = { | |
| placement: "top", | |
| container: "body", | |
| html: !0, | |
| title: title, | |
| trigger: "focus", | |
| content: "\n <p>" + line1 + "</p>\n <p>" + line2 + "</p>\n ", | |
| template: '\n <div class="popover" role="tooltip">\n <div class="arrow"></div>\n <div class="popover-title bold"></div>\n <div class="popover-content"></div>\n </div>\n ' | |
| }; | |
| element.popover(options), scope.$on("$destroy", function() { | |
| element.popover("destroy") | |
| }) | |
| } | |
| } | |
| }), angular.module("proton.formUtils").directive("danger", function(gettextCatalog) { | |
| function isDanger(value) { | |
| return value === dangerWord | |
| } | |
| var dangerWord = gettextCatalog.getString("DANGER"), | |
| placeholder = gettextCatalog.getString("Enter the word 'DANGER' here."); | |
| return { | |
| require: "ngModel", | |
| restrict: "A", | |
| scope: { | |
| dangerWord: "=" | |
| }, | |
| link: function(scope, element, attributes, ngModel) { | |
| scope.dangerWord = dangerWord, element.attr("placeholder", placeholder), ngModel.$validators.danger = isDanger | |
| } | |
| } | |
| }), angular.module("proton.formUtils").directive("formIsInvalid", function() { | |
| var getClassName = function() { | |
| return (arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : "") + "-is-invalid" | |
| }; | |
| return { | |
| link: function(scope, el, _ref) { | |
| var name = _ref.name; | |
| if (!name) throw new Error("A form must contains a name attribute"); | |
| var onSubmit = function() { | |
| if (scope[name].$invalid) return el[0].classList.add(getClassName(name)); | |
| el[0].classList.remove(getClassName(name)) | |
| }; | |
| el.on("submit", onSubmit), scope.$on("$destroy", function() { | |
| el.off("submit", onSubmit) | |
| }) | |
| } | |
| } | |
| }), angular.module("proton.formUtils").directive("password", function() { | |
| return { | |
| restrict: "E", | |
| replace: !0, | |
| templateUrl: "templates/formUtils/password.tpl.html", | |
| scope: { | |
| value: "=", | |
| form: "=", | |
| compare: "=" | |
| }, | |
| compile: function(element, _ref) { | |
| var autofocus = _ref.autofocus, | |
| compare = _ref.compare, | |
| _ref$id = _ref.id, | |
| id = void 0 === _ref$id ? "" : _ref$id, | |
| _ref$name = _ref.name, | |
| name = void 0 === _ref$name ? "" : _ref$name, | |
| _ref$placeholder = _ref.placeholder, | |
| placeholder = void 0 === _ref$placeholder ? "" : _ref$placeholder, | |
| _ref$tabindex = _ref.tabindex, | |
| tabindex = void 0 === _ref$tabindex ? 0 : _ref$tabindex, | |
| input = element[0].querySelector("input"); | |
| return input.setAttribute("id", id), input.setAttribute("name", name), input.setAttribute("placeholder", placeholder), input.setAttribute("tabindex", tabindex), compare && input.setAttribute("data-compare-to", "compare"), autofocus && input.setAttribute("autofocus", !0), | |
| function(scope, el, _ref2) { | |
| var autofocus = _ref2.autofocus, | |
| $input = el[0].querySelector(".password-input"); | |
| scope.message = scope.form[name].$error, autofocus && document.activeElement !== $input && _rAF(function() { | |
| return $input.focus() | |
| }) | |
| } | |
| } | |
| } | |
| }); | |
| var _templateObject = _taggedTemplateLiteral(['<button type="button" class="togglePassword-btn-toggle">\n <i class="togglePassword-icon-toText fa fa-eye" pt-tooltip="', '"></i>\n <i class="togglePassword-icon-toPassword fa fa-eye-slash" pt-tooltip="', '"></i>\n </button>'], ['<button type="button" class="togglePassword-btn-toggle">\n <i class="togglePassword-icon-toText fa fa-eye" pt-tooltip="', '"></i>\n <i class="togglePassword-icon-toPassword fa fa-eye-slash" pt-tooltip="', '"></i>\n </button>']); | |
| angular.module("proton.formUtils").directive("togglePassword", function(gettextCatalog, dedentTpl) { | |
| var hasNativeButton = "IE" === $.ua.browser.name || "Edge" === $.ua.browser.name, | |
| TOOLTIPS = { | |
| SHOW: gettextCatalog.getString("Show password", null, "toggle password"), | |
| HIDE: gettextCatalog.getString("Hide password", null, "toggle password") | |
| }, | |
| template = dedentTpl(_templateObject, TOOLTIPS.SHOW, TOOLTIPS.HIDE); | |
| return { | |
| restrict: "A", | |
| compile: function(el) { | |
| if (!hasNativeButton) { | |
| var container = el[0].parentElement; | |
| return container.insertAdjacentHTML("beforeEnd", template), container.classList.add("customPasswordToggler"), | |
| function(scope, el) { | |
| var btn = el[0].parentElement.querySelector(".togglePassword-btn-toggle"), | |
| onClick = function() { | |
| var type = "text" === el[0].type ? "password" : "text"; | |
| el[0].setAttribute("type", type), btn.classList.toggle("togglePassword-btn-display") | |
| }; | |
| btn.addEventListener("click", onClick), scope.$on("$destroy", function() { | |
| btn.removeEventListener("click", onClick) | |
| }) | |
| } | |
| } | |
| } | |
| } | |
| }), angular.module("proton.formUtils").directive("uniqueUsername", function($stateParams, gettextCatalog, User) { | |
| var clean = function() { | |
| return (arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : "").toLowerCase().replace(/\.|-|_/, "") | |
| }, | |
| validator = function(ngModel) { | |
| return function(username) { | |
| var usernameCleaned = clean(username); | |
| return delete ngModel.$error.alreadyTaken, delete ngModel.$error.tooMuch, delete ngModel.$error.uniqueError, usernameCleaned === $stateParams.inviteSelector ? Promise.resolve() : User.available(username).then(function() { | |
| var _ref = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {}, | |
| _ref$data = _ref.data, | |
| data = void 0 === _ref$data ? {} : _ref$data; | |
| if (1e3 === data.Code) { | |
| if (data.Available) return Promise.resolve(); | |
| ngModel.$error.alreadyTaken = !0 | |
| } | |
| return 429 === data.Error && (ngModel.$error.tooMuch = !0), ngModel.$error.uniqueError = !0, Promise.reject(!1) | |
| }) | |
| } | |
| }; | |
| return { | |
| require: "ngModel", | |
| restrict: "A", | |
| link: function(scope, el, attr, ngModel) { | |
| ngModel.$asyncValidators.unique = validator(ngModel) | |
| } | |
| } | |
| }), angular.module("proton.formUtils").directive("validRecovery", function() { | |
| var validator = function(scope) { | |
| return function(email) { | |
| var _scope$username = scope.username, | |
| username = void 0 === _scope$username ? "" : _scope$username, | |
| _scope$domain = scope.domain; | |
| return email !== username + "@" + (void 0 === _scope$domain ? "" : _scope$domain) | |
| } | |
| }; | |
| return { | |
| require: "ngModel", | |
| restrict: "A", | |
| scope: { | |
| domain: "=validRecoveryDomain", | |
| username: "=validRecoveryUsername" | |
| }, | |
| link: function(scope, el, attr, ngModel) { | |
| ngModel.$validators.validUsername = validator(scope) | |
| } | |
| } | |
| }), angular.module("proton.formUtils").directive("validUsername", function() { | |
| var IS_VALID = new RegExp(/^[A-Za-z0-9]+(?:[_.-][A-Za-z0-9]+)*$/); | |
| return { | |
| require: "ngModel", | |
| restrict: "A", | |
| link: function(scope, el, attr, ngModel) { | |
| ngModel.$validators.valid = function(input) { | |
| return IS_VALID.test(input) | |
| } | |
| } | |
| } | |
| }), angular.module("proton.formUtils").directive("validatorTypoEmail", function(checkTypoEmails) { | |
| return { | |
| link: function(scope, el) { | |
| var ngMessages = el[0].nextElementSibling, | |
| warningMessage = ngMessages.querySelector('[ng-message-warning="typo-email"]'), | |
| toggleWarning = function(valid) { | |
| var method = valid ? "add" : "remove"; | |
| el[0].classList[method]("ng-warning-typo-email"), warningMessage.style.display = valid ? "initial" : "none" | |
| }, | |
| onBlur = function(_ref) { | |
| var target = _ref.target; | |
| toggleWarning(checkTypoEmails(target.value)) | |
| }; | |
| el[0].addEventListener("blur", onBlur), scope.$on("$destroy", function() { | |
| el[0].removeEventListener("blur", onBlur) | |
| }) | |
| } | |
| } | |
| }), angular.module("proton.formUtils").factory("cardModel", function() { | |
| var clean = function(value) { | |
| return String(value).replace(/\s+/g, "") | |
| }, | |
| formatYear = function(year) { | |
| return (2 === String(year).length ? "20" : "") + year | |
| }; | |
| return function() { | |
| var data = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {}, | |
| card = angular.copy(data), | |
| number = function() { | |
| return clean(card.number) | |
| }, | |
| month = function() { | |
| return card.month | |
| }, | |
| year = function() { | |
| return formatYear(card.year) | |
| }, | |
| cvc = function() { | |
| return clean(card.cvc) | |
| }, | |
| fullname = function() { | |
| return card.fullname | |
| }, | |
| zip = function() { | |
| return card.zip | |
| }, | |
| country = function() { | |
| return card.country.value | |
| }; | |
| return { | |
| number: number, | |
| month: month, | |
| year: year, | |
| cvc: cvc, | |
| fullname: fullname, | |
| zip: zip, | |
| country: country, | |
| details: function() { | |
| return { | |
| Number: number(), | |
| ExpMonth: month(), | |
| ExpYear: year(), | |
| CVC: cvc(), | |
| Name: fullname(), | |
| Country: country(), | |
| ZIP: zip() | |
| } | |
| } | |
| } | |
| } | |
| }), angular.module("proton.commons").factory("countriesListModel", function() { | |
| var DEFAULT_SEPARATOR = { | |
| label: "------------------", | |
| value: "", | |
| disabled: !0 | |
| }, | |
| list = [{ | |
| value: "AF", | |
| label: "Afghanistan" | |
| }, { | |
| value: "AL", | |
| label: "Albania" | |
| }, { | |
| value: "DZ", | |
| label: "Algeria" | |
| }, { | |
| value: "AD", | |
| label: "Andorra" | |
| }, { | |
| value: "AO", | |
| label: "Angola" | |
| }, { | |
| value: "AI", | |
| label: "Anguilla" | |
| }, { | |
| value: "AG", | |
| label: "Antigua and Barbuda" | |
| }, { | |
| value: "AR", | |
| label: "Argentina" | |
| }, { | |
| value: "AM", | |
| label: "Armenia" | |
| }, { | |
| value: "AW", | |
| label: "Aruba" | |
| }, { | |
| value: "AU", | |
| label: "Australia" | |
| }, { | |
| value: "AT", | |
| label: "Austria" | |
| }, { | |
| value: "AZ", | |
| label: "Azerbaijan" | |
| }, { | |
| value: "BS", | |
| label: "Bahamas" | |
| }, { | |
| value: "BH", | |
| label: "Bahrain" | |
| }, { | |
| value: "BD", | |
| label: "Bangladesh" | |
| }, { | |
| value: "BB", | |
| label: "Barbados" | |
| }, { | |
| value: "BY", | |
| label: "Belarus" | |
| }, { | |
| value: "BE", | |
| label: "Belgium" | |
| }, { | |
| value: "BZ", | |
| label: "Belize" | |
| }, { | |
| value: "BJ", | |
| label: "Benin" | |
| }, { | |
| value: "BM", | |
| label: "Bermuda" | |
| }, { | |
| value: "BT", | |
| label: "Bhutan" | |
| }, { | |
| value: "BO", | |
| label: "Bolivia" | |
| }, { | |
| value: "BA", | |
| label: "Bosnia Herzegovina" | |
| }, { | |
| value: "BW", | |
| label: "Botswana" | |
| }, { | |
| value: "BV", | |
| label: "Bouvet Island" | |
| }, { | |
| value: "BR", | |
| label: "Brazil" | |
| }, { | |
| value: "IO", | |
| label: "British Indian Ocean Territory" | |
| }, { | |
| value: "VG", | |
| label: "British Virgin Islands" | |
| }, { | |
| value: "BN", | |
| label: "Brunei Darussalam" | |
| }, { | |
| value: "BG", | |
| label: "Bulgaria" | |
| }, { | |
| value: "BF", | |
| label: "Burkina Faso" | |
| }, { | |
| value: "BI", | |
| label: "Burundi" | |
| }, { | |
| value: "KH", | |
| label: "Cambodia" | |
| }, { | |
| value: "CM", | |
| label: "Cameroon" | |
| }, { | |
| value: "CA", | |
| label: "Canada" | |
| }, { | |
| value: "CV", | |
| label: "Cape Verde" | |
| }, { | |
| value: "KY", | |
| label: "Cayman Islands" | |
| }, { | |
| value: "CF", | |
| label: "Central African Republic" | |
| }, { | |
| value: "TD", | |
| label: "Chad" | |
| }, { | |
| value: "CL", | |
| label: "Chile" | |
| }, { | |
| value: "CN", | |
| label: "China" | |
| }, { | |
| value: "CX", | |
| label: "Christmas Island" | |
| }, { | |
| value: "CC", | |
| label: "Cocos (Keeling) Islands" | |
| }, { | |
| value: "CO", | |
| label: "Colombia" | |
| }, { | |
| value: "KM", | |
| label: "Comoros" | |
| }, { | |
| value: "CG", | |
| label: "Congo" | |
| }, { | |
| value: "CD", | |
| label: "Congo (The Democratic Republic of the)" | |
| }, { | |
| value: "CK", | |
| label: "Cook Islands" | |
| }, { | |
| value: "CR", | |
| label: "Costa Rica" | |
| }, { | |
| value: "CI", | |
| label: "Cote d Ivoire (Ivory Coast)" | |
| }, { | |
| value: "HR", | |
| label: "Croatia" | |
| }, { | |
| value: "CU", | |
| label: "Cuba" | |
| }, { | |
| value: "CY", | |
| label: "Cyprus" | |
| }, { | |
| value: "CZ", | |
| label: "Czech Republic" | |
| }, { | |
| value: "DK", | |
| label: "Denmark" | |
| }, { | |
| value: "DJ", | |
| label: "Djibouti" | |
| }, { | |
| value: "DM", | |
| label: "Dominica" | |
| }, { | |
| value: "DO", | |
| label: "Dominican Republic" | |
| }, { | |
| value: "TL", | |
| label: "East Timor" | |
| }, { | |
| value: "EC", | |
| label: "Ecuador" | |
| }, { | |
| value: "EG", | |
| label: "Egypt" | |
| }, { | |
| value: "SV", | |
| label: "El Salvador" | |
| }, { | |
| value: "GQ", | |
| label: "Equatorial Guinea" | |
| }, { | |
| value: "ER", | |
| label: "Eritrea" | |
| }, { | |
| value: "EE", | |
| label: "Estonia" | |
| }, { | |
| value: "ET", | |
| label: "Ethiopia" | |
| }, { | |
| value: "FK", | |
| label: "Falkland Islands (Malvinas)" | |
| }, { | |
| value: "FO", | |
| label: "Faroe Islands" | |
| }, { | |
| value: "FJ", | |
| label: "Fiji" | |
| }, { | |
| value: "FI", | |
| label: "Finland" | |
| }, { | |
| value: "FR", | |
| label: "France" | |
| }, { | |
| value: "GF", | |
| label: "French Guiana" | |
| }, { | |
| value: "PF", | |
| label: "French Polynesia" | |
| }, { | |
| value: "TF", | |
| label: "French Southern Territories" | |
| }, { | |
| value: "GA", | |
| label: "Gabon" | |
| }, { | |
| value: "GM", | |
| label: "Gambia" | |
| }, { | |
| value: "GE", | |
| label: "Georgia" | |
| }, { | |
| value: "DE", | |
| label: "Germany" | |
| }, { | |
| value: "GH", | |
| label: "Ghana" | |
| }, { | |
| value: "GI", | |
| label: "Gibraltar" | |
| }, { | |
| value: "GR", | |
| label: "Greece" | |
| }, { | |
| value: "GL", | |
| label: "Greenland" | |
| }, { | |
| value: "GD", | |
| label: "Grenada" | |
| }, { | |
| value: "GP", | |
| label: "Guadeloupe" | |
| }, { | |
| value: "GT", | |
| label: "Guatemala" | |
| }, { | |
| value: "GN", | |
| label: "Guinea" | |
| }, { | |
| value: "GW", | |
| label: "Guinea-Bissau" | |
| }, { | |
| value: "GY", | |
| label: "Guyana" | |
| }, { | |
| value: "HT", | |
| label: "Haiti" | |
| }, { | |
| value: "HM", | |
| label: "Heard Island and McDonald Islands" | |
| }, { | |
| value: "VA", | |
| label: "Holy See (Vatican City State)" | |
| }, { | |
| value: "HN", | |
| label: "Honduras" | |
| }, { | |
| value: "HK", | |
| label: "Hong Kong" | |
| }, { | |
| value: "HU", | |
| label: "Hungary" | |
| }, { | |
| value: "IS", | |
| label: "Iceland" | |
| }, { | |
| value: "IN", | |
| label: "India" | |
| }, { | |
| value: "ID", | |
| label: "Indonesia" | |
| }, { | |
| value: "IQ", | |
| label: "Iraq" | |
| }, { | |
| value: "IE", | |
| label: "Ireland" | |
| }, { | |
| value: "IR", | |
| label: "Islamic Republic of Iran" | |
| }, { | |
| value: "IL", | |
| label: "Israel" | |
| }, { | |
| value: "IT", | |
| label: "Italy" | |
| }, { | |
| value: "JM", | |
| label: "Jamaica" | |
| }, { | |
| value: "JP", | |
| label: "Japan" | |
| }, { | |
| value: "JO", | |
| label: "Jordan" | |
| }, { | |
| value: "KZ", | |
| label: "Kazakhstan" | |
| }, { | |
| value: "KE", | |
| label: "Kenya" | |
| }, { | |
| value: "KI", | |
| label: "Kiribati" | |
| }, { | |
| value: "KP", | |
| label: "Korea (Democratic People s Republic of)" | |
| }, { | |
| value: "KR", | |
| label: "Korea (Republic of)" | |
| }, { | |
| value: "KW", | |
| label: "Kuwait" | |
| }, { | |
| value: "KG", | |
| label: "Kyrgzstan" | |
| }, { | |
| value: "LA", | |
| label: "Lao People s Democratic Republic" | |
| }, { | |
| value: "LV", | |
| label: "Latvia" | |
| }, { | |
| value: "LB", | |
| label: "Lebanon" | |
| }, { | |
| value: "LS", | |
| label: "Lesotho" | |
| }, { | |
| value: "LR", | |
| label: "Liberia" | |
| }, { | |
| value: "LY", | |
| label: "Libyan Arab Jamahiriya" | |
| }, { | |
| value: "LI", | |
| label: "Liechtenstein" | |
| }, { | |
| value: "LT", | |
| label: "Lithuania" | |
| }, { | |
| value: "LU", | |
| label: "Luxembourg" | |
| }, { | |
| value: "MO", | |
| label: "Macao" | |
| }, { | |
| value: "MK", | |
| label: "Macedonia" | |
| }, { | |
| value: "MG", | |
| label: "Madagascar" | |
| }, { | |
| value: "MW", | |
| label: "Malawi" | |
| }, { | |
| value: "MY", | |
| label: "Malaysia" | |
| }, { | |
| value: "MV", | |
| label: "Maldives" | |
| }, { | |
| value: "ML", | |
| label: "Mali" | |
| }, { | |
| value: "MT", | |
| label: "Malta" | |
| }, { | |
| value: "MH", | |
| label: "Marshall Islands" | |
| }, { | |
| value: "MQ", | |
| label: "Martinique" | |
| }, { | |
| value: "MR", | |
| label: "Mauritania" | |
| }, { | |
| value: "MU", | |
| label: "Mauritius" | |
| }, { | |
| value: "YT", | |
| label: "Mayotte" | |
| }, { | |
| value: "MX", | |
| label: "Mexico" | |
| }, { | |
| value: "MD", | |
| label: "Moldova" | |
| }, { | |
| value: "MC", | |
| label: "Monaco" | |
| }, { | |
| value: "MN", | |
| label: "Mongolia" | |
| }, { | |
| value: "MS", | |
| label: "Montserrat" | |
| }, { | |
| value: "MA", | |
| label: "Morocco" | |
| }, { | |
| value: "MZ", | |
| label: "Mozambique" | |
| }, { | |
| value: "MM", | |
| label: "Myanmar" | |
| }, { | |
| value: "NA", | |
| label: "Namibia" | |
| }, { | |
| value: "NR", | |
| label: "Nauru" | |
| }, { | |
| value: "NP", | |
| label: "Nepal" | |
| }, { | |
| value: "NL", | |
| label: "Netherlands" | |
| }, { | |
| value: "AN", | |
| label: "Netherlands Antilles" | |
| }, { | |
| value: "NC", | |
| label: "New Caledonia" | |
| }, { | |
| value: "NZ", | |
| label: "New Zealand" | |
| }, { | |
| value: "NI", | |
| label: "Nicaragua" | |
| }, { | |
| value: "NE", | |
| label: "Niger" | |
| }, { | |
| value: "NG", | |
| label: "Nigeria" | |
| }, { | |
| value: "NU", | |
| label: "Niue" | |
| }, { | |
| value: "NF", | |
| label: "Norfolk Island" | |
| }, { | |
| value: "NO", | |
| label: "Norway" | |
| }, { | |
| value: "OM", | |
| label: "Oman" | |
| }, { | |
| value: "PK", | |
| label: "Pakistan" | |
| }, { | |
| value: "PW", | |
| label: "Palau" | |
| }, { | |
| value: "PA", | |
| label: "Panama" | |
| }, { | |
| value: "PG", | |
| label: "Papua New Guinea" | |
| }, { | |
| value: "PY", | |
| label: "Paraguay" | |
| }, { | |
| value: "PE", | |
| label: "Peru" | |
| }, { | |
| value: "PH", | |
| label: "Philippines" | |
| }, { | |
| value: "PN", | |
| label: "Pitcairn" | |
| }, { | |
| value: "PL", | |
| label: "Poland" | |
| }, { | |
| value: "PT", | |
| label: "Portugal" | |
| }, { | |
| value: "QA", | |
| label: "Qatar" | |
| }, { | |
| value: "RE", | |
| label: "Reunion" | |
| }, { | |
| value: "RO", | |
| label: "Romania" | |
| }, { | |
| value: "RU", | |
| label: "Russian Federation" | |
| }, { | |
| value: "RW", | |
| label: "Rwanda" | |
| }, { | |
| value: "SH", | |
| label: "Saint Helena" | |
| }, { | |
| value: "KN", | |
| label: "Saint Kitts and Nevis" | |
| }, { | |
| value: "LC", | |
| label: "Saint Lucia" | |
| }, { | |
| value: "PM", | |
| label: "Saint Pierre and Miquelon" | |
| }, { | |
| value: "VC", | |
| label: "Saint Vincent and the Grenadines" | |
| }, { | |
| value: "WS", | |
| label: "Samoa" | |
| }, { | |
| value: "SM", | |
| label: "San Marino" | |
| }, { | |
| value: "ST", | |
| label: "Sao Tome and Principe" | |
| }, { | |
| value: "SA", | |
| label: "Saudi Arabia" | |
| }, { | |
| value: "SN", | |
| label: "Senegal" | |
| }, { | |
| value: "RS", | |
| label: "Serbia" | |
| }, { | |
| value: "SC", | |
| label: "Seychelles" | |
| }, { | |
| value: "SL", | |
| label: "Sierra Leone" | |
| }, { | |
| value: "SG", | |
| label: "Singapore" | |
| }, { | |
| value: "SK", | |
| label: "Slovakia" | |
| }, { | |
| value: "SI", | |
| label: "Slovenia" | |
| }, { | |
| value: "SB", | |
| label: "Solomon Islands" | |
| }, { | |
| value: "SO", | |
| label: "Somalia" | |
| }, { | |
| value: "ZA", | |
| label: "South Africa" | |
| }, { | |
| value: "GS", | |
| label: "South Georgia and the South Sandwich Islands" | |
| }, { | |
| value: "ES", | |
| label: "Spain" | |
| }, { | |
| value: "LK", | |
| label: "Sri Lanka" | |
| }, { | |
| value: "SD", | |
| label: "Sudan" | |
| }, { | |
| value: "SR", | |
| label: "Suriname" | |
| }, { | |
| value: "SJ", | |
| label: "Svalbard and Jan Mayen" | |
| }, { | |
| value: "SZ", | |
| label: "Swaziland" | |
| }, { | |
| value: "SE", | |
| label: "Sweden" | |
| }, { | |
| value: "CH", | |
| label: "Switzerland" | |
| }, { | |
| value: "SY", | |
| label: "Syrian Arab Republic" | |
| }, { | |
| value: "TW", | |
| label: "Taiwan" | |
| }, { | |
| value: "TJ", | |
| label: "Tajikstan" | |
| }, { | |
| value: "TZ", | |
| label: "Tanzania United Republic" | |
| }, { | |
| value: "TH", | |
| label: "Thailand" | |
| }, { | |
| value: "TG", | |
| label: "Togo" | |
| }, { | |
| value: "TK", | |
| label: "Tokelau" | |
| }, { | |
| value: "TO", | |
| label: "Tonga" | |
| }, { | |
| value: "TT", | |
| label: "Trinidad and Tobago" | |
| }, { | |
| value: "TN", | |
| label: "Tunisia" | |
| }, { | |
| value: "TR", | |
| label: "Turkey" | |
| }, { | |
| value: "TM", | |
| label: "Turkmenistan" | |
| }, { | |
| value: "TC", | |
| label: "Turks and Caicos Islands" | |
| }, { | |
| value: "TV", | |
| label: "Tuvalu" | |
| }, { | |
| value: "UG", | |
| label: "Uganda" | |
| }, { | |
| value: "UA", | |
| label: "Ukraine" | |
| }, { | |
| value: "AE", | |
| label: "United Arab Emirates" | |
| }, { | |
| value: "GB", | |
| label: "United Kingdom" | |
| }, { | |
| value: "US", | |
| label: "United States" | |
| }, { | |
| value: "UY", | |
| label: "Uruguay" | |
| }, { | |
| value: "UZ", | |
| label: "Uzbekistan" | |
| }, { | |
| value: "VU", | |
| label: "Vanuatu" | |
| }, { | |
| value: "VE", | |
| label: "Venezuela" | |
| }, { | |
| value: "VN", | |
| label: "Vietnam" | |
| }, { | |
| value: "WF", | |
| label: "Wallis and Futuna" | |
| }, { | |
| value: "EH", | |
| label: "Western Sahara" | |
| }, { | |
| value: "YE", | |
| label: "Yemen" | |
| }, { | |
| value: "ZM", | |
| label: "Zambia" | |
| }, { | |
| value: "ZW", | |
| label: "Zimbabwe" | |
| }], | |
| topList = [{ | |
| label: "United States", | |
| value: "US" | |
| }, { | |
| label: "United Kingdom", | |
| value: "GB" | |
| }, { | |
| label: "Switzerland", | |
| value: "CH" | |
| }, { | |
| label: "France", | |
| value: "FR" | |
| }, { | |
| label: "Germany", | |
| value: "DE" | |
| }, { | |
| label: "Canada", | |
| value: "CA" | |
| }]; | |
| return function() { | |
| var separator = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : DEFAULT_SEPARATOR; | |
| return topList.concat([separator], list) | |
| } | |
| }); | |
| var _slicedToArray = function() { | |
| function sliceIterator(arr, i) { | |
| var _arr = [], | |
| _n = !0, | |
| _d = !1, | |
| _e = void 0; | |
| try { | |
| for (var _s, _i = arr[Symbol.iterator](); !(_n = (_s = _i.next()).done) && (_arr.push(_s.value), !i || _arr.length !== i); _n = !0); | |
| } catch (err) { | |
| _d = !0, _e = err | |
| } finally { | |
| try { | |
| !_n && _i.return && _i.return() | |
| } finally { | |
| if (_d) throw _e | |
| } | |
| } | |
| return _arr | |
| } | |
| return function(arr, i) { | |
| if (Array.isArray(arr)) return arr; | |
| if (Symbol.iterator in Object(arr)) return sliceIterator(arr, i); | |
| throw new TypeError("Invalid attempt to destructure non-iterable instance") | |
| } | |
| }(); | |
| angular.module("proton.keys").factory("changeMailboxPassword", function($log, authentication, CONSTANTS, gettextCatalog, Key, networkActivityTracker, organizationApi, passwords, pmcw, User) { | |
| function getUser() { | |
| var newMailPwd = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : "", | |
| keySalt = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : ""; | |
| return Promise.all([passwords.computeKeyPassword(newMailPwd, keySalt), User.get()]).then(function(_ref) { | |
| var _ref2 = _slicedToArray(_ref, 2), | |
| password = _ref2[0], | |
| _ref2$ = _ref2[1]; | |
| _ref2$ = void 0 === _ref2$ ? {} : _ref2$; | |
| var _ref2$$data = _ref2$.data, | |
| data = void 0 === _ref2$$data ? {} : _ref2$$data; | |
| if (1e3 === data.Code) return Promise.resolve({ | |
| password: password, | |
| user: data.User | |
| }); | |
| throw new Error(data.Error || gettextCatalog.getString("Unable to save your changes, please try again.", null, "Error")) | |
| }) | |
| } | |
| function manageOrganizationKeys() { | |
| var password = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : "", | |
| oldMailPwd = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : ""; | |
| return (arguments.length > 2 && void 0 !== arguments[2] ? arguments[2] : {}).Role === CONSTANTS.PAID_ADMIN_ROLE ? organizationApi.getKeys().then(function() { | |
| var _ref3 = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {}, | |
| _ref3$data = _ref3.data, | |
| data = void 0 === _ref3$data ? {} : _ref3$data; | |
| if (1e3 === data.Code) { | |
| var encryptPrivateKey = data.PrivateKey; | |
| return pmcw.decryptPrivateKey(encryptPrivateKey, oldMailPwd).then(function(pkg) { | |
| return Promise.resolve(pmcw.encryptPrivateKey(pkg, password)) | |
| }, function() { | |
| return Promise.resolve(0) | |
| }) | |
| } | |
| throw new Error(data.Error || gettextCatalog.getString("Unable to get organization keys", null, "Error")) | |
| }) : Promise.resolve(0) | |
| } | |
| function manageUserKeys() { | |
| var password = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : "", | |
| oldMailPwd = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : "", | |
| user = arguments.length > 2 && void 0 !== arguments[2] ? arguments[2] : {}, | |
| inputKeys = []; | |
| user.Keys.forEach(function(key) { | |
| return inputKeys.push(key) | |
| }), user.Addresses.forEach(function(address) { | |
| address.Keys.forEach(function(key) { | |
| return inputKeys.push(key) | |
| }) | |
| }); | |
| var promises = []; | |
| if (user.OrganizationPrivateKey) { | |
| var organizationKey = pmcw.decryptPrivateKey(user.OrganizationPrivateKey, oldMailPwd); | |
| promises = inputKeys.map(function(_ref4) { | |
| var PrivateKey = _ref4.PrivateKey, | |
| ID = _ref4.ID, | |
| Token = _ref4.Token; | |
| return organizationKey.then(function(key) { | |
| return pmcw.decryptMessage({ | |
| message: pmcw.getMessage(Token), | |
| privateKey: key | |
| }) | |
| }).then(function(_ref5) { | |
| var data = _ref5.data; | |
| return pmcw.decryptPrivateKey(PrivateKey, data) | |
| }).then(function(pkg) { | |
| return { | |
| ID: ID, | |
| pkg: pkg | |
| } | |
| }) | |
| }) | |
| } else promises = inputKeys.map(function(_ref6) { | |
| var PrivateKey = _ref6.PrivateKey, | |
| ID = _ref6.ID; | |
| return pmcw.decryptPrivateKey(PrivateKey, oldMailPwd).then(function(pkg) { | |
| return { | |
| ID: ID, | |
| pkg: pkg | |
| } | |
| }) | |
| }); | |
| return promises.map(function(promise) { | |
| return promise.then(function(_ref7) { | |
| var ID = _ref7.ID, | |
| pkg = _ref7.pkg; | |
| return pmcw.encryptPrivateKey(pkg, password).then(function(PrivateKey) { | |
| return { | |
| ID: ID, | |
| PrivateKey: PrivateKey | |
| } | |
| }) | |
| }, function(error) { | |
| return $log.error(error), 0 | |
| }) | |
| }) | |
| } | |
| function sendNewKeys(_ref8) { | |
| var _ref8$keys = _ref8.keys, | |
| keys = void 0 === _ref8$keys ? [] : _ref8$keys, | |
| _ref8$keySalt = _ref8.keySalt, | |
| keySalt = void 0 === _ref8$keySalt ? "" : _ref8$keySalt, | |
| _ref8$organizationKey = _ref8.organizationKey, | |
| organizationKey = void 0 === _ref8$organizationKey ? 0 : _ref8$organizationKey, | |
| _ref8$newLoginPasswor = _ref8.newLoginPassword, | |
| newLoginPassword = void 0 === _ref8$newLoginPasswor ? "" : _ref8$newLoginPasswor, | |
| keysFiltered = keys.filter(function(key) { | |
| return 0 !== key | |
| }), | |
| payload = { | |
| KeySalt: keySalt, | |
| Keys: keysFiltered | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment