diff --git a/dev/Admin/About.js b/dev/Admin/About.js deleted file mode 100644 index 399469f8c..000000000 --- a/dev/Admin/About.js +++ /dev/null @@ -1,76 +0,0 @@ -/* RainLoop Webmail (c) RainLoop Team | Licensed under CC BY-NC-SA 3.0 */ - -/** - * @constructor - */ -function AdminAbout() -{ - var oData = RL.data(); - - this.version = ko.observable(RL.settingsGet('Version')); - this.access = ko.observable(!!RL.settingsGet('CoreAccess')); - this.errorDesc = ko.observable(''); - - this.coreReal = oData.coreReal; - this.coreUpdatable = oData.coreUpdatable; - this.coreAccess = oData.coreAccess; - this.coreChecking = oData.coreChecking; - this.coreUpdating = oData.coreUpdating; - this.coreRemoteVersion = oData.coreRemoteVersion; - this.coreRemoteRelease = oData.coreRemoteRelease; - this.coreVersionCompare = oData.coreVersionCompare; - - this.statusType = ko.computed(function () { - - var - sType = '', - iVersionCompare = this.coreVersionCompare(), - bChecking = this.coreChecking(), - bUpdating = this.coreUpdating(), - bReal = this.coreReal() - ; - - if (bChecking) - { - sType = 'checking'; - } - else if (bUpdating) - { - sType = 'updating'; - } - else if (bReal && 0 === iVersionCompare) - { - sType = 'up-to-date'; - } - else if (bReal && -1 === iVersionCompare) - { - sType = 'available'; - } - else if (!bReal) - { - sType = 'error'; - this.errorDesc('Cannot access the repository at the moment.'); - } - - return sType; - - }, this); -} - -Utils.addSettingsViewModel(AdminAbout, 'AdminSettingsAbout', 'About', 'about'); - -AdminAbout.prototype.onBuild = function () -{ - if (this.access()) - { - RL.reloadCoreData(); - } -}; - -AdminAbout.prototype.updateCoreData = function () -{ - if (!this.coreUpdating()) - { - RL.updateCoreData(); - } -}; diff --git a/dev/Admin/AdminSettingsAbout.js b/dev/Admin/AdminSettingsAbout.js new file mode 100644 index 000000000..fbb267840 --- /dev/null +++ b/dev/Admin/AdminSettingsAbout.js @@ -0,0 +1,87 @@ +/* RainLoop Webmail (c) RainLoop Team | Licensed under CC BY-NC-SA 3.0 */ + +(function (module) { + + 'use strict'; + + var + ko = require('../External/ko.js'), + Data = require('../Storages/AdminDataStorage.js') + ; + + /** + * @constructor + */ + function AdminSettingsAbout() + { + this.version = ko.observable(RL.settingsGet('Version')); + this.access = ko.observable(!!RL.settingsGet('CoreAccess')); + this.errorDesc = ko.observable(''); + + this.coreReal = Data.coreReal; + this.coreUpdatable = Data.coreUpdatable; + this.coreAccess = Data.coreAccess; + this.coreChecking = Data.coreChecking; + this.coreUpdating = Data.coreUpdating; + this.coreRemoteVersion = Data.coreRemoteVersion; + this.coreRemoteRelease = Data.coreRemoteRelease; + this.coreVersionCompare = Data.coreVersionCompare; + + this.statusType = ko.computed(function () { + + var + sType = '', + iVersionCompare = this.coreVersionCompare(), + bChecking = this.coreChecking(), + bUpdating = this.coreUpdating(), + bReal = this.coreReal() + ; + + if (bChecking) + { + sType = 'checking'; + } + else if (bUpdating) + { + sType = 'updating'; + } + else if (bReal && 0 === iVersionCompare) + { + sType = 'up-to-date'; + } + else if (bReal && -1 === iVersionCompare) + { + sType = 'available'; + } + else if (!bReal) + { + sType = 'error'; + this.errorDesc('Cannot access the repository at the moment.'); + } + + return sType; + + }, this); + } + + kn.addSettingsViewModel(AdminSettingsAbout, 'AdminSettingsAbout', 'About', 'about'); + + AdminSettingsAbout.prototype.onBuild = function () + { + if (this.access()) + { + RL.reloadCoreData(); + } + }; + + AdminSettingsAbout.prototype.updateCoreData = function () + { + if (!this.coreUpdating()) + { + RL.updateCoreData(); + } + }; + + module.exports = AdminSettingsAbout; + +}(module)); \ No newline at end of file diff --git a/dev/Admin/AdminSettingsBranding.js b/dev/Admin/AdminSettingsBranding.js new file mode 100644 index 000000000..7c9c76c92 --- /dev/null +++ b/dev/Admin/AdminSettingsBranding.js @@ -0,0 +1,87 @@ +/* RainLoop Webmail (c) RainLoop Team | Licensed under CC BY-NC-SA 3.0 */ + +(function (module) { + + 'use strict'; + + var + _ = require('../External/underscore.js'), + ko = require('../External/ko.js'), + Enums = require('../Common/Enums.js'), + Utils = require('../Common/Utils.js'), + kn = require('../Knoin/Knoin.js'), + Remote = require('../Storages/AdminAjaxRemoteStorage.js') + ; + + /** + * @constructor + */ + function AdminSettingsBranding() + { + this.title = ko.observable(RL.settingsGet('Title')); + this.title.trigger = ko.observable(Enums.SaveSettingsStep.Idle); + + this.loadingDesc = ko.observable(RL.settingsGet('LoadingDescription')); + this.loadingDesc.trigger = ko.observable(Enums.SaveSettingsStep.Idle); + + this.loginLogo = ko.observable(RL.settingsGet('LoginLogo')); + this.loginLogo.trigger = ko.observable(Enums.SaveSettingsStep.Idle); + + this.loginDescription = ko.observable(RL.settingsGet('LoginDescription')); + this.loginDescription.trigger = ko.observable(Enums.SaveSettingsStep.Idle); + + this.loginCss = ko.observable(RL.settingsGet('LoginCss')); + this.loginCss.trigger = ko.observable(Enums.SaveSettingsStep.Idle); + } + + kn.addSettingsViewModel(AdminSettingsBranding, 'AdminSettingsBranding', 'Branding', 'branding'); + + AdminSettingsBranding.prototype.onBuild = function () + { + var self = this; + _.delay(function () { + + var + f1 = Utils.settingsSaveHelperSimpleFunction(self.title.trigger, self), + f2 = Utils.settingsSaveHelperSimpleFunction(self.loadingDesc.trigger, self), + f3 = Utils.settingsSaveHelperSimpleFunction(self.loginLogo.trigger, self), + f4 = Utils.settingsSaveHelperSimpleFunction(self.loginDescription.trigger, self), + f5 = Utils.settingsSaveHelperSimpleFunction(self.loginCss.trigger, self) + ; + + self.title.subscribe(function (sValue) { + Remote.saveAdminConfig(f1, { + 'Title': Utils.trim(sValue) + }); + }); + + self.loadingDesc.subscribe(function (sValue) { + Remote.saveAdminConfig(f2, { + 'LoadingDescription': Utils.trim(sValue) + }); + }); + + self.loginLogo.subscribe(function (sValue) { + Remote.saveAdminConfig(f3, { + 'LoginLogo': Utils.trim(sValue) + }); + }); + + self.loginDescription.subscribe(function (sValue) { + Remote.saveAdminConfig(f4, { + 'LoginDescription': Utils.trim(sValue) + }); + }); + + self.loginCss.subscribe(function (sValue) { + Remote.saveAdminConfig(f5, { + 'LoginCss': Utils.trim(sValue) + }); + }); + + }, 50); + }; + + module.exports = AdminSettingsBranding; + +}(module)); \ No newline at end of file diff --git a/dev/Admin/AdminSettingsContacts.js b/dev/Admin/AdminSettingsContacts.js new file mode 100644 index 000000000..e7fe3db41 --- /dev/null +++ b/dev/Admin/AdminSettingsContacts.js @@ -0,0 +1,235 @@ +/* RainLoop Webmail (c) RainLoop Team | Licensed under CC BY-NC-SA 3.0 */ + +(function (module) { + + 'use strict'; + + var + _ = require('../External/underscore.js'), + ko = require('../External/ko.js'), + Enums = require('../Common/Enums.js'), + Utils = require('../Common/Utils.js'), + Remote = require('../Storages/AdminAjaxRemoteStorage.js') + ; + + /** + * @constructor + */ + function AdminSettingsContacts() + { + this.defautOptionsAfterRender = Utils.defautOptionsAfterRender; + this.enableContacts = ko.observable(!!RL.settingsGet('ContactsEnable')); + this.contactsSharing = ko.observable(!!RL.settingsGet('ContactsSharing')); + this.contactsSync = ko.observable(!!RL.settingsGet('ContactsSync')); + + var + aTypes = ['sqlite', 'mysql', 'pgsql'], + aSupportedTypes = [], + getTypeName = function(sName) { + switch (sName) + { + case 'sqlite': + sName = 'SQLite'; + break; + case 'mysql': + sName = 'MySQL'; + break; + case 'pgsql': + sName = 'PostgreSQL'; + break; + } + + return sName; + } + ; + + if (!!RL.settingsGet('SQLiteIsSupported')) + { + aSupportedTypes.push('sqlite'); + } + if (!!RL.settingsGet('MySqlIsSupported')) + { + aSupportedTypes.push('mysql'); + } + if (!!RL.settingsGet('PostgreSqlIsSupported')) + { + aSupportedTypes.push('pgsql'); + } + + this.contactsSupported = 0 < aSupportedTypes.length; + + this.contactsTypes = ko.observableArray([]); + this.contactsTypesOptions = this.contactsTypes.map(function (sValue) { + var bDisabled = -1 === Utils.inArray(sValue, aSupportedTypes); + return { + 'id': sValue, + 'name': getTypeName(sValue) + (bDisabled ? ' (not supported)' : ''), + 'disabled': bDisabled + }; + }); + + this.contactsTypes(aTypes); + this.contactsType = ko.observable(''); + + this.mainContactsType = ko.computed({ + 'owner': this, + 'read': this.contactsType, + 'write': function (sValue) { + if (sValue !== this.contactsType()) + { + if (-1 < Utils.inArray(sValue, aSupportedTypes)) + { + this.contactsType(sValue); + } + else if (0 < aSupportedTypes.length) + { + this.contactsType(''); + } + } + else + { + this.contactsType.valueHasMutated(); + } + } + }); + + this.contactsType.subscribe(function () { + this.testContactsSuccess(false); + this.testContactsError(false); + this.testContactsErrorMessage(''); + }, this); + + this.pdoDsn = ko.observable(RL.settingsGet('ContactsPdoDsn')); + this.pdoUser = ko.observable(RL.settingsGet('ContactsPdoUser')); + this.pdoPassword = ko.observable(RL.settingsGet('ContactsPdoPassword')); + + this.pdoDsnTrigger = ko.observable(Enums.SaveSettingsStep.Idle); + this.pdoUserTrigger = ko.observable(Enums.SaveSettingsStep.Idle); + this.pdoPasswordTrigger = ko.observable(Enums.SaveSettingsStep.Idle); + this.contactsTypeTrigger = ko.observable(Enums.SaveSettingsStep.Idle); + + this.testing = ko.observable(false); + this.testContactsSuccess = ko.observable(false); + this.testContactsError = ko.observable(false); + this.testContactsErrorMessage = ko.observable(''); + + this.testContactsCommand = Utils.createCommand(this, function () { + + this.testContactsSuccess(false); + this.testContactsError(false); + this.testContactsErrorMessage(''); + this.testing(true); + + Remote.testContacts(this.onTestContactsResponse, { + 'ContactsPdoType': this.contactsType(), + 'ContactsPdoDsn': this.pdoDsn(), + 'ContactsPdoUser': this.pdoUser(), + 'ContactsPdoPassword': this.pdoPassword() + }); + + }, function () { + return '' !== this.pdoDsn() && '' !== this.pdoUser(); + }); + + this.contactsType(RL.settingsGet('ContactsPdoType')); + + this.onTestContactsResponse = _.bind(this.onTestContactsResponse, this); + } + + kn.addSettingsViewModel(AdminSettingsContacts, 'AdminSettingsContacts', 'Contacts', 'contacts'); + + AdminSettingsContacts.prototype.onTestContactsResponse = function (sResult, oData) + { + this.testContactsSuccess(false); + this.testContactsError(false); + this.testContactsErrorMessage(''); + + if (Enums.StorageResultType.Success === sResult && oData && oData.Result && oData.Result.Result) + { + this.testContactsSuccess(true); + } + else + { + this.testContactsError(true); + if (oData && oData.Result) + { + this.testContactsErrorMessage(oData.Result.Message || ''); + } + else + { + this.testContactsErrorMessage(''); + } + } + + this.testing(false); + }; + + AdminSettingsContacts.prototype.onShow = function () + { + this.testContactsSuccess(false); + this.testContactsError(false); + this.testContactsErrorMessage(''); + }; + + AdminSettingsContacts.prototype.onBuild = function () + { + var self = this; + _.delay(function () { + + var + f1 = Utils.settingsSaveHelperSimpleFunction(self.pdoDsnTrigger, self), + f3 = Utils.settingsSaveHelperSimpleFunction(self.pdoUserTrigger, self), + f4 = Utils.settingsSaveHelperSimpleFunction(self.pdoPasswordTrigger, self), + f5 = Utils.settingsSaveHelperSimpleFunction(self.contactsTypeTrigger, self) + ; + + self.enableContacts.subscribe(function (bValue) { + Remote.saveAdminConfig(null, { + 'ContactsEnable': bValue ? '1' : '0' + }); + }); + + self.contactsSharing.subscribe(function (bValue) { + Remote.saveAdminConfig(null, { + 'ContactsSharing': bValue ? '1' : '0' + }); + }); + + self.contactsSync.subscribe(function (bValue) { + Remote.saveAdminConfig(null, { + 'ContactsSync': bValue ? '1' : '0' + }); + }); + + self.contactsType.subscribe(function (sValue) { + Remote.saveAdminConfig(f5, { + 'ContactsPdoType': sValue + }); + }); + + self.pdoDsn.subscribe(function (sValue) { + Remote.saveAdminConfig(f1, { + 'ContactsPdoDsn': Utils.trim(sValue) + }); + }); + + self.pdoUser.subscribe(function (sValue) { + Remote.saveAdminConfig(f3, { + 'ContactsPdoUser': Utils.trim(sValue) + }); + }); + + self.pdoPassword.subscribe(function (sValue) { + Remote.saveAdminConfig(f4, { + 'ContactsPdoPassword': Utils.trim(sValue) + }); + }); + + self.contactsType(RL.settingsGet('ContactsPdoType')); + + }, 50); + }; + + module.exports = AdminSettingsContacts; + +}(module)); \ No newline at end of file diff --git a/dev/Admin/AdminSettingsDomains.js b/dev/Admin/AdminSettingsDomains.js new file mode 100644 index 000000000..c087b78fe --- /dev/null +++ b/dev/Admin/AdminSettingsDomains.js @@ -0,0 +1,107 @@ +/* RainLoop Webmail (c) RainLoop Team | Licensed under CC BY-NC-SA 3.0 */ + +(function (module) { + + 'use strict'; + + var + window = require('../External/window.js'), + _ = require('../External/underscore.js'), + ko = require('../External/ko.js'), + + Enums = require('../Common/Enums.js'), + + Data = require('../Storages/AdminDataStorage.js'), + Remote = require('../Storages/AdminAjaxRemoteStorage.js') + ; + + /** + * @constructor + */ + function AdminSettingsDomains() + { + this.domains = Data.domains; + this.domainsLoading = Data.domainsLoading; + + this.iDomainForDeletionTimeout = 0; + + this.visibility = ko.computed(function () { + return Data.domainsLoading() ? 'visible' : 'hidden'; + }, this); + + this.domainForDeletion = ko.observable(null).extend({'toggleSubscribe': [this, + function (oPrev) { + if (oPrev) + { + oPrev.deleteAccess(false); + } + }, function (oNext) { + if (oNext) + { + oNext.deleteAccess(true); + this.startDomainForDeletionTimeout(); + } + } + ]}); + } + + kn.addSettingsViewModel(AdminSettingsDomains, 'AdminSettingsDomains', 'Domains', 'domains'); + + AdminSettingsDomains.prototype.startDomainForDeletionTimeout = function () + { + var self = this; + window.clearInterval(this.iDomainForDeletionTimeout); + this.iDomainForDeletionTimeout = window.setTimeout(function () { + self.domainForDeletion(null); + }, 1000 * 3); + }; + + AdminSettingsDomains.prototype.createDomain = function () + { + kn.showScreenPopup(PopupsDomainViewModel); + }; + + AdminSettingsDomains.prototype.deleteDomain = function (oDomain) + { + this.domains.remove(oDomain); + Remote.domainDelete(_.bind(this.onDomainListChangeRequest, this), oDomain.name); + }; + + AdminSettingsDomains.prototype.disableDomain = function (oDomain) + { + oDomain.disabled(!oDomain.disabled()); + Remote.domainDisable(_.bind(this.onDomainListChangeRequest, this), oDomain.name, oDomain.disabled()); + }; + + AdminSettingsDomains.prototype.onBuild = function (oDom) + { + var self = this; + oDom + .on('click', '.b-admin-domains-list-table .e-item .e-action', function () { + var oDomainItem = ko.dataFor(this); + if (oDomainItem) + { + Remote.domain(_.bind(self.onDomainLoadRequest, self), oDomainItem.name); + } + }) + ; + + RL.reloadDomainList(); + }; + + AdminSettingsDomains.prototype.onDomainLoadRequest = function (sResult, oData) + { + if (Enums.StorageResultType.Success === sResult && oData && oData.Result) + { + kn.showScreenPopup(PopupsDomainViewModel, [oData.Result]); + } + }; + + AdminSettingsDomains.prototype.onDomainListChangeRequest = function () + { + RL.reloadDomainList(); + }; + + module.exports = AdminSettingsDomains; + +}(module)); \ No newline at end of file diff --git a/dev/Admin/AdminSettingsGeneral.js b/dev/Admin/AdminSettingsGeneral.js new file mode 100644 index 000000000..c8f4d08c7 --- /dev/null +++ b/dev/Admin/AdminSettingsGeneral.js @@ -0,0 +1,148 @@ +/* RainLoop Webmail (c) RainLoop Team | Licensed under CC BY-NC-SA 3.0 */ + +(function (module) { + + 'use strict'; + + var + _ = require('../External/underscore.js'), + ko = require('../External/ko.js'), + + Enums = require('../Common/Enums.js'), + Utils = require('../Common/Utils.js'), + LinkBuilder = require('../Common/LinkBuilder.js'), + + kn = require('../Knoin/Knoin.js'), + + Data = require('../Storages/AdminDataStorage.js'), + Remote = require('../Storages/AdminAjaxRemoteStorage.js'), + + PopupsLanguagesViewModel = require('../ViewModels/Popups/PopupsLanguagesViewModel.js') + ; + + /** + * @constructor + */ + function AdminSettingsGeneral() + { + this.mainLanguage = Data.mainLanguage; + this.mainTheme = Data.mainTheme; + + this.language = Data.language; + this.theme = Data.theme; + + this.allowLanguagesOnSettings = Data.allowLanguagesOnSettings; + this.capaThemes = Data.capaThemes; + this.capaGravatar = Data.capaGravatar; + this.capaAdditionalAccounts = Data.capaAdditionalAccounts; + this.capaAdditionalIdentities = Data.capaAdditionalIdentities; + + this.mainAttachmentLimit = ko.observable(Utils.pInt(RL.settingsGet('AttachmentLimit')) / (1024 * 1024)).extend({'posInterer': 25}); + this.uploadData = RL.settingsGet('PhpUploadSizes'); + this.uploadDataDesc = this.uploadData && (this.uploadData['upload_max_filesize'] || this.uploadData['post_max_size']) ? + [ + this.uploadData['upload_max_filesize'] ? 'upload_max_filesize = ' + this.uploadData['upload_max_filesize'] + '; ' : '', + this.uploadData['post_max_size'] ? 'post_max_size = ' + this.uploadData['post_max_size'] : '' + ].join('') + : ''; + + this.themesOptions = ko.computed(function () { + return _.map(Data.themes(), function (sTheme) { + return { + 'optValue': sTheme, + 'optText': Utils.convertThemeName(sTheme) + }; + }); + }); + + this.mainLanguageFullName = ko.computed(function () { + return Utils.convertLangName(this.mainLanguage()); + }, this); + + this.weakPassword = !!RL.settingsGet('WeakPassword'); + + this.attachmentLimitTrigger = ko.observable(Enums.SaveSettingsStep.Idle); + this.languageTrigger = ko.observable(Enums.SaveSettingsStep.Idle); + this.themeTrigger = ko.observable(Enums.SaveSettingsStep.Idle); + } + + kn.addSettingsViewModel(AdminSettingsGeneral, 'AdminSettingsGeneral', 'General', 'general', true); + + AdminSettingsGeneral.prototype.onBuild = function () + { + var self = this; + _.delay(function () { + + var + f1 = Utils.settingsSaveHelperSimpleFunction(self.attachmentLimitTrigger, self), + f2 = Utils.settingsSaveHelperSimpleFunction(self.languageTrigger, self), + f3 = Utils.settingsSaveHelperSimpleFunction(self.themeTrigger, self) + ; + + self.mainAttachmentLimit.subscribe(function (sValue) { + Remote.saveAdminConfig(f1, { + 'AttachmentLimit': Utils.pInt(sValue) + }); + }); + + self.language.subscribe(function (sValue) { + Remote.saveAdminConfig(f2, { + 'Language': Utils.trim(sValue) + }); + }); + + self.theme.subscribe(function (sValue) { + Remote.saveAdminConfig(f3, { + 'Theme': Utils.trim(sValue) + }); + }); + + self.capaAdditionalAccounts.subscribe(function (bValue) { + Remote.saveAdminConfig(null, { + 'CapaAdditionalAccounts': bValue ? '1' : '0' + }); + }); + + self.capaAdditionalIdentities.subscribe(function (bValue) { + Remote.saveAdminConfig(null, { + 'CapaAdditionalIdentities': bValue ? '1' : '0' + }); + }); + + self.capaGravatar.subscribe(function (bValue) { + Remote.saveAdminConfig(null, { + 'CapaGravatar': bValue ? '1' : '0' + }); + }); + + self.capaThemes.subscribe(function (bValue) { + Remote.saveAdminConfig(null, { + 'CapaThemes': bValue ? '1' : '0' + }); + }); + + self.allowLanguagesOnSettings.subscribe(function (bValue) { + Remote.saveAdminConfig(null, { + 'AllowLanguagesOnSettings': bValue ? '1' : '0' + }); + }); + + }, 50); + }; + + AdminSettingsGeneral.prototype.selectLanguage = function () + { + kn.showScreenPopup(PopupsLanguagesViewModel); + }; + + /** + * @return {string} + */ + AdminSettingsGeneral.prototype.phpInfoLink = function () + { + return LinkBuilder.phpInfo(); + }; + + module.exports = AdminSettingsGeneral; + +}(module)); \ No newline at end of file diff --git a/dev/Admin/AdminSettingsLicensing.js b/dev/Admin/AdminSettingsLicensing.js new file mode 100644 index 000000000..8d6e5ba6b --- /dev/null +++ b/dev/Admin/AdminSettingsLicensing.js @@ -0,0 +1,75 @@ +/* RainLoop Webmail (c) RainLoop Team | Licensed under CC BY-NC-SA 3.0 */ + +(function (module) { + + 'use strict'; + + var + ko = require('../External/ko.js'), + moment = require('../External/moment.js'), + + Data = require('../Storages/AdminDataStorage.js'), + + kn = require('../Knoin/Knoin.js'), + PopupsActivateViewModel = require('../ViewModels/Popups/PopupsActivateViewModel.js') + ; + + /** + * @constructor + */ + function AdminSettingsLicensing() + { + this.licensing = Data.licensing; + this.licensingProcess = Data.licensingProcess; + this.licenseValid = Data.licenseValid; + this.licenseExpired = Data.licenseExpired; + this.licenseError = Data.licenseError; + this.licenseTrigger = Data.licenseTrigger; + + this.adminDomain = ko.observable(''); + this.subscriptionEnabled = ko.observable(!!RL.settingsGet('SubscriptionEnabled')); + + this.licenseTrigger.subscribe(function () { + if (this.subscriptionEnabled()) + { + RL.reloadLicensing(true); + } + }, this); + } + + kn.addSettingsViewModel(AdminSettingsLicensing, 'AdminSettingsLicensing', 'Licensing', 'licensing'); + + AdminSettingsLicensing.prototype.onBuild = function () + { + if (this.subscriptionEnabled()) + { + RL.reloadLicensing(false); + } + }; + + AdminSettingsLicensing.prototype.onShow = function () + { + this.adminDomain(RL.settingsGet('AdminDomain')); + }; + + AdminSettingsLicensing.prototype.showActivationForm = function () + { + kn.showScreenPopup(PopupsActivateViewModel); + }; + + /** + * @returns {string} + */ + AdminSettingsLicensing.prototype.licenseExpiredMomentValue = function () + { + var + iTime = this.licenseExpired(), + oDate = moment.unix(iTime) + ; + + return iTime && 1898625600 === iTime ? 'Never' : (oDate.format('LL') + ' (' + oDate.from(moment()) + ')'); + }; + + module.exports = AdminSettingsLicensing; + +}(module)); \ No newline at end of file diff --git a/dev/Admin/AdminSettingsLogin.js b/dev/Admin/AdminSettingsLogin.js new file mode 100644 index 000000000..9c5791f49 --- /dev/null +++ b/dev/Admin/AdminSettingsLogin.js @@ -0,0 +1,69 @@ +/* RainLoop Webmail (c) RainLoop Team | Licensed under CC BY-NC-SA 3.0 */ + +(function (module) { + + 'use strict'; + + var + ko = require('../External/ko.js'), + + Enums = require('../Common/Enums.js'), + Utils = require('../Common/Utils.js'), + + Data = require('../Storages/AdminDataStorage.js'), + Remote = require('../Storages/AdminAjaxRemoteStorage.js') + ; + + /** + * @constructor + */ + function AdminSettingsLogin() + { + this.determineUserLanguage = Data.determineUserLanguage; + this.determineUserDomain = Data.determineUserDomain; + + this.defaultDomain = ko.observable(RL.settingsGet('LoginDefaultDomain')); + + this.allowLanguagesOnLogin = Data.allowLanguagesOnLogin; + this.defaultDomainTrigger = ko.observable(Enums.SaveSettingsStep.Idle); + } + + kn.addSettingsViewModel(AdminSettingsLogin, 'AdminSettingsLogin', 'Login', 'login'); + + AdminSettingsLogin.prototype.onBuild = function () + { + var self = this; + _.delay(function () { + + var f1 = Utils.settingsSaveHelperSimpleFunction(self.defaultDomainTrigger, self); + + self.determineUserLanguage.subscribe(function (bValue) { + Remote.saveAdminConfig(null, { + 'DetermineUserLanguage': bValue ? '1' : '0' + }); + }); + + self.determineUserDomain.subscribe(function (bValue) { + Remote.saveAdminConfig(null, { + 'DetermineUserDomain': bValue ? '1' : '0' + }); + }); + + self.allowLanguagesOnLogin.subscribe(function (bValue) { + Remote.saveAdminConfig(null, { + 'AllowLanguagesOnLogin': bValue ? '1' : '0' + }); + }); + + self.defaultDomain.subscribe(function (sValue) { + Remote.saveAdminConfig(f1, { + 'LoginDefaultDomain': Utils.trim(sValue) + }); + }); + + }, 50); + }; + + module.exports = AdminSettingsLogin; + +}(module)); \ No newline at end of file diff --git a/dev/Admin/AdminSettingsPackages.js b/dev/Admin/AdminSettingsPackages.js new file mode 100644 index 000000000..2460d618d --- /dev/null +++ b/dev/Admin/AdminSettingsPackages.js @@ -0,0 +1,116 @@ +/* RainLoop Webmail (c) RainLoop Team | Licensed under CC BY-NC-SA 3.0 */ + +(function (module) { + + 'use strict'; + + var + window = require('../External/window.js'), + ko = require('../External/ko.js'), + + Enums = require('../Common/Enums.js'), + Utils = require('../Common/Utils.js'), + + Data = require('../Storages/AdminDataStorage.js'), + Remote = require('../Storages/AdminAjaxRemoteStorage.js') + ; + + /** + * @constructor + */ + function AdminSettingsPackages() + { + this.packagesError = ko.observable(''); + + this.packages = Data.packages; + this.packagesLoading = Data.packagesLoading; + this.packagesReal = Data.packagesReal; + this.packagesMainUpdatable = Data.packagesMainUpdatable; + + this.packagesCurrent = this.packages.filter(function (oItem) { + return oItem && '' !== oItem['installed'] && !oItem['compare']; + }); + + this.packagesAvailableForUpdate = this.packages.filter(function (oItem) { + return oItem && '' !== oItem['installed'] && !!oItem['compare']; + }); + + this.packagesAvailableForInstallation = this.packages.filter(function (oItem) { + return oItem && '' === oItem['installed']; + }); + + this.visibility = ko.computed(function () { + return Data.packagesLoading() ? 'visible' : 'hidden'; + }, this); + } + + kn.addSettingsViewModel(AdminSettingsPackages, 'AdminSettingsPackages', 'Packages', 'packages'); + + AdminSettingsPackages.prototype.onShow = function () + { + this.packagesError(''); + }; + + AdminSettingsPackages.prototype.onBuild = function () + { + RL.reloadPackagesList(); + }; + + AdminSettingsPackages.prototype.requestHelper = function (oPackage, bInstall) + { + var self = this; + return function (sResult, oData) { + + if (Enums.StorageResultType.Success !== sResult || !oData || !oData.Result) + { + if (oData && oData.ErrorCode) + { + self.packagesError(Utils.getNotification(oData.ErrorCode)); + } + else + { + self.packagesError(Utils.getNotification( + bInstall ? Enums.Notification.CantInstallPackage : Enums.Notification.CantDeletePackage)); + } + } + + _.each(Data.packages(), function (oItem) { + if (oItem && oPackage && oItem['loading']() && oPackage['file'] === oItem['file']) + { + oPackage['loading'](false); + oItem['loading'](false); + } + }); + + if (Enums.StorageResultType.Success === sResult && oData && oData.Result && oData.Result['Reload']) + { + window.location.reload(); + } + else + { + RL.reloadPackagesList(); + } + }; + }; + + AdminSettingsPackages.prototype.deletePackage = function (oPackage) + { + if (oPackage) + { + oPackage['loading'](true); + Remote.packageDelete(this.requestHelper(oPackage, false), oPackage); + } + }; + + AdminSettingsPackages.prototype.installPackage = function (oPackage) + { + if (oPackage) + { + oPackage['loading'](true); + Remote.packageInstall(this.requestHelper(oPackage, true), oPackage); + } + }; + + module.exports = AdminSettingsPackages; + +}(module)); \ No newline at end of file diff --git a/dev/Admin/AdminSettingsPlugins.js b/dev/Admin/AdminSettingsPlugins.js new file mode 100644 index 000000000..a6ce8c39f --- /dev/null +++ b/dev/Admin/AdminSettingsPlugins.js @@ -0,0 +1,117 @@ +/* RainLoop Webmail (c) RainLoop Team | Licensed under CC BY-NC-SA 3.0 */ + +(function (module) { + + 'use strict'; + + var + _ = require('../External/underscore.js'), + ko = require('../External/ko.js'), + + Enums = require('../Common/Enums.js'), + Utils = require('../Common/Utils.js'), + + Data = require('../Storages/AdminDataStorage.js'), + Remote = require('../Storages/AdminAjaxRemoteStorage.js'), + + PopupsPluginViewModel = require('../ViewModels/Popups/PopupsPluginViewModel.js') + ; + + /** + * @constructor + */ + function AdminSettingsPlugins() + { + this.enabledPlugins = ko.observable(!!RL.settingsGet('EnabledPlugins')); + + this.pluginsError = ko.observable(''); + + this.plugins = Data.plugins; + this.pluginsLoading = Data.pluginsLoading; + + this.visibility = ko.computed(function () { + return Data.pluginsLoading() ? 'visible' : 'hidden'; + }, this); + + this.onPluginLoadRequest = _.bind(this.onPluginLoadRequest, this); + this.onPluginDisableRequest = _.bind(this.onPluginDisableRequest, this); + } + + kn.addSettingsViewModel(AdminSettingsPlugins, 'AdminSettingsPlugins', 'Plugins', 'plugins'); + + AdminSettingsPlugins.prototype.disablePlugin = function (oPlugin) + { + oPlugin.disabled(!oPlugin.disabled()); + Remote.pluginDisable(this.onPluginDisableRequest, oPlugin.name, oPlugin.disabled()); + }; + + AdminSettingsPlugins.prototype.configurePlugin = function (oPlugin) + { + Remote.plugin(this.onPluginLoadRequest, oPlugin.name); + }; + + AdminSettingsPlugins.prototype.onBuild = function (oDom) + { + var self = this; + + oDom + .on('click', '.e-item .configure-plugin-action', function () { + var oPlugin = ko.dataFor(this); + if (oPlugin) + { + self.configurePlugin(oPlugin); + } + }) + .on('click', '.e-item .disabled-plugin', function () { + var oPlugin = ko.dataFor(this); + if (oPlugin) + { + self.disablePlugin(oPlugin); + } + }) + ; + + this.enabledPlugins.subscribe(function (bValue) { + Remote.saveAdminConfig(Utils.emptyFunction, { + 'EnabledPlugins': bValue ? '1' : '0' + }); + }); + }; + + AdminSettingsPlugins.prototype.onShow = function () + { + this.pluginsError(''); + RL.reloadPluginList(); + }; + + AdminSettingsPlugins.prototype.onPluginLoadRequest = function (sResult, oData) + { + if (Enums.StorageResultType.Success === sResult && oData && oData.Result) + { + kn.showScreenPopup(PopupsPluginViewModel, [oData.Result]); + } + }; + + AdminSettingsPlugins.prototype.onPluginDisableRequest = function (sResult, oData) + { + if (Enums.StorageResultType.Success === sResult && oData) + { + if (!oData.Result && oData.ErrorCode) + { + if (Enums.Notification.UnsupportedPluginPackage === oData.ErrorCode && oData.ErrorMessage && '' !== oData.ErrorMessage) + { + this.pluginsError(oData.ErrorMessage); + } + else + { + this.pluginsError(Utils.getNotification(oData.ErrorCode)); + } + } + } + + RL.reloadPluginList(); + }; + + module.exports = AdminSettingsPlugins; + +}(module)); \ No newline at end of file diff --git a/dev/Admin/AdminSettingsSecurity.js b/dev/Admin/AdminSettingsSecurity.js new file mode 100644 index 000000000..5ddc27106 --- /dev/null +++ b/dev/Admin/AdminSettingsSecurity.js @@ -0,0 +1,134 @@ +/* RainLoop Webmail (c) RainLoop Team | Licensed under CC BY-NC-SA 3.0 */ + +(function (module) { + + 'use strict'; + + var + _ = require('../External/underscore.js'), + ko = require('../External/ko.js'), + + Enums = require('../Common/Enums.js'), + Utils = require('../Common/Utils.js'), + LinkBuilder = require('../Common/LinkBuilder.js'), + + Data = require('../Storages/AdminDataStorage.js'), + Remote = require('../Storages/AdminAjaxRemoteStorage.js') + ; + + /** + * @constructor + */ + function AdminSettingsSecurity() + { + this.useLocalProxyForExternalImages = Data.useLocalProxyForExternalImages; + + this.capaOpenPGP = ko.observable(RL.capa(Enums.Capa.OpenPGP)); + this.capaTwoFactorAuth = ko.observable(RL.capa(Enums.Capa.TwoFactor)); + + this.adminLogin = ko.observable(RL.settingsGet('AdminLogin')); + this.adminPassword = ko.observable(''); + this.adminPasswordNew = ko.observable(''); + this.adminPasswordNew2 = ko.observable(''); + this.adminPasswordNewError = ko.observable(false); + + this.adminPasswordUpdateError = ko.observable(false); + this.adminPasswordUpdateSuccess = ko.observable(false); + + this.adminPassword.subscribe(function () { + this.adminPasswordUpdateError(false); + this.adminPasswordUpdateSuccess(false); + }, this); + + this.adminPasswordNew.subscribe(function () { + this.adminPasswordUpdateError(false); + this.adminPasswordUpdateSuccess(false); + this.adminPasswordNewError(false); + }, this); + + this.adminPasswordNew2.subscribe(function () { + this.adminPasswordUpdateError(false); + this.adminPasswordUpdateSuccess(false); + this.adminPasswordNewError(false); + }, this); + + this.saveNewAdminPasswordCommand = Utils.createCommand(this, function () { + + if (this.adminPasswordNew() !== this.adminPasswordNew2()) + { + this.adminPasswordNewError(true); + return false; + } + + this.adminPasswordUpdateError(false); + this.adminPasswordUpdateSuccess(false); + + Remote.saveNewAdminPassword(this.onNewAdminPasswordResponse, { + 'Password': this.adminPassword(), + 'NewPassword': this.adminPasswordNew() + }); + + }, function () { + return '' !== this.adminPassword() && '' !== this.adminPasswordNew() && '' !== this.adminPasswordNew2(); + }); + + this.onNewAdminPasswordResponse = _.bind(this.onNewAdminPasswordResponse, this); + } + + kn.addSettingsViewModel(AdminSettingsSecurity, 'AdminSettingsSecurity', 'Security', 'security'); + + AdminSettingsSecurity.prototype.onNewAdminPasswordResponse = function (sResult, oData) + { + if (Enums.StorageResultType.Success === sResult && oData && oData.Result) + { + this.adminPassword(''); + this.adminPasswordNew(''); + this.adminPasswordNew2(''); + + this.adminPasswordUpdateSuccess(true); + } + else + { + this.adminPasswordUpdateError(true); + } + }; + + AdminSettingsSecurity.prototype.onBuild = function () + { + this.capaOpenPGP.subscribe(function (bValue) { + Remote.saveAdminConfig(Utils.emptyFunction, { + 'CapaOpenPGP': bValue ? '1' : '0' + }); + }); + + this.capaTwoFactorAuth.subscribe(function (bValue) { + Remote.saveAdminConfig(Utils.emptyFunction, { + 'CapaTwoFactorAuth': bValue ? '1' : '0' + }); + }); + + this.useLocalProxyForExternalImages.subscribe(function (bValue) { + Remote.saveAdminConfig(null, { + 'UseLocalProxyForExternalImages': bValue ? '1' : '0' + }); + }); + }; + + AdminSettingsSecurity.prototype.onHide = function () + { + this.adminPassword(''); + this.adminPasswordNew(''); + this.adminPasswordNew2(''); + }; + + /** + * @return {string} + */ + AdminSettingsSecurity.prototype.phpInfoLink = function () + { + return LinkBuilder.phpInfo(); + }; + + module.exports = AdminSettingsSecurity; + +}(module)); diff --git a/dev/Admin/AdminSettingsSocial.js b/dev/Admin/AdminSettingsSocial.js new file mode 100644 index 000000000..764519bbf --- /dev/null +++ b/dev/Admin/AdminSettingsSocial.js @@ -0,0 +1,153 @@ +/* RainLoop Webmail (c) RainLoop Team | Licensed under CC BY-NC-SA 3.0 */ + +(function (module) { + + 'use strict'; + + var + _ = require('../External/underscore.js'), + ko = require('../External/ko.js'), + + Enums = require('../Common/Enums.js'), + Utils = require('../Common/Utils.js'), + + Data = require('../Storages/AdminDataStorage.js'), + Remote = require('../Storages/AdminAjaxRemoteStorage.js') + ; + + /** + * @constructor + */ + function AdminSettingsSocial() + { + this.googleEnable = Data.googleEnable; + this.googleClientID = Data.googleClientID; + this.googleApiKey = Data.googleApiKey; + this.googleClientSecret = Data.googleClientSecret; + this.googleTrigger1 = ko.observable(Enums.SaveSettingsStep.Idle); + this.googleTrigger2 = ko.observable(Enums.SaveSettingsStep.Idle); + this.googleTrigger3 = ko.observable(Enums.SaveSettingsStep.Idle); + + this.facebookSupported = Data.facebookSupported; + this.facebookEnable = Data.facebookEnable; + this.facebookAppID = Data.facebookAppID; + this.facebookAppSecret = Data.facebookAppSecret; + this.facebookTrigger1 = ko.observable(Enums.SaveSettingsStep.Idle); + this.facebookTrigger2 = ko.observable(Enums.SaveSettingsStep.Idle); + + this.twitterEnable = Data.twitterEnable; + this.twitterConsumerKey = Data.twitterConsumerKey; + this.twitterConsumerSecret = Data.twitterConsumerSecret; + this.twitterTrigger1 = ko.observable(Enums.SaveSettingsStep.Idle); + this.twitterTrigger2 = ko.observable(Enums.SaveSettingsStep.Idle); + + this.dropboxEnable = Data.dropboxEnable; + this.dropboxApiKey = Data.dropboxApiKey; + this.dropboxTrigger1 = ko.observable(Enums.SaveSettingsStep.Idle); + } + + kn.addSettingsViewModel(AdminSettingsSocial, 'AdminSettingsSocial', 'Social', 'social'); + + AdminSettingsSocial.prototype.onBuild = function () + { + var self = this; + _.delay(function () { + + var + f1 = Utils.settingsSaveHelperSimpleFunction(self.facebookTrigger1, self), + f2 = Utils.settingsSaveHelperSimpleFunction(self.facebookTrigger2, self), + f3 = Utils.settingsSaveHelperSimpleFunction(self.twitterTrigger1, self), + f4 = Utils.settingsSaveHelperSimpleFunction(self.twitterTrigger2, self), + f5 = Utils.settingsSaveHelperSimpleFunction(self.googleTrigger1, self), + f6 = Utils.settingsSaveHelperSimpleFunction(self.googleTrigger2, self), + f7 = Utils.settingsSaveHelperSimpleFunction(self.googleTrigger3, self), + f8 = Utils.settingsSaveHelperSimpleFunction(self.dropboxTrigger1, self) + ; + + self.facebookEnable.subscribe(function (bValue) { + if (self.facebookSupported()) + { + Remote.saveAdminConfig(Utils.emptyFunction, { + 'FacebookEnable': bValue ? '1' : '0' + }); + } + }); + + self.facebookAppID.subscribe(function (sValue) { + if (self.facebookSupported()) + { + Remote.saveAdminConfig(f1, { + 'FacebookAppID': Utils.trim(sValue) + }); + } + }); + + self.facebookAppSecret.subscribe(function (sValue) { + if (self.facebookSupported()) + { + Remote.saveAdminConfig(f2, { + 'FacebookAppSecret': Utils.trim(sValue) + }); + } + }); + + self.twitterEnable.subscribe(function (bValue) { + Remote.saveAdminConfig(Utils.emptyFunction, { + 'TwitterEnable': bValue ? '1' : '0' + }); + }); + + self.twitterConsumerKey.subscribe(function (sValue) { + Remote.saveAdminConfig(f3, { + 'TwitterConsumerKey': Utils.trim(sValue) + }); + }); + + self.twitterConsumerSecret.subscribe(function (sValue) { + Remote.saveAdminConfig(f4, { + 'TwitterConsumerSecret': Utils.trim(sValue) + }); + }); + + self.googleEnable.subscribe(function (bValue) { + Remote.saveAdminConfig(Utils.emptyFunction, { + 'GoogleEnable': bValue ? '1' : '0' + }); + }); + + self.googleClientID.subscribe(function (sValue) { + Remote.saveAdminConfig(f5, { + 'GoogleClientID': Utils.trim(sValue) + }); + }); + + self.googleClientSecret.subscribe(function (sValue) { + Remote.saveAdminConfig(f6, { + 'GoogleClientSecret': Utils.trim(sValue) + }); + }); + + self.googleApiKey.subscribe(function (sValue) { + Remote.saveAdminConfig(f7, { + 'GoogleApiKey': Utils.trim(sValue) + }); + }); + + self.dropboxEnable.subscribe(function (bValue) { + Remote.saveAdminConfig(Utils.emptyFunction, { + 'DropboxEnable': bValue ? '1' : '0' + }); + }); + + self.dropboxApiKey.subscribe(function (sValue) { + Remote.saveAdminConfig(f8, { + 'DropboxApiKey': Utils.trim(sValue) + }); + }); + + }, 50); + }; + + module.exports = AdminSettingsSocial; + +}(module)); \ No newline at end of file diff --git a/dev/Admin/Branding.js b/dev/Admin/Branding.js deleted file mode 100644 index f3e6323b7..000000000 --- a/dev/Admin/Branding.js +++ /dev/null @@ -1,70 +0,0 @@ -/* RainLoop Webmail (c) RainLoop Team | Licensed under CC BY-NC-SA 3.0 */ - -/** - * @constructor - */ -function AdminBranding() -{ - this.title = ko.observable(RL.settingsGet('Title')); - this.title.trigger = ko.observable(Enums.SaveSettingsStep.Idle); - - this.loadingDesc = ko.observable(RL.settingsGet('LoadingDescription')); - this.loadingDesc.trigger = ko.observable(Enums.SaveSettingsStep.Idle); - - this.loginLogo = ko.observable(RL.settingsGet('LoginLogo')); - this.loginLogo.trigger = ko.observable(Enums.SaveSettingsStep.Idle); - - this.loginDescription = ko.observable(RL.settingsGet('LoginDescription')); - this.loginDescription.trigger = ko.observable(Enums.SaveSettingsStep.Idle); - - this.loginCss = ko.observable(RL.settingsGet('LoginCss')); - this.loginCss.trigger = ko.observable(Enums.SaveSettingsStep.Idle); -} - -Utils.addSettingsViewModel(AdminBranding, 'AdminSettingsBranding', 'Branding', 'branding'); - -AdminBranding.prototype.onBuild = function () -{ - var self = this; - _.delay(function () { - - var - f1 = Utils.settingsSaveHelperSimpleFunction(self.title.trigger, self), - f2 = Utils.settingsSaveHelperSimpleFunction(self.loadingDesc.trigger, self), - f3 = Utils.settingsSaveHelperSimpleFunction(self.loginLogo.trigger, self), - f4 = Utils.settingsSaveHelperSimpleFunction(self.loginDescription.trigger, self), - f5 = Utils.settingsSaveHelperSimpleFunction(self.loginCss.trigger, self) - ; - - self.title.subscribe(function (sValue) { - RL.remote().saveAdminConfig(f1, { - 'Title': Utils.trim(sValue) - }); - }); - - self.loadingDesc.subscribe(function (sValue) { - RL.remote().saveAdminConfig(f2, { - 'LoadingDescription': Utils.trim(sValue) - }); - }); - - self.loginLogo.subscribe(function (sValue) { - RL.remote().saveAdminConfig(f3, { - 'LoginLogo': Utils.trim(sValue) - }); - }); - - self.loginDescription.subscribe(function (sValue) { - RL.remote().saveAdminConfig(f4, { - 'LoginDescription': Utils.trim(sValue) - }); - }); - - self.loginCss.subscribe(function (sValue) { - RL.remote().saveAdminConfig(f5, { - 'LoginCss': Utils.trim(sValue) - }); - }); - - }, 50); -}; diff --git a/dev/Admin/Contacts.js b/dev/Admin/Contacts.js deleted file mode 100644 index 768bba028..000000000 --- a/dev/Admin/Contacts.js +++ /dev/null @@ -1,221 +0,0 @@ -/* RainLoop Webmail (c) RainLoop Team | Licensed under CC BY-NC-SA 3.0 */ - -/** - * @constructor - */ -function AdminContacts() -{ -// var oData = RL.data(); - - this.defautOptionsAfterRender = Utils.defautOptionsAfterRender; - this.enableContacts = ko.observable(!!RL.settingsGet('ContactsEnable')); - this.contactsSharing = ko.observable(!!RL.settingsGet('ContactsSharing')); - this.contactsSync = ko.observable(!!RL.settingsGet('ContactsSync')); - - var - aTypes = ['sqlite', 'mysql', 'pgsql'], - aSupportedTypes = [], - getTypeName = function(sName) { - switch (sName) - { - case 'sqlite': - sName = 'SQLite'; - break; - case 'mysql': - sName = 'MySQL'; - break; - case 'pgsql': - sName = 'PostgreSQL'; - break; - } - - return sName; - } - ; - - if (!!RL.settingsGet('SQLiteIsSupported')) - { - aSupportedTypes.push('sqlite'); - } - if (!!RL.settingsGet('MySqlIsSupported')) - { - aSupportedTypes.push('mysql'); - } - if (!!RL.settingsGet('PostgreSqlIsSupported')) - { - aSupportedTypes.push('pgsql'); - } - - this.contactsSupported = 0 < aSupportedTypes.length; - - this.contactsTypes = ko.observableArray([]); - this.contactsTypesOptions = this.contactsTypes.map(function (sValue) { - var bDisabled = -1 === Utils.inArray(sValue, aSupportedTypes); - return { - 'id': sValue, - 'name': getTypeName(sValue) + (bDisabled ? ' (not supported)' : ''), - 'disabled': bDisabled - }; - }); - - this.contactsTypes(aTypes); - this.contactsType = ko.observable(''); - - this.mainContactsType = ko.computed({ - 'owner': this, - 'read': this.contactsType, - 'write': function (sValue) { - if (sValue !== this.contactsType()) - { - if (-1 < Utils.inArray(sValue, aSupportedTypes)) - { - this.contactsType(sValue); - } - else if (0 < aSupportedTypes.length) - { - this.contactsType(''); - } - } - else - { - this.contactsType.valueHasMutated(); - } - } - }); - - this.contactsType.subscribe(function () { - this.testContactsSuccess(false); - this.testContactsError(false); - this.testContactsErrorMessage(''); - }, this); - - this.pdoDsn = ko.observable(RL.settingsGet('ContactsPdoDsn')); - this.pdoUser = ko.observable(RL.settingsGet('ContactsPdoUser')); - this.pdoPassword = ko.observable(RL.settingsGet('ContactsPdoPassword')); - - this.pdoDsnTrigger = ko.observable(Enums.SaveSettingsStep.Idle); - this.pdoUserTrigger = ko.observable(Enums.SaveSettingsStep.Idle); - this.pdoPasswordTrigger = ko.observable(Enums.SaveSettingsStep.Idle); - this.contactsTypeTrigger = ko.observable(Enums.SaveSettingsStep.Idle); - - this.testing = ko.observable(false); - this.testContactsSuccess = ko.observable(false); - this.testContactsError = ko.observable(false); - this.testContactsErrorMessage = ko.observable(''); - - this.testContactsCommand = Utils.createCommand(this, function () { - - this.testContactsSuccess(false); - this.testContactsError(false); - this.testContactsErrorMessage(''); - this.testing(true); - - RL.remote().testContacts(this.onTestContactsResponse, { - 'ContactsPdoType': this.contactsType(), - 'ContactsPdoDsn': this.pdoDsn(), - 'ContactsPdoUser': this.pdoUser(), - 'ContactsPdoPassword': this.pdoPassword() - }); - - }, function () { - return '' !== this.pdoDsn() && '' !== this.pdoUser(); - }); - - this.contactsType(RL.settingsGet('ContactsPdoType')); - - this.onTestContactsResponse = _.bind(this.onTestContactsResponse, this); -} - -Utils.addSettingsViewModel(AdminContacts, 'AdminSettingsContacts', 'Contacts', 'contacts'); - -AdminContacts.prototype.onTestContactsResponse = function (sResult, oData) -{ - this.testContactsSuccess(false); - this.testContactsError(false); - this.testContactsErrorMessage(''); - - if (Enums.StorageResultType.Success === sResult && oData && oData.Result && oData.Result.Result) - { - this.testContactsSuccess(true); - } - else - { - this.testContactsError(true); - if (oData && oData.Result) - { - this.testContactsErrorMessage(oData.Result.Message || ''); - } - else - { - this.testContactsErrorMessage(''); - } - } - - this.testing(false); -}; - -AdminContacts.prototype.onShow = function () -{ - this.testContactsSuccess(false); - this.testContactsError(false); - this.testContactsErrorMessage(''); -}; - -AdminContacts.prototype.onBuild = function () -{ - var self = this; - _.delay(function () { - - var - f1 = Utils.settingsSaveHelperSimpleFunction(self.pdoDsnTrigger, self), - f3 = Utils.settingsSaveHelperSimpleFunction(self.pdoUserTrigger, self), - f4 = Utils.settingsSaveHelperSimpleFunction(self.pdoPasswordTrigger, self), - f5 = Utils.settingsSaveHelperSimpleFunction(self.contactsTypeTrigger, self) - ; - - self.enableContacts.subscribe(function (bValue) { - RL.remote().saveAdminConfig(null, { - 'ContactsEnable': bValue ? '1' : '0' - }); - }); - - self.contactsSharing.subscribe(function (bValue) { - RL.remote().saveAdminConfig(null, { - 'ContactsSharing': bValue ? '1' : '0' - }); - }); - - self.contactsSync.subscribe(function (bValue) { - RL.remote().saveAdminConfig(null, { - 'ContactsSync': bValue ? '1' : '0' - }); - }); - - self.contactsType.subscribe(function (sValue) { - RL.remote().saveAdminConfig(f5, { - 'ContactsPdoType': sValue - }); - }); - - self.pdoDsn.subscribe(function (sValue) { - RL.remote().saveAdminConfig(f1, { - 'ContactsPdoDsn': Utils.trim(sValue) - }); - }); - - self.pdoUser.subscribe(function (sValue) { - RL.remote().saveAdminConfig(f3, { - 'ContactsPdoUser': Utils.trim(sValue) - }); - }); - - self.pdoPassword.subscribe(function (sValue) { - RL.remote().saveAdminConfig(f4, { - 'ContactsPdoPassword': Utils.trim(sValue) - }); - }); - - self.contactsType(RL.settingsGet('ContactsPdoType')); - - }, 50); -}; diff --git a/dev/Admin/Domains.js b/dev/Admin/Domains.js deleted file mode 100644 index ac2428268..000000000 --- a/dev/Admin/Domains.js +++ /dev/null @@ -1,90 +0,0 @@ -/* RainLoop Webmail (c) RainLoop Team | Licensed under CC BY-NC-SA 3.0 */ - -/** - * @constructor - */ -function AdminDomains() -{ - var oData = RL.data(); - - this.domains = oData.domains; - this.domainsLoading = oData.domainsLoading; - - this.iDomainForDeletionTimeout = 0; - - this.visibility = ko.computed(function () { - return oData.domainsLoading() ? 'visible' : 'hidden'; - }, this); - - this.domainForDeletion = ko.observable(null).extend({'toggleSubscribe': [this, - function (oPrev) { - if (oPrev) - { - oPrev.deleteAccess(false); - } - }, function (oNext) { - if (oNext) - { - oNext.deleteAccess(true); - this.startDomainForDeletionTimeout(); - } - } - ]}); -} - -Utils.addSettingsViewModel(AdminDomains, 'AdminSettingsDomains', 'Domains', 'domains'); - -AdminDomains.prototype.startDomainForDeletionTimeout = function () -{ - var self = this; - window.clearInterval(this.iDomainForDeletionTimeout); - this.iDomainForDeletionTimeout = window.setTimeout(function () { - self.domainForDeletion(null); - }, 1000 * 3); -}; - -AdminDomains.prototype.createDomain = function () -{ - kn.showScreenPopup(PopupsDomainViewModel); -}; - -AdminDomains.prototype.deleteDomain = function (oDomain) -{ - this.domains.remove(oDomain); - RL.remote().domainDelete(_.bind(this.onDomainListChangeRequest, this), oDomain.name); -}; - -AdminDomains.prototype.disableDomain = function (oDomain) -{ - oDomain.disabled(!oDomain.disabled()); - RL.remote().domainDisable(_.bind(this.onDomainListChangeRequest, this), oDomain.name, oDomain.disabled()); -}; - -AdminDomains.prototype.onBuild = function (oDom) -{ - var self = this; - oDom - .on('click', '.b-admin-domains-list-table .e-item .e-action', function () { - var oDomainItem = ko.dataFor(this); - if (oDomainItem) - { - RL.remote().domain(_.bind(self.onDomainLoadRequest, self), oDomainItem.name); - } - }) - ; - - RL.reloadDomainList(); -}; - -AdminDomains.prototype.onDomainLoadRequest = function (sResult, oData) -{ - if (Enums.StorageResultType.Success === sResult && oData && oData.Result) - { - kn.showScreenPopup(PopupsDomainViewModel, [oData.Result]); - } -}; - -AdminDomains.prototype.onDomainListChangeRequest = function () -{ - RL.reloadDomainList(); -}; diff --git a/dev/Admin/General.js b/dev/Admin/General.js deleted file mode 100644 index 9169e338b..000000000 --- a/dev/Admin/General.js +++ /dev/null @@ -1,127 +0,0 @@ -/* RainLoop Webmail (c) RainLoop Team | Licensed under CC BY-NC-SA 3.0 */ - -/** - * @constructor - */ -function AdminGeneral() -{ - var oData = RL.data(); - - this.mainLanguage = oData.mainLanguage; - this.mainTheme = oData.mainTheme; - - this.language = oData.language; - this.theme = oData.theme; - - this.allowLanguagesOnSettings = oData.allowLanguagesOnSettings; - this.capaThemes = oData.capaThemes; - this.capaGravatar = oData.capaGravatar; - this.capaAdditionalAccounts = oData.capaAdditionalAccounts; - this.capaAdditionalIdentities = oData.capaAdditionalIdentities; - - this.mainAttachmentLimit = ko.observable(Utils.pInt(RL.settingsGet('AttachmentLimit')) / (1024 * 1024)).extend({'posInterer': 25}); - this.uploadData = RL.settingsGet('PhpUploadSizes'); - this.uploadDataDesc = this.uploadData && (this.uploadData['upload_max_filesize'] || this.uploadData['post_max_size']) ? - [ - this.uploadData['upload_max_filesize'] ? 'upload_max_filesize = ' + this.uploadData['upload_max_filesize'] + '; ' : '', - this.uploadData['post_max_size'] ? 'post_max_size = ' + this.uploadData['post_max_size'] : '' - ].join('') - : ''; - - this.themesOptions = ko.computed(function () { - return _.map(oData.themes(), function (sTheme) { - return { - 'optValue': sTheme, - 'optText': Utils.convertThemeName(sTheme) - }; - }); - }); - - this.mainLanguageFullName = ko.computed(function () { - return Utils.convertLangName(this.mainLanguage()); - }, this); - - this.weakPassword = !!RL.settingsGet('WeakPassword'); - - this.attachmentLimitTrigger = ko.observable(Enums.SaveSettingsStep.Idle); - this.languageTrigger = ko.observable(Enums.SaveSettingsStep.Idle); - this.themeTrigger = ko.observable(Enums.SaveSettingsStep.Idle); -} - -Utils.addSettingsViewModel(AdminGeneral, 'AdminSettingsGeneral', 'General', 'general', true); - -AdminGeneral.prototype.onBuild = function () -{ - var self = this; - _.delay(function () { - - var - f1 = Utils.settingsSaveHelperSimpleFunction(self.attachmentLimitTrigger, self), - f2 = Utils.settingsSaveHelperSimpleFunction(self.languageTrigger, self), - f3 = Utils.settingsSaveHelperSimpleFunction(self.themeTrigger, self) - ; - - self.mainAttachmentLimit.subscribe(function (sValue) { - RL.remote().saveAdminConfig(f1, { - 'AttachmentLimit': Utils.pInt(sValue) - }); - }); - - self.language.subscribe(function (sValue) { - RL.remote().saveAdminConfig(f2, { - 'Language': Utils.trim(sValue) - }); - }); - - self.theme.subscribe(function (sValue) { - RL.remote().saveAdminConfig(f3, { - 'Theme': Utils.trim(sValue) - }); - }); - - self.capaAdditionalAccounts.subscribe(function (bValue) { - RL.remote().saveAdminConfig(null, { - 'CapaAdditionalAccounts': bValue ? '1' : '0' - }); - }); - - self.capaAdditionalIdentities.subscribe(function (bValue) { - RL.remote().saveAdminConfig(null, { - 'CapaAdditionalIdentities': bValue ? '1' : '0' - }); - }); - - self.capaGravatar.subscribe(function (bValue) { - RL.remote().saveAdminConfig(null, { - 'CapaGravatar': bValue ? '1' : '0' - }); - }); - - self.capaThemes.subscribe(function (bValue) { - RL.remote().saveAdminConfig(null, { - 'CapaThemes': bValue ? '1' : '0' - }); - }); - - self.allowLanguagesOnSettings.subscribe(function (bValue) { - RL.remote().saveAdminConfig(null, { - 'AllowLanguagesOnSettings': bValue ? '1' : '0' - }); - }); - - }, 50); -}; - -AdminGeneral.prototype.selectLanguage = function () -{ - kn.showScreenPopup(PopupsLanguagesViewModel); -}; - -/** - * @return {string} - */ -AdminGeneral.prototype.phpInfoLink = function () -{ - return RL.link().phpInfo(); -}; - diff --git a/dev/Admin/Licensing.js b/dev/Admin/Licensing.js deleted file mode 100644 index 27e2d58e8..000000000 --- a/dev/Admin/Licensing.js +++ /dev/null @@ -1,57 +0,0 @@ -/* RainLoop Webmail (c) RainLoop Team | Licensed under CC BY-NC-SA 3.0 */ - -/** - * @constructor - */ -function AdminLicensing() -{ - this.licensing = RL.data().licensing; - this.licensingProcess = RL.data().licensingProcess; - this.licenseValid = RL.data().licenseValid; - this.licenseExpired = RL.data().licenseExpired; - this.licenseError = RL.data().licenseError; - this.licenseTrigger = RL.data().licenseTrigger; - - this.adminDomain = ko.observable(''); - this.subscriptionEnabled = ko.observable(!!RL.settingsGet('SubscriptionEnabled')); - - this.licenseTrigger.subscribe(function () { - if (this.subscriptionEnabled()) - { - RL.reloadLicensing(true); - } - }, this); -} - -Utils.addSettingsViewModel(AdminLicensing, 'AdminSettingsLicensing', 'Licensing', 'licensing'); - -AdminLicensing.prototype.onBuild = function () -{ - if (this.subscriptionEnabled()) - { - RL.reloadLicensing(false); - } -}; - -AdminLicensing.prototype.onShow = function () -{ - this.adminDomain(RL.settingsGet('AdminDomain')); -}; - -AdminLicensing.prototype.showActivationForm = function () -{ - kn.showScreenPopup(PopupsActivateViewModel); -}; - -/** - * @returns {string} - */ -AdminLicensing.prototype.licenseExpiredMomentValue = function () -{ - var - iTime = this.licenseExpired(), - oDate = moment.unix(iTime) - ; - - return iTime && 1898625600 === iTime ? 'Never' : (oDate.format('LL') + ' (' + oDate.from(moment()) + ')'); -}; \ No newline at end of file diff --git a/dev/Admin/Login.js b/dev/Admin/Login.js deleted file mode 100644 index b707212a9..000000000 --- a/dev/Admin/Login.js +++ /dev/null @@ -1,53 +0,0 @@ -/* RainLoop Webmail (c) RainLoop Team | Licensed under CC BY-NC-SA 3.0 */ - -/** - * @constructor - */ -function AdminLogin() -{ - var oData = RL.data(); - - this.determineUserLanguage = oData.determineUserLanguage; - this.determineUserDomain = oData.determineUserDomain; - - this.defaultDomain = ko.observable(RL.settingsGet('LoginDefaultDomain')); - - this.allowLanguagesOnLogin = oData.allowLanguagesOnLogin; - this.defaultDomainTrigger = ko.observable(Enums.SaveSettingsStep.Idle); -} - -Utils.addSettingsViewModel(AdminLogin, 'AdminSettingsLogin', 'Login', 'login'); - -AdminLogin.prototype.onBuild = function () -{ - var self = this; - _.delay(function () { - - var f1 = Utils.settingsSaveHelperSimpleFunction(self.defaultDomainTrigger, self); - - self.determineUserLanguage.subscribe(function (bValue) { - RL.remote().saveAdminConfig(null, { - 'DetermineUserLanguage': bValue ? '1' : '0' - }); - }); - - self.determineUserDomain.subscribe(function (bValue) { - RL.remote().saveAdminConfig(null, { - 'DetermineUserDomain': bValue ? '1' : '0' - }); - }); - - self.allowLanguagesOnLogin.subscribe(function (bValue) { - RL.remote().saveAdminConfig(null, { - 'AllowLanguagesOnLogin': bValue ? '1' : '0' - }); - }); - - self.defaultDomain.subscribe(function (sValue) { - RL.remote().saveAdminConfig(f1, { - 'LoginDefaultDomain': Utils.trim(sValue) - }); - }); - - }, 50); -}; diff --git a/dev/Admin/Packages.js b/dev/Admin/Packages.js deleted file mode 100644 index f718a0f4b..000000000 --- a/dev/Admin/Packages.js +++ /dev/null @@ -1,99 +0,0 @@ -/* RainLoop Webmail (c) RainLoop Team | Licensed under CC BY-NC-SA 3.0 */ - -/** - * @constructor - */ -function AdminPackages() -{ - var oData = RL.data(); - - this.packagesError = ko.observable(''); - - this.packages = oData.packages; - this.packagesLoading = oData.packagesLoading; - this.packagesReal = oData.packagesReal; - this.packagesMainUpdatable = oData.packagesMainUpdatable; - - this.packagesCurrent = this.packages.filter(function (oItem) { - return oItem && '' !== oItem['installed'] && !oItem['compare']; - }); - - this.packagesAvailableForUpdate = this.packages.filter(function (oItem) { - return oItem && '' !== oItem['installed'] && !!oItem['compare']; - }); - - this.packagesAvailableForInstallation = this.packages.filter(function (oItem) { - return oItem && '' === oItem['installed']; - }); - - this.visibility = ko.computed(function () { - return oData.packagesLoading() ? 'visible' : 'hidden'; - }, this); -} - -Utils.addSettingsViewModel(AdminPackages, 'AdminSettingsPackages', 'Packages', 'packages'); - -AdminPackages.prototype.onShow = function () -{ - this.packagesError(''); -}; - -AdminPackages.prototype.onBuild = function () -{ - RL.reloadPackagesList(); -}; - -AdminPackages.prototype.requestHelper = function (oPackage, bInstall) -{ - var self = this; - return function (sResult, oData) { - - if (Enums.StorageResultType.Success !== sResult || !oData || !oData.Result) - { - if (oData && oData.ErrorCode) - { - self.packagesError(Utils.getNotification(oData.ErrorCode)); - } - else - { - self.packagesError(Utils.getNotification( - bInstall ? Enums.Notification.CantInstallPackage : Enums.Notification.CantDeletePackage)); - } - } - - _.each(RL.data().packages(), function (oItem) { - if (oItem && oPackage && oItem['loading']() && oPackage['file'] === oItem['file']) - { - oPackage['loading'](false); - oItem['loading'](false); - } - }); - - if (Enums.StorageResultType.Success === sResult && oData && oData.Result && oData.Result['Reload']) - { - window.location.reload(); - } - else - { - RL.reloadPackagesList(); - } - }; -}; - -AdminPackages.prototype.deletePackage = function (oPackage) -{ - if (oPackage) - { - oPackage['loading'](true); - RL.remote().packageDelete(this.requestHelper(oPackage, false), oPackage); - } -}; - -AdminPackages.prototype.installPackage = function (oPackage) -{ - if (oPackage) - { - oPackage['loading'](true); - RL.remote().packageInstall(this.requestHelper(oPackage, true), oPackage); - } -}; diff --git a/dev/Admin/Plugins.js b/dev/Admin/Plugins.js deleted file mode 100644 index db4dcbcc9..000000000 --- a/dev/Admin/Plugins.js +++ /dev/null @@ -1,98 +0,0 @@ -/* RainLoop Webmail (c) RainLoop Team | Licensed under CC BY-NC-SA 3.0 */ - -/** - * @constructor - */ -function AdminPlugins() -{ - var oData = RL.data(); - - this.enabledPlugins = ko.observable(!!RL.settingsGet('EnabledPlugins')); - - this.pluginsError = ko.observable(''); - - this.plugins = oData.plugins; - this.pluginsLoading = oData.pluginsLoading; - - this.visibility = ko.computed(function () { - return oData.pluginsLoading() ? 'visible' : 'hidden'; - }, this); - - this.onPluginLoadRequest = _.bind(this.onPluginLoadRequest, this); - this.onPluginDisableRequest = _.bind(this.onPluginDisableRequest, this); -} - -Utils.addSettingsViewModel(AdminPlugins, 'AdminSettingsPlugins', 'Plugins', 'plugins'); - -AdminPlugins.prototype.disablePlugin = function (oPlugin) -{ - oPlugin.disabled(!oPlugin.disabled()); - RL.remote().pluginDisable(this.onPluginDisableRequest, oPlugin.name, oPlugin.disabled()); -}; - -AdminPlugins.prototype.configurePlugin = function (oPlugin) -{ - RL.remote().plugin(this.onPluginLoadRequest, oPlugin.name); -}; - -AdminPlugins.prototype.onBuild = function (oDom) -{ - var self = this; - - oDom - .on('click', '.e-item .configure-plugin-action', function () { - var oPlugin = ko.dataFor(this); - if (oPlugin) - { - self.configurePlugin(oPlugin); - } - }) - .on('click', '.e-item .disabled-plugin', function () { - var oPlugin = ko.dataFor(this); - if (oPlugin) - { - self.disablePlugin(oPlugin); - } - }) - ; - - this.enabledPlugins.subscribe(function (bValue) { - RL.remote().saveAdminConfig(Utils.emptyFunction, { - 'EnabledPlugins': bValue ? '1' : '0' - }); - }); -}; - -AdminPlugins.prototype.onShow = function () -{ - this.pluginsError(''); - RL.reloadPluginList(); -}; - -AdminPlugins.prototype.onPluginLoadRequest = function (sResult, oData) -{ - if (Enums.StorageResultType.Success === sResult && oData && oData.Result) - { - kn.showScreenPopup(PopupsPluginViewModel, [oData.Result]); - } -}; - -AdminPlugins.prototype.onPluginDisableRequest = function (sResult, oData) -{ - if (Enums.StorageResultType.Success === sResult && oData) - { - if (!oData.Result && oData.ErrorCode) - { - if (Enums.Notification.UnsupportedPluginPackage === oData.ErrorCode && oData.ErrorMessage && '' !== oData.ErrorMessage) - { - this.pluginsError(oData.ErrorMessage); - } - else - { - this.pluginsError(Utils.getNotification(oData.ErrorCode)); - } - } - } - - RL.reloadPluginList(); -}; diff --git a/dev/Admin/Security.js b/dev/Admin/Security.js deleted file mode 100644 index a99e55b4c..000000000 --- a/dev/Admin/Security.js +++ /dev/null @@ -1,114 +0,0 @@ -/* RainLoop Webmail (c) RainLoop Team | Licensed under CC BY-NC-SA 3.0 */ - -/** - * @constructor - */ -function AdminSecurity() -{ - this.useLocalProxyForExternalImages = RL.data().useLocalProxyForExternalImages; - - this.capaOpenPGP = ko.observable(RL.capa(Enums.Capa.OpenPGP)); - this.capaTwoFactorAuth = ko.observable(RL.capa(Enums.Capa.TwoFactor)); - - this.adminLogin = ko.observable(RL.settingsGet('AdminLogin')); - this.adminPassword = ko.observable(''); - this.adminPasswordNew = ko.observable(''); - this.adminPasswordNew2 = ko.observable(''); - this.adminPasswordNewError = ko.observable(false); - - this.adminPasswordUpdateError = ko.observable(false); - this.adminPasswordUpdateSuccess = ko.observable(false); - - this.adminPassword.subscribe(function () { - this.adminPasswordUpdateError(false); - this.adminPasswordUpdateSuccess(false); - }, this); - - this.adminPasswordNew.subscribe(function () { - this.adminPasswordUpdateError(false); - this.adminPasswordUpdateSuccess(false); - this.adminPasswordNewError(false); - }, this); - - this.adminPasswordNew2.subscribe(function () { - this.adminPasswordUpdateError(false); - this.adminPasswordUpdateSuccess(false); - this.adminPasswordNewError(false); - }, this); - - this.saveNewAdminPasswordCommand = Utils.createCommand(this, function () { - - if (this.adminPasswordNew() !== this.adminPasswordNew2()) - { - this.adminPasswordNewError(true); - return false; - } - - this.adminPasswordUpdateError(false); - this.adminPasswordUpdateSuccess(false); - - RL.remote().saveNewAdminPassword(this.onNewAdminPasswordResponse, { - 'Password': this.adminPassword(), - 'NewPassword': this.adminPasswordNew() - }); - - }, function () { - return '' !== this.adminPassword() && '' !== this.adminPasswordNew() && '' !== this.adminPasswordNew2(); - }); - - this.onNewAdminPasswordResponse = _.bind(this.onNewAdminPasswordResponse, this); -} - -Utils.addSettingsViewModel(AdminSecurity, 'AdminSettingsSecurity', 'Security', 'security'); - -AdminSecurity.prototype.onNewAdminPasswordResponse = function (sResult, oData) -{ - if (Enums.StorageResultType.Success === sResult && oData && oData.Result) - { - this.adminPassword(''); - this.adminPasswordNew(''); - this.adminPasswordNew2(''); - - this.adminPasswordUpdateSuccess(true); - } - else - { - this.adminPasswordUpdateError(true); - } -}; - -AdminSecurity.prototype.onBuild = function () -{ - this.capaOpenPGP.subscribe(function (bValue) { - RL.remote().saveAdminConfig(Utils.emptyFunction, { - 'CapaOpenPGP': bValue ? '1' : '0' - }); - }); - - this.capaTwoFactorAuth.subscribe(function (bValue) { - RL.remote().saveAdminConfig(Utils.emptyFunction, { - 'CapaTwoFactorAuth': bValue ? '1' : '0' - }); - }); - - this.useLocalProxyForExternalImages.subscribe(function (bValue) { - RL.remote().saveAdminConfig(null, { - 'UseLocalProxyForExternalImages': bValue ? '1' : '0' - }); - }); -}; - -AdminSecurity.prototype.onHide = function () -{ - this.adminPassword(''); - this.adminPasswordNew(''); - this.adminPasswordNew2(''); -}; - -/** - * @return {string} - */ -AdminSecurity.prototype.phpInfoLink = function () -{ - return RL.link().phpInfo(); -}; diff --git a/dev/Admin/Social.js b/dev/Admin/Social.js deleted file mode 100644 index c3ded5477..000000000 --- a/dev/Admin/Social.js +++ /dev/null @@ -1,136 +0,0 @@ -/* RainLoop Webmail (c) RainLoop Team | Licensed under CC BY-NC-SA 3.0 */ - -/** - * @constructor - */ -function AdminSocial() -{ - var oData = RL.data(); - - this.googleEnable = oData.googleEnable; - this.googleClientID = oData.googleClientID; - this.googleApiKey = oData.googleApiKey; - this.googleClientSecret = oData.googleClientSecret; - this.googleTrigger1 = ko.observable(Enums.SaveSettingsStep.Idle); - this.googleTrigger2 = ko.observable(Enums.SaveSettingsStep.Idle); - this.googleTrigger3 = ko.observable(Enums.SaveSettingsStep.Idle); - - this.facebookSupported = oData.facebookSupported; - this.facebookEnable = oData.facebookEnable; - this.facebookAppID = oData.facebookAppID; - this.facebookAppSecret = oData.facebookAppSecret; - this.facebookTrigger1 = ko.observable(Enums.SaveSettingsStep.Idle); - this.facebookTrigger2 = ko.observable(Enums.SaveSettingsStep.Idle); - - this.twitterEnable = oData.twitterEnable; - this.twitterConsumerKey = oData.twitterConsumerKey; - this.twitterConsumerSecret = oData.twitterConsumerSecret; - this.twitterTrigger1 = ko.observable(Enums.SaveSettingsStep.Idle); - this.twitterTrigger2 = ko.observable(Enums.SaveSettingsStep.Idle); - - this.dropboxEnable = oData.dropboxEnable; - this.dropboxApiKey = oData.dropboxApiKey; - this.dropboxTrigger1 = ko.observable(Enums.SaveSettingsStep.Idle); -} - -Utils.addSettingsViewModel(AdminSocial, 'AdminSettingsSocial', 'Social', 'social'); - -AdminSocial.prototype.onBuild = function () -{ - var self = this; - _.delay(function () { - - var - f1 = Utils.settingsSaveHelperSimpleFunction(self.facebookTrigger1, self), - f2 = Utils.settingsSaveHelperSimpleFunction(self.facebookTrigger2, self), - f3 = Utils.settingsSaveHelperSimpleFunction(self.twitterTrigger1, self), - f4 = Utils.settingsSaveHelperSimpleFunction(self.twitterTrigger2, self), - f5 = Utils.settingsSaveHelperSimpleFunction(self.googleTrigger1, self), - f6 = Utils.settingsSaveHelperSimpleFunction(self.googleTrigger2, self), - f7 = Utils.settingsSaveHelperSimpleFunction(self.googleTrigger3, self), - f8 = Utils.settingsSaveHelperSimpleFunction(self.dropboxTrigger1, self) - ; - - self.facebookEnable.subscribe(function (bValue) { - if (self.facebookSupported()) - { - RL.remote().saveAdminConfig(Utils.emptyFunction, { - 'FacebookEnable': bValue ? '1' : '0' - }); - } - }); - - self.facebookAppID.subscribe(function (sValue) { - if (self.facebookSupported()) - { - RL.remote().saveAdminConfig(f1, { - 'FacebookAppID': Utils.trim(sValue) - }); - } - }); - - self.facebookAppSecret.subscribe(function (sValue) { - if (self.facebookSupported()) - { - RL.remote().saveAdminConfig(f2, { - 'FacebookAppSecret': Utils.trim(sValue) - }); - } - }); - - self.twitterEnable.subscribe(function (bValue) { - RL.remote().saveAdminConfig(Utils.emptyFunction, { - 'TwitterEnable': bValue ? '1' : '0' - }); - }); - - self.twitterConsumerKey.subscribe(function (sValue) { - RL.remote().saveAdminConfig(f3, { - 'TwitterConsumerKey': Utils.trim(sValue) - }); - }); - - self.twitterConsumerSecret.subscribe(function (sValue) { - RL.remote().saveAdminConfig(f4, { - 'TwitterConsumerSecret': Utils.trim(sValue) - }); - }); - - self.googleEnable.subscribe(function (bValue) { - RL.remote().saveAdminConfig(Utils.emptyFunction, { - 'GoogleEnable': bValue ? '1' : '0' - }); - }); - - self.googleClientID.subscribe(function (sValue) { - RL.remote().saveAdminConfig(f5, { - 'GoogleClientID': Utils.trim(sValue) - }); - }); - - self.googleClientSecret.subscribe(function (sValue) { - RL.remote().saveAdminConfig(f6, { - 'GoogleClientSecret': Utils.trim(sValue) - }); - }); - - self.googleApiKey.subscribe(function (sValue) { - RL.remote().saveAdminConfig(f7, { - 'GoogleApiKey': Utils.trim(sValue) - }); - }); - - self.dropboxEnable.subscribe(function (bValue) { - RL.remote().saveAdminConfig(Utils.emptyFunction, { - 'DropboxEnable': bValue ? '1' : '0' - }); - }); - - self.dropboxApiKey.subscribe(function (sValue) { - RL.remote().saveAdminConfig(f8, { - 'DropboxApiKey': Utils.trim(sValue) - }); - }); - - }, 50); -}; diff --git a/dev/AdminBoot.js b/dev/AdminBoot.js index a3c22bbb8..3ead2b25f 100644 --- a/dev/AdminBoot.js +++ b/dev/AdminBoot.js @@ -4,7 +4,8 @@ var kn = require('./Knoin/Knoin.js'), - RL = require('./Boots/AdminApp.js') + RL = require('./Boots/AdminApp.js'), + Remote = require('./Storages/AdminAjaxRemoteStorage.js') ; -kn.bootstart(RL); \ No newline at end of file +kn.bootstart(RL, Remote); \ No newline at end of file diff --git a/dev/Boots/AbstractApp.js b/dev/Boots/AbstractApp.js index 30ac22293..9824d1f36 100644 --- a/dev/Boots/AbstractApp.js +++ b/dev/Boots/AbstractApp.js @@ -13,10 +13,16 @@ $window = require('../External/$window.js'), $doc = require('../External/$doc.js'), AppData = require('../External/AppData.js'), + Globals = require('../Common/Globals.js'), Utils = require('../Common/Utils.js'), - KnoinAbstractBoot = require('../Knoin/KnoinAbstractBoot.js'), - RL = require('./RL.js') + Plugins = require('../Common/Plugins.js'), + LinkBuilder = require('../Common/LinkBuilder.js'), + + Remote = require('../Remote.js'), + + kn = require('../Knoin/Knoin.js'), + KnoinAbstractBoot = require('../Knoin/KnoinAbstractBoot.js') ; /** @@ -49,8 +55,7 @@ 'Script error.', 'Uncaught Error: Error calling method on NPObject.' ])) { - // TODO cjs - RL.remote().jsError( + Remote().jsError( Utils.emptyFunction, oEvent.originalEvent.message, oEvent.originalEvent.filename, @@ -126,32 +131,6 @@ return true; }; - /** - * @return {LinkBuilder} - */ - AbstractApp.prototype.link = function () - { - if (null === this.oLink) - { - this.oLink = new LinkBuilder(); // TODO cjs - } - - return this.oLink; - }; - - /** - * @return {LocalStorage} - */ - AbstractApp.prototype.local = function () - { - if (null === this.oLocal) - { - this.oLocal = new LocalStorage(); // TODO cjs - } - - return this.oLocal; - }; - /** * @param {string} sName * @return {?} @@ -183,7 +162,7 @@ AbstractApp.prototype.setTitle = function (sTitle) { sTitle = ((Utils.isNormal(sTitle) && 0 < sTitle.length) ? sTitle + ' - ' : '') + - RL.settingsGet('Title') || ''; // TODO cjs + this.settingsGet('Title') || ''; window.document.title = '_'; window.document.title = sTitle; @@ -196,12 +175,10 @@ AbstractApp.prototype.loginAndLogoutReload = function (bLogout, bClose) { var - sCustomLogoutLink = Utils.pString(RL.settingsGet('CustomLogoutLink')), - bInIframe = !!RL.settingsGet('InIframe') + sCustomLogoutLink = Utils.pString(this.settingsGet('CustomLogoutLink')), + bInIframe = !!this.settingsGet('InIframe') ; - // TODO cjs - bLogout = Utils.isUnd(bLogout) ? false : !!bLogout; bClose = Utils.isUnd(bClose) ? false : !!bClose; @@ -226,7 +203,7 @@ else { kn.routeOff(); - kn.setHash(RL.link().root(), true); + kn.setHash(LinkBuilder.root(), true); kn.routeOff(); _.delay(function () { @@ -307,7 +284,10 @@ AbstractApp.prototype.bootstart = function () { - var ssm = require('../External/ssm.js'); + var + self = this, + ssm = require('../External/ssm.js') + ; Utils.initOnStartOrLangChange(function () { Utils.initNotificationLanguage(); @@ -322,11 +302,11 @@ 'maxWidth': 767, 'onEnter': function() { $html.addClass('ssm-state-mobile'); - RL.pub('ssm.mobile-enter'); + self.pub('ssm.mobile-enter'); }, 'onLeave': function() { $html.removeClass('ssm-state-mobile'); - RL.pub('ssm.mobile-leave'); + self.pub('ssm.mobile-leave'); } }); @@ -365,12 +345,12 @@ } }); - RL.sub('ssm.mobile-enter', function () { // TODO cjs - RL.data().leftPanelDisabled(true); + this.sub('ssm.mobile-enter', function () { + RL.data().leftPanelDisabled(true); // TODO cjs }); - RL.sub('ssm.mobile-leave', function () { // TODO cjs - RL.data().leftPanelDisabled(false); + this.sub('ssm.mobile-leave', function () { + RL.data().leftPanelDisabled(false); // TODO cjs }); RL.data().leftPanelDisabled.subscribe(function (bValue) { // TODO cjs diff --git a/dev/Boots/AdminApp.js b/dev/Boots/AdminApp.js index 7d3aaa440..862066d74 100644 --- a/dev/Boots/AdminApp.js +++ b/dev/Boots/AdminApp.js @@ -8,9 +8,16 @@ ko = require('../External/ko.js'), _ = require('../External/underscore.js'), window = require('../External/window.js'), + Enums = require('../Common/Enums.js'), Utils = require('../Common/Utils.js'), + LinkBuilder = require('../Common/LinkBuilder.js'), + kn = require('../Knoin/Knoin.js'), + + Data = require('../Storages/AdminDataStorage.js'), + Remote = require('../Storages/AdminAjaxRemoteStorage.js'), + AbstractApp = require('./AbstractApp.js') ; @@ -59,25 +66,12 @@ return this.oRemote; }; - /** - * @return {AdminCacheStorage} - */ - AdminApp.prototype.cache = function () - { - if (null === this.oCache) - { - this.oCache = new AdminCacheStorage(); // TODO cjs - } - - return this.oCache; - }; - AdminApp.prototype.reloadDomainList = function () { // TODO cjs - RL.data().domainsLoading(true); - RL.remote().domainList(function (sResult, oData) { - RL.data().domainsLoading(false); + Data.domainsLoading(true); + Remote.domainList(function (sResult, oData) { + Data.domainsLoading(false); if (Enums.StorageResultType.Success === sResult && oData && oData.Result) { var aList = _.map(oData.Result, function (bEnabled, sName) { @@ -88,7 +82,7 @@ }; }, this); - RL.data().domains(aList); + Data.domains(aList); } }); }; @@ -96,9 +90,9 @@ AdminApp.prototype.reloadPluginList = function () { // TODO cjs - RL.data().pluginsLoading(true); - RL.remote().pluginList(function (sResult, oData) { - RL.data().pluginsLoading(false); + Data.pluginsLoading(true); + Remote.pluginList(function (sResult, oData) { + Data.pluginsLoading(false); if (Enums.StorageResultType.Success === sResult && oData && oData.Result) { var aList = _.map(oData.Result, function (oItem) { @@ -109,7 +103,7 @@ }; }, this); - RL.data().plugins(aList); + Data.plugins(aList); } }); }; @@ -117,24 +111,24 @@ AdminApp.prototype.reloadPackagesList = function () { // TODO cjs - RL.data().packagesLoading(true); - RL.data().packagesReal(true); + Data.packagesLoading(true); + Data.packagesReal(true); - RL.remote().packagesList(function (sResult, oData) { + Remote.packagesList(function (sResult, oData) { - RL.data().packagesLoading(false); + Data.packagesLoading(false); if (Enums.StorageResultType.Success === sResult && oData && oData.Result) { - RL.data().packagesReal(!!oData.Result.Real); - RL.data().packagesMainUpdatable(!!oData.Result.MainUpdatable); + Data.packagesReal(!!oData.Result.Real); + Data.packagesMainUpdatable(!!oData.Result.MainUpdatable); var aList = [], aLoading = {} ; - _.each(RL.data().packages(), function (oItem) { + _.each(Data.packages(), function (oItem) { if (oItem && oItem['loading']()) { aLoading[oItem['file']] = oItem; @@ -153,36 +147,33 @@ })); } - RL.data().packages(aList); + Data.packages(aList); } else { - RL.data().packagesReal(false); + Data.packagesReal(false); } }); }; AdminApp.prototype.updateCoreData = function () { - // TODO cjs - var oRainData = RL.data(); + Data.coreUpdating(true); + Remote.updateCoreData(function (sResult, oData) { - oRainData.coreUpdating(true); - RL.remote().updateCoreData(function (sResult, oData) { - - oRainData.coreUpdating(false); - oRainData.coreRemoteVersion(''); - oRainData.coreRemoteRelease(''); - oRainData.coreVersionCompare(-2); + Data.coreUpdating(false); + Data.coreRemoteVersion(''); + Data.coreRemoteRelease(''); + Data.coreVersionCompare(-2); if (Enums.StorageResultType.Success === sResult && oData && oData.Result) { - oRainData.coreReal(true); + Data.coreReal(true); window.location.reload(); } else { - oRainData.coreReal(false); + Data.coreReal(false); } }); @@ -190,30 +181,28 @@ AdminApp.prototype.reloadCoreData = function () { - var oRainData = RL.data(); + Data.coreChecking(true); + Data.coreReal(true); - oRainData.coreChecking(true); - oRainData.coreReal(true); + Remote.coreData(function (sResult, oData) { - RL.remote().coreData(function (sResult, oData) { - - oRainData.coreChecking(false); + Data.coreChecking(false); if (Enums.StorageResultType.Success === sResult && oData && oData.Result) { - oRainData.coreReal(!!oData.Result.Real); - oRainData.coreUpdatable(!!oData.Result.Updatable); - oRainData.coreAccess(!!oData.Result.Access); - oRainData.coreRemoteVersion(oData.Result.RemoteVersion || ''); - oRainData.coreRemoteRelease(oData.Result.RemoteRelease || ''); - oRainData.coreVersionCompare(Utils.pInt(oData.Result.VersionCompare)); + Data.coreReal(!!oData.Result.Real); + Data.coreUpdatable(!!oData.Result.Updatable); + Data.coreAccess(!!oData.Result.Access); + Data.coreRemoteVersion(oData.Result.RemoteVersion || ''); + Data.coreRemoteRelease(oData.Result.RemoteRelease || ''); + Data.coreVersionCompare(Utils.pInt(oData.Result.VersionCompare)); } else { - oRainData.coreReal(false); - oRainData.coreRemoteVersion(''); - oRainData.coreRemoteRelease(''); - oRainData.coreVersionCompare(-2); + Data.coreReal(false); + Data.coreRemoteVersion(''); + Data.coreRemoteRelease(''); + Data.coreVersionCompare(-2); } }); }; @@ -227,18 +216,18 @@ bForce = Utils.isUnd(bForce) ? false : !!bForce; // TODO cjs - RL.data().licensingProcess(true); - RL.data().licenseError(''); + Data.licensingProcess(true); + Data.licenseError(''); - RL.remote().licensing(function (sResult, oData) { - RL.data().licensingProcess(false); + Remote.licensing(function (sResult, oData) { + Data.licensingProcess(false); if (Enums.StorageResultType.Success === sResult && oData && oData.Result && Utils.isNormal(oData.Result['Expired'])) { - RL.data().licenseValid(true); - RL.data().licenseExpired(Utils.pInt(oData.Result['Expired'])); - RL.data().licenseError(''); + Data.licenseValid(true); + Data.licenseExpired(Utils.pInt(oData.Result['Expired'])); + Data.licenseError(''); - RL.data().licensing(true); + Data.licensing(true); } else { @@ -247,19 +236,19 @@ Enums.Notification.LicensingExpired ])) { - RL.data().licenseError(Utils.getNotification(Utils.pInt(oData.ErrorCode))); - RL.data().licensing(true); + Data.licenseError(Utils.getNotification(Utils.pInt(oData.ErrorCode))); + Data.licensing(true); } else { if (Enums.StorageResultType.Abort === sResult) { - RL.data().licenseError(Utils.getNotification(Enums.Notification.LicensingServerIsUnavailable)); - RL.data().licensing(true); + Data.licenseError(Utils.getNotification(Enums.Notification.LicensingServerIsUnavailable)); + Data.licensing(true); } else { - RL.data().licensing(false); + Data.licensing(false); } } } @@ -270,14 +259,14 @@ { AbstractApp.prototype.bootstart.call(this); - RL.data().populateDataOnStart(); + Data.populateDataOnStart(); kn.hideLoading(); if (!RL.settingsGet('AllowAdminPanel')) { kn.routeOff(); - kn.setHash(RL.link().root(), true); + kn.setHash(LinkBuilder.root(), true); kn.routeOff(); _.defer(function () { @@ -286,11 +275,11 @@ } else { - // Utils.removeSettingsViewModel(AdminAbout); + // kn.removeSettingsViewModel(AdminAbout); if (!RL.capa(Enums.Capa.Prem)) { - Utils.removeSettingsViewModel(AdminBranding); + kn.removeSettingsViewModel(AdminBranding); } if (!!RL.settingsGet('Auth')) @@ -298,7 +287,7 @@ // TODO // if (!RL.settingsGet('AllowPackages') && AdminPackages) // { - // Utils.disableSettingsViewModel(AdminPackages); + // kn.disableSettingsViewModel(AdminPackages); // } kn.startScreens([AdminSettingsScreen]); diff --git a/dev/Boots/RainLoopApp.js b/dev/Boots/RainLoopApp.js index 655071e41..fbf2323c2 100644 --- a/dev/Boots/RainLoopApp.js +++ b/dev/Boots/RainLoopApp.js @@ -8,12 +8,24 @@ window = require('../External/window.js'), $ = require('../External/jquery.js'), _ = require('../External/underscore.js'), + moment = require('../External/moment.js'), + Enums = require('../Common/Enums.js'), Globals = require('../Common/Globals.js'), Consts = require('../Common/Consts.js'), Plugins = require('../Common/Plugins.js'), Utils = require('../Common/Utils.js'), + LinkBuilder = require('../Common/LinkBuilder.js'), + kn = require('../Knoin/Knoin.js'), + + Data = require('../Storages/WebMailDataStorage.js'), + Cache = require('../Storages/WebMailCacheStorage.js'), + Remote = require('../Storages/WebMailAjaxRemoteStorage.js'), + + PopupsFolderSystemViewModel = require('../ViewModels/Popups/PopupsAskViewModel.js'), + PopupsAskViewModel = require('../ViewModels/Popups/PopupsAskViewModel.js'), + AbstractApp = require('./AbstractApp.js') ; @@ -66,7 +78,7 @@ }, 60000 * 5); $.wakeUp(function () { - RL.remote().jsVersion(function (sResult, oData) { + Remote.jsVersion(function (sResult, oData) { if (Enums.StorageResultType.Success === sResult && oData && !oData.Result) { if (window.parent && !!RL.settingsGet('InIframe')) @@ -114,27 +126,13 @@ return this.oRemote; }; - /** - * @return {WebMailCacheStorage} - */ - RainLoopApp.prototype.cache = function () - { - if (null === this.oCache) - { - this.oCache = new WebMailCacheStorage(); - } - - return this.oCache; - }; - RainLoopApp.prototype.reloadFlagsCurrentMessageListAndMessageFromCache = function () { - var oCache = RL.cache(); - _.each(RL.data().messageList(), function (oMessage) { - oCache.initMessageFlagsFromCache(oMessage); + _.each(Data.messageList(), function (oMessage) { + Cache.initMessageFlagsFromCache(oMessage); }); - oCache.initMessageFlagsFromCache(RL.data().message()); + Cache.initMessageFlagsFromCache(Data.message()); }; /** @@ -144,50 +142,49 @@ RainLoopApp.prototype.reloadMessageList = function (bDropPagePosition, bDropCurrenFolderCache) { var - oRLData = RL.data(), - iOffset = (oRLData.messageListPage() - 1) * oRLData.messagesPerPage() + iOffset = (Data.messageListPage() - 1) * Data.messagesPerPage() ; if (Utils.isUnd(bDropCurrenFolderCache) ? false : !!bDropCurrenFolderCache) { - RL.cache().setFolderHash(oRLData.currentFolderFullNameRaw(), ''); + Cache.setFolderHash(Data.currentFolderFullNameRaw(), ''); } if (Utils.isUnd(bDropPagePosition) ? false : !!bDropPagePosition) { - oRLData.messageListPage(1); + Data.messageListPage(1); iOffset = 0; } - oRLData.messageListLoading(true); - RL.remote().messageList(function (sResult, oData, bCached) { + Data.messageListLoading(true); + Remote.messageList(function (sResult, oData, bCached) { if (Enums.StorageResultType.Success === sResult && oData && oData.Result) { - oRLData.messageListError(''); - oRLData.messageListLoading(false); - oRLData.setMessageList(oData, bCached); + Data.messageListError(''); + Data.messageListLoading(false); + Data.setMessageList(oData, bCached); } else if (Enums.StorageResultType.Unload === sResult) { - oRLData.messageListError(''); - oRLData.messageListLoading(false); + Data.messageListError(''); + Data.messageListLoading(false); } else if (Enums.StorageResultType.Abort !== sResult) { - oRLData.messageList([]); - oRLData.messageListLoading(false); - oRLData.messageListError(oData && oData.ErrorCode ? + Data.messageList([]); + Data.messageListLoading(false); + Data.messageListError(oData && oData.ErrorCode ? Utils.getNotification(oData.ErrorCode) : Utils.i18n('NOTIFICATIONS/CANT_GET_MESSAGE_LIST') ); } - }, oRLData.currentFolderFullNameRaw(), iOffset, oRLData.messagesPerPage(), oRLData.messageListSearch()); + }, Data.currentFolderFullNameRaw(), iOffset, Data.messagesPerPage(), Data.messageListSearch()); }; RainLoopApp.prototype.recacheInboxMessageList = function () { - RL.remote().messageList(Utils.emptyFunction, 'INBOX', 0, RL.data().messagesPerPage(), '', true); + Remote.messageList(Utils.emptyFunction, 'INBOX', 0, Data.messagesPerPage(), '', true); }; RainLoopApp.prototype.reloadMessageListHelper = function (bEmptyList) @@ -201,15 +198,15 @@ */ RainLoopApp.prototype.contactsSync = function (fResultFunc) { - var oContacts = RL.data().contacts; - if (oContacts.importing() || oContacts.syncing() || !RL.data().enableContactsSync() || !RL.data().allowContactsSync()) + var oContacts = Data.contacts; + if (oContacts.importing() || oContacts.syncing() || !Data.enableContactsSync() || !Data.allowContactsSync()) { return false; } oContacts.syncing(true); - RL.remote().contactsSync(function (sResult, oData) { + Remote.contactsSync(function (sResult, oData) { oContacts.syncing(false); @@ -226,7 +223,7 @@ { var self = this, - sSpamFolder = RL.data().spamFolder() + sSpamFolder = Data.spamFolder() ; _.each(this.oMoveCache, function (oItem) { @@ -236,7 +233,7 @@ bHam = !bSpam && sSpamFolder === oItem['From'] && 'INBOX' === oItem['To'] ; - RL.remote().messagesMove(self.moveOrDeleteResponseHelper, oItem['From'], oItem['To'], oItem['Uid'], + Remote.messagesMove(self.moveOrDeleteResponseHelper, oItem['From'], oItem['To'], oItem['Uid'], bSpam ? 'SPAM' : (bHam ? 'HAM' : '')); }); @@ -261,7 +258,7 @@ RainLoopApp.prototype.messagesCopyHelper = function (sFromFolderFullNameRaw, sToFolderFullNameRaw, aUidForCopy) { - RL.remote().messagesCopy( + Remote.messagesCopy( this.moveOrDeleteResponseHelper, sFromFolderFullNameRaw, sToFolderFullNameRaw, @@ -271,7 +268,7 @@ RainLoopApp.prototype.messagesDeleteHelper = function (sFromFolderFullNameRaw, aUidForRemove) { - RL.remote().messagesDelete( + Remote.messagesDelete( this.moveOrDeleteResponseHelper, sFromFolderFullNameRaw, aUidForRemove @@ -280,15 +277,15 @@ RainLoopApp.prototype.moveOrDeleteResponseHelper = function (sResult, oData) { - if (Enums.StorageResultType.Success === sResult && RL.data().currentFolder()) + if (Enums.StorageResultType.Success === sResult && Data.currentFolder()) { if (oData && Utils.isArray(oData.Result) && 2 === oData.Result.length) { - RL.cache().setFolderHash(oData.Result[0], oData.Result[1]); + Cache.setFolderHash(oData.Result[0], oData.Result[1]); } else { - RL.cache().setFolderHash(RL.data().currentFolderFullNameRaw(), ''); + Cache.setFolderHash(Data.currentFolderFullNameRaw(), ''); if (oData && -1 < Utils.inArray(oData.ErrorCode, [Enums.Notification.CantMoveMessage, Enums.Notification.CantCopyMessage])) @@ -297,7 +294,7 @@ } } - RL.reloadMessageListHelper(0 === RL.data().messageList().length); + RL.reloadMessageListHelper(0 === Data.messageList().length); RL.quotaDebounce(); } }; @@ -309,7 +306,7 @@ RainLoopApp.prototype.deleteMessagesFromFolderWithoutCheck = function (sFromFolderFullNameRaw, aUidForRemove) { this.messagesDeleteHelper(sFromFolderFullNameRaw, aUidForRemove); - RL.data().removeMessagesFromList(sFromFolderFullNameRaw, aUidForRemove); + Data.removeMessagesFromList(sFromFolderFullNameRaw, aUidForRemove); }; /** @@ -322,8 +319,6 @@ { var self = this, - oData = RL.data(), - oCache = RL.cache(), oMoveFolder = null, nSetSystemFoldersNotification = null ; @@ -331,18 +326,18 @@ switch (iDeleteType) { case Enums.FolderType.Spam: - oMoveFolder = oCache.getFolderFromCacheList(oData.spamFolder()); + oMoveFolder = Cache.getFolderFromCacheList(Data.spamFolder()); nSetSystemFoldersNotification = Enums.SetSystemFoldersNotification.Spam; break; case Enums.FolderType.NotSpam: - oMoveFolder = oCache.getFolderFromCacheList('INBOX'); + oMoveFolder = Cache.getFolderFromCacheList('INBOX'); break; case Enums.FolderType.Trash: - oMoveFolder = oCache.getFolderFromCacheList(oData.trashFolder()); + oMoveFolder = Cache.getFolderFromCacheList(Data.trashFolder()); nSetSystemFoldersNotification = Enums.SetSystemFoldersNotification.Trash; break; case Enums.FolderType.Archive: - oMoveFolder = oCache.getFolderFromCacheList(oData.archiveFolder()); + oMoveFolder = Cache.getFolderFromCacheList(Data.archiveFolder()); nSetSystemFoldersNotification = Enums.SetSystemFoldersNotification.Archive; break; } @@ -350,9 +345,9 @@ bUseFolder = Utils.isUnd(bUseFolder) ? true : !!bUseFolder; if (bUseFolder) { - if ((Enums.FolderType.Spam === iDeleteType && Consts.Values.UnuseOptionValue === oData.spamFolder()) || - (Enums.FolderType.Trash === iDeleteType && Consts.Values.UnuseOptionValue === oData.trashFolder()) || - (Enums.FolderType.Archive === iDeleteType && Consts.Values.UnuseOptionValue === oData.archiveFolder())) + if ((Enums.FolderType.Spam === iDeleteType && Consts.Values.UnuseOptionValue === Data.spamFolder()) || + (Enums.FolderType.Trash === iDeleteType && Consts.Values.UnuseOptionValue === Data.trashFolder()) || + (Enums.FolderType.Archive === iDeleteType && Consts.Values.UnuseOptionValue === Data.archiveFolder())) { bUseFolder = false; } @@ -363,19 +358,19 @@ kn.showScreenPopup(PopupsFolderSystemViewModel, [nSetSystemFoldersNotification]); } else if (!bUseFolder || (Enums.FolderType.Trash === iDeleteType && - (sFromFolderFullNameRaw === oData.spamFolder() || sFromFolderFullNameRaw === oData.trashFolder()))) + (sFromFolderFullNameRaw === Data.spamFolder() || sFromFolderFullNameRaw === Data.trashFolder()))) { kn.showScreenPopup(PopupsAskViewModel, [Utils.i18n('POPUPS_ASK/DESC_WANT_DELETE_MESSAGES'), function () { self.messagesDeleteHelper(sFromFolderFullNameRaw, aUidForRemove); - oData.removeMessagesFromList(sFromFolderFullNameRaw, aUidForRemove); + Data.removeMessagesFromList(sFromFolderFullNameRaw, aUidForRemove); }]); } else if (oMoveFolder) { this.messagesMoveHelper(sFromFolderFullNameRaw, oMoveFolder.fullNameRaw, aUidForRemove); - oData.removeMessagesFromList(sFromFolderFullNameRaw, aUidForRemove, oMoveFolder.fullNameRaw); + Data.removeMessagesFromList(sFromFolderFullNameRaw, aUidForRemove, oMoveFolder.fullNameRaw); } }; @@ -390,8 +385,8 @@ if (sFromFolderFullNameRaw !== sToFolderFullNameRaw && Utils.isArray(aUidForMove) && 0 < aUidForMove.length) { var - oFromFolder = RL.cache().getFolderFromCacheList(sFromFolderFullNameRaw), - oToFolder = RL.cache().getFolderFromCacheList(sToFolderFullNameRaw) + oFromFolder = Cache.getFolderFromCacheList(sFromFolderFullNameRaw), + oToFolder = Cache.getFolderFromCacheList(sToFolderFullNameRaw) ; if (oFromFolder && oToFolder) @@ -405,7 +400,7 @@ this.messagesMoveHelper(oFromFolder.fullNameRaw, oToFolder.fullNameRaw, aUidForMove); } - RL.data().removeMessagesFromList(oFromFolder.fullNameRaw, aUidForMove, oToFolder.fullNameRaw, bCopy); + Data.removeMessagesFromList(oFromFolder.fullNameRaw, aUidForMove, oToFolder.fullNameRaw, bCopy); return true; } } @@ -421,7 +416,7 @@ this.data().foldersLoading(true); this.remote().folders(_.bind(function (sResult, oData) { - RL.data().foldersLoading(false); + Data.foldersLoading(false); if (Enums.StorageResultType.Success === sResult) { this.data().setFolders(oData); @@ -442,12 +437,12 @@ RainLoopApp.prototype.reloadOpenPgpKeys = function () { - if (RL.data().capaOpenPGP()) + if (Data.capaOpenPGP()) { var aKeys = [], oEmail = new EmailModel(), - oOpenpgpKeyring = RL.data().openpgpKeyring, + oOpenpgpKeyring = Data.openpgpKeyring, oOpenpgpKeys = oOpenpgpKeyring ? oOpenpgpKeyring.getAllKeys() : [] ; @@ -479,41 +474,39 @@ } }); - RL.data().openpgpkeys(aKeys); + Data.openpgpkeys(aKeys); } }; RainLoopApp.prototype.accountsAndIdentities = function () { - var oRainLoopData = RL.data(); + Data.accountsLoading(true); + Data.identitiesLoading(true); - oRainLoopData.accountsLoading(true); - oRainLoopData.identitiesLoading(true); + Remote.accountsAndIdentities(function (sResult, oData) { - RL.remote().accountsAndIdentities(function (sResult, oData) { - - oRainLoopData.accountsLoading(false); - oRainLoopData.identitiesLoading(false); + Data.accountsLoading(false); + Data.identitiesLoading(false); if (Enums.StorageResultType.Success === sResult && oData.Result) { var sParentEmail = RL.settingsGet('ParentEmail'), - sAccountEmail = oRainLoopData.accountEmail() + sAccountEmail = Data.accountEmail() ; sParentEmail = '' === sParentEmail ? sAccountEmail : sParentEmail; if (Utils.isArray(oData.Result['Accounts'])) { - oRainLoopData.accounts(_.map(oData.Result['Accounts'], function (sValue) { + Data.accounts(_.map(oData.Result['Accounts'], function (sValue) { return new AccountModel(sValue, sValue !== sParentEmail); })); } if (Utils.isArray(oData.Result['Identities'])) { - oRainLoopData.identities(_.map(oData.Result['Identities'], function (oIdentityData) { + Data.identities(_.map(oData.Result['Identities'], function (oIdentityData) { var sId = Utils.pString(oIdentityData['Id']), @@ -539,8 +532,8 @@ Utils.isArray(oData.Result) && 1 < oData.Result.length && Utils.isPosNumeric(oData.Result[0], true) && Utils.isPosNumeric(oData.Result[1], true)) { - RL.data().userQuota(Utils.pInt(oData.Result[1]) * 1024); - RL.data().userUsageSize(Utils.pInt(oData.Result[0]) * 1024); + Data.userQuota(Utils.pInt(oData.Result[1]) * 1024); + Data.userUsageSize(Utils.pInt(oData.Result[0]) * 1024); } }); }; @@ -560,8 +553,8 @@ { var iUtc = moment().unix(), - sHash = RL.cache().getFolderHash(oData.Result.Folder), - oFolder = RL.cache().getFolderFromCacheList(oData.Result.Folder), + sHash = Cache.getFolderHash(oData.Result.Folder), + oFolder = Cache.getFolderFromCacheList(oData.Result.Folder), bCheck = false, sUid = '', aList = [], @@ -575,7 +568,7 @@ if (oData.Result.Hash) { - RL.cache().setFolderHash(oData.Result.Folder, oData.Result.Hash); + Cache.setFolderHash(oData.Result.Folder, oData.Result.Hash); } if (Utils.isNormal(oData.Result.MessageCount)) @@ -595,7 +588,7 @@ if (bUnreadCountChange) { - RL.cache().clearMessageFlagsFromCacheByFolder(oFolder.fullNameRaw); + Cache.clearMessageFlagsFromCacheByFolder(oFolder.fullNameRaw); } if (oData.Result.Flags) @@ -606,7 +599,7 @@ { bCheck = true; oFlags = oData.Result.Flags[sUid]; - RL.cache().storeMessageFlagsToCacheByFolderAndUid(oFolder.fullNameRaw, sUid.toString(), [ + Cache.storeMessageFlagsToCacheByFolderAndUid(oFolder.fullNameRaw, sUid.toString(), [ !oFlags['IsSeen'], !!oFlags['IsFlagged'], !!oFlags['IsAnswered'], !!oFlags['IsForwarded'], !!oFlags['IsReadReceipt'] ]); } @@ -618,11 +611,11 @@ } } - RL.data().initUidNextAndNewMessages(oFolder.fullNameRaw, oData.Result.UidNext, oData.Result.NewMessages); + Data.initUidNextAndNewMessages(oFolder.fullNameRaw, oData.Result.UidNext, oData.Result.NewMessages); if (oData.Result.Hash !== sHash || '' === sHash) { - if (oFolder.fullNameRaw === RL.data().currentFolderFullNameRaw()) + if (oFolder.fullNameRaw === Data.currentFolderFullNameRaw()) { RL.reloadMessageList(); } @@ -633,9 +626,9 @@ } else if (bUnreadCountChange) { - if (oFolder.fullNameRaw === RL.data().currentFolderFullNameRaw()) + if (oFolder.fullNameRaw === Data.currentFolderFullNameRaw()) { - aList = RL.data().messageList(); + aList = Data.messageList(); if (Utils.isNonEmptyArray(aList)) { RL.folderInformation(oFolder.fullNameRaw, aList); @@ -658,7 +651,7 @@ var iUtc = moment().unix(), - aFolders = RL.data().getNextFolderNames(bBoot) + aFolders = Data.getNextFolderNames(bBoot) ; if (Utils.isNonEmptyArray(aFolders)) @@ -672,8 +665,8 @@ var aList = [], - sHash = RL.cache().getFolderHash(oItem.Folder), - oFolder = RL.cache().getFolderFromCacheList(oItem.Folder), + sHash = Cache.getFolderHash(oItem.Folder), + oFolder = Cache.getFolderFromCacheList(oItem.Folder), bUnreadCountChange = false ; @@ -683,7 +676,7 @@ if (oItem.Hash) { - RL.cache().setFolderHash(oItem.Folder, oItem.Hash); + Cache.setFolderHash(oItem.Folder, oItem.Hash); } if (Utils.isNormal(oItem.MessageCount)) @@ -703,21 +696,21 @@ if (bUnreadCountChange) { - RL.cache().clearMessageFlagsFromCacheByFolder(oFolder.fullNameRaw); + Cache.clearMessageFlagsFromCacheByFolder(oFolder.fullNameRaw); } if (oItem.Hash !== sHash || '' === sHash) { - if (oFolder.fullNameRaw === RL.data().currentFolderFullNameRaw()) + if (oFolder.fullNameRaw === Data.currentFolderFullNameRaw()) { RL.reloadMessageList(); } } else if (bUnreadCountChange) { - if (oFolder.fullNameRaw === RL.data().currentFolderFullNameRaw()) + if (oFolder.fullNameRaw === Data.currentFolderFullNameRaw()) { - aList = RL.data().messageList(); + aList = Data.messageList(); if (Utils.isNonEmptyArray(aList)) { RL.folderInformation(oFolder.fullNameRaw, aList); @@ -743,33 +736,33 @@ { oMessage.unseen(false); - var oFolder = RL.cache().getFolderFromCacheList(oMessage.folderFullNameRaw); + var oFolder = Cache.getFolderFromCacheList(oMessage.folderFullNameRaw); if (oFolder) { oFolder.messageCountUnread(0 <= oFolder.messageCountUnread() - 1 ? oFolder.messageCountUnread() - 1 : 0); } - RL.cache().storeMessageFlagsToCache(oMessage); + Cache.storeMessageFlagsToCache(oMessage); RL.reloadFlagsCurrentMessageListAndMessageFromCache(); } - RL.remote().messageSetSeen(Utils.emptyFunction, oMessage.folderFullNameRaw, [oMessage.uid], true); + Remote.messageSetSeen(Utils.emptyFunction, oMessage.folderFullNameRaw, [oMessage.uid], true); }; RainLoopApp.prototype.googleConnect = function () { - window.open(RL.link().socialGoogle(), 'Google', 'left=200,top=100,width=650,height=600,menubar=no,status=no,resizable=yes,scrollbars=yes'); + window.open(LinkBuilder.socialGoogle(), 'Google', 'left=200,top=100,width=650,height=600,menubar=no,status=no,resizable=yes,scrollbars=yes'); }; RainLoopApp.prototype.twitterConnect = function () { - window.open(RL.link().socialTwitter(), 'Twitter', 'left=200,top=100,width=650,height=350,menubar=no,status=no,resizable=yes,scrollbars=yes'); + window.open(LinkBuilder.socialTwitter(), 'Twitter', 'left=200,top=100,width=650,height=350,menubar=no,status=no,resizable=yes,scrollbars=yes'); }; RainLoopApp.prototype.facebookConnect = function () { - window.open(RL.link().socialFacebook(), 'Facebook', 'left=200,top=100,width=650,height=335,menubar=no,status=no,resizable=yes,scrollbars=yes'); + window.open(LinkBuilder.socialFacebook(), 'Facebook', 'left=200,top=100,width=650,height=335,menubar=no,status=no,resizable=yes,scrollbars=yes'); }; /** @@ -777,60 +770,58 @@ */ RainLoopApp.prototype.socialUsers = function (bFireAllActions) { - var oRainLoopData = RL.data(); - if (bFireAllActions) { - oRainLoopData.googleActions(true); - oRainLoopData.facebookActions(true); - oRainLoopData.twitterActions(true); + Data.googleActions(true); + Data.facebookActions(true); + Data.twitterActions(true); } - RL.remote().socialUsers(function (sResult, oData) { + Remote.socialUsers(function (sResult, oData) { if (Enums.StorageResultType.Success === sResult && oData && oData.Result) { - oRainLoopData.googleUserName(oData.Result['Google'] || ''); - oRainLoopData.facebookUserName(oData.Result['Facebook'] || ''); - oRainLoopData.twitterUserName(oData.Result['Twitter'] || ''); + Data.googleUserName(oData.Result['Google'] || ''); + Data.facebookUserName(oData.Result['Facebook'] || ''); + Data.twitterUserName(oData.Result['Twitter'] || ''); } else { - oRainLoopData.googleUserName(''); - oRainLoopData.facebookUserName(''); - oRainLoopData.twitterUserName(''); + Data.googleUserName(''); + Data.facebookUserName(''); + Data.twitterUserName(''); } - oRainLoopData.googleLoggined('' !== oRainLoopData.googleUserName()); - oRainLoopData.facebookLoggined('' !== oRainLoopData.facebookUserName()); - oRainLoopData.twitterLoggined('' !== oRainLoopData.twitterUserName()); + Data.googleLoggined('' !== Data.googleUserName()); + Data.facebookLoggined('' !== Data.facebookUserName()); + Data.twitterLoggined('' !== Data.twitterUserName()); - oRainLoopData.googleActions(false); - oRainLoopData.facebookActions(false); - oRainLoopData.twitterActions(false); + Data.googleActions(false); + Data.facebookActions(false); + Data.twitterActions(false); }); }; RainLoopApp.prototype.googleDisconnect = function () { - RL.data().googleActions(true); - RL.remote().googleDisconnect(function () { + Data.googleActions(true); + Remote.googleDisconnect(function () { RL.socialUsers(); }); }; RainLoopApp.prototype.facebookDisconnect = function () { - RL.data().facebookActions(true); - RL.remote().facebookDisconnect(function () { + Data.facebookActions(true); + Remote.facebookDisconnect(function () { RL.socialUsers(); }); }; RainLoopApp.prototype.twitterDisconnect = function () { - RL.data().twitterActions(true); - RL.remote().twitterDisconnect(function () { + Data.twitterActions(true); + Remote.twitterDisconnect(function () { RL.socialUsers(); }); }; @@ -974,7 +965,7 @@ aData = [] ; - RL.remote().suggestions(function (sResult, oData) { + Remote.suggestions(function (sResult, oData) { if (Enums.StorageResultType.Success === sResult && oData && Utils.isArray(oData.Result)) { aData = _.map(oData.Result, function (aItem) { @@ -997,7 +988,7 @@ */ RainLoopApp.prototype.getContactTagsAutocomplete = function (sQuery, fCallback) { - fCallback(_.filter(RL.data().contactTags(), function (oContactTag) { + fCallback(_.filter(Data.contactTags(), function (oContactTag) { return oContactTag && oContactTag.filterHelper(sQuery); })); }; @@ -1042,7 +1033,7 @@ RL.pub('rl.bootstart'); AbstractApp.prototype.bootstart.call(this); - RL.data().populateDataOnStart(); + Data.populateDataOnStart(); var sCustomLoginLink = '', @@ -1055,51 +1046,51 @@ if (!RL.settingsGet('ChangePasswordIsAllowed')) { - Utils.removeSettingsViewModel(SettingsChangePasswordScreen); + kn.removeSettingsViewModel(SettingsChangePasswordScreen); } if (!RL.settingsGet('ContactsIsAllowed')) { - Utils.removeSettingsViewModel(SettingsContacts); + kn.removeSettingsViewModel(SettingsContacts); } if (!RL.capa(Enums.Capa.AdditionalAccounts)) { - Utils.removeSettingsViewModel(SettingsAccounts); + kn.removeSettingsViewModel(SettingsAccounts); } if (RL.capa(Enums.Capa.AdditionalIdentities)) { - Utils.removeSettingsViewModel(SettingsIdentity); + kn.removeSettingsViewModel(SettingsIdentity); } else { - Utils.removeSettingsViewModel(SettingsIdentities); + kn.removeSettingsViewModel(SettingsIdentities); } if (!RL.capa(Enums.Capa.OpenPGP)) { - Utils.removeSettingsViewModel(SettingsOpenPGP); + kn.removeSettingsViewModel(SettingsOpenPGP); } if (!RL.capa(Enums.Capa.TwoFactor)) { - Utils.removeSettingsViewModel(SettingsSecurity); + kn.removeSettingsViewModel(SettingsSecurity); } if (!RL.capa(Enums.Capa.Themes)) { - Utils.removeSettingsViewModel(SettingsThemes); + kn.removeSettingsViewModel(SettingsThemes); } if (!RL.capa(Enums.Capa.Filters)) { - Utils.removeSettingsViewModel(SettingsFilters); + kn.removeSettingsViewModel(SettingsFilters); } if (!bGoogle && !bFacebook && !bTwitter) { - Utils.removeSettingsViewModel(SettingsSocialScreen); + kn.removeSettingsViewModel(SettingsSocialScreen); } Utils.initOnStartOrLangChange(function () { @@ -1140,11 +1131,11 @@ { if (window.$LAB && window.crypto && window.crypto.getRandomValues && RL.capa(Enums.Capa.OpenPGP)) { - window.$LAB.script(window.openpgp ? '' : RL.link().openPgpJs()).wait(function () { + window.$LAB.script(window.openpgp ? '' : LinkBuilder.openPgpJs()).wait(function () { if (window.openpgp) { - RL.data().openpgpKeyring = new window.openpgp.Keyring(); - RL.data().capaOpenPGP(true); + Data.openpgpKeyring = new window.openpgp.Keyring(); + Data.capaOpenPGP(true); RL.pub('openpgp.init'); @@ -1154,7 +1145,7 @@ } else { - RL.data().capaOpenPGP(false); + Data.capaOpenPGP(false); } kn.startScreens([MailBoxScreen, SettingsScreen]); @@ -1169,7 +1160,7 @@ }); RL.sub('interval.2m', function () { - var sF = RL.data().currentFolderFullNameRaw(); + var sF = Data.currentFolderFullNameRaw(); if ('INBOX' !== sF) { RL.folderInformation(sF); @@ -1263,7 +1254,7 @@ else { kn.routeOff(); - kn.setHash(RL.link().root(), true); + kn.setHash(LinkBuilder.root(), true); kn.routeOff(); _.defer(function () { @@ -1275,7 +1266,7 @@ if (bGoogle) { window['rl_' + sJsHash + '_google_service'] = function () { - RL.data().googleActions(true); + Data.googleActions(true); RL.socialUsers(); }; } @@ -1283,7 +1274,7 @@ if (bFacebook) { window['rl_' + sJsHash + '_facebook_service'] = function () { - RL.data().facebookActions(true); + Data.facebookActions(true); RL.socialUsers(); }; } @@ -1291,7 +1282,7 @@ if (bTwitter) { window['rl_' + sJsHash + '_twitter_service'] = function () { - RL.data().twitterActions(true); + Data.twitterActions(true); RL.socialUsers(); }; } diff --git a/dev/Common/LinkBuilder.js b/dev/Common/LinkBuilder.js index 13c3df960..3456df4de 100644 --- a/dev/Common/LinkBuilder.js +++ b/dev/Common/LinkBuilder.js @@ -323,6 +323,6 @@ return this.sServer + 'SocialFacebook' + ('' !== this.sSpecSuffix ? '/' + this.sSpecSuffix + '/' : ''); }; - module.exports = LinkBuilder; + module.exports = new LinkBuilder(); }(module)); \ No newline at end of file diff --git a/dev/Common/Plugins.js b/dev/Common/Plugins.js index 34e8ce87b..052f91cf6 100644 --- a/dev/Common/Plugins.js +++ b/dev/Common/Plugins.js @@ -6,7 +6,9 @@ var Plugins = {}, - Utils = require('./Utils.js') + Utils = require('./Utils.js'), + Remote = require('../Remote.js'), + RL = require('../RL.js') ; /** @@ -70,7 +72,7 @@ */ Plugins.mainSettingsGet = function (sName) { - return RL ? RL.settingsGet(sName) : null; // TODO cjs + return RL ? RL().settingsGet(sName) : null; }; /** @@ -83,9 +85,9 @@ */ Plugins.remoteRequest = function (fCallback, sAction, oParameters, iTimeout, sGetAdd, aAbortActions) { - if (RL) // TODO cjs + if (Remote) { - RL.remote().defaultRequest(fCallback, sAction, oParameters, iTimeout, sGetAdd, aAbortActions); // TODO cjs + Remote().defaultRequest(fCallback, sAction, oParameters, iTimeout, sGetAdd, aAbortActions); } }; diff --git a/dev/Common/Utils.js b/dev/Common/Utils.js index 774931b0c..b7aa9b778 100644 --- a/dev/Common/Utils.js +++ b/dev/Common/Utils.js @@ -6,13 +6,20 @@ var Utils = {}, + $ = require('../External/jquery.js'), _ = require('../External/underscore.js'), ko = require('../External/ko.js'), + key = require('../External/key.js'), window = require('../External/window.js'), $window = require('../External/$window.js'), $doc = require('../External/$doc.js'), NotificationClass = require('../External/NotificationClass.js'), + + LocalStorage = require('../Storages/LocalStorage.js'), + + kn = require('../Knoin/Knoin.js'), + Enums = require('./Enums.js'), Globals = require('./Globals.js') ; @@ -1240,7 +1247,7 @@ */ Utils.isFolderExpanded = function (sFullNameHash) { - var aExpandedList = /** @type {Array|null} */ RL.local().get(Enums.ClientSideKeyName.ExpandedFolders); + var aExpandedList = /** @type {Array|null} */ LocalStorage.get(Enums.ClientSideKeyName.ExpandedFolders); return _.isArray(aExpandedList) && -1 !== _.indexOf(aExpandedList, sFullNameHash); }; @@ -1250,7 +1257,7 @@ */ Utils.setExpandedFolder = function (sFullNameHash, bExpanded) { - var aExpandedList = /** @type {Array|null} */ RL.local().get(Enums.ClientSideKeyName.ExpandedFolders); + var aExpandedList = /** @type {Array|null} */ LocalStorage.get(Enums.ClientSideKeyName.ExpandedFolders); if (!_.isArray(aExpandedList)) { aExpandedList = []; @@ -1266,7 +1273,7 @@ aExpandedList = _.without(aExpandedList, sFullNameHash); } - RL.local().set(Enums.ClientSideKeyName.ExpandedFolders, aExpandedList); + LocalStorage.set(Enums.ClientSideKeyName.ExpandedFolders, aExpandedList); }; Utils.initLayoutResizer = function (sLeft, sRight, sClientSideKeyName) @@ -1277,7 +1284,7 @@ oLeft = $(sLeft), oRight = $(sRight), - mLeftWidth = RL.local().get(sClientSideKeyName) || null, + mLeftWidth = LocalStorage.get(sClientSideKeyName) || null, fSetWidth = function (iWidth) { if (iWidth) @@ -1301,7 +1308,7 @@ else { oLeft.resizable('enable'); - var iWidth = Utils.pInt(RL.local().get(sClientSideKeyName)) || iMinWidth; + var iWidth = Utils.pInt(LocalStorage.get(sClientSideKeyName)) || iMinWidth; fSetWidth(iWidth > iMinWidth ? iWidth : iMinWidth); } }, @@ -1309,7 +1316,7 @@ fResizeFunction = function (oEvent, oObject) { if (oObject && oObject.size && oObject.size.width) { - RL.local().set(sClientSideKeyName, oObject.size.width); + LocalStorage.set(sClientSideKeyName, oObject.size.width); oRight.css({ 'left': '' + oObject.size.width + 'px' @@ -1401,61 +1408,6 @@ } }; - /** - * @param {string} sName - * @param {Function} ViewModelClass - * @param {Function=} AbstractViewModel = KnoinAbstractViewModel - */ - Utils.extendAsViewModel = function (sName, ViewModelClass, AbstractViewModel) - { - if (ViewModelClass) - { - if (!AbstractViewModel) - { - AbstractViewModel = KnoinAbstractViewModel; - } - - ViewModelClass.__name = sName; - Plugins.regViewModelHook(sName, ViewModelClass); - _.extend(ViewModelClass.prototype, AbstractViewModel.prototype); - } - }; - - /** - * @param {Function} SettingsViewModelClass - * @param {string} sLabelName - * @param {string} sTemplate - * @param {string} sRoute - * @param {boolean=} bDefault - */ - Utils.addSettingsViewModel = function (SettingsViewModelClass, sTemplate, sLabelName, sRoute, bDefault) - { - SettingsViewModelClass.__rlSettingsData = { - 'Label': sLabelName, - 'Template': sTemplate, - 'Route': sRoute, - 'IsDefault': !!bDefault - }; - - Globals.aViewModels['settings'].push(SettingsViewModelClass); - }; - - /** - * @param {Function} SettingsViewModelClass - */ - Utils.removeSettingsViewModel = function (SettingsViewModelClass) - { - Globals.aViewModels['settings-removed'].push(SettingsViewModelClass); - }; - - /** - * @param {Function} SettingsViewModelClass - */ - Utils.disableSettingsViewModel = function (SettingsViewModelClass) - { - Globals.aViewModels['settings-disabled'].push(SettingsViewModelClass); - }; - Utils.convertThemeName = function (sTheme) { if ('@custom' === sTheme.substr(-7)) @@ -1510,7 +1462,7 @@ while (sResult.length < iLen) { - sResult += sLine.substr(Math.round(Math.random() * sLine.length), 1); + sResult += sLine.substr(window.Math.round(window.Math.random() * sLine.length), 1); } return sResult; @@ -1574,7 +1526,7 @@ Utils.i18nToNode(oBody); - Knoin.prototype.applyExternal(oViewModel, $('#rl-content', oBody)[0]); + kn.applyExternal(oViewModel, $('#rl-content', oBody)[0]); window[sFunc] = null; diff --git a/dev/External/Jua.js b/dev/External/Jua.js new file mode 100644 index 000000000..1edcac5f1 --- /dev/null +++ b/dev/External/Jua.js @@ -0,0 +1,5 @@ +/* RainLoop Webmail (c) RainLoop Team | Licensed under CC BY-NC-SA 3.0 */ + +'use strict'; + +module.exports = Jua; \ No newline at end of file diff --git a/dev/External/ifvisible.js b/dev/External/ifvisible.js new file mode 100644 index 000000000..fc4ae3a18 --- /dev/null +++ b/dev/External/ifvisible.js @@ -0,0 +1,5 @@ +/* RainLoop Webmail (c) RainLoop Team | Licensed under CC BY-NC-SA 3.0 */ + +'use strict'; + +module.exports = ifvisible; \ No newline at end of file diff --git a/dev/External/ko.js b/dev/External/ko.js index c1eb7e90f..91f42f0f7 100644 --- a/dev/External/ko.js +++ b/dev/External/ko.js @@ -10,8 +10,11 @@ window = require('./window.js'), $window = require('./$window.js'), $doc = require('./$doc.js'), + Globals = require('../Common/Globals.js'), - Utils = require('../Common/Utils.js') + Utils = require('../Common/Utils.js'), + + RL = require('../RL.js') ; ko.bindingHandlers.tooltip = { @@ -555,7 +558,7 @@ 'focusCallback': fFocusCallback, 'inputDelimiters': [',', ';'], 'autoCompleteSource': function (oData, fResponse) { - RL.getAutocomplete(oData.term, function (aData) { + RL().getAutocomplete(oData.term, function (aData) { fResponse(_.map(aData, function (oEmailItem) { return oEmailItem.toLine(false); })); @@ -630,7 +633,7 @@ 'inputDelimiters': [',', ';'], 'outputDelimiter': ',', 'autoCompleteSource': function (oData, fResponse) { - RL.getContactTagsAutocomplete(oData.term, function (aData) { // TODO cjs + RL().getContactTagsAutocomplete(oData.term, function (aData) { fResponse(_.map(aData, function (oTagItem) { return oTagItem.toLine(false); })); diff --git a/dev/Knoin/Knoin.js b/dev/Knoin/Knoin.js index 29da06e4e..77d16b4e5 100644 --- a/dev/Knoin/Knoin.js +++ b/dev/Knoin/Knoin.js @@ -11,9 +11,11 @@ hasher = require('../External/hasher.js'), crossroads = require('../External/crossroads.js'), $html = require('../External/$html.js'), - Utils = require('../Common/Utils.js'), Globals = require('../Common/Globals.js'), - Enums = require('../Common/Enums.js') + Enums = require('../Common/Enums.js'), + Plugins = require('../Common/Plugins.js'), + Utils = require('../Common/Utils.js'), + KnoinAbstractViewModel = require('../Knoin/KnoinAbstractViewModel.js') ; /** @@ -53,6 +55,11 @@ return this.oBoot; }; + Knoin.prototype.remote = function () + { + return this.oRemote; + }; + /** * @param {Object} thisObject */ @@ -64,6 +71,61 @@ } }; + /** + * @param {string} sName + * @param {Function} ViewModelClass + * @param {Function=} AbstractViewModel = KnoinAbstractViewModel + */ + Knoin.prototype.extendAsViewModel = function (sName, ViewModelClass, AbstractViewModel) + { + if (ViewModelClass) + { + if (!AbstractViewModel) + { + AbstractViewModel = KnoinAbstractViewModel; + } + + ViewModelClass.__name = sName; + Plugins.regViewModelHook(sName, ViewModelClass); + _.extend(ViewModelClass.prototype, AbstractViewModel.prototype); + } + }; + + /** + * @param {Function} SettingsViewModelClass + * @param {string} sLabelName + * @param {string} sTemplate + * @param {string} sRoute + * @param {boolean=} bDefault + */ + Knoin.prototype.addSettingsViewModel = function (SettingsViewModelClass, sTemplate, sLabelName, sRoute, bDefault) + { + SettingsViewModelClass.__rlSettingsData = { + 'Label': sLabelName, + 'Template': sTemplate, + 'Route': sRoute, + 'IsDefault': !!bDefault + }; + + Globals.aViewModels['settings'].push(SettingsViewModelClass); + }; + + /** + * @param {Function} SettingsViewModelClass + */ + Knoin.prototype.removeSettingsViewModel = function (SettingsViewModelClass) + { + Globals.aViewModels['settings-removed'].push(SettingsViewModelClass); + }; + + /** + * @param {Function} SettingsViewModelClass + */ + Knoin.prototype.disableSettingsViewModel = function (SettingsViewModelClass) + { + Globals.aViewModels['settings-disabled'].push(SettingsViewModelClass); + }; + Knoin.prototype.routeOff = function () { hasher.changed.active = false; @@ -420,9 +482,10 @@ /** * @return {Knoin} */ - Knoin.prototype.bootstart = function (RL) + Knoin.prototype.bootstart = function (RL, Remote) { this.oBoot = RL; + this.oRemote = Remote; var window = require('../External/window.js'), @@ -449,7 +512,7 @@ window['rl']['settingsGet'] = Plugins.mainSettingsGet; window['rl']['remoteRequest'] = Plugins.remoteRequest; window['rl']['pluginSettingsGet'] = Plugins.settingsGet; - window['rl']['addSettingsViewModel'] = Utils.addSettingsViewModel; + window['rl']['addSettingsViewModel'] = _.bind(this.addSettingsViewModel, this); window['rl']['createCommand'] = Utils.createCommand; window['rl']['EmailModel'] = EmailModel; diff --git a/dev/Models/AccountModel.js b/dev/Models/AccountModel.js index c089bd6e6..84491f7dd 100644 --- a/dev/Models/AccountModel.js +++ b/dev/Models/AccountModel.js @@ -5,7 +5,8 @@ 'use strict'; var - ko = require('../External/ko.js') + ko = require('../External/ko.js'), + LinkBuilder = require('../Common/LinkBuilder.js') ; /** @@ -27,7 +28,7 @@ */ AccountModel.prototype.changeAccountLink = function () { - return RL.link().change(this.email); // TODO cjs + return LinkBuilder.change(this.email); }; module.exports = AccountModel; diff --git a/dev/Models/AttachmentModel.js b/dev/Models/AttachmentModel.js index c2109eb64..3790d6670 100644 --- a/dev/Models/AttachmentModel.js +++ b/dev/Models/AttachmentModel.js @@ -7,7 +7,8 @@ var window = require('../External/window.js'), Globals = require('../Common/Globals.js'), - Utils = require('../Common/Utils.js') + Utils = require('../Common/Utils.js'), + LinkBuilder = require('../Common/LinkBuilder.js') ; /** @@ -117,7 +118,7 @@ */ AttachmentModel.prototype.linkDownload = function () { - return RL.link().attachmentDownload(this.download); // TODO cjs + return LinkBuilder.attachmentDownload(this.download); // TODO cjs }; /** @@ -125,7 +126,7 @@ */ AttachmentModel.prototype.linkPreview = function () { - return RL.link().attachmentPreview(this.download); // TODO cjs + return LinkBuilder.attachmentPreview(this.download); // TODO cjs }; /** @@ -133,7 +134,7 @@ */ AttachmentModel.prototype.linkPreviewAsPlain = function () { - return RL.link().attachmentPreviewAsPlain(this.download); + return LinkBuilder.attachmentPreviewAsPlain(this.download); }; /** diff --git a/dev/Models/ContactModel.js b/dev/Models/ContactModel.js index 9cdf931a8..5d307d60d 100644 --- a/dev/Models/ContactModel.js +++ b/dev/Models/ContactModel.js @@ -8,7 +8,8 @@ _ = require('../External/underscore.js'), ko = require('../External/ko.js'), Enums = require('../Common/Enums.js'), - Utils = require('../Common/Utils.js') + Utils = require('../Common/Utils.js'), + LinkBuilder = require('../Common/LinkBuilder.js') ; /** @@ -98,7 +99,7 @@ */ ContactModel.prototype.srcAttr = function () { - return RL.link().emptyContactPic(); // TODO cjs + return LinkBuilder.emptyContactPic(); }; /** diff --git a/dev/Models/MessageModel.js b/dev/Models/MessageModel.js index 93151a7bd..2a5ad1866 100644 --- a/dev/Models/MessageModel.js +++ b/dev/Models/MessageModel.js @@ -15,6 +15,7 @@ Enums = require('../Common/Enums.js'), Utils = require('../Common/Utils.js'), + LinkBuilder = require('../Common/LinkBuilder.js'), EmailModel = require('./EmailModel.js'), AttachmentModel = require('./AttachmentModel.js') @@ -730,7 +731,7 @@ */ MessageModel.prototype.viewLink = function () { - return RL.link().messageViewLink(this.requestHash);// TODO cjs + return LinkBuilder.messageViewLink(this.requestHash);// TODO cjs }; /** @@ -738,7 +739,7 @@ */ MessageModel.prototype.downloadLink = function () { - return RL.link().messageDownloadLink(this.requestHash);// TODO cjs + return LinkBuilder.messageDownloadLink(this.requestHash);// TODO cjs }; /** diff --git a/dev/Models/OpenPgpKeyModel.js b/dev/Models/OpenPgpKeyModel.js index ba517bfa5..8acd51938 100644 --- a/dev/Models/OpenPgpKeyModel.js +++ b/dev/Models/OpenPgpKeyModel.js @@ -5,7 +5,7 @@ 'use strict'; var - ko = require('./ko.js') + ko = require('../Externalko.js') ; /** diff --git a/dev/RainLoopBoot.js b/dev/RainLoopBoot.js index 3467fd945..db30e9aaf 100644 --- a/dev/RainLoopBoot.js +++ b/dev/RainLoopBoot.js @@ -4,7 +4,8 @@ var kn = require('./Knoin/Knoin.js'), - RL = require('./Boots/RainLoopApp.js') + RL = require('./Boots/RainLoopApp.js'), + Remote = require('./Storages/WebMailAjaxRemoteStorage.js') ; -kn.bootstart(RL); \ No newline at end of file +kn.bootstart(RL, Remote); \ No newline at end of file diff --git a/dev/Remote.js b/dev/Remote.js new file mode 100644 index 000000000..e3270e6ab --- /dev/null +++ b/dev/Remote.js @@ -0,0 +1,7 @@ +/* RainLoop Webmail (c) RainLoop Team | Licensed under CC BY-NC-SA 3.0 */ + +'use strict'; + +module.exports = function () { + return require('./Knoin/Knoin.js').remote(); +}; \ No newline at end of file diff --git a/dev/Screens/AbstractSettings.js b/dev/Screens/AbstractSettings.js index 61fc66d9e..92e34c117 100644 --- a/dev/Screens/AbstractSettings.js +++ b/dev/Screens/AbstractSettings.js @@ -5,13 +5,16 @@ 'use strict'; var - $ = require('./External/jquery.js'), - _ = require('./External/underscore.js'), - ko = require('./External/ko.js'), - Globals = require('./Common/Globals.js'), - Utils = require('./Common/Utils.js'), - kn = require('./Knoin/Knoin.js'), - KnoinAbstractScreen = require('./Knoin/KnoinAbstractScreen.js') + $ = require('../External/jquery.js'), + _ = require('../External/underscore.js'), + ko = require('../External/ko.js'), + + Globals = require('../Common/Globals.js'), + Utils = require('../Common/Utils.js'), + LinkBuilder = require('../Common/LinkBuilder.js'), + + kn = require('../Knoin/Knoin.js'), + KnoinAbstractScreen = require('../Knoin/KnoinAbstractScreen.js') ; /** @@ -136,7 +139,7 @@ } else { - kn.setHash(RL.link().settings(), false, true); // TODO cjs + kn.setHash(LinkBuilder.settings(), false, true); // TODO cjs } }; diff --git a/dev/Screens/AdminLogin.js b/dev/Screens/AdminLogin.js index 94ebf35c4..d604a9e8d 100644 --- a/dev/Screens/AdminLogin.js +++ b/dev/Screens/AdminLogin.js @@ -5,9 +5,9 @@ 'use strict'; var - _ = require('./External/underscore.js'), - KnoinAbstractScreen = require('./Knoin/KnoinAbstractScreen.js'), - AdminLoginViewModel = require('./ViewModels/AdminLoginViewModel.js') + _ = require('../External/underscore.js'), + KnoinAbstractScreen = require('../Knoin/KnoinAbstractScreen.js'), + AdminLoginViewModel = require('../ViewModels/AdminLoginViewModel.js') ; /** diff --git a/dev/Screens/AdminSettings.js b/dev/Screens/AdminSettings.js index 57696532b..ac4ecf66e 100644 --- a/dev/Screens/AdminSettings.js +++ b/dev/Screens/AdminSettings.js @@ -5,10 +5,10 @@ 'use strict'; var - _ = require('./External/underscore.js'), - AbstractSettings = require('./Screens/AbstractSettings.js'), - AdminMenuViewModel = require('./ViewModels/AdminMenuViewModel.js'), - AdminPaneViewModel = require('./ViewModels/AdminPaneViewModel.js') + _ = require('../External/underscore.js'), + AbstractSettings = require('./AbstractSettings.js'), + AdminMenuViewModel = require('../ViewModels/AdminMenuViewModel.js'), + AdminPaneViewModel = require('../ViewModels/AdminPaneViewModel.js') ; /** diff --git a/dev/Screens/Login.js b/dev/Screens/Login.js index f366939cb..1ca6c92bb 100644 --- a/dev/Screens/Login.js +++ b/dev/Screens/Login.js @@ -5,9 +5,9 @@ 'use strict'; var - _ = require('./External/underscore.js'), - KnoinAbstractScreen = require('./Knoin/KnoinAbstractScreen.js'), - LoginViewModel = require('./ViewModels/LoginViewModel.js') + _ = require('../External/underscore.js'), + KnoinAbstractScreen = require('../Knoin/KnoinAbstractScreen.js'), + LoginViewModel = require('../ViewModels/LoginViewModel.js') ; /** diff --git a/dev/Screens/MailBox.js b/dev/Screens/MailBox.js index 5b9cd0a4b..7c195d2a7 100644 --- a/dev/Screens/MailBox.js +++ b/dev/Screens/MailBox.js @@ -5,15 +5,21 @@ 'use strict'; var - _ = require('./External/underscore.js'), - $html = require('./External/$html.js'), - Enums = require('./Common/Enums.js'), - Utils = require('./Common/Utils.js'), - KnoinAbstractScreen = require('./Knoin/KnoinAbstractScreen.js'), - MailBoxSystemDropDownViewModel = require('./ViewModels/MailBoxSystemDropDownViewModel.js'), - MailBoxFolderListViewModel = require('./ViewModels/MailBoxFolderListViewModel.js'), - MailBoxMessageListViewModel = require('./ViewModels/MailBoxMessageListViewModel.js'), - MailBoxMessageViewViewModel = require('./ViewModels/MailBoxMessageViewViewModel.js') + _ = require('../External/underscore.js'), + $html = require('../External/$html.js'), + + Enums = require('../Common/Enums.js'), + Utils = require('../Common/Utils.js'), + + KnoinAbstractScreen = require('../Knoin/KnoinAbstractScreen.js'), + + Cache = require('../Storages/WebMailCacheStorage.js'), + Remote = require('../Storages/WebMailAjaxRemoteStorage.js'), + + MailBoxSystemDropDownViewModel = require('../ViewModels/MailBoxSystemDropDownViewModel.js'), + MailBoxFolderListViewModel = require('../ViewModels/MailBoxFolderListViewModel.js'), + MailBoxMessageListViewModel = require('../ViewModels/MailBoxMessageListViewModel.js'), + MailBoxMessageViewViewModel = require('../ViewModels/MailBoxMessageViewViewModel.js') ; /** @@ -75,8 +81,8 @@ { var oData = RL.data(),// TODO cjs - sFolderFullNameRaw = RL.cache().getFolderFullNameRaw(sFolderHash),// TODO cjs - oFolder = RL.cache().getFolderFromCacheList(sFolderFullNameRaw)// TODO cjs + sFolderFullNameRaw = Cache.getFolderFullNameRaw(sFolderHash), + oFolder = Cache.getFolderFromCacheList(sFolderFullNameRaw) ; if (oFolder) @@ -123,7 +129,7 @@ }, 5000); _.delay(function () { - RL.remote().appDelayStart(Utils.emptyFunction);// TODO cjs + Remote.appDelayStart(Utils.emptyFunction); }, 35000); $html.toggleClass('rl-no-preview-pane', Enums.Layout.NoPreview === oData.layout()); diff --git a/dev/Screens/Settings.js b/dev/Screens/Settings.js index 32a5c2cb8..66ef21821 100644 --- a/dev/Screens/Settings.js +++ b/dev/Screens/Settings.js @@ -5,13 +5,13 @@ 'use strict'; var - _ = require('./External/underscore.js'), - Enums = require('./Common/Enums.js'), - Utils = require('./Common/Utils.js'), - AbstractSettings = require('./Screens/AbstractSettings.js'), - SettingsSystemDropDownViewModel = require('./ViewModels/SettingsSystemDropDownViewModel.js'), - SettingsMenuViewModel = require('./ViewModels/SettingsMenuViewModel.js'), - SettingsPaneViewModel = require('./ViewModels/SettingsPaneViewModel.js') + _ = require('../External/underscore.js'), + Enums = require('../Common/Enums.js'), + Utils = require('../Common/Utils.js'), + AbstractSettings = require('../AbstractSettings.js'), + SettingsSystemDropDownViewModel = require('../ViewModels/SettingsSystemDropDownViewModel.js'), + SettingsMenuViewModel = require('../ViewModels/SettingsMenuViewModel.js'), + SettingsPaneViewModel = require('../ViewModels/SettingsPaneViewModel.js') ; /** diff --git a/dev/Settings/Accounts.js b/dev/Settings/Accounts.js deleted file mode 100644 index 19693489d..000000000 --- a/dev/Settings/Accounts.js +++ /dev/null @@ -1,82 +0,0 @@ -/* RainLoop Webmail (c) RainLoop Team | Licensed under CC BY-NC-SA 3.0 */ - -/** - * @constructor - */ -function SettingsAccounts() -{ - var oData = RL.data(); - - this.accounts = oData.accounts; - - this.processText = ko.computed(function () { - return oData.accountsLoading() ? Utils.i18n('SETTINGS_ACCOUNTS/LOADING_PROCESS') : ''; - }, this); - - this.visibility = ko.computed(function () { - return '' === this.processText() ? 'hidden' : 'visible'; - }, this); - - this.accountForDeletion = ko.observable(null).extend({'falseTimeout': 3000}).extend({'toggleSubscribe': [this, - function (oPrev) { - if (oPrev) - { - oPrev.deleteAccess(false); - } - }, function (oNext) { - if (oNext) - { - oNext.deleteAccess(true); - } - } - ]}); -} - -Utils.addSettingsViewModel(SettingsAccounts, 'SettingsAccounts', 'SETTINGS_LABELS/LABEL_ACCOUNTS_NAME', 'accounts'); - -SettingsAccounts.prototype.addNewAccount = function () -{ - kn.showScreenPopup(PopupsAddAccountViewModel); -}; - -/** - * @param {AccountModel} oAccountToRemove - */ -SettingsAccounts.prototype.deleteAccount = function (oAccountToRemove) -{ - if (oAccountToRemove && oAccountToRemove.deleteAccess()) - { - this.accountForDeletion(null); - - var - fRemoveAccount = function (oAccount) { - return oAccountToRemove === oAccount; - } - ; - - if (oAccountToRemove) - { - this.accounts.remove(fRemoveAccount); - - RL.remote().accountDelete(function (sResult, oData) { - - if (Enums.StorageResultType.Success === sResult && oData && - oData.Result && oData.Reload) - { - kn.routeOff(); - kn.setHash(RL.link().root(), true); - kn.routeOff(); - - _.defer(function () { - window.location.reload(); - }); - } - else - { - RL.accountsAndIdentities(); - } - - }, oAccountToRemove.email); - } - } -}; diff --git a/dev/Settings/ChangePassword.js b/dev/Settings/ChangePassword.js deleted file mode 100644 index d7ca390fd..000000000 --- a/dev/Settings/ChangePassword.js +++ /dev/null @@ -1,106 +0,0 @@ -/* RainLoop Webmail (c) RainLoop Team | Licensed under CC BY-NC-SA 3.0 */ - -/** - * @constructor - */ -function SettingsChangePasswordScreen() -{ - this.changeProcess = ko.observable(false); - - this.errorDescription = ko.observable(''); - this.passwordMismatch = ko.observable(false); - this.passwordUpdateError = ko.observable(false); - this.passwordUpdateSuccess = ko.observable(false); - - this.currentPassword = ko.observable(''); - this.currentPassword.error = ko.observable(false); - this.newPassword = ko.observable(''); - this.newPassword2 = ko.observable(''); - - this.currentPassword.subscribe(function () { - this.passwordUpdateError(false); - this.passwordUpdateSuccess(false); - this.currentPassword.error(false); - }, this); - - this.newPassword.subscribe(function () { - this.passwordUpdateError(false); - this.passwordUpdateSuccess(false); - this.passwordMismatch(false); - }, this); - - this.newPassword2.subscribe(function () { - this.passwordUpdateError(false); - this.passwordUpdateSuccess(false); - this.passwordMismatch(false); - }, this); - - this.saveNewPasswordCommand = Utils.createCommand(this, function () { - - if (this.newPassword() !== this.newPassword2()) - { - this.passwordMismatch(true); - this.errorDescription(Utils.i18n('SETTINGS_CHANGE_PASSWORD/ERROR_PASSWORD_MISMATCH')); - } - else - { - this.changeProcess(true); - - this.passwordUpdateError(false); - this.passwordUpdateSuccess(false); - this.currentPassword.error(false); - this.passwordMismatch(false); - this.errorDescription(''); - - RL.remote().changePassword(this.onChangePasswordResponse, this.currentPassword(), this.newPassword()); - } - - }, function () { - return !this.changeProcess() && '' !== this.currentPassword() && - '' !== this.newPassword() && '' !== this.newPassword2(); - }); - - this.onChangePasswordResponse = _.bind(this.onChangePasswordResponse, this); -} - -Utils.addSettingsViewModel(SettingsChangePasswordScreen, 'SettingsChangePassword', 'SETTINGS_LABELS/LABEL_CHANGE_PASSWORD_NAME', 'change-password'); - -SettingsChangePasswordScreen.prototype.onHide = function () -{ - this.changeProcess(false); - this.currentPassword(''); - this.newPassword(''); - this.newPassword2(''); - this.errorDescription(''); - this.passwordMismatch(false); - this.currentPassword.error(false); -}; - -SettingsChangePasswordScreen.prototype.onChangePasswordResponse = function (sResult, oData) -{ - this.changeProcess(false); - this.passwordMismatch(false); - this.errorDescription(''); - this.currentPassword.error(false); - - if (Enums.StorageResultType.Success === sResult && oData && oData.Result) - { - this.currentPassword(''); - this.newPassword(''); - this.newPassword2(''); - - this.passwordUpdateSuccess(true); - this.currentPassword.error(false); - } - else - { - if (oData && Enums.Notification.CurrentPasswordIncorrect === oData.ErrorCode) - { - this.currentPassword.error(true); - } - - this.passwordUpdateError(true); - this.errorDescription(oData && oData.ErrorCode ? Utils.getNotification(oData.ErrorCode) : - Utils.getNotification(Enums.Notification.CouldNotSaveNewPassword)); - } -}; diff --git a/dev/Settings/Contacts.js b/dev/Settings/Contacts.js deleted file mode 100644 index a9708a830..000000000 --- a/dev/Settings/Contacts.js +++ /dev/null @@ -1,51 +0,0 @@ -/* RainLoop Webmail (c) RainLoop Team | Licensed under CC BY-NC-SA 3.0 */ - -/** - * @constructor - */ -function SettingsContacts() -{ - var oData = RL.data(); - - this.contactsAutosave = oData.contactsAutosave; - - this.allowContactsSync = oData.allowContactsSync; - this.enableContactsSync = oData.enableContactsSync; - this.contactsSyncUrl = oData.contactsSyncUrl; - this.contactsSyncUser = oData.contactsSyncUser; - this.contactsSyncPass = oData.contactsSyncPass; - - this.saveTrigger = ko.computed(function () { - return [ - this.enableContactsSync() ? '1' : '0', - this.contactsSyncUrl(), - this.contactsSyncUser(), - this.contactsSyncPass() - ].join('|'); - }, this).extend({'throttle': 500}); - - this.saveTrigger.subscribe(function () { - RL.remote().saveContactsSyncData(null, - this.enableContactsSync(), - this.contactsSyncUrl(), - this.contactsSyncUser(), - this.contactsSyncPass() - ); - }, this); -} - -Utils.addSettingsViewModel(SettingsContacts, 'SettingsContacts', 'SETTINGS_LABELS/LABEL_CONTACTS_NAME', 'contacts'); - -SettingsContacts.prototype.onBuild = function () -{ - RL.data().contactsAutosave.subscribe(function (bValue) { - RL.remote().saveSettings(Utils.emptyFunction, { - 'ContactsAutosave': bValue ? '1' : '0' - }); - }); -}; - -//SettingsContacts.prototype.onShow = function () -//{ -// -//}; diff --git a/dev/Settings/Filters.js b/dev/Settings/Filters.js deleted file mode 100644 index 5e28fb94f..000000000 --- a/dev/Settings/Filters.js +++ /dev/null @@ -1,32 +0,0 @@ -/* RainLoop Webmail (c) RainLoop Team | Licensed under CC BY-NC-SA 3.0 */ - -/** - * @constructor - */ -function SettingsFilters() -{ -// var oData = RL.data(); - - this.filters = ko.observableArray([]); - this.filters.loading = ko.observable(false); - - this.filters.subscribe(function () { - Utils.windowResize(); - }); -} - -Utils.addSettingsViewModel(SettingsFilters, 'SettingsFilters', 'SETTINGS_LABELS/LABEL_FILTERS_NAME', 'filters'); - -//SettingsFilters.prototype.onBuild = function () -//{ -//}; - -SettingsFilters.prototype.deleteFilter = function (oFilter) -{ - this.filters.remove(oFilter); -}; - -SettingsFilters.prototype.addFilter = function () -{ - kn.showScreenPopup(PopupsFilterViewModel, [new FilterModel()]); -}; diff --git a/dev/Settings/Folders.js b/dev/Settings/Folders.js deleted file mode 100644 index c3f04b050..000000000 --- a/dev/Settings/Folders.js +++ /dev/null @@ -1,196 +0,0 @@ -/* RainLoop Webmail (c) RainLoop Team | Licensed under CC BY-NC-SA 3.0 */ - -/** - * @constructor - */ -function SettingsFolders() -{ - var oData = RL.data(); - - this.foldersListError = oData.foldersListError; - this.folderList = oData.folderList; - - this.processText = ko.computed(function () { - - var - oData = RL.data(), - bLoading = oData.foldersLoading(), - bCreating = oData.foldersCreating(), - bDeleting = oData.foldersDeleting(), - bRenaming = oData.foldersRenaming() - ; - - if (bCreating) - { - return Utils.i18n('SETTINGS_FOLDERS/CREATING_PROCESS'); - } - else if (bDeleting) - { - return Utils.i18n('SETTINGS_FOLDERS/DELETING_PROCESS'); - } - else if (bRenaming) - { - return Utils.i18n('SETTINGS_FOLDERS/RENAMING_PROCESS'); - } - else if (bLoading) - { - return Utils.i18n('SETTINGS_FOLDERS/LOADING_PROCESS'); - } - - return ''; - - }, this); - - this.visibility = ko.computed(function () { - return '' === this.processText() ? 'hidden' : 'visible'; - }, this); - - this.folderForDeletion = ko.observable(null).extend({'falseTimeout': 3000}).extend({'toggleSubscribe': [this, - function (oPrev) { - if (oPrev) - { - oPrev.deleteAccess(false); - } - }, function (oNext) { - if (oNext) - { - oNext.deleteAccess(true); - } - } - ]}); - - this.folderForEdit = ko.observable(null).extend({'toggleSubscribe': [this, - function (oPrev) { - if (oPrev) - { - oPrev.edited(false); - } - }, function (oNext) { - if (oNext && oNext.canBeEdited()) - { - oNext.edited(true); - } - } - ]}); - - this.useImapSubscribe = !!RL.settingsGet('UseImapSubscribe'); -} - -Utils.addSettingsViewModel(SettingsFolders, 'SettingsFolders', 'SETTINGS_LABELS/LABEL_FOLDERS_NAME', 'folders'); - -SettingsFolders.prototype.folderEditOnEnter = function (oFolder) -{ - var sEditName = oFolder ? Utils.trim(oFolder.nameForEdit()) : ''; - if ('' !== sEditName && oFolder.name() !== sEditName) - { - RL.local().set(Enums.ClientSideKeyName.FoldersLashHash, ''); - - RL.data().foldersRenaming(true); - RL.remote().folderRename(function (sResult, oData) { - - RL.data().foldersRenaming(false); - if (Enums.StorageResultType.Success !== sResult || !oData || !oData.Result) - { - RL.data().foldersListError( - oData && oData.ErrorCode ? Utils.getNotification(oData.ErrorCode) : Utils.i18n('NOTIFICATIONS/CANT_RENAME_FOLDER')); - } - - RL.folders(); - - }, oFolder.fullNameRaw, sEditName); - - RL.cache().removeFolderFromCacheList(oFolder.fullNameRaw); - - oFolder.name(sEditName); - } - - oFolder.edited(false); -}; - -SettingsFolders.prototype.folderEditOnEsc = function (oFolder) -{ - if (oFolder) - { - oFolder.edited(false); - } -}; - -SettingsFolders.prototype.onShow = function () -{ - RL.data().foldersListError(''); -}; - -SettingsFolders.prototype.createFolder = function () -{ - kn.showScreenPopup(PopupsFolderCreateViewModel); -}; - -SettingsFolders.prototype.systemFolder = function () -{ - kn.showScreenPopup(PopupsFolderSystemViewModel); -}; - -SettingsFolders.prototype.deleteFolder = function (oFolderToRemove) -{ - if (oFolderToRemove && oFolderToRemove.canBeDeleted() && oFolderToRemove.deleteAccess() && - 0 === oFolderToRemove.privateMessageCountAll()) - { - this.folderForDeletion(null); - - var - fRemoveFolder = function (oFolder) { - - if (oFolderToRemove === oFolder) - { - return true; - } - - oFolder.subFolders.remove(fRemoveFolder); - return false; - } - ; - - if (oFolderToRemove) - { - RL.local().set(Enums.ClientSideKeyName.FoldersLashHash, ''); - - RL.data().folderList.remove(fRemoveFolder); - - RL.data().foldersDeleting(true); - RL.remote().folderDelete(function (sResult, oData) { - - RL.data().foldersDeleting(false); - if (Enums.StorageResultType.Success !== sResult || !oData || !oData.Result) - { - RL.data().foldersListError( - oData && oData.ErrorCode ? Utils.getNotification(oData.ErrorCode) : Utils.i18n('NOTIFICATIONS/CANT_DELETE_FOLDER')); - } - - RL.folders(); - - }, oFolderToRemove.fullNameRaw); - - RL.cache().removeFolderFromCacheList(oFolderToRemove.fullNameRaw); - } - } - else if (0 < oFolderToRemove.privateMessageCountAll()) - { - RL.data().foldersListError(Utils.getNotification(Enums.Notification.CantDeleteNonEmptyFolder)); - } -}; - -SettingsFolders.prototype.subscribeFolder = function (oFolder) -{ - RL.local().set(Enums.ClientSideKeyName.FoldersLashHash, ''); - RL.remote().folderSetSubscribe(Utils.emptyFunction, oFolder.fullNameRaw, true); - - oFolder.subScribed(true); -}; - -SettingsFolders.prototype.unSubscribeFolder = function (oFolder) -{ - RL.local().set(Enums.ClientSideKeyName.FoldersLashHash, ''); - RL.remote().folderSetSubscribe(Utils.emptyFunction, oFolder.fullNameRaw, false); - - oFolder.subScribed(false); -}; diff --git a/dev/Settings/General.js b/dev/Settings/General.js deleted file mode 100644 index cd3e7669b..000000000 --- a/dev/Settings/General.js +++ /dev/null @@ -1,161 +0,0 @@ -/* RainLoop Webmail (c) RainLoop Team | Licensed under CC BY-NC-SA 3.0 */ - -/** - * @constructor - */ -function SettingsGeneral() -{ - var oData = RL.data(); - - this.mainLanguage = oData.mainLanguage; - this.mainMessagesPerPage = oData.mainMessagesPerPage; - this.mainMessagesPerPageArray = Consts.Defaults.MessagesPerPageArray; - this.editorDefaultType = oData.editorDefaultType; - this.showImages = oData.showImages; - this.interfaceAnimation = oData.interfaceAnimation; - this.useDesktopNotifications = oData.useDesktopNotifications; - this.threading = oData.threading; - this.useThreads = oData.useThreads; - this.replySameFolder = oData.replySameFolder; - this.layout = oData.layout; - this.usePreviewPane = oData.usePreviewPane; - this.useCheckboxesInList = oData.useCheckboxesInList; - this.allowLanguagesOnSettings = oData.allowLanguagesOnSettings; - - this.isDesktopNotificationsSupported = ko.computed(function () { - return Enums.DesktopNotifications.NotSupported !== oData.desktopNotificationsPermisions(); - }); - - this.isDesktopNotificationsDenied = ko.computed(function () { - return Enums.DesktopNotifications.NotSupported === oData.desktopNotificationsPermisions() || - Enums.DesktopNotifications.Denied === oData.desktopNotificationsPermisions(); - }); - - this.mainLanguageFullName = ko.computed(function () { - return Utils.convertLangName(this.mainLanguage()); - }, this); - - this.languageTrigger = ko.observable(Enums.SaveSettingsStep.Idle).extend({'throttle': 100}); - this.mppTrigger = ko.observable(Enums.SaveSettingsStep.Idle); - - this.isAnimationSupported = Globals.bAnimationSupported; -} - -Utils.addSettingsViewModel(SettingsGeneral, 'SettingsGeneral', 'SETTINGS_LABELS/LABEL_GENERAL_NAME', 'general', true); - -SettingsGeneral.prototype.toggleLayout = function () -{ - this.layout(Enums.Layout.NoPreview === this.layout() ? Enums.Layout.SidePreview : Enums.Layout.NoPreview); -}; - -SettingsGeneral.prototype.onBuild = function () -{ - var self = this; - - _.delay(function () { - - var - oData = RL.data(), - f1 = Utils.settingsSaveHelperSimpleFunction(self.mppTrigger, self) - ; - - oData.language.subscribe(function (sValue) { - - self.languageTrigger(Enums.SaveSettingsStep.Animate); - - $.ajax({ - 'url': RL.link().langLink(sValue), - 'dataType': 'script', - 'cache': true - }).done(function() { - Utils.i18nReload(); - self.languageTrigger(Enums.SaveSettingsStep.TrueResult); - }).fail(function() { - self.languageTrigger(Enums.SaveSettingsStep.FalseResult); - }).always(function() { - _.delay(function () { - self.languageTrigger(Enums.SaveSettingsStep.Idle); - }, 1000); - }); - - RL.remote().saveSettings(Utils.emptyFunction, { - 'Language': sValue - }); - }); - - oData.editorDefaultType.subscribe(function (sValue) { - RL.remote().saveSettings(Utils.emptyFunction, { - 'EditorDefaultType': sValue - }); - }); - - oData.messagesPerPage.subscribe(function (iValue) { - RL.remote().saveSettings(f1, { - 'MPP': iValue - }); - }); - - oData.showImages.subscribe(function (bValue) { - RL.remote().saveSettings(Utils.emptyFunction, { - 'ShowImages': bValue ? '1' : '0' - }); - }); - - oData.interfaceAnimation.subscribe(function (sValue) { - RL.remote().saveSettings(Utils.emptyFunction, { - 'InterfaceAnimation': sValue - }); - }); - - oData.useDesktopNotifications.subscribe(function (bValue) { - Utils.timeOutAction('SaveDesktopNotifications', function () { - RL.remote().saveSettings(Utils.emptyFunction, { - 'DesktopNotifications': bValue ? '1' : '0' - }); - }, 3000); - }); - - oData.replySameFolder.subscribe(function (bValue) { - Utils.timeOutAction('SaveReplySameFolder', function () { - RL.remote().saveSettings(Utils.emptyFunction, { - 'ReplySameFolder': bValue ? '1' : '0' - }); - }, 3000); - }); - - oData.useThreads.subscribe(function (bValue) { - - oData.messageList([]); - - RL.remote().saveSettings(Utils.emptyFunction, { - 'UseThreads': bValue ? '1' : '0' - }); - }); - - oData.layout.subscribe(function (nValue) { - - oData.messageList([]); - - RL.remote().saveSettings(Utils.emptyFunction, { - 'Layout': nValue - }); - }); - - oData.useCheckboxesInList.subscribe(function (bValue) { - RL.remote().saveSettings(Utils.emptyFunction, { - 'UseCheckboxesInList': bValue ? '1' : '0' - }); - }); - - }, 50); -}; - -SettingsGeneral.prototype.onShow = function () -{ - RL.data().desktopNotifications.valueHasMutated(); -}; - -SettingsGeneral.prototype.selectLanguage = function () -{ - kn.showScreenPopup(PopupsLanguagesViewModel); -}; diff --git a/dev/Settings/Identities.js b/dev/Settings/Identities.js deleted file mode 100644 index 55f4a813c..000000000 --- a/dev/Settings/Identities.js +++ /dev/null @@ -1,219 +0,0 @@ -/* RainLoop Webmail (c) RainLoop Team | Licensed under CC BY-NC-SA 3.0 */ - -/** - * @constructor - */ -function SettingsIdentities() -{ - var oData = RL.data(); - - this.editor = null; - this.defautOptionsAfterRender = Utils.defautOptionsAfterRender; - - this.accountEmail = oData.accountEmail; - this.displayName = oData.displayName; - this.signature = oData.signature; - this.signatureToAll = oData.signatureToAll; - this.replyTo = oData.replyTo; - - this.signatureDom = ko.observable(null); - - this.defaultIdentityIDTrigger = ko.observable(Enums.SaveSettingsStep.Idle); - this.displayNameTrigger = ko.observable(Enums.SaveSettingsStep.Idle); - this.replyTrigger = ko.observable(Enums.SaveSettingsStep.Idle); - this.signatureTrigger = ko.observable(Enums.SaveSettingsStep.Idle); - - this.identities = oData.identities; - this.defaultIdentityID = oData.defaultIdentityID; - - this.identitiesOptions = ko.computed(function () { - - var - aList = this.identities(), - aResult = [] - ; - - if (0 < aList.length) - { - aResult.push({ - 'id': this.accountEmail.peek(), - 'name': this.formattedAccountIdentity(), - 'seporator': false - }); - - aResult.push({ - 'id': '---', - 'name': '---', - 'seporator': true, - 'disabled': true - }); - - _.each(aList, function (oItem) { - aResult.push({ - 'id': oItem.id, - 'name': oItem.formattedNameForEmail(), - 'seporator': false - }); - }); - } - - return aResult; - }, this); - - this.processText = ko.computed(function () { - return oData.identitiesLoading() ? Utils.i18n('SETTINGS_IDENTITIES/LOADING_PROCESS') : ''; - }, this); - - this.visibility = ko.computed(function () { - return '' === this.processText() ? 'hidden' : 'visible'; - }, this); - - this.identityForDeletion = ko.observable(null).extend({'falseTimeout': 3000}).extend({'toggleSubscribe': [this, - function (oPrev) { - if (oPrev) - { - oPrev.deleteAccess(false); - } - }, function (oNext) { - if (oNext) - { - oNext.deleteAccess(true); - } - } - ]}); -} - -Utils.addSettingsViewModel(SettingsIdentities, 'SettingsIdentities', 'SETTINGS_LABELS/LABEL_IDENTITIES_NAME', 'identities'); - -/** - * - * @return {string} - */ -SettingsIdentities.prototype.formattedAccountIdentity = function () -{ - var - sDisplayName = this.displayName.peek(), - sEmail = this.accountEmail.peek() - ; - - return '' === sDisplayName ? sEmail : '"' + Utils.quoteName(sDisplayName) + '" <' + sEmail + '>'; -}; - -SettingsIdentities.prototype.addNewIdentity = function () -{ - kn.showScreenPopup(PopupsIdentityViewModel); -}; - -SettingsIdentities.prototype.editIdentity = function (oIdentity) -{ - kn.showScreenPopup(PopupsIdentityViewModel, [oIdentity]); -}; - -/** - * @param {IdentityModel} oIdentityToRemove - */ -SettingsIdentities.prototype.deleteIdentity = function (oIdentityToRemove) -{ - if (oIdentityToRemove && oIdentityToRemove.deleteAccess()) - { - this.identityForDeletion(null); - - var - fRemoveFolder = function (oIdentity) { - return oIdentityToRemove === oIdentity; - } - ; - - if (oIdentityToRemove) - { - this.identities.remove(fRemoveFolder); - - RL.remote().identityDelete(function () { - RL.accountsAndIdentities(); - }, oIdentityToRemove.id); - } - } -}; - -SettingsIdentities.prototype.onFocus = function () -{ - if (!this.editor && this.signatureDom()) - { - var - self = this, - sSignature = RL.data().signature() - ; - - this.editor = new NewHtmlEditorWrapper(self.signatureDom(), function () { - RL.data().signature( - (self.editor.isHtml() ? ':HTML:' : '') + self.editor.getData() - ); - }, function () { - if (':HTML:' === sSignature.substr(0, 6)) - { - self.editor.setHtml(sSignature.substr(6), false); - } - else - { - self.editor.setPlain(sSignature, false); - } - }); - } -}; - -SettingsIdentities.prototype.onBuild = function (oDom) -{ - var self = this; - - oDom - .on('click', '.identity-item .e-action', function () { - var oIdentityItem = ko.dataFor(this); - if (oIdentityItem) - { - self.editIdentity(oIdentityItem); - } - }) - ; - - _.delay(function () { - - var - oData = RL.data(), - f1 = Utils.settingsSaveHelperSimpleFunction(self.displayNameTrigger, self), - f2 = Utils.settingsSaveHelperSimpleFunction(self.replyTrigger, self), - f3 = Utils.settingsSaveHelperSimpleFunction(self.signatureTrigger, self), - f4 = Utils.settingsSaveHelperSimpleFunction(self.defaultIdentityIDTrigger, self) - ; - - oData.defaultIdentityID.subscribe(function (sValue) { - RL.remote().saveSettings(f4, { - 'DefaultIdentityID': sValue - }); - }); - - oData.displayName.subscribe(function (sValue) { - RL.remote().saveSettings(f1, { - 'DisplayName': sValue - }); - }); - - oData.replyTo.subscribe(function (sValue) { - RL.remote().saveSettings(f2, { - 'ReplyTo': sValue - }); - }); - - oData.signature.subscribe(function (sValue) { - RL.remote().saveSettings(f3, { - 'Signature': sValue - }); - }); - - oData.signatureToAll.subscribe(function (bValue) { - RL.remote().saveSettings(null, { - 'SignatureToAll': bValue ? '1' : '0' - }); - }); - - }, 50); -}; \ No newline at end of file diff --git a/dev/Settings/Identity.js b/dev/Settings/Identity.js deleted file mode 100644 index c2de4a3e4..000000000 --- a/dev/Settings/Identity.js +++ /dev/null @@ -1,89 +0,0 @@ -/* RainLoop Webmail (c) RainLoop Team | Licensed under CC BY-NC-SA 3.0 */ - -/** - * @constructor - */ -function SettingsIdentity() -{ - var oData = RL.data(); - - this.editor = null; - - this.displayName = oData.displayName; - this.signature = oData.signature; - this.signatureToAll = oData.signatureToAll; - this.replyTo = oData.replyTo; - - this.signatureDom = ko.observable(null); - - this.displayNameTrigger = ko.observable(Enums.SaveSettingsStep.Idle); - this.replyTrigger = ko.observable(Enums.SaveSettingsStep.Idle); - this.signatureTrigger = ko.observable(Enums.SaveSettingsStep.Idle); -} - -Utils.addSettingsViewModel(SettingsIdentity, 'SettingsIdentity', 'SETTINGS_LABELS/LABEL_IDENTITY_NAME', 'identity'); - -SettingsIdentity.prototype.onFocus = function () -{ - if (!this.editor && this.signatureDom()) - { - var - self = this, - sSignature = RL.data().signature() - ; - - this.editor = new NewHtmlEditorWrapper(self.signatureDom(), function () { - RL.data().signature( - (self.editor.isHtml() ? ':HTML:' : '') + self.editor.getData() - ); - }, function () { - if (':HTML:' === sSignature.substr(0, 6)) - { - self.editor.setHtml(sSignature.substr(6), false); - } - else - { - self.editor.setPlain(sSignature, false); - } - }); - } -}; - -SettingsIdentity.prototype.onBuild = function () -{ - var self = this; - _.delay(function () { - - var - oData = RL.data(), - f1 = Utils.settingsSaveHelperSimpleFunction(self.displayNameTrigger, self), - f2 = Utils.settingsSaveHelperSimpleFunction(self.replyTrigger, self), - f3 = Utils.settingsSaveHelperSimpleFunction(self.signatureTrigger, self) - ; - - oData.displayName.subscribe(function (sValue) { - RL.remote().saveSettings(f1, { - 'DisplayName': sValue - }); - }); - - oData.replyTo.subscribe(function (sValue) { - RL.remote().saveSettings(f2, { - 'ReplyTo': sValue - }); - }); - - oData.signature.subscribe(function (sValue) { - RL.remote().saveSettings(f3, { - 'Signature': sValue - }); - }); - - oData.signatureToAll.subscribe(function (bValue) { - RL.remote().saveSettings(null, { - 'SignatureToAll': bValue ? '1' : '0' - }); - }); - - }, 50); -}; diff --git a/dev/Settings/OpenPGP.js b/dev/Settings/OpenPGP.js deleted file mode 100644 index 06fc0f7c8..000000000 --- a/dev/Settings/OpenPGP.js +++ /dev/null @@ -1,70 +0,0 @@ -/* RainLoop Webmail (c) RainLoop Team | Licensed under CC BY-NC-SA 3.0 */ - -/** - * @constructor - */ -function SettingsOpenPGP() -{ - this.openpgpkeys = RL.data().openpgpkeys; - this.openpgpkeysPublic = RL.data().openpgpkeysPublic; - this.openpgpkeysPrivate = RL.data().openpgpkeysPrivate; - - this.openPgpKeyForDeletion = ko.observable(null).extend({'falseTimeout': 3000}).extend({'toggleSubscribe': [this, - function (oPrev) { - if (oPrev) - { - oPrev.deleteAccess(false); - } - }, function (oNext) { - if (oNext) - { - oNext.deleteAccess(true); - } - } - ]}); -} - -Utils.addSettingsViewModel(SettingsOpenPGP, 'SettingsOpenPGP', 'SETTINGS_LABELS/LABEL_OPEN_PGP_NAME', 'openpgp'); - -SettingsOpenPGP.prototype.addOpenPgpKey = function () -{ - kn.showScreenPopup(PopupsAddOpenPgpKeyViewModel); -}; - -SettingsOpenPGP.prototype.generateOpenPgpKey = function () -{ - kn.showScreenPopup(PopupsGenerateNewOpenPgpKeyViewModel); -}; - -SettingsOpenPGP.prototype.viewOpenPgpKey = function (oOpenPgpKey) -{ - if (oOpenPgpKey) - { - kn.showScreenPopup(PopupsViewOpenPgpKeyViewModel, [oOpenPgpKey]); - } -}; - -/** - * @param {OpenPgpKeyModel} oOpenPgpKeyToRemove - */ -SettingsOpenPGP.prototype.deleteOpenPgpKey = function (oOpenPgpKeyToRemove) -{ - if (oOpenPgpKeyToRemove && oOpenPgpKeyToRemove.deleteAccess()) - { - this.openPgpKeyForDeletion(null); - - if (oOpenPgpKeyToRemove && RL.data().openpgpKeyring) - { - this.openpgpkeys.remove(function (oOpenPgpKey) { - return oOpenPgpKeyToRemove === oOpenPgpKey; - }); - - RL.data().openpgpKeyring[oOpenPgpKeyToRemove.isPrivate ? 'privateKeys' : 'publicKeys'] - .removeForId(oOpenPgpKeyToRemove.guid); - - RL.data().openpgpKeyring.store(); - - RL.reloadOpenPgpKeys(); - } - } -}; \ No newline at end of file diff --git a/dev/Settings/Security.js b/dev/Settings/Security.js deleted file mode 100644 index bee2bd596..000000000 --- a/dev/Settings/Security.js +++ /dev/null @@ -1,151 +0,0 @@ -/* RainLoop Webmail (c) RainLoop Team | Licensed under CC BY-NC-SA 3.0 */ - -/** - * @constructor - */ -function SettingsSecurity() -{ - this.processing = ko.observable(false); - this.clearing = ko.observable(false); - this.secreting = ko.observable(false); - - this.viewUser = ko.observable(''); - this.viewEnable = ko.observable(false); - this.viewEnable.subs = true; - this.twoFactorStatus = ko.observable(false); - - this.viewSecret = ko.observable(''); - this.viewBackupCodes = ko.observable(''); - this.viewUrl = ko.observable(''); - - this.bFirst = true; - - this.viewTwoFactorStatus = ko.computed(function () { - Globals.langChangeTrigger(); - return Utils.i18n( - this.twoFactorStatus() ? - 'SETTINGS_SECURITY/TWO_FACTOR_SECRET_CONFIGURED_DESC' : - 'SETTINGS_SECURITY/TWO_FACTOR_SECRET_NOT_CONFIGURED_DESC' - ); - }, this); - - this.onResult = _.bind(this.onResult, this); - this.onSecretResult = _.bind(this.onSecretResult, this); -} - -Utils.addSettingsViewModel(SettingsSecurity, 'SettingsSecurity', 'SETTINGS_LABELS/LABEL_SECURITY_NAME', 'security'); - -SettingsSecurity.prototype.showSecret = function () -{ - this.secreting(true); - RL.remote().showTwoFactorSecret(this.onSecretResult); -}; - -SettingsSecurity.prototype.hideSecret = function () -{ - this.viewSecret(''); - this.viewBackupCodes(''); - this.viewUrl(''); -}; - -SettingsSecurity.prototype.createTwoFactor = function () -{ - this.processing(true); - RL.remote().createTwoFactor(this.onResult); -}; - -SettingsSecurity.prototype.enableTwoFactor = function () -{ - this.processing(true); - RL.remote().enableTwoFactor(this.onResult, this.viewEnable()); -}; - -SettingsSecurity.prototype.testTwoFactor = function () -{ - kn.showScreenPopup(PopupsTwoFactorTestViewModel); -}; - -SettingsSecurity.prototype.clearTwoFactor = function () -{ - this.viewSecret(''); - this.viewBackupCodes(''); - this.viewUrl(''); - - this.clearing(true); - RL.remote().clearTwoFactor(this.onResult); -}; - -SettingsSecurity.prototype.onShow = function () -{ - this.viewSecret(''); - this.viewBackupCodes(''); - this.viewUrl(''); -}; - -SettingsSecurity.prototype.onResult = function (sResult, oData) -{ - this.processing(false); - this.clearing(false); - - if (Enums.StorageResultType.Success === sResult && oData && oData.Result) - { - this.viewUser(Utils.pString(oData.Result.User)); - this.viewEnable(!!oData.Result.Enable); - this.twoFactorStatus(!!oData.Result.IsSet); - - this.viewSecret(Utils.pString(oData.Result.Secret)); - this.viewBackupCodes(Utils.pString(oData.Result.BackupCodes).replace(/[\s]+/g, ' ')); - this.viewUrl(Utils.pString(oData.Result.Url)); - } - else - { - this.viewUser(''); - this.viewEnable(false); - this.twoFactorStatus(false); - - this.viewSecret(''); - this.viewBackupCodes(''); - this.viewUrl(''); - } - - if (this.bFirst) - { - this.bFirst = false; - var self = this; - this.viewEnable.subscribe(function (bValue) { - if (this.viewEnable.subs) - { - RL.remote().enableTwoFactor(function (sResult, oData) { - if (Enums.StorageResultType.Success !== sResult || !oData || !oData.Result) - { - self.viewEnable.subs = false; - self.viewEnable(false); - self.viewEnable.subs = true; - } - }, bValue); - } - }, this); - } -}; - -SettingsSecurity.prototype.onSecretResult = function (sResult, oData) -{ - this.secreting(false); - - if (Enums.StorageResultType.Success === sResult && oData && oData.Result) - { - this.viewSecret(Utils.pString(oData.Result.Secret)); - this.viewUrl(Utils.pString(oData.Result.Url)); - } - else - { - this.viewSecret(''); - this.viewUrl(''); - } -}; - -SettingsSecurity.prototype.onBuild = function () -{ - this.processing(true); - RL.remote().getTwoFactor(this.onResult); -}; diff --git a/dev/Settings/SettingsAccounts.js b/dev/Settings/SettingsAccounts.js new file mode 100644 index 000000000..759d2dd57 --- /dev/null +++ b/dev/Settings/SettingsAccounts.js @@ -0,0 +1,105 @@ +/* RainLoop Webmail (c) RainLoop Team | Licensed under CC BY-NC-SA 3.0 */ + +(function (module) { + + 'use strict'; + + var + window = require('../External/window.js'), + _ = require('../External/underscore.js'), + ko = require('../External/ko.js'), + + Enums = require('../Common/Enums.js'), + Utils = require('../Common/Utils.js'), + LinkBuilder = require('../Common/LinkBuilder.js'), + + Remote = require('../Storages/WebMailAjaxRemoteStorage.js'), + + kn = require('../Knoin/Knoin.js'), + PopupsAddAccountViewModel = require('../ViewModels/Popups/PopupsAddAccountViewModel.js') + ; + + /** + * @constructor + */ + function SettingsAccounts() + { + var oData = RL.data(); + + this.accounts = oData.accounts; + + this.processText = ko.computed(function () { + return oData.accountsLoading() ? Utils.i18n('SETTINGS_ACCOUNTS/LOADING_PROCESS') : ''; + }, this); + + this.visibility = ko.computed(function () { + return '' === this.processText() ? 'hidden' : 'visible'; + }, this); + + this.accountForDeletion = ko.observable(null).extend({'falseTimeout': 3000}).extend({'toggleSubscribe': [this, + function (oPrev) { + if (oPrev) + { + oPrev.deleteAccess(false); + } + }, function (oNext) { + if (oNext) + { + oNext.deleteAccess(true); + } + } + ]}); + } + + kn.addSettingsViewModel(SettingsAccounts, 'SettingsAccounts', 'SETTINGS_LABELS/LABEL_ACCOUNTS_NAME', 'accounts'); + + SettingsAccounts.prototype.addNewAccount = function () + { + kn.showScreenPopup(PopupsAddAccountViewModel); + }; + + /** + * @param {AccountModel} oAccountToRemove + */ + SettingsAccounts.prototype.deleteAccount = function (oAccountToRemove) + { + if (oAccountToRemove && oAccountToRemove.deleteAccess()) + { + this.accountForDeletion(null); + + var + fRemoveAccount = function (oAccount) { + return oAccountToRemove === oAccount; + } + ; + + if (oAccountToRemove) + { + this.accounts.remove(fRemoveAccount); + + Remote.accountDelete(function (sResult, oData) { + + if (Enums.StorageResultType.Success === sResult && oData && + oData.Result && oData.Reload) + { + kn.routeOff(); + kn.setHash(LinkBuilder.root(), true); + kn.routeOff(); + + _.defer(function () { + window.location.reload(); + }); + } + else + { + RL.accountsAndIdentities(); + } + + }, oAccountToRemove.email); + } + } + }; + + module.exports = SettingsAccounts; + +}(module)); \ No newline at end of file diff --git a/dev/Settings/SettingsChangePassword.js b/dev/Settings/SettingsChangePassword.js new file mode 100644 index 000000000..2d06ce073 --- /dev/null +++ b/dev/Settings/SettingsChangePassword.js @@ -0,0 +1,124 @@ +/* RainLoop Webmail (c) RainLoop Team | Licensed under CC BY-NC-SA 3.0 */ + +(function (module) { + + 'use strict'; + + var + _ = require('../External/underscore.js'), + ko = require('../External/ko.js'), + + Enums = require('../Common/Enums.js'), + Utils = require('../Common/Utils.js'), + + Remote = require('../Storages/WebMailAjaxRemoteStorage.js') + ; + + /** + * @constructor + */ + function SettingsChangePassword() + { + this.changeProcess = ko.observable(false); + + this.errorDescription = ko.observable(''); + this.passwordMismatch = ko.observable(false); + this.passwordUpdateError = ko.observable(false); + this.passwordUpdateSuccess = ko.observable(false); + + this.currentPassword = ko.observable(''); + this.currentPassword.error = ko.observable(false); + this.newPassword = ko.observable(''); + this.newPassword2 = ko.observable(''); + + this.currentPassword.subscribe(function () { + this.passwordUpdateError(false); + this.passwordUpdateSuccess(false); + this.currentPassword.error(false); + }, this); + + this.newPassword.subscribe(function () { + this.passwordUpdateError(false); + this.passwordUpdateSuccess(false); + this.passwordMismatch(false); + }, this); + + this.newPassword2.subscribe(function () { + this.passwordUpdateError(false); + this.passwordUpdateSuccess(false); + this.passwordMismatch(false); + }, this); + + this.saveNewPasswordCommand = Utils.createCommand(this, function () { + + if (this.newPassword() !== this.newPassword2()) + { + this.passwordMismatch(true); + this.errorDescription(Utils.i18n('SETTINGS_CHANGE_PASSWORD/ERROR_PASSWORD_MISMATCH')); + } + else + { + this.changeProcess(true); + + this.passwordUpdateError(false); + this.passwordUpdateSuccess(false); + this.currentPassword.error(false); + this.passwordMismatch(false); + this.errorDescription(''); + + Remote.changePassword(this.onChangePasswordResponse, this.currentPassword(), this.newPassword()); + } + + }, function () { + return !this.changeProcess() && '' !== this.currentPassword() && + '' !== this.newPassword() && '' !== this.newPassword2(); + }); + + this.onChangePasswordResponse = _.bind(this.onChangePasswordResponse, this); + } + + kn.addSettingsViewModel(SettingsChangePassword, 'SettingsChangePassword', 'SETTINGS_LABELS/LABEL_CHANGE_PASSWORD_NAME', 'change-password'); + + SettingsChangePassword.prototype.onHide = function () + { + this.changeProcess(false); + this.currentPassword(''); + this.newPassword(''); + this.newPassword2(''); + this.errorDescription(''); + this.passwordMismatch(false); + this.currentPassword.error(false); + }; + + SettingsChangePassword.prototype.onChangePasswordResponse = function (sResult, oData) + { + this.changeProcess(false); + this.passwordMismatch(false); + this.errorDescription(''); + this.currentPassword.error(false); + + if (Enums.StorageResultType.Success === sResult && oData && oData.Result) + { + this.currentPassword(''); + this.newPassword(''); + this.newPassword2(''); + + this.passwordUpdateSuccess(true); + this.currentPassword.error(false); + } + else + { + if (oData && Enums.Notification.CurrentPasswordIncorrect === oData.ErrorCode) + { + this.currentPassword.error(true); + } + + this.passwordUpdateError(true); + this.errorDescription(oData && oData.ErrorCode ? Utils.getNotification(oData.ErrorCode) : + Utils.getNotification(Enums.Notification.CouldNotSaveNewPassword)); + } + }; + + module.exports = SettingsChangePassword; + +}(module)); \ No newline at end of file diff --git a/dev/Settings/SettingsContacts.js b/dev/Settings/SettingsContacts.js new file mode 100644 index 000000000..1d402cabe --- /dev/null +++ b/dev/Settings/SettingsContacts.js @@ -0,0 +1,62 @@ +/* RainLoop Webmail (c) RainLoop Team | Licensed under CC BY-NC-SA 3.0 */ + +(function (module) { + + 'use strict'; + + var + ko = require('../External/ko.js'), + + Utils = require('../Common/Utils.js'), + + Remote = require('../Storages/WebMailAjaxRemoteStorage.js') + ; + + /** + * @constructor + */ + function SettingsContacts() + { + var oData = RL.data(); + + this.contactsAutosave = oData.contactsAutosave; + + this.allowContactsSync = oData.allowContactsSync; + this.enableContactsSync = oData.enableContactsSync; + this.contactsSyncUrl = oData.contactsSyncUrl; + this.contactsSyncUser = oData.contactsSyncUser; + this.contactsSyncPass = oData.contactsSyncPass; + + this.saveTrigger = ko.computed(function () { + return [ + this.enableContactsSync() ? '1' : '0', + this.contactsSyncUrl(), + this.contactsSyncUser(), + this.contactsSyncPass() + ].join('|'); + }, this).extend({'throttle': 500}); + + this.saveTrigger.subscribe(function () { + Remote.saveContactsSyncData(null, + this.enableContactsSync(), + this.contactsSyncUrl(), + this.contactsSyncUser(), + this.contactsSyncPass() + ); + }, this); + } + + kn.addSettingsViewModel(SettingsContacts, 'SettingsContacts', 'SETTINGS_LABELS/LABEL_CONTACTS_NAME', 'contacts'); + + SettingsContacts.prototype.onBuild = function () + { + RL.data().contactsAutosave.subscribe(function (bValue) { + Remote.saveSettings(Utils.emptyFunction, { + 'ContactsAutosave': bValue ? '1' : '0' + }); + }); + }; + + module.exports = SettingsContacts; + +}(module)); \ No newline at end of file diff --git a/dev/Settings/SettingsFilters.js b/dev/Settings/SettingsFilters.js new file mode 100644 index 000000000..dafac3ff5 --- /dev/null +++ b/dev/Settings/SettingsFilters.js @@ -0,0 +1,40 @@ +/* RainLoop Webmail (c) RainLoop Team | Licensed under CC BY-NC-SA 3.0 */ + +(function (module) { + + 'use strict'; + + var + ko = require('../External/ko.js'), + Utils = require('../Common/Utils.js'), + PopupsFilterViewModel = require('../ViewModels/Popups/PopupsFilterViewModel.js') + ; + + /** + * @constructor + */ + function SettingsFilters() + { + this.filters = ko.observableArray([]); + this.filters.loading = ko.observable(false); + + this.filters.subscribe(function () { + Utils.windowResize(); + }); + } + + kn.addSettingsViewModel(SettingsFilters, 'SettingsFilters', 'SETTINGS_LABELS/LABEL_FILTERS_NAME', 'filters'); + + SettingsFilters.prototype.deleteFilter = function (oFilter) + { + this.filters.remove(oFilter); + }; + + SettingsFilters.prototype.addFilter = function () + { + kn.showScreenPopup(PopupsFilterViewModel, [new FilterModel()]); + }; + + module.exports = SettingsFilters; + +}(module)); \ No newline at end of file diff --git a/dev/Settings/SettingsFolders.js b/dev/Settings/SettingsFolders.js new file mode 100644 index 000000000..7e77f6838 --- /dev/null +++ b/dev/Settings/SettingsFolders.js @@ -0,0 +1,217 @@ +/* RainLoop Webmail (c) RainLoop Team | Licensed under CC BY-NC-SA 3.0 */ + +(function (module) { + + 'use strict'; + + var + ko = require('../External/ko.js'), + Enums = require('../Common/Enums.js'), + Utils = require('../Common/Utils.js'), + + LocalStorage = require('../Storages/LocalStorage.js'), + Cache = require('../Storages/WebMailCacheStorage.js'), + Remote = require('../Storages/WebMailAjaxRemoteStorage.js'), + + PopupsFolderCreateViewModel = require('../ViewModels/Popups/PopupsFolderCreateViewModel.js'), + PopupsFolderSystemViewModel = require('../ViewModels/Popups/PopupsFolderSystemViewModel.js') + ; + + /** + * @constructor + */ + function SettingsFolders() + { + var oData = RL.data(); + + this.foldersListError = oData.foldersListError; + this.folderList = oData.folderList; + + this.processText = ko.computed(function () { + + var + oData = RL.data(), + bLoading = oData.foldersLoading(), + bCreating = oData.foldersCreating(), + bDeleting = oData.foldersDeleting(), + bRenaming = oData.foldersRenaming() + ; + + if (bCreating) + { + return Utils.i18n('SETTINGS_FOLDERS/CREATING_PROCESS'); + } + else if (bDeleting) + { + return Utils.i18n('SETTINGS_FOLDERS/DELETING_PROCESS'); + } + else if (bRenaming) + { + return Utils.i18n('SETTINGS_FOLDERS/RENAMING_PROCESS'); + } + else if (bLoading) + { + return Utils.i18n('SETTINGS_FOLDERS/LOADING_PROCESS'); + } + + return ''; + + }, this); + + this.visibility = ko.computed(function () { + return '' === this.processText() ? 'hidden' : 'visible'; + }, this); + + this.folderForDeletion = ko.observable(null).extend({'falseTimeout': 3000}).extend({'toggleSubscribe': [this, + function (oPrev) { + if (oPrev) + { + oPrev.deleteAccess(false); + } + }, function (oNext) { + if (oNext) + { + oNext.deleteAccess(true); + } + } + ]}); + + this.folderForEdit = ko.observable(null).extend({'toggleSubscribe': [this, + function (oPrev) { + if (oPrev) + { + oPrev.edited(false); + } + }, function (oNext) { + if (oNext && oNext.canBeEdited()) + { + oNext.edited(true); + } + } + ]}); + + this.useImapSubscribe = !!RL.settingsGet('UseImapSubscribe'); + } + + kn.addSettingsViewModel(SettingsFolders, 'SettingsFolders', 'SETTINGS_LABELS/LABEL_FOLDERS_NAME', 'folders'); + + SettingsFolders.prototype.folderEditOnEnter = function (oFolder) + { + var sEditName = oFolder ? Utils.trim(oFolder.nameForEdit()) : ''; + if ('' !== sEditName && oFolder.name() !== sEditName) + { + LocalStorage.set(Enums.ClientSideKeyName.FoldersLashHash, ''); + + RL.data().foldersRenaming(true); + Remote.folderRename(function (sResult, oData) { + + RL.data().foldersRenaming(false); + if (Enums.StorageResultType.Success !== sResult || !oData || !oData.Result) + { + RL.data().foldersListError( + oData && oData.ErrorCode ? Utils.getNotification(oData.ErrorCode) : Utils.i18n('NOTIFICATIONS/CANT_RENAME_FOLDER')); + } + + RL.folders(); + + }, oFolder.fullNameRaw, sEditName); + + Cache.removeFolderFromCacheList(oFolder.fullNameRaw); + + oFolder.name(sEditName); + } + + oFolder.edited(false); + }; + + SettingsFolders.prototype.folderEditOnEsc = function (oFolder) + { + if (oFolder) + { + oFolder.edited(false); + } + }; + + SettingsFolders.prototype.onShow = function () + { + RL.data().foldersListError(''); + }; + + SettingsFolders.prototype.createFolder = function () + { + kn.showScreenPopup(PopupsFolderCreateViewModel); + }; + + SettingsFolders.prototype.systemFolder = function () + { + kn.showScreenPopup(PopupsFolderSystemViewModel); + }; + + SettingsFolders.prototype.deleteFolder = function (oFolderToRemove) + { + if (oFolderToRemove && oFolderToRemove.canBeDeleted() && oFolderToRemove.deleteAccess() && + 0 === oFolderToRemove.privateMessageCountAll()) + { + this.folderForDeletion(null); + + var + fRemoveFolder = function (oFolder) { + + if (oFolderToRemove === oFolder) + { + return true; + } + + oFolder.subFolders.remove(fRemoveFolder); + return false; + } + ; + + if (oFolderToRemove) + { + LocalStorage.set(Enums.ClientSideKeyName.FoldersLashHash, ''); + + RL.data().folderList.remove(fRemoveFolder); + + RL.data().foldersDeleting(true); + Remote.folderDelete(function (sResult, oData) { + + RL.data().foldersDeleting(false); + if (Enums.StorageResultType.Success !== sResult || !oData || !oData.Result) + { + RL.data().foldersListError( + oData && oData.ErrorCode ? Utils.getNotification(oData.ErrorCode) : Utils.i18n('NOTIFICATIONS/CANT_DELETE_FOLDER')); + } + + RL.folders(); + + }, oFolderToRemove.fullNameRaw); + + Cache.removeFolderFromCacheList(oFolderToRemove.fullNameRaw); + } + } + else if (0 < oFolderToRemove.privateMessageCountAll()) + { + RL.data().foldersListError(Utils.getNotification(Enums.Notification.CantDeleteNonEmptyFolder)); + } + }; + + SettingsFolders.prototype.subscribeFolder = function (oFolder) + { + LocalStorage.set(Enums.ClientSideKeyName.FoldersLashHash, ''); + Remote.folderSetSubscribe(Utils.emptyFunction, oFolder.fullNameRaw, true); + + oFolder.subScribed(true); + }; + + SettingsFolders.prototype.unSubscribeFolder = function (oFolder) + { + LocalStorage.set(Enums.ClientSideKeyName.FoldersLashHash, ''); + Remote.folderSetSubscribe(Utils.emptyFunction, oFolder.fullNameRaw, false); + + oFolder.subScribed(false); + }; + + module.exports = SettingsFolders; + +}(module)); \ No newline at end of file diff --git a/dev/Settings/SettingsGeneral.js b/dev/Settings/SettingsGeneral.js new file mode 100644 index 000000000..7d95da09e --- /dev/null +++ b/dev/Settings/SettingsGeneral.js @@ -0,0 +1,184 @@ +/* RainLoop Webmail (c) RainLoop Team | Licensed under CC BY-NC-SA 3.0 */ + +(function (module) { + + 'use strict'; + + var + ko = require('../External/ko.js'), + + Enums = require('../Common/Enums.js'), + Consts = require('../Common/Consts.js'), + Globals = require('../Common/Globals.js'), + Utils = require('../Common/Utils.js'), + LinkBuilder = require('../Common/LinkBuilder.js'), + + Remote = require('../Storages/WebMailAjaxRemoteStorage.js'), + + kn = require('../Knoin/Knoin.js'), + PopupsLanguagesViewModel = require('../ViewModels/Popups/PopupsLanguagesViewModel.js') + ; + + /** + * @constructor + */ + function SettingsGeneral() + { + var oData = RL.data(); + + this.mainLanguage = oData.mainLanguage; + this.mainMessagesPerPage = oData.mainMessagesPerPage; + this.mainMessagesPerPageArray = Consts.Defaults.MessagesPerPageArray; + this.editorDefaultType = oData.editorDefaultType; + this.showImages = oData.showImages; + this.interfaceAnimation = oData.interfaceAnimation; + this.useDesktopNotifications = oData.useDesktopNotifications; + this.threading = oData.threading; + this.useThreads = oData.useThreads; + this.replySameFolder = oData.replySameFolder; + this.layout = oData.layout; + this.usePreviewPane = oData.usePreviewPane; + this.useCheckboxesInList = oData.useCheckboxesInList; + this.allowLanguagesOnSettings = oData.allowLanguagesOnSettings; + + this.isDesktopNotificationsSupported = ko.computed(function () { + return Enums.DesktopNotifications.NotSupported !== oData.desktopNotificationsPermisions(); + }); + + this.isDesktopNotificationsDenied = ko.computed(function () { + return Enums.DesktopNotifications.NotSupported === oData.desktopNotificationsPermisions() || + Enums.DesktopNotifications.Denied === oData.desktopNotificationsPermisions(); + }); + + this.mainLanguageFullName = ko.computed(function () { + return Utils.convertLangName(this.mainLanguage()); + }, this); + + this.languageTrigger = ko.observable(Enums.SaveSettingsStep.Idle).extend({'throttle': 100}); + this.mppTrigger = ko.observable(Enums.SaveSettingsStep.Idle); + + this.isAnimationSupported = Globals.bAnimationSupported; + } + + kn.addSettingsViewModel(SettingsGeneral, 'SettingsGeneral', 'SETTINGS_LABELS/LABEL_GENERAL_NAME', 'general', true); + + SettingsGeneral.prototype.toggleLayout = function () + { + this.layout(Enums.Layout.NoPreview === this.layout() ? Enums.Layout.SidePreview : Enums.Layout.NoPreview); + }; + + SettingsGeneral.prototype.onBuild = function () + { + var self = this; + + _.delay(function () { + + var + oData = RL.data(), + f1 = Utils.settingsSaveHelperSimpleFunction(self.mppTrigger, self) + ; + + oData.language.subscribe(function (sValue) { + + self.languageTrigger(Enums.SaveSettingsStep.Animate); + + $.ajax({ + 'url': LinkBuilder.langLink(sValue), + 'dataType': 'script', + 'cache': true + }).done(function() { + Utils.i18nReload(); + self.languageTrigger(Enums.SaveSettingsStep.TrueResult); + }).fail(function() { + self.languageTrigger(Enums.SaveSettingsStep.FalseResult); + }).always(function() { + _.delay(function () { + self.languageTrigger(Enums.SaveSettingsStep.Idle); + }, 1000); + }); + + Remote.saveSettings(Utils.emptyFunction, { + 'Language': sValue + }); + }); + + oData.editorDefaultType.subscribe(function (sValue) { + Remote.saveSettings(Utils.emptyFunction, { + 'EditorDefaultType': sValue + }); + }); + + oData.messagesPerPage.subscribe(function (iValue) { + Remote.saveSettings(f1, { + 'MPP': iValue + }); + }); + + oData.showImages.subscribe(function (bValue) { + Remote.saveSettings(Utils.emptyFunction, { + 'ShowImages': bValue ? '1' : '0' + }); + }); + + oData.interfaceAnimation.subscribe(function (sValue) { + Remote.saveSettings(Utils.emptyFunction, { + 'InterfaceAnimation': sValue + }); + }); + + oData.useDesktopNotifications.subscribe(function (bValue) { + Utils.timeOutAction('SaveDesktopNotifications', function () { + Remote.saveSettings(Utils.emptyFunction, { + 'DesktopNotifications': bValue ? '1' : '0' + }); + }, 3000); + }); + + oData.replySameFolder.subscribe(function (bValue) { + Utils.timeOutAction('SaveReplySameFolder', function () { + Remote.saveSettings(Utils.emptyFunction, { + 'ReplySameFolder': bValue ? '1' : '0' + }); + }, 3000); + }); + + oData.useThreads.subscribe(function (bValue) { + + oData.messageList([]); + + Remote.saveSettings(Utils.emptyFunction, { + 'UseThreads': bValue ? '1' : '0' + }); + }); + + oData.layout.subscribe(function (nValue) { + + oData.messageList([]); + + Remote.saveSettings(Utils.emptyFunction, { + 'Layout': nValue + }); + }); + + oData.useCheckboxesInList.subscribe(function (bValue) { + Remote.saveSettings(Utils.emptyFunction, { + 'UseCheckboxesInList': bValue ? '1' : '0' + }); + }); + + }, 50); + }; + + SettingsGeneral.prototype.onShow = function () + { + RL.data().desktopNotifications.valueHasMutated(); + }; + + SettingsGeneral.prototype.selectLanguage = function () + { + kn.showScreenPopup(PopupsLanguagesViewModel); + }; + + module.exports = SettingsGeneral; + +}(module)); \ No newline at end of file diff --git a/dev/Settings/SettingsIdentities.js b/dev/Settings/SettingsIdentities.js new file mode 100644 index 000000000..f9db59549 --- /dev/null +++ b/dev/Settings/SettingsIdentities.js @@ -0,0 +1,239 @@ +/* RainLoop Webmail (c) RainLoop Team | Licensed under CC BY-NC-SA 3.0 */ + +(function (module) { + + 'use strict'; + + var + ko = require('../External/ko.js'), + + Enums = require('../Common/Enums.js'), + Utils = require('../Common/Utils.js'), + + Remote = require('../Storages/WebMailAjaxRemoteStorage.js'), + + kn = require('../Knoin/Knoin.js'), + PopupsIdentityViewModel = require('../ViewModels/Popups/PopupsIdentityViewModel.js') + ; + + /** + * @constructor + */ + function SettingsIdentities() + { + var oData = RL.data(); + + this.editor = null; + this.defautOptionsAfterRender = Utils.defautOptionsAfterRender; + + this.accountEmail = oData.accountEmail; + this.displayName = oData.displayName; + this.signature = oData.signature; + this.signatureToAll = oData.signatureToAll; + this.replyTo = oData.replyTo; + + this.signatureDom = ko.observable(null); + + this.defaultIdentityIDTrigger = ko.observable(Enums.SaveSettingsStep.Idle); + this.displayNameTrigger = ko.observable(Enums.SaveSettingsStep.Idle); + this.replyTrigger = ko.observable(Enums.SaveSettingsStep.Idle); + this.signatureTrigger = ko.observable(Enums.SaveSettingsStep.Idle); + + this.identities = oData.identities; + this.defaultIdentityID = oData.defaultIdentityID; + + this.identitiesOptions = ko.computed(function () { + + var + aList = this.identities(), + aResult = [] + ; + + if (0 < aList.length) + { + aResult.push({ + 'id': this.accountEmail.peek(), + 'name': this.formattedAccountIdentity(), + 'seporator': false + }); + + aResult.push({ + 'id': '---', + 'name': '---', + 'seporator': true, + 'disabled': true + }); + + _.each(aList, function (oItem) { + aResult.push({ + 'id': oItem.id, + 'name': oItem.formattedNameForEmail(), + 'seporator': false + }); + }); + } + + return aResult; + }, this); + + this.processText = ko.computed(function () { + return oData.identitiesLoading() ? Utils.i18n('SETTINGS_IDENTITIES/LOADING_PROCESS') : ''; + }, this); + + this.visibility = ko.computed(function () { + return '' === this.processText() ? 'hidden' : 'visible'; + }, this); + + this.identityForDeletion = ko.observable(null).extend({'falseTimeout': 3000}).extend({'toggleSubscribe': [this, + function (oPrev) { + if (oPrev) + { + oPrev.deleteAccess(false); + } + }, function (oNext) { + if (oNext) + { + oNext.deleteAccess(true); + } + } + ]}); + } + + kn.addSettingsViewModel(SettingsIdentities, 'SettingsIdentities', 'SETTINGS_LABELS/LABEL_IDENTITIES_NAME', 'identities'); + + /** + * + * @return {string} + */ + SettingsIdentities.prototype.formattedAccountIdentity = function () + { + var + sDisplayName = this.displayName.peek(), + sEmail = this.accountEmail.peek() + ; + + return '' === sDisplayName ? sEmail : '"' + Utils.quoteName(sDisplayName) + '" <' + sEmail + '>'; + }; + + SettingsIdentities.prototype.addNewIdentity = function () + { + kn.showScreenPopup(PopupsIdentityViewModel); + }; + + SettingsIdentities.prototype.editIdentity = function (oIdentity) + { + kn.showScreenPopup(PopupsIdentityViewModel, [oIdentity]); + }; + + /** + * @param {IdentityModel} oIdentityToRemove + */ + SettingsIdentities.prototype.deleteIdentity = function (oIdentityToRemove) + { + if (oIdentityToRemove && oIdentityToRemove.deleteAccess()) + { + this.identityForDeletion(null); + + var + fRemoveFolder = function (oIdentity) { + return oIdentityToRemove === oIdentity; + } + ; + + if (oIdentityToRemove) + { + this.identities.remove(fRemoveFolder); + + Remote.identityDelete(function () { + RL.accountsAndIdentities(); + }, oIdentityToRemove.id); + } + } + }; + + SettingsIdentities.prototype.onFocus = function () + { + if (!this.editor && this.signatureDom()) + { + var + self = this, + sSignature = RL.data().signature() + ; + + this.editor = new NewHtmlEditorWrapper(self.signatureDom(), function () { + RL.data().signature( + (self.editor.isHtml() ? ':HTML:' : '') + self.editor.getData() + ); + }, function () { + if (':HTML:' === sSignature.substr(0, 6)) + { + self.editor.setHtml(sSignature.substr(6), false); + } + else + { + self.editor.setPlain(sSignature, false); + } + }); + } + }; + + SettingsIdentities.prototype.onBuild = function (oDom) + { + var self = this; + + oDom + .on('click', '.identity-item .e-action', function () { + var oIdentityItem = ko.dataFor(this); + if (oIdentityItem) + { + self.editIdentity(oIdentityItem); + } + }) + ; + + _.delay(function () { + + var + oData = RL.data(), + f1 = Utils.settingsSaveHelperSimpleFunction(self.displayNameTrigger, self), + f2 = Utils.settingsSaveHelperSimpleFunction(self.replyTrigger, self), + f3 = Utils.settingsSaveHelperSimpleFunction(self.signatureTrigger, self), + f4 = Utils.settingsSaveHelperSimpleFunction(self.defaultIdentityIDTrigger, self) + ; + + oData.defaultIdentityID.subscribe(function (sValue) { + Remote.saveSettings(f4, { + 'DefaultIdentityID': sValue + }); + }); + + oData.displayName.subscribe(function (sValue) { + Remote.saveSettings(f1, { + 'DisplayName': sValue + }); + }); + + oData.replyTo.subscribe(function (sValue) { + Remote.saveSettings(f2, { + 'ReplyTo': sValue + }); + }); + + oData.signature.subscribe(function (sValue) { + Remote.saveSettings(f3, { + 'Signature': sValue + }); + }); + + oData.signatureToAll.subscribe(function (bValue) { + Remote.saveSettings(null, { + 'SignatureToAll': bValue ? '1' : '0' + }); + }); + + }, 50); + }; + + module.exports = SettingsIdentities; + +}(module)); \ No newline at end of file diff --git a/dev/Settings/SettingsIdentity.js b/dev/Settings/SettingsIdentity.js new file mode 100644 index 000000000..b97bc233d --- /dev/null +++ b/dev/Settings/SettingsIdentity.js @@ -0,0 +1,106 @@ +/* RainLoop Webmail (c) RainLoop Team | Licensed under CC BY-NC-SA 3.0 */ + +(function (module) { + + 'use strict'; + + var + ko = require('../External/ko.js'), + + Enums = require('../Common/Enums.js'), + Utils = require('../Common/Utils.js'), + + Remote = require('../Storages/WebMailAjaxRemoteStorage.js') + ; + + /** + * @constructor + */ + function SettingsIdentity() + { + var oData = RL.data(); + + this.editor = null; + + this.displayName = oData.displayName; + this.signature = oData.signature; + this.signatureToAll = oData.signatureToAll; + this.replyTo = oData.replyTo; + + this.signatureDom = ko.observable(null); + + this.displayNameTrigger = ko.observable(Enums.SaveSettingsStep.Idle); + this.replyTrigger = ko.observable(Enums.SaveSettingsStep.Idle); + this.signatureTrigger = ko.observable(Enums.SaveSettingsStep.Idle); + } + + kn.addSettingsViewModel(SettingsIdentity, 'SettingsIdentity', 'SETTINGS_LABELS/LABEL_IDENTITY_NAME', 'identity'); + + SettingsIdentity.prototype.onFocus = function () + { + if (!this.editor && this.signatureDom()) + { + var + self = this, + sSignature = RL.data().signature() + ; + + this.editor = new NewHtmlEditorWrapper(self.signatureDom(), function () { + RL.data().signature( + (self.editor.isHtml() ? ':HTML:' : '') + self.editor.getData() + ); + }, function () { + if (':HTML:' === sSignature.substr(0, 6)) + { + self.editor.setHtml(sSignature.substr(6), false); + } + else + { + self.editor.setPlain(sSignature, false); + } + }); + } + }; + + SettingsIdentity.prototype.onBuild = function () + { + var self = this; + _.delay(function () { + + var + oData = RL.data(), + f1 = Utils.settingsSaveHelperSimpleFunction(self.displayNameTrigger, self), + f2 = Utils.settingsSaveHelperSimpleFunction(self.replyTrigger, self), + f3 = Utils.settingsSaveHelperSimpleFunction(self.signatureTrigger, self) + ; + + oData.displayName.subscribe(function (sValue) { + Remote.saveSettings(f1, { + 'DisplayName': sValue + }); + }); + + oData.replyTo.subscribe(function (sValue) { + Remote.saveSettings(f2, { + 'ReplyTo': sValue + }); + }); + + oData.signature.subscribe(function (sValue) { + Remote.saveSettings(f3, { + 'Signature': sValue + }); + }); + + oData.signatureToAll.subscribe(function (bValue) { + Remote.saveSettings(null, { + 'SignatureToAll': bValue ? '1' : '0' + }); + }); + + }, 50); + }; + + module.exports = SettingsIdentity; + +}(module)); \ No newline at end of file diff --git a/dev/Settings/SettingsOpenPGP.js b/dev/Settings/SettingsOpenPGP.js new file mode 100644 index 000000000..6e05440e3 --- /dev/null +++ b/dev/Settings/SettingsOpenPGP.js @@ -0,0 +1,87 @@ +/* RainLoop Webmail (c) RainLoop Team | Licensed under CC BY-NC-SA 3.0 */ + +(function (module) { + + 'use strict'; + + var + ko = require('../External/ko.js'), + Utils = require('../Common/Utils.js'), + + PopupsAddOpenPgpKeyViewModel = require('../ViewModels/Popups/PopupsAddOpenPgpKeyViewModel.js'), + PopupsGenerateNewOpenPgpKeyViewModel = require('../ViewModels/Popups/PopupsGenerateNewOpenPgpKeyViewModel.js'), + PopupsViewOpenPgpKeyViewModel = require('../ViewModels/Popups/PopupsViewOpenPgpKeyViewModel.js') + ; + + /** + * @constructor + */ + function SettingsOpenPGP() + { + this.openpgpkeys = RL.data().openpgpkeys; + this.openpgpkeysPublic = RL.data().openpgpkeysPublic; + this.openpgpkeysPrivate = RL.data().openpgpkeysPrivate; + + this.openPgpKeyForDeletion = ko.observable(null).extend({'falseTimeout': 3000}).extend({'toggleSubscribe': [this, + function (oPrev) { + if (oPrev) + { + oPrev.deleteAccess(false); + } + }, function (oNext) { + if (oNext) + { + oNext.deleteAccess(true); + } + } + ]}); + } + + kn.addSettingsViewModel(SettingsOpenPGP, 'SettingsOpenPGP', 'SETTINGS_LABELS/LABEL_OPEN_PGP_NAME', 'openpgp'); + + SettingsOpenPGP.prototype.addOpenPgpKey = function () + { + kn.showScreenPopup(PopupsAddOpenPgpKeyViewModel); + }; + + SettingsOpenPGP.prototype.generateOpenPgpKey = function () + { + kn.showScreenPopup(PopupsGenerateNewOpenPgpKeyViewModel); + }; + + SettingsOpenPGP.prototype.viewOpenPgpKey = function (oOpenPgpKey) + { + if (oOpenPgpKey) + { + kn.showScreenPopup(PopupsViewOpenPgpKeyViewModel, [oOpenPgpKey]); + } + }; + + /** + * @param {OpenPgpKeyModel} oOpenPgpKeyToRemove + */ + SettingsOpenPGP.prototype.deleteOpenPgpKey = function (oOpenPgpKeyToRemove) + { + if (oOpenPgpKeyToRemove && oOpenPgpKeyToRemove.deleteAccess()) + { + this.openPgpKeyForDeletion(null); + + if (oOpenPgpKeyToRemove && RL.data().openpgpKeyring) + { + this.openpgpkeys.remove(function (oOpenPgpKey) { + return oOpenPgpKeyToRemove === oOpenPgpKey; + }); + + RL.data().openpgpKeyring[oOpenPgpKeyToRemove.isPrivate ? 'privateKeys' : 'publicKeys'] + .removeForId(oOpenPgpKeyToRemove.guid); + + RL.data().openpgpKeyring.store(); + + RL.reloadOpenPgpKeys(); + } + } + }; + + module.exports = SettingsOpenPGP; + +}(module)); \ No newline at end of file diff --git a/dev/Settings/SettingsSecurity.js b/dev/Settings/SettingsSecurity.js new file mode 100644 index 000000000..5098ebe87 --- /dev/null +++ b/dev/Settings/SettingsSecurity.js @@ -0,0 +1,172 @@ +/* RainLoop Webmail (c) RainLoop Team | Licensed under CC BY-NC-SA 3.0 */ + +(function (module) { + + 'use strict'; + + var + ko = require('../External/ko.js'), + + Enums = require('../Common/Utils.js'), + Globals = require('../Common/Globals.js'), + Utils = require('../Common/Utils.js'), + + Remote = require('../Storages/WebMailAjaxRemoteStorage.js'), + + kn = require('../Knoin/Knoin.js'), + PopupsTwoFactorTestViewModel = require('../ViewModels/Popups/PopupsTwoFactorTestViewModel.js') + ; + + /** + * @constructor + */ + function SettingsSecurity() + { + this.processing = ko.observable(false); + this.clearing = ko.observable(false); + this.secreting = ko.observable(false); + + this.viewUser = ko.observable(''); + this.viewEnable = ko.observable(false); + this.viewEnable.subs = true; + this.twoFactorStatus = ko.observable(false); + + this.viewSecret = ko.observable(''); + this.viewBackupCodes = ko.observable(''); + this.viewUrl = ko.observable(''); + + this.bFirst = true; + + this.viewTwoFactorStatus = ko.computed(function () { + Globals.langChangeTrigger(); + return Utils.i18n( + this.twoFactorStatus() ? + 'SETTINGS_SECURITY/TWO_FACTOR_SECRET_CONFIGURED_DESC' : + 'SETTINGS_SECURITY/TWO_FACTOR_SECRET_NOT_CONFIGURED_DESC' + ); + }, this); + + this.onResult = _.bind(this.onResult, this); + this.onSecretResult = _.bind(this.onSecretResult, this); + } + + kn.addSettingsViewModel(SettingsSecurity, 'SettingsSecurity', 'SETTINGS_LABELS/LABEL_SECURITY_NAME', 'security'); + + SettingsSecurity.prototype.showSecret = function () + { + this.secreting(true); + Remote.showTwoFactorSecret(this.onSecretResult); + }; + + SettingsSecurity.prototype.hideSecret = function () + { + this.viewSecret(''); + this.viewBackupCodes(''); + this.viewUrl(''); + }; + + SettingsSecurity.prototype.createTwoFactor = function () + { + this.processing(true); + Remote.createTwoFactor(this.onResult); + }; + + SettingsSecurity.prototype.enableTwoFactor = function () + { + this.processing(true); + Remote.enableTwoFactor(this.onResult, this.viewEnable()); + }; + + SettingsSecurity.prototype.testTwoFactor = function () + { + kn.showScreenPopup(PopupsTwoFactorTestViewModel); + }; + + SettingsSecurity.prototype.clearTwoFactor = function () + { + this.viewSecret(''); + this.viewBackupCodes(''); + this.viewUrl(''); + + this.clearing(true); + Remote.clearTwoFactor(this.onResult); + }; + + SettingsSecurity.prototype.onShow = function () + { + this.viewSecret(''); + this.viewBackupCodes(''); + this.viewUrl(''); + }; + + SettingsSecurity.prototype.onResult = function (sResult, oData) + { + this.processing(false); + this.clearing(false); + + if (Enums.StorageResultType.Success === sResult && oData && oData.Result) + { + this.viewUser(Utils.pString(oData.Result.User)); + this.viewEnable(!!oData.Result.Enable); + this.twoFactorStatus(!!oData.Result.IsSet); + + this.viewSecret(Utils.pString(oData.Result.Secret)); + this.viewBackupCodes(Utils.pString(oData.Result.BackupCodes).replace(/[\s]+/g, ' ')); + this.viewUrl(Utils.pString(oData.Result.Url)); + } + else + { + this.viewUser(''); + this.viewEnable(false); + this.twoFactorStatus(false); + + this.viewSecret(''); + this.viewBackupCodes(''); + this.viewUrl(''); + } + + if (this.bFirst) + { + this.bFirst = false; + var self = this; + this.viewEnable.subscribe(function (bValue) { + if (this.viewEnable.subs) + { + Remote.enableTwoFactor(function (sResult, oData) { + if (Enums.StorageResultType.Success !== sResult || !oData || !oData.Result) + { + self.viewEnable.subs = false; + self.viewEnable(false); + self.viewEnable.subs = true; + } + }, bValue); + } + }, this); + } + }; + + SettingsSecurity.prototype.onSecretResult = function (sResult, oData) + { + this.secreting(false); + + if (Enums.StorageResultType.Success === sResult && oData && oData.Result) + { + this.viewSecret(Utils.pString(oData.Result.Secret)); + this.viewUrl(Utils.pString(oData.Result.Url)); + } + else + { + this.viewSecret(''); + this.viewUrl(''); + } + }; + + SettingsSecurity.prototype.onBuild = function () + { + this.processing(true); + Remote.getTwoFactor(this.onResult); + }; + + module.exports = SettingsSecurity; + +}(module)); \ No newline at end of file diff --git a/dev/Settings/SettingsSocial.js b/dev/Settings/SettingsSocial.js new file mode 100644 index 000000000..f25655fbb --- /dev/null +++ b/dev/Settings/SettingsSocial.js @@ -0,0 +1,80 @@ +/* RainLoop Webmail (c) RainLoop Team | Licensed under CC BY-NC-SA 3.0 */ + +(function (module) { + + 'use strict'; + + var + Utils = require('../Common/Utils.js') + ; + + /** + * @constructor + */ + function SettingsSocial() + { + var oData = RL.data(); + + this.googleEnable = oData.googleEnable; + + this.googleActions = oData.googleActions; + this.googleLoggined = oData.googleLoggined; + this.googleUserName = oData.googleUserName; + + this.facebookEnable = oData.facebookEnable; + + this.facebookActions = oData.facebookActions; + this.facebookLoggined = oData.facebookLoggined; + this.facebookUserName = oData.facebookUserName; + + this.twitterEnable = oData.twitterEnable; + + this.twitterActions = oData.twitterActions; + this.twitterLoggined = oData.twitterLoggined; + this.twitterUserName = oData.twitterUserName; + + this.connectGoogle = Utils.createCommand(this, function () { + if (!this.googleLoggined()) + { + RL.googleConnect(); + } + }, function () { + return !this.googleLoggined() && !this.googleActions(); + }); + + this.disconnectGoogle = Utils.createCommand(this, function () { + RL.googleDisconnect(); + }); + + this.connectFacebook = Utils.createCommand(this, function () { + if (!this.facebookLoggined()) + { + RL.facebookConnect(); + } + }, function () { + return !this.facebookLoggined() && !this.facebookActions(); + }); + + this.disconnectFacebook = Utils.createCommand(this, function () { + RL.facebookDisconnect(); + }); + + this.connectTwitter = Utils.createCommand(this, function () { + if (!this.twitterLoggined()) + { + RL.twitterConnect(); + } + }, function () { + return !this.twitterLoggined() && !this.twitterActions(); + }); + + this.disconnectTwitter = Utils.createCommand(this, function () { + RL.twitterDisconnect(); + }); + } + + kn.addSettingsViewModel(SettingsSocial, 'SettingsSocial', 'SETTINGS_LABELS/LABEL_SOCIAL_NAME', 'social'); + + module.exports = SettingsSocial; + +}(module)); \ No newline at end of file diff --git a/dev/Settings/SettingsThemes.js b/dev/Settings/SettingsThemes.js new file mode 100644 index 000000000..bd8effd0c --- /dev/null +++ b/dev/Settings/SettingsThemes.js @@ -0,0 +1,136 @@ +/* RainLoop Webmail (c) RainLoop Team | Licensed under CC BY-NC-SA 3.0 */ + +(function (module) { + + 'use strict'; + + var + window = require('../External/window.js'), + $ = require('../External/jquery.js'), + ko = require('../External/ko.js'), + + Enums = require('../Common/Enums.js'), + Utils = require('../Common/Utils.js'), + LinkBuilder = require('../Common/LinkBuilder.js'), + + Remote = require('../Storages/WebMailAjaxRemoteStorage.js') + ; + + /** + * @constructor + */ + function SettingsThemes() + { + var + self = this, + oData = RL.data() + ; + + this.mainTheme = oData.mainTheme; + this.themesObjects = ko.observableArray([]); + + this.themeTrigger = ko.observable(Enums.SaveSettingsStep.Idle).extend({'throttle': 100}); + + this.oLastAjax = null; + this.iTimer = 0; + + RL.data().theme.subscribe(function (sValue) { + + _.each(this.themesObjects(), function (oTheme) { + oTheme.selected(sValue === oTheme.name); + }); + + var + oThemeLink = $('#rlThemeLink'), + oThemeStyle = $('#rlThemeStyle'), + sUrl = oThemeLink.attr('href') + ; + + if (!sUrl) + { + sUrl = oThemeStyle.attr('data-href'); + } + + if (sUrl) + { + sUrl = sUrl.toString().replace(/\/-\/[^\/]+\/\-\//, '/-/' + sValue + '/-/'); + sUrl = sUrl.toString().replace(/\/Css\/[^\/]+\/User\//, '/Css/0/User/'); + + if ('Json/' !== sUrl.substring(sUrl.length - 5, sUrl.length)) + { + sUrl += 'Json/'; + } + + window.clearTimeout(self.iTimer); + self.themeTrigger(Enums.SaveSettingsStep.Animate); + + if (this.oLastAjax && this.oLastAjax.abort) + { + this.oLastAjax.abort(); + } + + this.oLastAjax = $.ajax({ + 'url': sUrl, + 'dataType': 'json' + }).done(function(aData) { + + if (aData && Utils.isArray(aData) && 2 === aData.length) + { + if (oThemeLink && oThemeLink[0] && (!oThemeStyle || !oThemeStyle[0])) + { + oThemeStyle = $(''); + oThemeLink.after(oThemeStyle); + oThemeLink.remove(); + } + + if (oThemeStyle && oThemeStyle[0]) + { + oThemeStyle.attr('data-href', sUrl).attr('data-theme', aData[0]); + if (oThemeStyle && oThemeStyle[0] && oThemeStyle[0].styleSheet && !Utils.isUnd(oThemeStyle[0].styleSheet.cssText)) + { + oThemeStyle[0].styleSheet.cssText = aData[1]; + } + else + { + oThemeStyle.text(aData[1]); + } + } + + self.themeTrigger(Enums.SaveSettingsStep.TrueResult); + } + + }).always(function() { + + self.iTimer = window.setTimeout(function () { + self.themeTrigger(Enums.SaveSettingsStep.Idle); + }, 1000); + + self.oLastAjax = null; + }); + } + + Remote.saveSettings(null, { + 'Theme': sValue + }); + + }, this); + } + + kn.addSettingsViewModel(SettingsThemes, 'SettingsThemes', 'SETTINGS_LABELS/LABEL_THEMES_NAME', 'themes'); + + SettingsThemes.prototype.onBuild = function () + { + var sCurrentTheme = RL.data().theme(); + this.themesObjects(_.map(RL.data().themes(), function (sTheme) { + return { + 'name': sTheme, + 'nameDisplay': Utils.convertThemeName(sTheme), + 'selected': ko.observable(sTheme === sCurrentTheme), + 'themePreviewSrc': LinkBuilder.themePreviewLink(sTheme) + }; + })); + }; + + module.exports = SettingsThemes; + +}(module)); \ No newline at end of file diff --git a/dev/Settings/Social.js b/dev/Settings/Social.js deleted file mode 100644 index 3c4deaaaa..000000000 --- a/dev/Settings/Social.js +++ /dev/null @@ -1,68 +0,0 @@ -/* RainLoop Webmail (c) RainLoop Team | Licensed under CC BY-NC-SA 3.0 */ - -/** - * @constructor - */ -function SettingsSocialScreen() -{ - var oData = RL.data(); - - this.googleEnable = oData.googleEnable; - - this.googleActions = oData.googleActions; - this.googleLoggined = oData.googleLoggined; - this.googleUserName = oData.googleUserName; - - this.facebookEnable = oData.facebookEnable; - - this.facebookActions = oData.facebookActions; - this.facebookLoggined = oData.facebookLoggined; - this.facebookUserName = oData.facebookUserName; - - this.twitterEnable = oData.twitterEnable; - - this.twitterActions = oData.twitterActions; - this.twitterLoggined = oData.twitterLoggined; - this.twitterUserName = oData.twitterUserName; - - this.connectGoogle = Utils.createCommand(this, function () { - if (!this.googleLoggined()) - { - RL.googleConnect(); - } - }, function () { - return !this.googleLoggined() && !this.googleActions(); - }); - - this.disconnectGoogle = Utils.createCommand(this, function () { - RL.googleDisconnect(); - }); - - this.connectFacebook = Utils.createCommand(this, function () { - if (!this.facebookLoggined()) - { - RL.facebookConnect(); - } - }, function () { - return !this.facebookLoggined() && !this.facebookActions(); - }); - - this.disconnectFacebook = Utils.createCommand(this, function () { - RL.facebookDisconnect(); - }); - - this.connectTwitter = Utils.createCommand(this, function () { - if (!this.twitterLoggined()) - { - RL.twitterConnect(); - } - }, function () { - return !this.twitterLoggined() && !this.twitterActions(); - }); - - this.disconnectTwitter = Utils.createCommand(this, function () { - RL.twitterDisconnect(); - }); -} - -Utils.addSettingsViewModel(SettingsSocialScreen, 'SettingsSocial', 'SETTINGS_LABELS/LABEL_SOCIAL_NAME', 'social'); diff --git a/dev/Settings/Themes.js b/dev/Settings/Themes.js deleted file mode 100644 index 975f76ea4..000000000 --- a/dev/Settings/Themes.js +++ /dev/null @@ -1,115 +0,0 @@ -/* RainLoop Webmail (c) RainLoop Team | Licensed under CC BY-NC-SA 3.0 */ - -/** - * @constructor - */ -function SettingsThemes() -{ - var - self = this, - oData = RL.data() - ; - - this.mainTheme = oData.mainTheme; - this.themesObjects = ko.observableArray([]); - - this.themeTrigger = ko.observable(Enums.SaveSettingsStep.Idle).extend({'throttle': 100}); - - this.oLastAjax = null; - this.iTimer = 0; - - RL.data().theme.subscribe(function (sValue) { - - _.each(this.themesObjects(), function (oTheme) { - oTheme.selected(sValue === oTheme.name); - }); - - var - oThemeLink = $('#rlThemeLink'), - oThemeStyle = $('#rlThemeStyle'), - sUrl = oThemeLink.attr('href') - ; - - if (!sUrl) - { - sUrl = oThemeStyle.attr('data-href'); - } - - if (sUrl) - { - sUrl = sUrl.toString().replace(/\/-\/[^\/]+\/\-\//, '/-/' + sValue + '/-/'); - sUrl = sUrl.toString().replace(/\/Css\/[^\/]+\/User\//, '/Css/0/User/'); - - if ('Json/' !== sUrl.substring(sUrl.length - 5, sUrl.length)) - { - sUrl += 'Json/'; - } - - window.clearTimeout(self.iTimer); - self.themeTrigger(Enums.SaveSettingsStep.Animate); - - if (this.oLastAjax && this.oLastAjax.abort) - { - this.oLastAjax.abort(); - } - - this.oLastAjax = $.ajax({ - 'url': sUrl, - 'dataType': 'json' - }).done(function(aData) { - if (aData && Utils.isArray(aData) && 2 === aData.length) - { - if (oThemeLink && oThemeLink[0] && (!oThemeStyle || !oThemeStyle[0])) - { - oThemeStyle = $(''); - oThemeLink.after(oThemeStyle); - oThemeLink.remove(); - } - - if (oThemeStyle && oThemeStyle[0]) - { - oThemeStyle.attr('data-href', sUrl).attr('data-theme', aData[0]); - if (oThemeStyle && oThemeStyle[0] && oThemeStyle[0].styleSheet && !Utils.isUnd(oThemeStyle[0].styleSheet.cssText)) - { - oThemeStyle[0].styleSheet.cssText = aData[1]; - } - else - { - oThemeStyle.text(aData[1]); - } - } - - self.themeTrigger(Enums.SaveSettingsStep.TrueResult); - } - - }).always(function() { - - self.iTimer = window.setTimeout(function () { - self.themeTrigger(Enums.SaveSettingsStep.Idle); - }, 1000); - - self.oLastAjax = null; - }); - } - - RL.remote().saveSettings(null, { - 'Theme': sValue - }); - - }, this); -} - -Utils.addSettingsViewModel(SettingsThemes, 'SettingsThemes', 'SETTINGS_LABELS/LABEL_THEMES_NAME', 'themes'); - -SettingsThemes.prototype.onBuild = function () -{ - var sCurrentTheme = RL.data().theme(); - this.themesObjects(_.map(RL.data().themes(), function (sTheme) { - return { - 'name': sTheme, - 'nameDisplay': Utils.convertThemeName(sTheme), - 'selected': ko.observable(sTheme === sCurrentTheme), - 'themePreviewSrc': RL.link().themePreviewLink(sTheme) - }; - })); -}; diff --git a/dev/Storages/AbstractAjaxRemoteStorage.js b/dev/Storages/AbstractAjaxRemoteStorage.js index e42771189..e325b8edb 100644 --- a/dev/Storages/AbstractAjaxRemoteStorage.js +++ b/dev/Storages/AbstractAjaxRemoteStorage.js @@ -5,13 +5,17 @@ 'use strict'; var - window = require('./External/window.js'), - $ = require('./External/jquery.js'), - Consts = require('./Common/Consts.js'), - Enums = require('./Common/Enums.js'), - Globals = require('./Common/Globals.js'), - Utils = require('./Common/Utils.js'), - Plugins = require('./Common/Plugins.js') + window = require('../External/window.js'), + $ = require('../External/jquery.js'), + + Consts = require('../Common/Consts.js'), + Enums = require('../Common/Enums.js'), + Globals = require('../Common/Globals.js'), + Utils = require('../Common/Utils.js'), + Plugins = require('../Common/Plugins.js'), + LinkBuilder = require('../Common/LinkBuilder.js'), + + RL = require('../RL.js') ; /** @@ -59,7 +63,7 @@ if (Consts.Values.TokenErrorLimit < Globals.iTokenErrorCount) { - RL.loginAndLogoutReload(true); // TODO cjs + RL().loginAndLogoutReload(true); } if (oData.Logout || Consts.Values.AjaxErrorLimit < Globals.iAjaxErrorCount) @@ -69,7 +73,7 @@ window.__rlah_clear(); } - RL.loginAndLogoutReload(true); // TODO cjs + RL().loginAndLogoutReload(true); } } else if (Enums.StorageResultType.Success === sType && oData && oData.Result) @@ -164,7 +168,7 @@ oDefAjax = $.ajax({ 'type': bPost ? 'POST' : 'GET', - 'url': RL.link().ajax(sGetAdd), // TODO cjs + 'url': LinkBuilder.ajax(sGetAdd), 'async': true, 'dataType': 'json', 'data': bPost ? oParameters : {}, diff --git a/dev/Storages/AbstractCacheStorage.js b/dev/Storages/AbstractCacheStorage.js deleted file mode 100644 index 1fd364064..000000000 --- a/dev/Storages/AbstractCacheStorage.js +++ /dev/null @@ -1,48 +0,0 @@ -/* RainLoop Webmail (c) RainLoop Team | Licensed under CC BY-NC-SA 3.0 */ - -(function (module) { - - 'use strict'; - - var - Enums = require('./Common/Enums.js'), - Utils = require('./Common/Utils.js'), - RL = require('./RL.js') - ; - - /** - * @constructor - */ - function AbstractCacheStorage() - { - this.bCapaGravatar = RL().capa(Enums.Capa.Gravatar); - } - - /** - * @type {Object} - */ - AbstractCacheStorage.prototype.oServices = {}; - - /** - * @type {boolean} - */ - AbstractCacheStorage.prototype.bCapaGravatar = false; - - AbstractCacheStorage.prototype.clear = function () - { - this.bCapaGravatar = !!this.bCapaGravatar; // TODO - }; - - /** - * @param {string} sEmail - * @return {string} - */ - AbstractCacheStorage.prototype.getUserPic = function (sEmail, fCallback) - { - sEmail = Utils.trim(sEmail); - fCallback(this.bCapaGravatar && '' !== sEmail ? RL().link().avatarLink(sEmail) : '', sEmail); - }; - - module.exports = AbstractCacheStorage; - -}(module)); \ No newline at end of file diff --git a/dev/Storages/AbstractData.js b/dev/Storages/AbstractData.js index a373dfa76..2c696980d 100644 --- a/dev/Storages/AbstractData.js +++ b/dev/Storages/AbstractData.js @@ -5,11 +5,11 @@ 'use strict'; var - ko = require('./External/ko.js'), - key = require('./External/key.js'), - Enums = require('./Common/Enums.js'), - Globals = require('./Common/Globals.js'), - Utils = require('./Common/Utils.js') + ko = require('../External/ko.js'), + key = require('../External/key.js'), + Enums = require('../Common/Enums.js'), + Globals = require('../Common/Globals.js'), + Utils = require('../Common/Utils.js') ; /** diff --git a/dev/Storages/AdminAjaxRemoteStorage.js b/dev/Storages/AdminAjaxRemoteStorage.js index 094d9ba6f..28ff78859 100644 --- a/dev/Storages/AdminAjaxRemoteStorage.js +++ b/dev/Storages/AdminAjaxRemoteStorage.js @@ -5,8 +5,8 @@ 'use strict'; var - _ = require('./External/underscore.js'), - AbstractAjaxRemoteStorage = require('./Storages/AbstractAjaxRemoteStorage.js') + _ = require('../External/underscore.js'), + AbstractAjaxRemoteStorage = require('./AbstractAjaxRemoteStorage.js') ; /** @@ -270,6 +270,6 @@ this.defaultRequest(fCallback, 'AdminPing'); }; - module.exports = AdminAjaxRemoteStorage; + module.exports = new AdminAjaxRemoteStorage(); }(module)); \ No newline at end of file diff --git a/dev/Storages/AdminCacheStorage.js b/dev/Storages/AdminCacheStorage.js deleted file mode 100644 index c24d74ad3..000000000 --- a/dev/Storages/AdminCacheStorage.js +++ /dev/null @@ -1,25 +0,0 @@ -/* RainLoop Webmail (c) RainLoop Team | Licensed under CC BY-NC-SA 3.0 */ - -(function (module) { - - 'use strict'; - - var - _ = require('./External/underscore.js'), - AbstractCacheStorage = require('./Storages/AbstractCacheStorage.js') - ; - - /** - * @constructor - * @extends AbstractCacheStorage - */ - function AdminCacheStorage() - { - AbstractCacheStorage.call(this); - } - - _.extend(AdminCacheStorage.prototype, AbstractCacheStorage.prototype); - - module.exports = AdminCacheStorage; - -}(module)); \ No newline at end of file diff --git a/dev/Storages/AdminDataStorage.js b/dev/Storages/AdminDataStorage.js index e4b1f4a81..4e94e2c5e 100644 --- a/dev/Storages/AdminDataStorage.js +++ b/dev/Storages/AdminDataStorage.js @@ -5,9 +5,10 @@ 'use strict'; var - _ = require('./External/underscore.js'), - ko = require('./External/ko.js'), - AbstractData = require('./Storages/AbstractData.js') + _ = require('../External/underscore.js'), + ko = require('../External/ko.js'), + + AbstractData = require('./AbstractData.js') ; /** @@ -62,6 +63,6 @@ AbstractData.prototype.populateDataOnStart.call(this); }; - module.exports = AdminDataStorage; + module.exports = new AdminDataStorage(); }(module)); \ No newline at end of file diff --git a/dev/Storages/LocalStorage.js b/dev/Storages/LocalStorage.js index b78fb8899..76e3e18c4 100644 --- a/dev/Storages/LocalStorage.js +++ b/dev/Storages/LocalStorage.js @@ -5,9 +5,9 @@ 'use strict'; var - _ = require('./External/underscore.js'), - CookieDriver = require('./Storages/LocalStorages/CookieDriver.js'), - LocalStorageDriver = require('./Storages/LocalStorages/LocalStorageDriver.js') + _ = require('../External/underscore.js'), + CookieDriver = require('./LocalStorages/CookieDriver.js'), + LocalStorageDriver = require('./LocalStorages/LocalStorageDriver.js') ; /** @@ -49,6 +49,6 @@ return this.oDriver ? this.oDriver.get('p' + iKey) : null; }; - module.exports = LocalStorage; + module.exports = new LocalStorage(); }(module)); \ No newline at end of file diff --git a/dev/Storages/LocalStorages/CookieDriver.js b/dev/Storages/LocalStorages/CookieDriver.js index 5cc4bbf87..c7076328b 100644 --- a/dev/Storages/LocalStorages/CookieDriver.js +++ b/dev/Storages/LocalStorages/CookieDriver.js @@ -5,10 +5,10 @@ 'use strict'; var - $ = require('./External/jquery.js'), - JSON = require('./External/JSON.js'), - Consts = require('./Common/Consts.js'), - Utils = require('./Common/Utils.js') + $ = require('../../External/jquery.js'), + JSON = require('../../External/JSON.js'), + Consts = require('../../Common/Consts.js'), + Utils = require('../../Common/Utils.js') ; /** diff --git a/dev/Storages/LocalStorages/LocalStorageDriver.js b/dev/Storages/LocalStorages/LocalStorageDriver.js index 36864d3ca..f5538c40d 100644 --- a/dev/Storages/LocalStorages/LocalStorageDriver.js +++ b/dev/Storages/LocalStorages/LocalStorageDriver.js @@ -5,10 +5,10 @@ 'use strict'; var - window = require('./External/window.js'), - JSON = require('./External/JSON.js'), - Consts = require('./Common/Consts.js'), - Utils = require('./Common/Utils.js') + window = require('../../External/window.js'), + JSON = require('../../External/JSON.js'), + Consts = require('../../Common/Consts.js'), + Utils = require('../../Common/Utils.js') ; /** diff --git a/dev/Storages/WebMailAjaxRemoteStorage.js b/dev/Storages/WebMailAjaxRemoteStorage.js index 9d356d458..796a4842e 100644 --- a/dev/Storages/WebMailAjaxRemoteStorage.js +++ b/dev/Storages/WebMailAjaxRemoteStorage.js @@ -1,791 +1,807 @@ /* RainLoop Webmail (c) RainLoop Team | Licensed under CC BY-NC-SA 3.0 */ -/** - * @constructor - * @extends AbstractAjaxRemoteStorage - */ -function WebMailAjaxRemoteStorage() -{ - AbstractAjaxRemoteStorage.call(this); +(function (module) { - this.oRequests = {}; -} - -_.extend(WebMailAjaxRemoteStorage.prototype, AbstractAjaxRemoteStorage.prototype); - -/** - * @param {?Function} fCallback - */ -WebMailAjaxRemoteStorage.prototype.folders = function (fCallback) -{ - this.defaultRequest(fCallback, 'Folders', { - 'SentFolder': RL.settingsGet('SentFolder'), - 'DraftFolder': RL.settingsGet('DraftFolder'), - 'SpamFolder': RL.settingsGet('SpamFolder'), - 'TrashFolder': RL.settingsGet('TrashFolder'), - 'ArchiveFolder': RL.settingsGet('ArchiveFolder') - }, null, '', ['Folders']); -}; - -/** - * @param {?Function} fCallback - * @param {string} sEmail - * @param {string} sLogin - * @param {string} sPassword - * @param {boolean} bSignMe - * @param {string=} sLanguage - * @param {string=} sAdditionalCode - * @param {boolean=} bAdditionalCodeSignMe - */ -WebMailAjaxRemoteStorage.prototype.login = function (fCallback, sEmail, sLogin, sPassword, bSignMe, sLanguage, sAdditionalCode, bAdditionalCodeSignMe) -{ - this.defaultRequest(fCallback, 'Login', { - 'Email': sEmail, - 'Login': sLogin, - 'Password': sPassword, - 'Language': sLanguage || '', - 'AdditionalCode': sAdditionalCode || '', - 'AdditionalCodeSignMe': bAdditionalCodeSignMe ? '1' : '0', - 'SignMe': bSignMe ? '1' : '0' - }); -}; - -/** - * @param {?Function} fCallback - */ -WebMailAjaxRemoteStorage.prototype.getTwoFactor = function (fCallback) -{ - this.defaultRequest(fCallback, 'GetTwoFactorInfo'); -}; - -/** - * @param {?Function} fCallback - */ -WebMailAjaxRemoteStorage.prototype.createTwoFactor = function (fCallback) -{ - this.defaultRequest(fCallback, 'CreateTwoFactorSecret'); -}; - -/** - * @param {?Function} fCallback - */ -WebMailAjaxRemoteStorage.prototype.clearTwoFactor = function (fCallback) -{ - this.defaultRequest(fCallback, 'ClearTwoFactorInfo'); -}; - -/** - * @param {?Function} fCallback - */ -WebMailAjaxRemoteStorage.prototype.showTwoFactorSecret = function (fCallback) -{ - this.defaultRequest(fCallback, 'ShowTwoFactorSecret'); -}; - -/** - * @param {?Function} fCallback - * @param {string} sCode - */ -WebMailAjaxRemoteStorage.prototype.testTwoFactor = function (fCallback, sCode) -{ - this.defaultRequest(fCallback, 'TestTwoFactorInfo', { - 'Code': sCode - }); -}; - -/** - * @param {?Function} fCallback - * @param {boolean} bEnable - */ -WebMailAjaxRemoteStorage.prototype.enableTwoFactor = function (fCallback, bEnable) -{ - this.defaultRequest(fCallback, 'EnableTwoFactor', { - 'Enable': bEnable ? '1' : '0' - }); -}; - -/** - * @param {?Function} fCallback - */ -WebMailAjaxRemoteStorage.prototype.clearTwoFactorInfo = function (fCallback) -{ - this.defaultRequest(fCallback, 'ClearTwoFactorInfo'); -}; - -/** - * @param {?Function} fCallback - */ -WebMailAjaxRemoteStorage.prototype.contactsSync = function (fCallback) -{ - this.defaultRequest(fCallback, 'ContactsSync', null, Consts.Defaults.ContactsSyncAjaxTimeout); -}; - -/** - * @param {?Function} fCallback - * @param {boolean} bEnable - * @param {string} sUrl - * @param {string} sUser - * @param {string} sPassword - */ -WebMailAjaxRemoteStorage.prototype.saveContactsSyncData = function (fCallback, bEnable, sUrl, sUser, sPassword) -{ - this.defaultRequest(fCallback, 'SaveContactsSyncData', { - 'Enable': bEnable ? '1' : '0', - 'Url': sUrl, - 'User': sUser, - 'Password': sPassword - }); -}; - -/** - * @param {?Function} fCallback - * @param {string} sEmail - * @param {string} sLogin - * @param {string} sPassword - */ -WebMailAjaxRemoteStorage.prototype.accountAdd = function (fCallback, sEmail, sLogin, sPassword) -{ - this.defaultRequest(fCallback, 'AccountAdd', { - 'Email': sEmail, - 'Login': sLogin, - 'Password': sPassword - }); -}; - -/** - * @param {?Function} fCallback - * @param {string} sEmailToDelete - */ -WebMailAjaxRemoteStorage.prototype.accountDelete = function (fCallback, sEmailToDelete) -{ - this.defaultRequest(fCallback, 'AccountDelete', { - 'EmailToDelete': sEmailToDelete - }); -}; - -/** - * @param {?Function} fCallback - * @param {string} sId - * @param {string} sEmail - * @param {string} sName - * @param {string} sReplyTo - * @param {string} sBcc - */ -WebMailAjaxRemoteStorage.prototype.identityUpdate = function (fCallback, sId, sEmail, sName, sReplyTo, sBcc) -{ - this.defaultRequest(fCallback, 'IdentityUpdate', { - 'Id': sId, - 'Email': sEmail, - 'Name': sName, - 'ReplyTo': sReplyTo, - 'Bcc': sBcc - }); -}; - -/** - * @param {?Function} fCallback - * @param {string} sIdToDelete - */ -WebMailAjaxRemoteStorage.prototype.identityDelete = function (fCallback, sIdToDelete) -{ - this.defaultRequest(fCallback, 'IdentityDelete', { - 'IdToDelete': sIdToDelete - }); -}; - -/** - * @param {?Function} fCallback - */ -WebMailAjaxRemoteStorage.prototype.accountsAndIdentities = function (fCallback) -{ - this.defaultRequest(fCallback, 'AccountsAndIdentities'); -}; - -/** - * @param {?Function} fCallback - * @param {string} sFolderFullNameRaw - * @param {number=} iOffset = 0 - * @param {number=} iLimit = 20 - * @param {string=} sSearch = '' - * @param {boolean=} bSilent = false - */ -WebMailAjaxRemoteStorage.prototype.messageList = function (fCallback, sFolderFullNameRaw, iOffset, iLimit, sSearch, bSilent) -{ - sFolderFullNameRaw = Utils.pString(sFolderFullNameRaw); + 'use strict'; var - oData = RL.data(), - sFolderHash = RL.cache().getFolderHash(sFolderFullNameRaw) + _ = require('../External/underscore.js'), + + Utils = require('../Common/Utils.js'), + + Cache = require('../Storages/WebMailCacheStorage.js'), + + AbstractAjaxRemoteStorage = require('./AbstractAjaxRemoteStorage.js') ; - bSilent = Utils.isUnd(bSilent) ? false : !!bSilent; - iOffset = Utils.isUnd(iOffset) ? 0 : Utils.pInt(iOffset); - iLimit = Utils.isUnd(iOffset) ? 20 : Utils.pInt(iLimit); - sSearch = Utils.pString(sSearch); + /** + * @constructor + * @extends AbstractAjaxRemoteStorage + */ + function WebMailAjaxRemoteStorage() + { + AbstractAjaxRemoteStorage.call(this); - if ('' !== sFolderHash && ('' === sSearch || -1 === sSearch.indexOf('is:'))) - { - this.defaultRequest(fCallback, 'MessageList', {}, - '' === sSearch ? Consts.Defaults.DefaultAjaxTimeout : Consts.Defaults.SearchAjaxTimeout, - 'MessageList/' + Base64.urlsafe_encode([ - sFolderFullNameRaw, - iOffset, - iLimit, - sSearch, - oData.projectHash(), - sFolderHash, - 'INBOX' === sFolderFullNameRaw ? RL.cache().getFolderUidNext(sFolderFullNameRaw) : '', - oData.threading() && oData.useThreads() ? '1' : '0', - oData.threading() && sFolderFullNameRaw === oData.messageListThreadFolder() ? oData.messageListThreadUids().join(',') : '' - ].join(String.fromCharCode(0))), bSilent ? [] : ['MessageList']); + this.oRequests = {}; } - else + + _.extend(WebMailAjaxRemoteStorage.prototype, AbstractAjaxRemoteStorage.prototype); + + /** + * @param {?Function} fCallback + */ + WebMailAjaxRemoteStorage.prototype.folders = function (fCallback) { - this.defaultRequest(fCallback, 'MessageList', { + this.defaultRequest(fCallback, 'Folders', { + 'SentFolder': RL.settingsGet('SentFolder'), + 'DraftFolder': RL.settingsGet('DraftFolder'), + 'SpamFolder': RL.settingsGet('SpamFolder'), + 'TrashFolder': RL.settingsGet('TrashFolder'), + 'ArchiveFolder': RL.settingsGet('ArchiveFolder') + }, null, '', ['Folders']); + }; + + /** + * @param {?Function} fCallback + * @param {string} sEmail + * @param {string} sLogin + * @param {string} sPassword + * @param {boolean} bSignMe + * @param {string=} sLanguage + * @param {string=} sAdditionalCode + * @param {boolean=} bAdditionalCodeSignMe + */ + WebMailAjaxRemoteStorage.prototype.login = function (fCallback, sEmail, sLogin, sPassword, bSignMe, sLanguage, sAdditionalCode, bAdditionalCodeSignMe) + { + this.defaultRequest(fCallback, 'Login', { + 'Email': sEmail, + 'Login': sLogin, + 'Password': sPassword, + 'Language': sLanguage || '', + 'AdditionalCode': sAdditionalCode || '', + 'AdditionalCodeSignMe': bAdditionalCodeSignMe ? '1' : '0', + 'SignMe': bSignMe ? '1' : '0' + }); + }; + + /** + * @param {?Function} fCallback + */ + WebMailAjaxRemoteStorage.prototype.getTwoFactor = function (fCallback) + { + this.defaultRequest(fCallback, 'GetTwoFactorInfo'); + }; + + /** + * @param {?Function} fCallback + */ + WebMailAjaxRemoteStorage.prototype.createTwoFactor = function (fCallback) + { + this.defaultRequest(fCallback, 'CreateTwoFactorSecret'); + }; + + /** + * @param {?Function} fCallback + */ + WebMailAjaxRemoteStorage.prototype.clearTwoFactor = function (fCallback) + { + this.defaultRequest(fCallback, 'ClearTwoFactorInfo'); + }; + + /** + * @param {?Function} fCallback + */ + WebMailAjaxRemoteStorage.prototype.showTwoFactorSecret = function (fCallback) + { + this.defaultRequest(fCallback, 'ShowTwoFactorSecret'); + }; + + /** + * @param {?Function} fCallback + * @param {string} sCode + */ + WebMailAjaxRemoteStorage.prototype.testTwoFactor = function (fCallback, sCode) + { + this.defaultRequest(fCallback, 'TestTwoFactorInfo', { + 'Code': sCode + }); + }; + + /** + * @param {?Function} fCallback + * @param {boolean} bEnable + */ + WebMailAjaxRemoteStorage.prototype.enableTwoFactor = function (fCallback, bEnable) + { + this.defaultRequest(fCallback, 'EnableTwoFactor', { + 'Enable': bEnable ? '1' : '0' + }); + }; + + /** + * @param {?Function} fCallback + */ + WebMailAjaxRemoteStorage.prototype.clearTwoFactorInfo = function (fCallback) + { + this.defaultRequest(fCallback, 'ClearTwoFactorInfo'); + }; + + /** + * @param {?Function} fCallback + */ + WebMailAjaxRemoteStorage.prototype.contactsSync = function (fCallback) + { + this.defaultRequest(fCallback, 'ContactsSync', null, Consts.Defaults.ContactsSyncAjaxTimeout); + }; + + /** + * @param {?Function} fCallback + * @param {boolean} bEnable + * @param {string} sUrl + * @param {string} sUser + * @param {string} sPassword + */ + WebMailAjaxRemoteStorage.prototype.saveContactsSyncData = function (fCallback, bEnable, sUrl, sUser, sPassword) + { + this.defaultRequest(fCallback, 'SaveContactsSyncData', { + 'Enable': bEnable ? '1' : '0', + 'Url': sUrl, + 'User': sUser, + 'Password': sPassword + }); + }; + + /** + * @param {?Function} fCallback + * @param {string} sEmail + * @param {string} sLogin + * @param {string} sPassword + */ + WebMailAjaxRemoteStorage.prototype.accountAdd = function (fCallback, sEmail, sLogin, sPassword) + { + this.defaultRequest(fCallback, 'AccountAdd', { + 'Email': sEmail, + 'Login': sLogin, + 'Password': sPassword + }); + }; + + /** + * @param {?Function} fCallback + * @param {string} sEmailToDelete + */ + WebMailAjaxRemoteStorage.prototype.accountDelete = function (fCallback, sEmailToDelete) + { + this.defaultRequest(fCallback, 'AccountDelete', { + 'EmailToDelete': sEmailToDelete + }); + }; + + /** + * @param {?Function} fCallback + * @param {string} sId + * @param {string} sEmail + * @param {string} sName + * @param {string} sReplyTo + * @param {string} sBcc + */ + WebMailAjaxRemoteStorage.prototype.identityUpdate = function (fCallback, sId, sEmail, sName, sReplyTo, sBcc) + { + this.defaultRequest(fCallback, 'IdentityUpdate', { + 'Id': sId, + 'Email': sEmail, + 'Name': sName, + 'ReplyTo': sReplyTo, + 'Bcc': sBcc + }); + }; + + /** + * @param {?Function} fCallback + * @param {string} sIdToDelete + */ + WebMailAjaxRemoteStorage.prototype.identityDelete = function (fCallback, sIdToDelete) + { + this.defaultRequest(fCallback, 'IdentityDelete', { + 'IdToDelete': sIdToDelete + }); + }; + + /** + * @param {?Function} fCallback + */ + WebMailAjaxRemoteStorage.prototype.accountsAndIdentities = function (fCallback) + { + this.defaultRequest(fCallback, 'AccountsAndIdentities'); + }; + + /** + * @param {?Function} fCallback + * @param {string} sFolderFullNameRaw + * @param {number=} iOffset = 0 + * @param {number=} iLimit = 20 + * @param {string=} sSearch = '' + * @param {boolean=} bSilent = false + */ + WebMailAjaxRemoteStorage.prototype.messageList = function (fCallback, sFolderFullNameRaw, iOffset, iLimit, sSearch, bSilent) + { + sFolderFullNameRaw = Utils.pString(sFolderFullNameRaw); + + var + oData = RL.data(), + sFolderHash = Cache.getFolderHash(sFolderFullNameRaw) + ; + + bSilent = Utils.isUnd(bSilent) ? false : !!bSilent; + iOffset = Utils.isUnd(iOffset) ? 0 : Utils.pInt(iOffset); + iLimit = Utils.isUnd(iOffset) ? 20 : Utils.pInt(iLimit); + sSearch = Utils.pString(sSearch); + + if ('' !== sFolderHash && ('' === sSearch || -1 === sSearch.indexOf('is:'))) + { + this.defaultRequest(fCallback, 'MessageList', {}, + '' === sSearch ? Consts.Defaults.DefaultAjaxTimeout : Consts.Defaults.SearchAjaxTimeout, + 'MessageList/' + Base64.urlsafe_encode([ + sFolderFullNameRaw, + iOffset, + iLimit, + sSearch, + oData.projectHash(), + sFolderHash, + 'INBOX' === sFolderFullNameRaw ? Cache.getFolderUidNext(sFolderFullNameRaw) : '', + oData.threading() && oData.useThreads() ? '1' : '0', + oData.threading() && sFolderFullNameRaw === oData.messageListThreadFolder() ? oData.messageListThreadUids().join(',') : '' + ].join(String.fromCharCode(0))), bSilent ? [] : ['MessageList']); + } + else + { + this.defaultRequest(fCallback, 'MessageList', { + 'Folder': sFolderFullNameRaw, + 'Offset': iOffset, + 'Limit': iLimit, + 'Search': sSearch, + 'UidNext': 'INBOX' === sFolderFullNameRaw ? Cache.getFolderUidNext(sFolderFullNameRaw) : '', + 'UseThreads': RL.data().threading() && RL.data().useThreads() ? '1' : '0', + 'ExpandedThreadUid': oData.threading() && sFolderFullNameRaw === oData.messageListThreadFolder() ? oData.messageListThreadUids().join(',') : '' + }, '' === sSearch ? Consts.Defaults.DefaultAjaxTimeout : Consts.Defaults.SearchAjaxTimeout, '', bSilent ? [] : ['MessageList']); + } + }; + + /** + * @param {?Function} fCallback + * @param {Array} aDownloads + */ + WebMailAjaxRemoteStorage.prototype.messageUploadAttachments = function (fCallback, aDownloads) + { + this.defaultRequest(fCallback, 'MessageUploadAttachments', { + 'Attachments': aDownloads + }, 999000); + }; + + /** + * @param {?Function} fCallback + * @param {string} sFolderFullNameRaw + * @param {number} iUid + * @return {boolean} + */ + WebMailAjaxRemoteStorage.prototype.message = function (fCallback, sFolderFullNameRaw, iUid) + { + sFolderFullNameRaw = Utils.pString(sFolderFullNameRaw); + iUid = Utils.pInt(iUid); + + if (Cache.getFolderFromCacheList(sFolderFullNameRaw) && 0 < iUid) + { + this.defaultRequest(fCallback, 'Message', {}, null, + 'Message/' + Base64.urlsafe_encode([ + sFolderFullNameRaw, + iUid, + RL.data().projectHash(), + RL.data().threading() && RL.data().useThreads() ? '1' : '0' + ].join(String.fromCharCode(0))), ['Message']); + + return true; + } + + return false; + }; + + /** + * @param {?Function} fCallback + * @param {Array} aExternals + */ + WebMailAjaxRemoteStorage.prototype.composeUploadExternals = function (fCallback, aExternals) + { + this.defaultRequest(fCallback, 'ComposeUploadExternals', { + 'Externals': aExternals + }, 999000); + }; + + /** + * @param {?Function} fCallback + * @param {string} sUrl + * @param {string} sAccessToken + */ + WebMailAjaxRemoteStorage.prototype.composeUploadDrive = function (fCallback, sUrl, sAccessToken) + { + this.defaultRequest(fCallback, 'ComposeUploadDrive', { + 'AccessToken': sAccessToken, + 'Url': sUrl + }, 999000); + }; + + /** + * @param {?Function} fCallback + * @param {string} sFolder + * @param {Array=} aList = [] + */ + WebMailAjaxRemoteStorage.prototype.folderInformation = function (fCallback, sFolder, aList) + { + var + bRequest = true, + aUids = [] + ; + + if (Utils.isArray(aList) && 0 < aList.length) + { + bRequest = false; + _.each(aList, function (oMessageListItem) { + if (!Cache.getMessageFlagsFromCache(oMessageListItem.folderFullNameRaw, oMessageListItem.uid)) + { + aUids.push(oMessageListItem.uid); + } + + if (0 < oMessageListItem.threads().length) + { + _.each(oMessageListItem.threads(), function (sUid) { + if (!Cache.getMessageFlagsFromCache(oMessageListItem.folderFullNameRaw, sUid)) + { + aUids.push(sUid); + } + }); + } + }); + + if (0 < aUids.length) + { + bRequest = true; + } + } + + if (bRequest) + { + this.defaultRequest(fCallback, 'FolderInformation', { + 'Folder': sFolder, + 'FlagsUids': Utils.isArray(aUids) ? aUids.join(',') : '', + 'UidNext': 'INBOX' === sFolder ? Cache.getFolderUidNext(sFolder) : '' + }); + } + else if (RL.data().useThreads()) + { + RL.reloadFlagsCurrentMessageListAndMessageFromCache(); + } + }; + + /** + * @param {?Function} fCallback + * @param {Array} aFolders + */ + WebMailAjaxRemoteStorage.prototype.folderInformationMultiply = function (fCallback, aFolders) + { + this.defaultRequest(fCallback, 'FolderInformationMultiply', { + 'Folders': aFolders + }); + }; + + /** + * @param {?Function} fCallback + */ + WebMailAjaxRemoteStorage.prototype.logout = function (fCallback) + { + this.defaultRequest(fCallback, 'Logout'); + }; + + /** + * @param {?Function} fCallback + * @param {string} sFolderFullNameRaw + * @param {Array} aUids + * @param {boolean} bSetFlagged + */ + WebMailAjaxRemoteStorage.prototype.messageSetFlagged = function (fCallback, sFolderFullNameRaw, aUids, bSetFlagged) + { + this.defaultRequest(fCallback, 'MessageSetFlagged', { 'Folder': sFolderFullNameRaw, + 'Uids': aUids.join(','), + 'SetAction': bSetFlagged ? '1' : '0' + }); + }; + + /** + * @param {?Function} fCallback + * @param {string} sFolderFullNameRaw + * @param {Array} aUids + * @param {boolean} bSetSeen + */ + WebMailAjaxRemoteStorage.prototype.messageSetSeen = function (fCallback, sFolderFullNameRaw, aUids, bSetSeen) + { + this.defaultRequest(fCallback, 'MessageSetSeen', { + 'Folder': sFolderFullNameRaw, + 'Uids': aUids.join(','), + 'SetAction': bSetSeen ? '1' : '0' + }); + }; + + /** + * @param {?Function} fCallback + * @param {string} sFolderFullNameRaw + * @param {boolean} bSetSeen + */ + WebMailAjaxRemoteStorage.prototype.messageSetSeenToAll = function (fCallback, sFolderFullNameRaw, bSetSeen) + { + this.defaultRequest(fCallback, 'MessageSetSeenToAll', { + 'Folder': sFolderFullNameRaw, + 'SetAction': bSetSeen ? '1' : '0' + }); + }; + + /** + * @param {?Function} fCallback + * @param {string} sMessageFolder + * @param {string} sMessageUid + * @param {string} sDraftFolder + * @param {string} sFrom + * @param {string} sTo + * @param {string} sCc + * @param {string} sBcc + * @param {string} sSubject + * @param {boolean} bTextIsHtml + * @param {string} sText + * @param {Array} aAttachments + * @param {(Array|null)} aDraftInfo + * @param {string} sInReplyTo + * @param {string} sReferences + */ + WebMailAjaxRemoteStorage.prototype.saveMessage = function (fCallback, sMessageFolder, sMessageUid, sDraftFolder, + sFrom, sTo, sCc, sBcc, sSubject, bTextIsHtml, sText, aAttachments, aDraftInfo, sInReplyTo, sReferences) + { + this.defaultRequest(fCallback, 'SaveMessage', { + 'MessageFolder': sMessageFolder, + 'MessageUid': sMessageUid, + 'DraftFolder': sDraftFolder, + 'From': sFrom, + 'To': sTo, + 'Cc': sCc, + 'Bcc': sBcc, + 'Subject': sSubject, + 'TextIsHtml': bTextIsHtml ? '1' : '0', + 'Text': sText, + 'DraftInfo': aDraftInfo, + 'InReplyTo': sInReplyTo, + 'References': sReferences, + 'Attachments': aAttachments + }, Consts.Defaults.SaveMessageAjaxTimeout); + }; + + + /** + * @param {?Function} fCallback + * @param {string} sMessageFolder + * @param {string} sMessageUid + * @param {string} sReadReceipt + * @param {string} sSubject + * @param {string} sText + */ + WebMailAjaxRemoteStorage.prototype.sendReadReceiptMessage = function (fCallback, sMessageFolder, sMessageUid, sReadReceipt, sSubject, sText) + { + this.defaultRequest(fCallback, 'SendReadReceiptMessage', { + 'MessageFolder': sMessageFolder, + 'MessageUid': sMessageUid, + 'ReadReceipt': sReadReceipt, + 'Subject': sSubject, + 'Text': sText + }); + }; + + /** + * @param {?Function} fCallback + * @param {string} sMessageFolder + * @param {string} sMessageUid + * @param {string} sSentFolder + * @param {string} sFrom + * @param {string} sTo + * @param {string} sCc + * @param {string} sBcc + * @param {string} sSubject + * @param {boolean} bTextIsHtml + * @param {string} sText + * @param {Array} aAttachments + * @param {(Array|null)} aDraftInfo + * @param {string} sInReplyTo + * @param {string} sReferences + * @param {boolean} bRequestReadReceipt + */ + WebMailAjaxRemoteStorage.prototype.sendMessage = function (fCallback, sMessageFolder, sMessageUid, sSentFolder, + sFrom, sTo, sCc, sBcc, sSubject, bTextIsHtml, sText, aAttachments, aDraftInfo, sInReplyTo, sReferences, bRequestReadReceipt) + { + this.defaultRequest(fCallback, 'SendMessage', { + 'MessageFolder': sMessageFolder, + 'MessageUid': sMessageUid, + 'SentFolder': sSentFolder, + 'From': sFrom, + 'To': sTo, + 'Cc': sCc, + 'Bcc': sBcc, + 'Subject': sSubject, + 'TextIsHtml': bTextIsHtml ? '1' : '0', + 'Text': sText, + 'DraftInfo': aDraftInfo, + 'InReplyTo': sInReplyTo, + 'References': sReferences, + 'ReadReceiptRequest': bRequestReadReceipt ? '1' : '0', + 'Attachments': aAttachments + }, Consts.Defaults.SendMessageAjaxTimeout); + }; + + /** + * @param {?Function} fCallback + * @param {Object} oData + */ + WebMailAjaxRemoteStorage.prototype.saveSystemFolders = function (fCallback, oData) + { + this.defaultRequest(fCallback, 'SystemFoldersUpdate', oData); + }; + + /** + * @param {?Function} fCallback + * @param {Object} oData + */ + WebMailAjaxRemoteStorage.prototype.saveSettings = function (fCallback, oData) + { + this.defaultRequest(fCallback, 'SettingsUpdate', oData); + }; + + /** + * @param {?Function} fCallback + * @param {string} sPrevPassword + * @param {string} sNewPassword + */ + WebMailAjaxRemoteStorage.prototype.changePassword = function (fCallback, sPrevPassword, sNewPassword) + { + this.defaultRequest(fCallback, 'ChangePassword', { + 'PrevPassword': sPrevPassword, + 'NewPassword': sNewPassword + }); + }; + + /** + * @param {?Function} fCallback + * @param {string} sNewFolderName + * @param {string} sParentName + */ + WebMailAjaxRemoteStorage.prototype.folderCreate = function (fCallback, sNewFolderName, sParentName) + { + this.defaultRequest(fCallback, 'FolderCreate', { + 'Folder': sNewFolderName, + 'Parent': sParentName + }, null, '', ['Folders']); + }; + + /** + * @param {?Function} fCallback + * @param {string} sFolderFullNameRaw + */ + WebMailAjaxRemoteStorage.prototype.folderDelete = function (fCallback, sFolderFullNameRaw) + { + this.defaultRequest(fCallback, 'FolderDelete', { + 'Folder': sFolderFullNameRaw + }, null, '', ['Folders']); + }; + + /** + * @param {?Function} fCallback + * @param {string} sPrevFolderFullNameRaw + * @param {string} sNewFolderName + */ + WebMailAjaxRemoteStorage.prototype.folderRename = function (fCallback, sPrevFolderFullNameRaw, sNewFolderName) + { + this.defaultRequest(fCallback, 'FolderRename', { + 'Folder': sPrevFolderFullNameRaw, + 'NewFolderName': sNewFolderName + }, null, '', ['Folders']); + }; + + /** + * @param {?Function} fCallback + * @param {string} sFolderFullNameRaw + */ + WebMailAjaxRemoteStorage.prototype.folderClear = function (fCallback, sFolderFullNameRaw) + { + this.defaultRequest(fCallback, 'FolderClear', { + 'Folder': sFolderFullNameRaw + }); + }; + + /** + * @param {?Function} fCallback + * @param {string} sFolderFullNameRaw + * @param {boolean} bSubscribe + */ + WebMailAjaxRemoteStorage.prototype.folderSetSubscribe = function (fCallback, sFolderFullNameRaw, bSubscribe) + { + this.defaultRequest(fCallback, 'FolderSubscribe', { + 'Folder': sFolderFullNameRaw, + 'Subscribe': bSubscribe ? '1' : '0' + }); + }; + + /** + * @param {?Function} fCallback + * @param {string} sFolder + * @param {string} sToFolder + * @param {Array} aUids + * @param {string=} sLearning + */ + WebMailAjaxRemoteStorage.prototype.messagesMove = function (fCallback, sFolder, sToFolder, aUids, sLearning) + { + this.defaultRequest(fCallback, 'MessageMove', { + 'FromFolder': sFolder, + 'ToFolder': sToFolder, + 'Uids': aUids.join(','), + 'Learning': sLearning || '' + }, null, '', ['MessageList']); + }; + + /** + * @param {?Function} fCallback + * @param {string} sFolder + * @param {string} sToFolder + * @param {Array} aUids + */ + WebMailAjaxRemoteStorage.prototype.messagesCopy = function (fCallback, sFolder, sToFolder, aUids) + { + this.defaultRequest(fCallback, 'MessageCopy', { + 'FromFolder': sFolder, + 'ToFolder': sToFolder, + 'Uids': aUids.join(',') + }); + }; + + /** + * @param {?Function} fCallback + * @param {string} sFolder + * @param {Array} aUids + */ + WebMailAjaxRemoteStorage.prototype.messagesDelete = function (fCallback, sFolder, aUids) + { + this.defaultRequest(fCallback, 'MessageDelete', { + 'Folder': sFolder, + 'Uids': aUids.join(',') + }, null, '', ['MessageList']); + }; + + /** + * @param {?Function} fCallback + */ + WebMailAjaxRemoteStorage.prototype.appDelayStart = function (fCallback) + { + this.defaultRequest(fCallback, 'AppDelayStart'); + }; + + /** + * @param {?Function} fCallback + */ + WebMailAjaxRemoteStorage.prototype.quota = function (fCallback) + { + this.defaultRequest(fCallback, 'Quota'); + }; + + /** + * @param {?Function} fCallback + * @param {number} iOffset + * @param {number} iLimit + * @param {string} sSearch + */ + WebMailAjaxRemoteStorage.prototype.contacts = function (fCallback, iOffset, iLimit, sSearch) + { + this.defaultRequest(fCallback, 'Contacts', { 'Offset': iOffset, 'Limit': iLimit, - 'Search': sSearch, - 'UidNext': 'INBOX' === sFolderFullNameRaw ? RL.cache().getFolderUidNext(sFolderFullNameRaw) : '', - 'UseThreads': RL.data().threading() && RL.data().useThreads() ? '1' : '0', - 'ExpandedThreadUid': oData.threading() && sFolderFullNameRaw === oData.messageListThreadFolder() ? oData.messageListThreadUids().join(',') : '' - }, '' === sSearch ? Consts.Defaults.DefaultAjaxTimeout : Consts.Defaults.SearchAjaxTimeout, '', bSilent ? [] : ['MessageList']); - } -}; + 'Search': sSearch + }, null, '', ['Contacts']); + }; -/** - * @param {?Function} fCallback - * @param {Array} aDownloads - */ -WebMailAjaxRemoteStorage.prototype.messageUploadAttachments = function (fCallback, aDownloads) -{ - this.defaultRequest(fCallback, 'MessageUploadAttachments', { - 'Attachments': aDownloads - }, 999000); -}; - -/** - * @param {?Function} fCallback - * @param {string} sFolderFullNameRaw - * @param {number} iUid - * @return {boolean} - */ -WebMailAjaxRemoteStorage.prototype.message = function (fCallback, sFolderFullNameRaw, iUid) -{ - sFolderFullNameRaw = Utils.pString(sFolderFullNameRaw); - iUid = Utils.pInt(iUid); - - if (RL.cache().getFolderFromCacheList(sFolderFullNameRaw) && 0 < iUid) + /** + * @param {?Function} fCallback + */ + WebMailAjaxRemoteStorage.prototype.contactSave = function (fCallback, sRequestUid, sUid, sTags, aProperties) { - this.defaultRequest(fCallback, 'Message', {}, null, - 'Message/' + Base64.urlsafe_encode([ - sFolderFullNameRaw, - iUid, - RL.data().projectHash(), - RL.data().threading() && RL.data().useThreads() ? '1' : '0' - ].join(String.fromCharCode(0))), ['Message']); - - return true; - } - - return false; -}; - -/** - * @param {?Function} fCallback - * @param {Array} aExternals - */ -WebMailAjaxRemoteStorage.prototype.composeUploadExternals = function (fCallback, aExternals) -{ - this.defaultRequest(fCallback, 'ComposeUploadExternals', { - 'Externals': aExternals - }, 999000); -}; - -/** - * @param {?Function} fCallback - * @param {string} sUrl - * @param {string} sAccessToken - */ -WebMailAjaxRemoteStorage.prototype.composeUploadDrive = function (fCallback, sUrl, sAccessToken) -{ - this.defaultRequest(fCallback, 'ComposeUploadDrive', { - 'AccessToken': sAccessToken, - 'Url': sUrl - }, 999000); -}; - -/** - * @param {?Function} fCallback - * @param {string} sFolder - * @param {Array=} aList = [] - */ -WebMailAjaxRemoteStorage.prototype.folderInformation = function (fCallback, sFolder, aList) -{ - var - bRequest = true, - oCache = RL.cache(), - aUids = [] - ; - - if (Utils.isArray(aList) && 0 < aList.length) - { - bRequest = false; - _.each(aList, function (oMessageListItem) { - if (!oCache.getMessageFlagsFromCache(oMessageListItem.folderFullNameRaw, oMessageListItem.uid)) - { - aUids.push(oMessageListItem.uid); - } - - if (0 < oMessageListItem.threads().length) - { - _.each(oMessageListItem.threads(), function (sUid) { - if (!oCache.getMessageFlagsFromCache(oMessageListItem.folderFullNameRaw, sUid)) - { - aUids.push(sUid); - } - }); - } + this.defaultRequest(fCallback, 'ContactSave', { + 'RequestUid': sRequestUid, + 'Uid': Utils.trim(sUid), + 'Tags': Utils.trim(sTags), + 'Properties': aProperties }); + }; - if (0 < aUids.length) - { - bRequest = true; - } - } - - if (bRequest) + /** + * @param {?Function} fCallback + * @param {Array} aUids + */ + WebMailAjaxRemoteStorage.prototype.contactsDelete = function (fCallback, aUids) { - this.defaultRequest(fCallback, 'FolderInformation', { - 'Folder': sFolder, - 'FlagsUids': Utils.isArray(aUids) ? aUids.join(',') : '', - 'UidNext': 'INBOX' === sFolder ? RL.cache().getFolderUidNext(sFolder) : '' + this.defaultRequest(fCallback, 'ContactsDelete', { + 'Uids': aUids.join(',') }); - } - else if (RL.data().useThreads()) + }; + + /** + * @param {?Function} fCallback + * @param {string} sQuery + * @param {number} iPage + */ + WebMailAjaxRemoteStorage.prototype.suggestions = function (fCallback, sQuery, iPage) { - RL.reloadFlagsCurrentMessageListAndMessageFromCache(); - } -}; + this.defaultRequest(fCallback, 'Suggestions', { + 'Query': sQuery, + 'Page': iPage + }, null, '', ['Suggestions']); + }; -/** - * @param {?Function} fCallback - * @param {Array} aFolders - */ -WebMailAjaxRemoteStorage.prototype.folderInformationMultiply = function (fCallback, aFolders) -{ - this.defaultRequest(fCallback, 'FolderInformationMultiply', { - 'Folders': aFolders - }); -}; + /** + * @param {?Function} fCallback + */ + WebMailAjaxRemoteStorage.prototype.facebookUser = function (fCallback) + { + this.defaultRequest(fCallback, 'SocialFacebookUserInformation'); + }; -/** - * @param {?Function} fCallback - */ -WebMailAjaxRemoteStorage.prototype.logout = function (fCallback) -{ - this.defaultRequest(fCallback, 'Logout'); -}; + /** + * @param {?Function} fCallback + */ + WebMailAjaxRemoteStorage.prototype.facebookDisconnect = function (fCallback) + { + this.defaultRequest(fCallback, 'SocialFacebookDisconnect'); + }; -/** - * @param {?Function} fCallback - * @param {string} sFolderFullNameRaw - * @param {Array} aUids - * @param {boolean} bSetFlagged - */ -WebMailAjaxRemoteStorage.prototype.messageSetFlagged = function (fCallback, sFolderFullNameRaw, aUids, bSetFlagged) -{ - this.defaultRequest(fCallback, 'MessageSetFlagged', { - 'Folder': sFolderFullNameRaw, - 'Uids': aUids.join(','), - 'SetAction': bSetFlagged ? '1' : '0' - }); -}; + /** + * @param {?Function} fCallback + */ + WebMailAjaxRemoteStorage.prototype.twitterUser = function (fCallback) + { + this.defaultRequest(fCallback, 'SocialTwitterUserInformation'); + }; -/** - * @param {?Function} fCallback - * @param {string} sFolderFullNameRaw - * @param {Array} aUids - * @param {boolean} bSetSeen - */ -WebMailAjaxRemoteStorage.prototype.messageSetSeen = function (fCallback, sFolderFullNameRaw, aUids, bSetSeen) -{ - this.defaultRequest(fCallback, 'MessageSetSeen', { - 'Folder': sFolderFullNameRaw, - 'Uids': aUids.join(','), - 'SetAction': bSetSeen ? '1' : '0' - }); -}; + /** + * @param {?Function} fCallback + */ + WebMailAjaxRemoteStorage.prototype.twitterDisconnect = function (fCallback) + { + this.defaultRequest(fCallback, 'SocialTwitterDisconnect'); + }; -/** - * @param {?Function} fCallback - * @param {string} sFolderFullNameRaw - * @param {boolean} bSetSeen - */ -WebMailAjaxRemoteStorage.prototype.messageSetSeenToAll = function (fCallback, sFolderFullNameRaw, bSetSeen) -{ - this.defaultRequest(fCallback, 'MessageSetSeenToAll', { - 'Folder': sFolderFullNameRaw, - 'SetAction': bSetSeen ? '1' : '0' - }); -}; + /** + * @param {?Function} fCallback + */ + WebMailAjaxRemoteStorage.prototype.googleUser = function (fCallback) + { + this.defaultRequest(fCallback, 'SocialGoogleUserInformation'); + }; -/** - * @param {?Function} fCallback - * @param {string} sMessageFolder - * @param {string} sMessageUid - * @param {string} sDraftFolder - * @param {string} sFrom - * @param {string} sTo - * @param {string} sCc - * @param {string} sBcc - * @param {string} sSubject - * @param {boolean} bTextIsHtml - * @param {string} sText - * @param {Array} aAttachments - * @param {(Array|null)} aDraftInfo - * @param {string} sInReplyTo - * @param {string} sReferences - */ -WebMailAjaxRemoteStorage.prototype.saveMessage = function (fCallback, sMessageFolder, sMessageUid, sDraftFolder, - sFrom, sTo, sCc, sBcc, sSubject, bTextIsHtml, sText, aAttachments, aDraftInfo, sInReplyTo, sReferences) -{ - this.defaultRequest(fCallback, 'SaveMessage', { - 'MessageFolder': sMessageFolder, - 'MessageUid': sMessageUid, - 'DraftFolder': sDraftFolder, - 'From': sFrom, - 'To': sTo, - 'Cc': sCc, - 'Bcc': sBcc, - 'Subject': sSubject, - 'TextIsHtml': bTextIsHtml ? '1' : '0', - 'Text': sText, - 'DraftInfo': aDraftInfo, - 'InReplyTo': sInReplyTo, - 'References': sReferences, - 'Attachments': aAttachments - }, Consts.Defaults.SaveMessageAjaxTimeout); -}; + /** + * @param {?Function} fCallback + */ + WebMailAjaxRemoteStorage.prototype.googleDisconnect = function (fCallback) + { + this.defaultRequest(fCallback, 'SocialGoogleDisconnect'); + }; + /** + * @param {?Function} fCallback + */ + WebMailAjaxRemoteStorage.prototype.socialUsers = function (fCallback) + { + this.defaultRequest(fCallback, 'SocialUsers'); + }; -/** - * @param {?Function} fCallback - * @param {string} sMessageFolder - * @param {string} sMessageUid - * @param {string} sReadReceipt - * @param {string} sSubject - * @param {string} sText - */ -WebMailAjaxRemoteStorage.prototype.sendReadReceiptMessage = function (fCallback, sMessageFolder, sMessageUid, sReadReceipt, sSubject, sText) -{ - this.defaultRequest(fCallback, 'SendReadReceiptMessage', { - 'MessageFolder': sMessageFolder, - 'MessageUid': sMessageUid, - 'ReadReceipt': sReadReceipt, - 'Subject': sSubject, - 'Text': sText - }); -}; - -/** - * @param {?Function} fCallback - * @param {string} sMessageFolder - * @param {string} sMessageUid - * @param {string} sSentFolder - * @param {string} sFrom - * @param {string} sTo - * @param {string} sCc - * @param {string} sBcc - * @param {string} sSubject - * @param {boolean} bTextIsHtml - * @param {string} sText - * @param {Array} aAttachments - * @param {(Array|null)} aDraftInfo - * @param {string} sInReplyTo - * @param {string} sReferences - * @param {boolean} bRequestReadReceipt - */ -WebMailAjaxRemoteStorage.prototype.sendMessage = function (fCallback, sMessageFolder, sMessageUid, sSentFolder, - sFrom, sTo, sCc, sBcc, sSubject, bTextIsHtml, sText, aAttachments, aDraftInfo, sInReplyTo, sReferences, bRequestReadReceipt) -{ - this.defaultRequest(fCallback, 'SendMessage', { - 'MessageFolder': sMessageFolder, - 'MessageUid': sMessageUid, - 'SentFolder': sSentFolder, - 'From': sFrom, - 'To': sTo, - 'Cc': sCc, - 'Bcc': sBcc, - 'Subject': sSubject, - 'TextIsHtml': bTextIsHtml ? '1' : '0', - 'Text': sText, - 'DraftInfo': aDraftInfo, - 'InReplyTo': sInReplyTo, - 'References': sReferences, - 'ReadReceiptRequest': bRequestReadReceipt ? '1' : '0', - 'Attachments': aAttachments - }, Consts.Defaults.SendMessageAjaxTimeout); -}; - -/** - * @param {?Function} fCallback - * @param {Object} oData - */ -WebMailAjaxRemoteStorage.prototype.saveSystemFolders = function (fCallback, oData) -{ - this.defaultRequest(fCallback, 'SystemFoldersUpdate', oData); -}; - -/** - * @param {?Function} fCallback - * @param {Object} oData - */ -WebMailAjaxRemoteStorage.prototype.saveSettings = function (fCallback, oData) -{ - this.defaultRequest(fCallback, 'SettingsUpdate', oData); -}; - -/** - * @param {?Function} fCallback - * @param {string} sPrevPassword - * @param {string} sNewPassword - */ -WebMailAjaxRemoteStorage.prototype.changePassword = function (fCallback, sPrevPassword, sNewPassword) -{ - this.defaultRequest(fCallback, 'ChangePassword', { - 'PrevPassword': sPrevPassword, - 'NewPassword': sNewPassword - }); -}; - -/** - * @param {?Function} fCallback - * @param {string} sNewFolderName - * @param {string} sParentName - */ -WebMailAjaxRemoteStorage.prototype.folderCreate = function (fCallback, sNewFolderName, sParentName) -{ - this.defaultRequest(fCallback, 'FolderCreate', { - 'Folder': sNewFolderName, - 'Parent': sParentName - }, null, '', ['Folders']); -}; - -/** - * @param {?Function} fCallback - * @param {string} sFolderFullNameRaw - */ -WebMailAjaxRemoteStorage.prototype.folderDelete = function (fCallback, sFolderFullNameRaw) -{ - this.defaultRequest(fCallback, 'FolderDelete', { - 'Folder': sFolderFullNameRaw - }, null, '', ['Folders']); -}; - -/** - * @param {?Function} fCallback - * @param {string} sPrevFolderFullNameRaw - * @param {string} sNewFolderName - */ -WebMailAjaxRemoteStorage.prototype.folderRename = function (fCallback, sPrevFolderFullNameRaw, sNewFolderName) -{ - this.defaultRequest(fCallback, 'FolderRename', { - 'Folder': sPrevFolderFullNameRaw, - 'NewFolderName': sNewFolderName - }, null, '', ['Folders']); -}; - -/** - * @param {?Function} fCallback - * @param {string} sFolderFullNameRaw - */ -WebMailAjaxRemoteStorage.prototype.folderClear = function (fCallback, sFolderFullNameRaw) -{ - this.defaultRequest(fCallback, 'FolderClear', { - 'Folder': sFolderFullNameRaw - }); -}; - -/** - * @param {?Function} fCallback - * @param {string} sFolderFullNameRaw - * @param {boolean} bSubscribe - */ -WebMailAjaxRemoteStorage.prototype.folderSetSubscribe = function (fCallback, sFolderFullNameRaw, bSubscribe) -{ - this.defaultRequest(fCallback, 'FolderSubscribe', { - 'Folder': sFolderFullNameRaw, - 'Subscribe': bSubscribe ? '1' : '0' - }); -}; - -/** - * @param {?Function} fCallback - * @param {string} sFolder - * @param {string} sToFolder - * @param {Array} aUids - * @param {string=} sLearning - */ -WebMailAjaxRemoteStorage.prototype.messagesMove = function (fCallback, sFolder, sToFolder, aUids, sLearning) -{ - this.defaultRequest(fCallback, 'MessageMove', { - 'FromFolder': sFolder, - 'ToFolder': sToFolder, - 'Uids': aUids.join(','), - 'Learning': sLearning || '' - }, null, '', ['MessageList']); -}; - -/** - * @param {?Function} fCallback - * @param {string} sFolder - * @param {string} sToFolder - * @param {Array} aUids - */ -WebMailAjaxRemoteStorage.prototype.messagesCopy = function (fCallback, sFolder, sToFolder, aUids) -{ - this.defaultRequest(fCallback, 'MessageCopy', { - 'FromFolder': sFolder, - 'ToFolder': sToFolder, - 'Uids': aUids.join(',') - }); -}; - -/** - * @param {?Function} fCallback - * @param {string} sFolder - * @param {Array} aUids - */ -WebMailAjaxRemoteStorage.prototype.messagesDelete = function (fCallback, sFolder, aUids) -{ - this.defaultRequest(fCallback, 'MessageDelete', { - 'Folder': sFolder, - 'Uids': aUids.join(',') - }, null, '', ['MessageList']); -}; - -/** - * @param {?Function} fCallback - */ -WebMailAjaxRemoteStorage.prototype.appDelayStart = function (fCallback) -{ - this.defaultRequest(fCallback, 'AppDelayStart'); -}; - -/** - * @param {?Function} fCallback - */ -WebMailAjaxRemoteStorage.prototype.quota = function (fCallback) -{ - this.defaultRequest(fCallback, 'Quota'); -}; - -/** - * @param {?Function} fCallback - * @param {number} iOffset - * @param {number} iLimit - * @param {string} sSearch - */ -WebMailAjaxRemoteStorage.prototype.contacts = function (fCallback, iOffset, iLimit, sSearch) -{ - this.defaultRequest(fCallback, 'Contacts', { - 'Offset': iOffset, - 'Limit': iLimit, - 'Search': sSearch - }, null, '', ['Contacts']); -}; - -/** - * @param {?Function} fCallback - */ -WebMailAjaxRemoteStorage.prototype.contactSave = function (fCallback, sRequestUid, sUid, sTags, aProperties) -{ - this.defaultRequest(fCallback, 'ContactSave', { - 'RequestUid': sRequestUid, - 'Uid': Utils.trim(sUid), - 'Tags': Utils.trim(sTags), - 'Properties': aProperties - }); -}; - -/** - * @param {?Function} fCallback - * @param {Array} aUids - */ -WebMailAjaxRemoteStorage.prototype.contactsDelete = function (fCallback, aUids) -{ - this.defaultRequest(fCallback, 'ContactsDelete', { - 'Uids': aUids.join(',') - }); -}; - -/** - * @param {?Function} fCallback - * @param {string} sQuery - * @param {number} iPage - */ -WebMailAjaxRemoteStorage.prototype.suggestions = function (fCallback, sQuery, iPage) -{ - this.defaultRequest(fCallback, 'Suggestions', { - 'Query': sQuery, - 'Page': iPage - }, null, '', ['Suggestions']); -}; - -/** - * @param {?Function} fCallback - */ -WebMailAjaxRemoteStorage.prototype.facebookUser = function (fCallback) -{ - this.defaultRequest(fCallback, 'SocialFacebookUserInformation'); -}; - -/** - * @param {?Function} fCallback - */ -WebMailAjaxRemoteStorage.prototype.facebookDisconnect = function (fCallback) -{ - this.defaultRequest(fCallback, 'SocialFacebookDisconnect'); -}; - -/** - * @param {?Function} fCallback - */ -WebMailAjaxRemoteStorage.prototype.twitterUser = function (fCallback) -{ - this.defaultRequest(fCallback, 'SocialTwitterUserInformation'); -}; - -/** - * @param {?Function} fCallback - */ -WebMailAjaxRemoteStorage.prototype.twitterDisconnect = function (fCallback) -{ - this.defaultRequest(fCallback, 'SocialTwitterDisconnect'); -}; - -/** - * @param {?Function} fCallback - */ -WebMailAjaxRemoteStorage.prototype.googleUser = function (fCallback) -{ - this.defaultRequest(fCallback, 'SocialGoogleUserInformation'); -}; - -/** - * @param {?Function} fCallback - */ -WebMailAjaxRemoteStorage.prototype.googleDisconnect = function (fCallback) -{ - this.defaultRequest(fCallback, 'SocialGoogleDisconnect'); -}; - -/** - * @param {?Function} fCallback - */ -WebMailAjaxRemoteStorage.prototype.socialUsers = function (fCallback) -{ - this.defaultRequest(fCallback, 'SocialUsers'); -}; + module.exports = new WebMailAjaxRemoteStorage(); +}(module)); \ No newline at end of file diff --git a/dev/Storages/WebMailCacheStorage.js b/dev/Storages/WebMailCacheStorage.js index b6f4b4857..5c541d2d9 100644 --- a/dev/Storages/WebMailCacheStorage.js +++ b/dev/Storages/WebMailCacheStorage.js @@ -1,319 +1,349 @@ /* RainLoop Webmail (c) RainLoop Team | Licensed under CC BY-NC-SA 3.0 */ -/** - * @constructor - * @extends AbstractCacheStorage - */ -function WebMailCacheStorage() -{ - AbstractCacheStorage.call(this); +(function (module) { - this.oFoldersCache = {}; - this.oFoldersNamesCache = {}; - this.oFolderHashCache = {}; - this.oFolderUidNextCache = {}; - this.oMessageListHashCache = {}; - this.oMessageFlagsCache = {}; - this.oNewMessage = {}; - this.oRequestedMessage = {}; -} + 'use strict'; -_.extend(WebMailCacheStorage.prototype, AbstractCacheStorage.prototype); + var + _ = require('../External/underscore.js'), + + Enums = require('../Common/Enums.js'), + Utils = require('../Common/Utils.js'), + LinkBuilder = require('../Common/LinkBuilder.js'), -/** - * @type {Object} - */ -WebMailCacheStorage.prototype.oFoldersCache = {}; + RL = require('../RL.js') + ; -/** - * @type {Object} - */ -WebMailCacheStorage.prototype.oFoldersNamesCache = {}; - -/** - * @type {Object} - */ -WebMailCacheStorage.prototype.oFolderHashCache = {}; - -/** - * @type {Object} - */ -WebMailCacheStorage.prototype.oFolderUidNextCache = {}; - -/** - * @type {Object} - */ -WebMailCacheStorage.prototype.oMessageListHashCache = {}; - -/** - * @type {Object} - */ -WebMailCacheStorage.prototype.oMessageFlagsCache = {}; - -/** - * @type {Object} - */ -WebMailCacheStorage.prototype.oBodies = {}; - -/** - * @type {Object} - */ -WebMailCacheStorage.prototype.oNewMessage = {}; - -/** - * @type {Object} - */ -WebMailCacheStorage.prototype.oRequestedMessage = {}; - -WebMailCacheStorage.prototype.clear = function () -{ - AbstractCacheStorage.prototype.clear.call(this); - - this.oFoldersCache = {}; - this.oFoldersNamesCache = {}; - this.oFolderHashCache = {}; - this.oFolderUidNextCache = {}; - this.oMessageListHashCache = {}; - this.oMessageFlagsCache = {}; - this.oBodies = {}; -}; - -/** - * @param {string} sFolderFullNameRaw - * @param {string} sUid - * @return {string} - */ -WebMailCacheStorage.prototype.getMessageKey = function (sFolderFullNameRaw, sUid) -{ - return sFolderFullNameRaw + '#' + sUid; -}; - -/** - * @param {string} sFolder - * @param {string} sUid - */ -WebMailCacheStorage.prototype.addRequestedMessage = function (sFolder, sUid) -{ - this.oRequestedMessage[this.getMessageKey(sFolder, sUid)] = true; -}; - -/** - * @param {string} sFolder - * @param {string} sUid - * @return {boolean} - */ -WebMailCacheStorage.prototype.hasRequestedMessage = function (sFolder, sUid) -{ - return true === this.oRequestedMessage[this.getMessageKey(sFolder, sUid)]; -}; - -/** - * @param {string} sFolderFullNameRaw - * @param {string} sUid - */ -WebMailCacheStorage.prototype.addNewMessageCache = function (sFolderFullNameRaw, sUid) -{ - this.oNewMessage[this.getMessageKey(sFolderFullNameRaw, sUid)] = true; -}; - -/** - * @param {string} sFolderFullNameRaw - * @param {string} sUid - */ -WebMailCacheStorage.prototype.hasNewMessageAndRemoveFromCache = function (sFolderFullNameRaw, sUid) -{ - if (this.oNewMessage[this.getMessageKey(sFolderFullNameRaw, sUid)]) + /** + * @constructor + */ + function WebMailCacheStorage() { - this.oNewMessage[this.getMessageKey(sFolderFullNameRaw, sUid)] = null; - return true; + this.oFoldersCache = {}; + this.oFoldersNamesCache = {}; + this.oFolderHashCache = {}; + this.oFolderUidNextCache = {}; + this.oMessageListHashCache = {}; + this.oMessageFlagsCache = {}; + this.oNewMessage = {}; + this.oRequestedMessage = {}; + + this.bCapaGravatar = RL().capa(Enums.Capa.Gravatar); } - return false; -}; + /** + * @type {boolean} + */ + WebMailCacheStorage.prototype.bCapaGravatar = false; -WebMailCacheStorage.prototype.clearNewMessageCache = function () -{ - this.oNewMessage = {}; -}; + /** + * @type {Object} + */ + WebMailCacheStorage.prototype.oFoldersCache = {}; -/** - * @param {string} sFolderHash - * @return {string} - */ -WebMailCacheStorage.prototype.getFolderFullNameRaw = function (sFolderHash) -{ - return '' !== sFolderHash && this.oFoldersNamesCache[sFolderHash] ? this.oFoldersNamesCache[sFolderHash] : ''; -}; + /** + * @type {Object} + */ + WebMailCacheStorage.prototype.oFoldersNamesCache = {}; -/** - * @param {string} sFolderHash - * @param {string} sFolderFullNameRaw - */ -WebMailCacheStorage.prototype.setFolderFullNameRaw = function (sFolderHash, sFolderFullNameRaw) -{ - this.oFoldersNamesCache[sFolderHash] = sFolderFullNameRaw; -}; + /** + * @type {Object} + */ + WebMailCacheStorage.prototype.oFolderHashCache = {}; -/** - * @param {string} sFolderFullNameRaw - * @return {string} - */ -WebMailCacheStorage.prototype.getFolderHash = function (sFolderFullNameRaw) -{ - return '' !== sFolderFullNameRaw && this.oFolderHashCache[sFolderFullNameRaw] ? this.oFolderHashCache[sFolderFullNameRaw] : ''; -}; + /** + * @type {Object} + */ + WebMailCacheStorage.prototype.oFolderUidNextCache = {}; -/** - * @param {string} sFolderFullNameRaw - * @param {string} sFolderHash - */ -WebMailCacheStorage.prototype.setFolderHash = function (sFolderFullNameRaw, sFolderHash) -{ - this.oFolderHashCache[sFolderFullNameRaw] = sFolderHash; -}; + /** + * @type {Object} + */ + WebMailCacheStorage.prototype.oMessageListHashCache = {}; -/** - * @param {string} sFolderFullNameRaw - * @return {string} - */ -WebMailCacheStorage.prototype.getFolderUidNext = function (sFolderFullNameRaw) -{ - return '' !== sFolderFullNameRaw && this.oFolderUidNextCache[sFolderFullNameRaw] ? this.oFolderUidNextCache[sFolderFullNameRaw] : ''; -}; + /** + * @type {Object} + */ + WebMailCacheStorage.prototype.oMessageFlagsCache = {}; -/** - * @param {string} sFolderFullNameRaw - * @param {string} sUidNext - */ -WebMailCacheStorage.prototype.setFolderUidNext = function (sFolderFullNameRaw, sUidNext) -{ - this.oFolderUidNextCache[sFolderFullNameRaw] = sUidNext; -}; + /** + * @type {Object} + */ + WebMailCacheStorage.prototype.oBodies = {}; -/** - * @param {string} sFolderFullNameRaw - * @return {?FolderModel} - */ -WebMailCacheStorage.prototype.getFolderFromCacheList = function (sFolderFullNameRaw) -{ - return '' !== sFolderFullNameRaw && this.oFoldersCache[sFolderFullNameRaw] ? this.oFoldersCache[sFolderFullNameRaw] : null; -}; + /** + * @type {Object} + */ + WebMailCacheStorage.prototype.oNewMessage = {}; -/** - * @param {string} sFolderFullNameRaw - * @param {?FolderModel} oFolder - */ -WebMailCacheStorage.prototype.setFolderToCacheList = function (sFolderFullNameRaw, oFolder) -{ - this.oFoldersCache[sFolderFullNameRaw] = oFolder; -}; + /** + * @type {Object} + */ + WebMailCacheStorage.prototype.oRequestedMessage = {}; -/** - * @param {string} sFolderFullNameRaw - */ -WebMailCacheStorage.prototype.removeFolderFromCacheList = function (sFolderFullNameRaw) -{ - this.setFolderToCacheList(sFolderFullNameRaw, null); -}; + WebMailCacheStorage.prototype.clear = function () + { + this.oFoldersCache = {}; + this.oFoldersNamesCache = {}; + this.oFolderHashCache = {}; + this.oFolderUidNextCache = {}; + this.oMessageListHashCache = {}; + this.oMessageFlagsCache = {}; + this.oBodies = {}; + }; -/** - * @param {string} sFolderFullName - * @param {string} sUid - * @return {?Array} - */ -WebMailCacheStorage.prototype.getMessageFlagsFromCache = function (sFolderFullName, sUid) -{ - return this.oMessageFlagsCache[sFolderFullName] && this.oMessageFlagsCache[sFolderFullName][sUid] ? - this.oMessageFlagsCache[sFolderFullName][sUid] : null; -}; -/** - * @param {string} sFolderFullName - * @param {string} sUid - * @param {Array} aFlagsCache - */ -WebMailCacheStorage.prototype.setMessageFlagsToCache = function (sFolderFullName, sUid, aFlagsCache) -{ - if (!this.oMessageFlagsCache[sFolderFullName]) + /** + * @param {string} sEmail + * @param {Function} fCallback + * @return {string} + */ + WebMailCacheStorage.prototype.getUserPic = function (sEmail, fCallback) + { + sEmail = Utils.trim(sEmail); + fCallback(this.bCapaGravatar && '' !== sEmail ? LinkBuilder.avatarLink(sEmail) : '', sEmail); + }; + + /** + * @param {string} sFolderFullNameRaw + * @param {string} sUid + * @return {string} + */ + WebMailCacheStorage.prototype.getMessageKey = function (sFolderFullNameRaw, sUid) + { + return sFolderFullNameRaw + '#' + sUid; + }; + + /** + * @param {string} sFolder + * @param {string} sUid + */ + WebMailCacheStorage.prototype.addRequestedMessage = function (sFolder, sUid) + { + this.oRequestedMessage[this.getMessageKey(sFolder, sUid)] = true; + }; + + /** + * @param {string} sFolder + * @param {string} sUid + * @return {boolean} + */ + WebMailCacheStorage.prototype.hasRequestedMessage = function (sFolder, sUid) + { + return true === this.oRequestedMessage[this.getMessageKey(sFolder, sUid)]; + }; + + /** + * @param {string} sFolderFullNameRaw + * @param {string} sUid + */ + WebMailCacheStorage.prototype.addNewMessageCache = function (sFolderFullNameRaw, sUid) + { + this.oNewMessage[this.getMessageKey(sFolderFullNameRaw, sUid)] = true; + }; + + /** + * @param {string} sFolderFullNameRaw + * @param {string} sUid + */ + WebMailCacheStorage.prototype.hasNewMessageAndRemoveFromCache = function (sFolderFullNameRaw, sUid) + { + if (this.oNewMessage[this.getMessageKey(sFolderFullNameRaw, sUid)]) + { + this.oNewMessage[this.getMessageKey(sFolderFullNameRaw, sUid)] = null; + return true; + } + + return false; + }; + + WebMailCacheStorage.prototype.clearNewMessageCache = function () + { + this.oNewMessage = {}; + }; + + /** + * @param {string} sFolderHash + * @return {string} + */ + WebMailCacheStorage.prototype.getFolderFullNameRaw = function (sFolderHash) + { + return '' !== sFolderHash && this.oFoldersNamesCache[sFolderHash] ? this.oFoldersNamesCache[sFolderHash] : ''; + }; + + /** + * @param {string} sFolderHash + * @param {string} sFolderFullNameRaw + */ + WebMailCacheStorage.prototype.setFolderFullNameRaw = function (sFolderHash, sFolderFullNameRaw) + { + this.oFoldersNamesCache[sFolderHash] = sFolderFullNameRaw; + }; + + /** + * @param {string} sFolderFullNameRaw + * @return {string} + */ + WebMailCacheStorage.prototype.getFolderHash = function (sFolderFullNameRaw) + { + return '' !== sFolderFullNameRaw && this.oFolderHashCache[sFolderFullNameRaw] ? this.oFolderHashCache[sFolderFullNameRaw] : ''; + }; + + /** + * @param {string} sFolderFullNameRaw + * @param {string} sFolderHash + */ + WebMailCacheStorage.prototype.setFolderHash = function (sFolderFullNameRaw, sFolderHash) + { + this.oFolderHashCache[sFolderFullNameRaw] = sFolderHash; + }; + + /** + * @param {string} sFolderFullNameRaw + * @return {string} + */ + WebMailCacheStorage.prototype.getFolderUidNext = function (sFolderFullNameRaw) + { + return '' !== sFolderFullNameRaw && this.oFolderUidNextCache[sFolderFullNameRaw] ? this.oFolderUidNextCache[sFolderFullNameRaw] : ''; + }; + + /** + * @param {string} sFolderFullNameRaw + * @param {string} sUidNext + */ + WebMailCacheStorage.prototype.setFolderUidNext = function (sFolderFullNameRaw, sUidNext) + { + this.oFolderUidNextCache[sFolderFullNameRaw] = sUidNext; + }; + + /** + * @param {string} sFolderFullNameRaw + * @return {?FolderModel} + */ + WebMailCacheStorage.prototype.getFolderFromCacheList = function (sFolderFullNameRaw) + { + return '' !== sFolderFullNameRaw && this.oFoldersCache[sFolderFullNameRaw] ? this.oFoldersCache[sFolderFullNameRaw] : null; + }; + + /** + * @param {string} sFolderFullNameRaw + * @param {?FolderModel} oFolder + */ + WebMailCacheStorage.prototype.setFolderToCacheList = function (sFolderFullNameRaw, oFolder) + { + this.oFoldersCache[sFolderFullNameRaw] = oFolder; + }; + + /** + * @param {string} sFolderFullNameRaw + */ + WebMailCacheStorage.prototype.removeFolderFromCacheList = function (sFolderFullNameRaw) + { + this.setFolderToCacheList(sFolderFullNameRaw, null); + }; + + /** + * @param {string} sFolderFullName + * @param {string} sUid + * @return {?Array} + */ + WebMailCacheStorage.prototype.getMessageFlagsFromCache = function (sFolderFullName, sUid) + { + return this.oMessageFlagsCache[sFolderFullName] && this.oMessageFlagsCache[sFolderFullName][sUid] ? + this.oMessageFlagsCache[sFolderFullName][sUid] : null; + }; + + /** + * @param {string} sFolderFullName + * @param {string} sUid + * @param {Array} aFlagsCache + */ + WebMailCacheStorage.prototype.setMessageFlagsToCache = function (sFolderFullName, sUid, aFlagsCache) + { + if (!this.oMessageFlagsCache[sFolderFullName]) + { + this.oMessageFlagsCache[sFolderFullName] = {}; + } + + this.oMessageFlagsCache[sFolderFullName][sUid] = aFlagsCache; + }; + + /** + * @param {string} sFolderFullName + */ + WebMailCacheStorage.prototype.clearMessageFlagsFromCacheByFolder = function (sFolderFullName) { this.oMessageFlagsCache[sFolderFullName] = {}; - } - - this.oMessageFlagsCache[sFolderFullName][sUid] = aFlagsCache; -}; + }; -/** - * @param {string} sFolderFullName - */ -WebMailCacheStorage.prototype.clearMessageFlagsFromCacheByFolder = function (sFolderFullName) -{ - this.oMessageFlagsCache[sFolderFullName] = {}; -}; - -/** - * @param {(MessageModel|null)} oMessage - */ -WebMailCacheStorage.prototype.initMessageFlagsFromCache = function (oMessage) -{ - if (oMessage) + /** + * @param {(MessageModel|null)} oMessage + */ + WebMailCacheStorage.prototype.initMessageFlagsFromCache = function (oMessage) { - var - self = this, - aFlags = this.getMessageFlagsFromCache(oMessage.folderFullNameRaw, oMessage.uid), - mUnseenSubUid = null, - mFlaggedSubUid = null - ; - - if (aFlags && 0 < aFlags.length) + if (oMessage) { - oMessage.unseen(!!aFlags[0]); - oMessage.flagged(!!aFlags[1]); - oMessage.answered(!!aFlags[2]); - oMessage.forwarded(!!aFlags[3]); - oMessage.isReadReceipt(!!aFlags[4]); - } + var + self = this, + aFlags = this.getMessageFlagsFromCache(oMessage.folderFullNameRaw, oMessage.uid), + mUnseenSubUid = null, + mFlaggedSubUid = null + ; - if (0 < oMessage.threads().length) + if (aFlags && 0 < aFlags.length) + { + oMessage.unseen(!!aFlags[0]); + oMessage.flagged(!!aFlags[1]); + oMessage.answered(!!aFlags[2]); + oMessage.forwarded(!!aFlags[3]); + oMessage.isReadReceipt(!!aFlags[4]); + } + + if (0 < oMessage.threads().length) + { + mUnseenSubUid = _.find(oMessage.threads(), function (iSubUid) { + var aFlags = self.getMessageFlagsFromCache(oMessage.folderFullNameRaw, iSubUid); + return aFlags && 0 < aFlags.length && !!aFlags[0]; + }); + + mFlaggedSubUid = _.find(oMessage.threads(), function (iSubUid) { + var aFlags = self.getMessageFlagsFromCache(oMessage.folderFullNameRaw, iSubUid); + return aFlags && 0 < aFlags.length && !!aFlags[1]; + }); + + oMessage.hasUnseenSubMessage(mUnseenSubUid && 0 < Utils.pInt(mUnseenSubUid)); + oMessage.hasFlaggedSubMessage(mFlaggedSubUid && 0 < Utils.pInt(mFlaggedSubUid)); + } + } + }; + + /** + * @param {(MessageModel|null)} oMessage + */ + WebMailCacheStorage.prototype.storeMessageFlagsToCache = function (oMessage) + { + if (oMessage) { - mUnseenSubUid = _.find(oMessage.threads(), function (iSubUid) { - var aFlags = self.getMessageFlagsFromCache(oMessage.folderFullNameRaw, iSubUid); - return aFlags && 0 < aFlags.length && !!aFlags[0]; - }); - - mFlaggedSubUid = _.find(oMessage.threads(), function (iSubUid) { - var aFlags = self.getMessageFlagsFromCache(oMessage.folderFullNameRaw, iSubUid); - return aFlags && 0 < aFlags.length && !!aFlags[1]; - }); - - oMessage.hasUnseenSubMessage(mUnseenSubUid && 0 < Utils.pInt(mUnseenSubUid)); - oMessage.hasFlaggedSubMessage(mFlaggedSubUid && 0 < Utils.pInt(mFlaggedSubUid)); + this.setMessageFlagsToCache( + oMessage.folderFullNameRaw, + oMessage.uid, + [oMessage.unseen(), oMessage.flagged(), oMessage.answered(), oMessage.forwarded(), oMessage.isReadReceipt()] + ); } - } -}; + }; + /** + * @param {string} sFolder + * @param {string} sUid + * @param {Array} aFlags + */ + WebMailCacheStorage.prototype.storeMessageFlagsToCacheByFolderAndUid = function (sFolder, sUid, aFlags) + { + if (Utils.isArray(aFlags) && 0 < aFlags.length) + { + this.setMessageFlagsToCache(sFolder, sUid, aFlags); + } + }; -/** - * @param {(MessageModel|null)} oMessage - */ -WebMailCacheStorage.prototype.storeMessageFlagsToCache = function (oMessage) -{ - if (oMessage) - { - this.setMessageFlagsToCache( - oMessage.folderFullNameRaw, - oMessage.uid, - [oMessage.unseen(), oMessage.flagged(), oMessage.answered(), oMessage.forwarded(), oMessage.isReadReceipt()] - ); - } -}; -/** - * @param {string} sFolder - * @param {string} sUid - * @param {Array} aFlags - */ -WebMailCacheStorage.prototype.storeMessageFlagsToCacheByFolderAndUid = function (sFolder, sUid, aFlags) -{ - if (Utils.isArray(aFlags) && 0 < aFlags.length) - { - this.setMessageFlagsToCache(sFolder, sUid, aFlags); - } -}; + module.exports = new WebMailCacheStorage(); + +}(module)); \ No newline at end of file diff --git a/dev/Storages/WebMailDataStorage.js b/dev/Storages/WebMailDataStorage.js index a6ed96345..6e0971c5c 100644 --- a/dev/Storages/WebMailDataStorage.js +++ b/dev/Storages/WebMailDataStorage.js @@ -5,19 +5,29 @@ 'use strict'; var - window = require('./External/window.js'), - $ = require('./External/jquery.js'), - _ = require('./External/underscore.js'), - ko = require('./External/ko.js'), - moment = require('./External/moment.js'), - $div = require('./External/$div.js'), - NotificationClass = require('./External/NotificationClass.js'), - Consts = require('./Common/Consts.js'), - Enums = require('./Common/Enums.js'), - Globals = require('./Common/Globals.js'), - Utils = require('./Common/Utils.js'), - kn = require('./Knoin/Knoin.js'), - AbstractData = require('./Storages/AbstractData.js') + window = require('../External/window.js'), + $ = require('../External/jquery.js'), + _ = require('../External/underscore.js'), + ko = require('../External/ko.js'), + moment = require('../External/moment.js'), + $div = require('../External/$div.js'), + NotificationClass = require('../External/NotificationClass.js'), + + Consts = require('../Common/Consts.js'), + Enums = require('../Common/Enums.js'), + Globals = require('../Common/Globals.js'), + Utils = require('../Common/Utils.js'), + LinkBuilder = require('../Common/LinkBuilder.js'), + + Cache = require('../Storages/WebMailCacheStorage.js'), + Remote = require('../Storages/WebMailAjaxRemoteStorage.js'), + + kn = require('../Knoin/Knoin.js'), + + MessageModel = require('../Models/MessageModel.js'), + + LocalStorage = require('./LocalStorage.js'), + AbstractData = require('./AbstractData.js') ; /** @@ -31,7 +41,7 @@ var fRemoveSystemFolderType = function (observable) { return function () { - var oFolder = RL.cache().getFolderFromCacheList(observable()); // TODO cjs + var oFolder = Cache.getFolderFromCacheList(observable()); // TODO cjs if (oFolder) { oFolder.type(Enums.FolderType.User); @@ -40,7 +50,7 @@ }, fSetSystemFolderType = function (iType) { return function (sValue) { - var oFolder = RL.cache().getFolderFromCacheList(sValue); // TODO cjs + var oFolder = Cache.getFolderFromCacheList(sValue); // TODO cjs if (oFolder) { oFolder.type(iType); @@ -219,7 +229,7 @@ this.folderListSystem = ko.computed(function () { return _.compact(_.map(this.folderListSystemNames(), function (sName) { - return RL.cache().getFolderFromCacheList(sName); // TODO cjs + return Cache.getFolderFromCacheList(sName); // TODO cjs })); }, this); @@ -263,7 +273,7 @@ this.mainMessageListSearch = ko.computed({ 'read': this.messageListSearch, 'write': function (sValue) { - kn.setHash(RL.link().mailBox( // TODO cjs + kn.setHash(LinkBuilder.mailBox( // TODO cjs this.currentFolderFullNameHash(), 1, Utils.trim(sValue.toString()) )); }, @@ -513,7 +523,7 @@ this.signatureToAll(!!RL.settingsGet('SignatureToAll')); this.enableTwoFactor(!!RL.settingsGet('EnableTwoFactor')); - this.lastFoldersHash = RL.local().get(Enums.ClientSideKeyName.FoldersLashHash) || ''; + this.lastFoldersHash = LocalStorage.get(Enums.ClientSideKeyName.FoldersLashHash) || ''; this.remoteSuggestions = !!RL.settingsGet('RemoteSuggestions'); @@ -528,7 +538,6 @@ if (Utils.isArray(aNewMessages) && 0 < aNewMessages.length) { var - oCache = RL.cache(),// TODO cjs iIndex = 0, iLen = aNewMessages.length, fNotificationHelper = function (sImageSrc, sTitle, sText) @@ -566,13 +575,13 @@ ; _.each(aNewMessages, function (oItem) { - oCache.addNewMessageCache(sFolder, oItem.Uid); + Cache.addNewMessageCache(sFolder, oItem.Uid); }); if (3 < iLen) { fNotificationHelper( - RL.link().notificationMailIcon(),// TODO cjs + LinkBuilder.notificationMailIcon(), RL.data().accountEmail(), Utils.i18n('MESSAGE_LIST/NEW_MESSAGE_NOTIFICATION', { 'COUNT': iLen @@ -584,15 +593,15 @@ for (; iIndex < iLen; iIndex++) { fNotificationHelper( - RL.link().notificationMailIcon(),// TODO cjs - MessageModel.emailsToLine(MessageModel.initEmailsFromJson(aNewMessages[iIndex].From), false),// TODO cjs + LinkBuilder.notificationMailIcon(), + MessageModel.emailsToLine(MessageModel.initEmailsFromJson(aNewMessages[iIndex].From), false), aNewMessages[iIndex].Subject ); } } } - RL.cache().setFolderUidNext(sFolder, sUidNext);// TODO cjs + Cache.setFolderUidNext(sFolder, sUidNext); } }; @@ -620,14 +629,14 @@ { sFolderFullNameRaw = oFolder.FullNameRaw; - oCacheFolder = RL.cache().getFolderFromCacheList(sFolderFullNameRaw);// TODO cjs + oCacheFolder = Cache.getFolderFromCacheList(sFolderFullNameRaw);// TODO cjs if (!oCacheFolder) { oCacheFolder = FolderModel.newInstanceFromJson(oFolder);// TODO cjs if (oCacheFolder) { - RL.cache().setFolderToCacheList(sFolderFullNameRaw, oCacheFolder);// TODO cjs - RL.cache().setFolderFullNameRaw(oCacheFolder.fullNameHash, sFolderFullNameRaw);// TODO cjs + Cache.setFolderToCacheList(sFolderFullNameRaw, oCacheFolder);// TODO cjs + Cache.setFolderFullNameRaw(oCacheFolder.fullNameHash, sFolderFullNameRaw);// TODO cjs } } @@ -639,7 +648,7 @@ { if (oFolder.Extended.Hash) { - RL.cache().setFolderHash(oCacheFolder.fullNameRaw, oFolder.Extended.Hash);// TODO cjs + Cache.setFolderHash(oCacheFolder.fullNameRaw, oFolder.Extended.Hash);// TODO cjs } if (Utils.isNormal(oFolder.Extended.MessageCount)) @@ -680,7 +689,7 @@ oRLData = RL.data(),// TODO cjs fNormalizeFolder = function (sFolderFullNameRaw) { return ('' === sFolderFullNameRaw || Consts.Values.UnuseOptionValue === sFolderFullNameRaw || - null !== RL.cache().getFolderFromCacheList(sFolderFullNameRaw)) ? sFolderFullNameRaw : '';// TODO cjs + null !== Cache.getFolderFromCacheList(sFolderFullNameRaw)) ? sFolderFullNameRaw : '';// TODO cjs } ; @@ -722,8 +731,7 @@ if (bUpdate) { - // TODO cjs - RL.remote().saveSystemFolders(Utils.emptyFunction, { + Remote.saveSystemFolders(Utils.emptyFunction, { 'SentFolder': oRLData.sentFolder(), 'DraftFolder': oRLData.draftFolder(), 'SpamFolder': oRLData.spamFolder(), @@ -733,8 +741,7 @@ }); } - // TODO cjs - RL.local().set(Enums.ClientSideKeyName.FoldersLashHash, oData.Result.FoldersHash); + LocalStorage.set(Enums.ClientSideKeyName.FoldersLashHash, oData.Result.FoldersHash); } }; @@ -795,7 +802,7 @@ }); _.find(aTimeouts, function (aItem) { - var oFolder = RL.cache().getFolderFromCacheList(aItem[1]);// TODO cjs + var oFolder = Cache.getFolderFromCacheList(aItem[1]);// TODO cjs if (oFolder) { oFolder.interval = iUtc; @@ -827,10 +834,9 @@ var iUnseenCount = 0, oData = RL.data(),// TODO cjs - oCache = RL.cache(),// TODO cjs aMessageList = oData.messageList(), - oFromFolder = RL.cache().getFolderFromCacheList(sFromFolderFullNameRaw), - oToFolder = '' === sToFolderFullNameRaw ? null : oCache.getFolderFromCacheList(sToFolderFullNameRaw || ''), + oFromFolder = Cache.getFolderFromCacheList(sFromFolderFullNameRaw), + oToFolder = '' === sToFolderFullNameRaw ? null : Cache.getFolderFromCacheList(sToFolderFullNameRaw || ''), sCurrentFolderFullNameRaw = oData.currentFolderFullNameRaw(), oCurrentMessage = oData.message(), aMessages = sCurrentFolderFullNameRaw === sFromFolderFullNameRaw ? _.filter(aMessageList, function (oMessage) { @@ -900,12 +906,12 @@ if ('' !== sFromFolderFullNameRaw) { - oCache.setFolderHash(sFromFolderFullNameRaw, ''); + Cache.setFolderHash(sFromFolderFullNameRaw, ''); } if ('' !== sToFolderFullNameRaw) { - oCache.setFolderHash(sToFolderFullNameRaw, ''); + Cache.setFolderHash(sToFolderFullNameRaw, ''); } }; @@ -931,7 +937,7 @@ this.messageError(''); oMessage.initUpdateByMessageJson(oData.Result); - RL.cache().addRequestedMessage(oMessage.folderFullNameRaw, oMessage.uid);// TODO cjs + Cache.addRequestedMessage(oMessage.folderFullNameRaw, oMessage.uid);// TODO cjs if (!bCached) { @@ -1052,7 +1058,7 @@ } } - RL.cache().initMessageFlagsFromCache(oMessage); + Cache.initMessageFlagsFromCache(oMessage); if (oMessage.unseen()) { RL.setMessageSeen(oMessage); @@ -1080,7 +1086,6 @@ { var oRainLoopData = RL.data(), - oCache = RL.cache(), mLastCollapsedThreadUids = null, iIndex = 0, iLen = 0, @@ -1104,14 +1109,14 @@ mLastCollapsedThreadUids = oData.Result.LastCollapsedThreadUids; } - oFolder = RL.cache().getFolderFromCacheList( + oFolder = Cache.getFolderFromCacheList( Utils.isNormal(oData.Result.Folder) ? oData.Result.Folder : ''); if (oFolder && !bCached) { oFolder.interval = iUtc; - RL.cache().setFolderHash(oData.Result.Folder, oData.Result.FolderHash); + Cache.setFolderHash(oData.Result.Folder, oData.Result.FolderHash); if (Utils.isNormal(oData.Result.MessageCount)) { @@ -1133,7 +1138,7 @@ if (bUnreadCountChange && oFolder) { - RL.cache().clearMessageFlagsFromCacheByFolder(oFolder.fullNameRaw); + Cache.clearMessageFlagsFromCacheByFolder(oFolder.fullNameRaw); } for (iIndex = 0, iLen = oData.Result['@Collection'].length; iIndex < iLen; iIndex++) @@ -1149,7 +1154,7 @@ if (oMessage) { - if (oCache.hasNewMessageAndRemoveFromCache(oMessage.folderFullNameRaw, oMessage.uid) && 5 >= iNewCount) + if (Cache.hasNewMessageAndRemoveFromCache(oMessage.folderFullNameRaw, oMessage.uid) && 5 >= iNewCount) { iNewCount++; oMessage.newForAnimation(true); @@ -1159,11 +1164,11 @@ if (bCached) { - RL.cache().initMessageFlagsFromCache(oMessage); + Cache.initMessageFlagsFromCache(oMessage); } else { - RL.cache().storeMessageFlagsToCache(oMessage); + Cache.storeMessageFlagsToCache(oMessage); } oMessage.lastInCollapsedThread(mLastCollapsedThreadUids && -1 < Utils.inArray(Utils.pInt(oMessage.uid), mLastCollapsedThreadUids) ? true : false); @@ -1188,7 +1193,7 @@ oRainLoopData.staticMessageList = aList; } - oCache.clearNewMessageCache(); + Cache.clearNewMessageCache(); if (oFolder && (bCached || bUnreadCountChange || RL.data().useThreads())) { @@ -1282,6 +1287,6 @@ return this.findPrivateKeyByEmail(this.accountEmail(), sPassword); }; - module.exports = WebMailDataStorage; + module.exports = new WebMailDataStorage(); }(module)); diff --git a/dev/ViewModels/AbstractSystemDropDownViewModel.js b/dev/ViewModels/AbstractSystemDropDownViewModel.js index d914f9210..2487374c5 100644 --- a/dev/ViewModels/AbstractSystemDropDownViewModel.js +++ b/dev/ViewModels/AbstractSystemDropDownViewModel.js @@ -1,97 +1,121 @@ /* RainLoop Webmail (c) RainLoop Team | Licensed under CC BY-NC-SA 3.0 */ -/** - * @constructor - * @extends KnoinAbstractViewModel - */ -function AbstractSystemDropDownViewModel() -{ - KnoinAbstractViewModel.call(this, 'Right', 'SystemDropDown'); +(function (module) { - var oData = RL.data(); + 'use strict'; - this.accounts = oData.accounts; - this.accountEmail = oData.accountEmail; - this.accountsLoading = oData.accountsLoading; + var + _ = require('../External/underscore.js'), + ko = require('../External/ko.js'), + window = require('../External/window.js'), + key = require('../External/key.js'), + + Enums = require('../Common/Enums.js'), + Utils = require('../Common/Utils.js'), + LinkBuilder = require('../Common/LinkBuilder.js'), - this.accountMenuDropdownTrigger = ko.observable(false); + Remote = require('../Storages/WebMailAjaxRemoteStorage.js'), - this.capaAdditionalAccounts = RL.capa(Enums.Capa.AdditionalAccounts); + kn = require('../Knoin/Knoin.js'), + KnoinAbstractViewModel = require('../Knoin/KnoinAbstractViewModel.js') + ; - this.loading = ko.computed(function () { - return this.accountsLoading(); - }, this); + /** + * @constructor + * @extends KnoinAbstractViewModel + */ + function AbstractSystemDropDownViewModel() + { + KnoinAbstractViewModel.call(this, 'Right', 'SystemDropDown'); - this.accountClick = _.bind(this.accountClick, this); -} + var oData = RL.data(); -_.extend(AbstractSystemDropDownViewModel.prototype, KnoinAbstractViewModel.prototype); + this.accounts = oData.accounts; + this.accountEmail = oData.accountEmail; + this.accountsLoading = oData.accountsLoading; -AbstractSystemDropDownViewModel.prototype.accountClick = function (oAccount, oEvent) -{ - if (oAccount && oEvent && !Utils.isUnd(oEvent.which) && 1 === oEvent.which) + this.accountMenuDropdownTrigger = ko.observable(false); + + this.capaAdditionalAccounts = RL.capa(Enums.Capa.AdditionalAccounts); + + this.loading = ko.computed(function () { + return this.accountsLoading(); + }, this); + + this.accountClick = _.bind(this.accountClick, this); + } + + _.extend(AbstractSystemDropDownViewModel.prototype, KnoinAbstractViewModel.prototype); + + AbstractSystemDropDownViewModel.prototype.accountClick = function (oAccount, oEvent) + { + if (oAccount && oEvent && !Utils.isUnd(oEvent.which) && 1 === oEvent.which) + { + var self = this; + this.accountsLoading(true); + _.delay(function () { + self.accountsLoading(false); + }, 1000); + } + + return true; + }; + + AbstractSystemDropDownViewModel.prototype.emailTitle = function () + { + return RL.data().accountEmail(); + }; + + AbstractSystemDropDownViewModel.prototype.settingsClick = function () + { + kn.setHash(LinkBuilder.settings()); + }; + + AbstractSystemDropDownViewModel.prototype.settingsHelp = function () + { + kn.showScreenPopup(PopupsKeyboardShortcutsHelpViewModel); + }; + + AbstractSystemDropDownViewModel.prototype.addAccountClick = function () + { + if (this.capaAdditionalAccounts) + { + kn.showScreenPopup(PopupsAddAccountViewModel); + } + }; + + AbstractSystemDropDownViewModel.prototype.logoutClick = function () + { + Remote.logout(function () { + if (window.__rlah_clear) + { + window.__rlah_clear(); + } + + RL.loginAndLogoutReload(true, RL.settingsGet('ParentEmail') && 0 < RL.settingsGet('ParentEmail').length); + }); + }; + + AbstractSystemDropDownViewModel.prototype.onBuild = function () { var self = this; - this.accountsLoading(true); - _.delay(function () { - self.accountsLoading(false); - }, 1000); - } + key('`', [Enums.KeyState.MessageList, Enums.KeyState.MessageView, Enums.KeyState.Settings], function () { + if (self.viewModelVisibility()) + { + self.accountMenuDropdownTrigger(true); + } + }); - return true; -}; + // shortcuts help + key('shift+/', [Enums.KeyState.MessageList, Enums.KeyState.MessageView, Enums.KeyState.Settings], function () { + if (self.viewModelVisibility()) + { + kn.showScreenPopup(PopupsKeyboardShortcutsHelpViewModel); + return false; + } + }); + }; -AbstractSystemDropDownViewModel.prototype.emailTitle = function () -{ - return RL.data().accountEmail(); -}; + module.exports = new AbstractSystemDropDownViewModel(); -AbstractSystemDropDownViewModel.prototype.settingsClick = function () -{ - kn.setHash(RL.link().settings()); -}; - -AbstractSystemDropDownViewModel.prototype.settingsHelp = function () -{ - kn.showScreenPopup(PopupsKeyboardShortcutsHelpViewModel); -}; - -AbstractSystemDropDownViewModel.prototype.addAccountClick = function () -{ - if (this.capaAdditionalAccounts) - { - kn.showScreenPopup(PopupsAddAccountViewModel); - } -}; - -AbstractSystemDropDownViewModel.prototype.logoutClick = function () -{ - RL.remote().logout(function () { - if (window.__rlah_clear) - { - window.__rlah_clear(); - } - - RL.loginAndLogoutReload(true, RL.settingsGet('ParentEmail') && 0 < RL.settingsGet('ParentEmail').length); - }); -}; - -AbstractSystemDropDownViewModel.prototype.onBuild = function () -{ - var self = this; - key('`', [Enums.KeyState.MessageList, Enums.KeyState.MessageView, Enums.KeyState.Settings], function () { - if (self.viewModelVisibility()) - { - self.accountMenuDropdownTrigger(true); - } - }); - - // shortcuts help - key('shift+/', [Enums.KeyState.MessageList, Enums.KeyState.MessageView, Enums.KeyState.Settings], function () { - if (self.viewModelVisibility()) - { - kn.showScreenPopup(PopupsKeyboardShortcutsHelpViewModel); - return false; - } - }); -}; +}(module)); \ No newline at end of file diff --git a/dev/ViewModels/AdminLoginViewModel.js b/dev/ViewModels/AdminLoginViewModel.js index 694c4cd76..5e4109be1 100644 --- a/dev/ViewModels/AdminLoginViewModel.js +++ b/dev/ViewModels/AdminLoginViewModel.js @@ -1,100 +1,121 @@ /* RainLoop Webmail (c) RainLoop Team | Licensed under CC BY-NC-SA 3.0 */ -/** - * @constructor - * @extends KnoinAbstractViewModel - */ -function AdminLoginViewModel() -{ - KnoinAbstractViewModel.call(this, 'Center', 'AdminLogin'); +(function (module) { - this.login = ko.observable(''); - this.password = ko.observable(''); + 'use strict'; - this.loginError = ko.observable(false); - this.passwordError = ko.observable(false); + var + _ = require('../External/underscore.js'), + ko = require('../External/ko.js'), + + Enums = require('../Common/Enums.js'), + Utils = require('../Common/Utils.js'), - this.loginFocus = ko.observable(false); + Remote = require('../Storages/AdminAjaxRemoteStorage.js'), + + kn = require('../Knoin/Knoin.js'), + KnoinAbstractViewModel = require('../Knoin/KnoinAbstractViewModel.js') + ; - this.login.subscribe(function () { - this.loginError(false); - }, this); + /** + * @constructor + * @extends KnoinAbstractViewModel + */ + function AdminLoginViewModel() + { + KnoinAbstractViewModel.call(this, 'Center', 'AdminLogin'); - this.password.subscribe(function () { - this.passwordError(false); - }, this); + this.login = ko.observable(''); + this.password = ko.observable(''); - this.submitRequest = ko.observable(false); - this.submitError = ko.observable(''); + this.loginError = ko.observable(false); + this.passwordError = ko.observable(false); - this.submitCommand = Utils.createCommand(this, function () { + this.loginFocus = ko.observable(false); - Utils.triggerAutocompleteInputChange(); + this.login.subscribe(function () { + this.loginError(false); + }, this); - this.loginError('' === Utils.trim(this.login())); - this.passwordError('' === Utils.trim(this.password())); + this.password.subscribe(function () { + this.passwordError(false); + }, this); - if (this.loginError() || this.passwordError()) - { - return false; - } + this.submitRequest = ko.observable(false); + this.submitError = ko.observable(''); - this.submitRequest(true); + this.submitCommand = Utils.createCommand(this, function () { - RL.remote().adminLogin(_.bind(function (sResult, oData) { + Utils.triggerAutocompleteInputChange(); - if (Enums.StorageResultType.Success === sResult && oData && 'AdminLogin' === oData.Action) + this.loginError('' === Utils.trim(this.login())); + this.passwordError('' === Utils.trim(this.password())); + + if (this.loginError() || this.passwordError()) { - if (oData.Result) + return false; + } + + this.submitRequest(true); + + Remote.adminLogin(_.bind(function (sResult, oData) { + + if (Enums.StorageResultType.Success === sResult && oData && 'AdminLogin' === oData.Action) { - RL.loginAndLogoutReload(); + if (oData.Result) + { + RL.loginAndLogoutReload(); + } + else if (oData.ErrorCode) + { + this.submitRequest(false); + this.submitError(Utils.getNotification(oData.ErrorCode)); + } } - else if (oData.ErrorCode) + else { this.submitRequest(false); - this.submitError(Utils.getNotification(oData.ErrorCode)); + this.submitError(Utils.getNotification(Enums.Notification.UnknownError)); } - } - else - { - this.submitRequest(false); - this.submitError(Utils.getNotification(Enums.Notification.UnknownError)); - } - }, this), this.login(), this.password()); + }, this), this.login(), this.password()); - return true; + return true; - }, function () { - return !this.submitRequest(); - }); + }, function () { + return !this.submitRequest(); + }); - Knoin.constructorEnd(this); -} + kn.constructorEnd(this); + } -Utils.extendAsViewModel('AdminLoginViewModel', AdminLoginViewModel); + kn.extendAsViewModel('AdminLoginViewModel', AdminLoginViewModel); -AdminLoginViewModel.prototype.onShow = function () -{ - kn.routeOff(); + AdminLoginViewModel.prototype.onShow = function () + { + kn.routeOff(); - _.delay(_.bind(function () { - this.loginFocus(true); - }, this), 100); + _.delay(_.bind(function () { + this.loginFocus(true); + }, this), 100); -}; + }; -AdminLoginViewModel.prototype.onHide = function () -{ - this.loginFocus(false); -}; + AdminLoginViewModel.prototype.onHide = function () + { + this.loginFocus(false); + }; -AdminLoginViewModel.prototype.onBuild = function () -{ - Utils.triggerAutocompleteInputChange(true); -}; + AdminLoginViewModel.prototype.onBuild = function () + { + Utils.triggerAutocompleteInputChange(true); + }; -AdminLoginViewModel.prototype.submitForm = function () -{ - this.submitCommand(); -}; + AdminLoginViewModel.prototype.submitForm = function () + { + this.submitCommand(); + }; + + module.exports = new AdminLoginViewModel(); + +}(module)); \ No newline at end of file diff --git a/dev/ViewModels/AdminMenuViewModel.js b/dev/ViewModels/AdminMenuViewModel.js index ce97bcb1c..de73acd39 100644 --- a/dev/ViewModels/AdminMenuViewModel.js +++ b/dev/ViewModels/AdminMenuViewModel.js @@ -1,25 +1,38 @@ /* RainLoop Webmail (c) RainLoop Team | Licensed under CC BY-NC-SA 3.0 */ -/** - * @param {?} oScreen - * - * @constructor - * @extends KnoinAbstractViewModel - */ -function AdminMenuViewModel(oScreen) -{ - KnoinAbstractViewModel.call(this, 'Left', 'AdminMenu'); +(function (module) { - this.leftPanelDisabled = RL.data().leftPanelDisabled; + 'use strict'; - this.menu = oScreen.menu; + var + kn = require('../External/kn.js'), + KnoinAbstractViewModel = require('../Knoin/KnoinAbstractViewModel.js') + ; + + /** + * @param {?} oScreen + * + * @constructor + * @extends KnoinAbstractViewModel + */ + function AdminMenuViewModel(oScreen) + { + KnoinAbstractViewModel.call(this, 'Left', 'AdminMenu'); - Knoin.constructorEnd(this); -} + this.leftPanelDisabled = RL.data().leftPanelDisabled; -Utils.extendAsViewModel('AdminMenuViewModel', AdminMenuViewModel); + this.menu = oScreen.menu; -AdminMenuViewModel.prototype.link = function (sRoute) -{ - return '#/' + sRoute; -}; + kn.constructorEnd(this); + } + + kn.extendAsViewModel('AdminMenuViewModel', AdminMenuViewModel); + + AdminMenuViewModel.prototype.link = function (sRoute) + { + return '#/' + sRoute; + }; + + module.exports = new AdminMenuViewModel(); + +}(module)); diff --git a/dev/ViewModels/AdminPaneViewModel.js b/dev/ViewModels/AdminPaneViewModel.js index 86b749ee3..374165697 100644 --- a/dev/ViewModels/AdminPaneViewModel.js +++ b/dev/ViewModels/AdminPaneViewModel.js @@ -1,26 +1,43 @@ /* RainLoop Webmail (c) RainLoop Team | Licensed under CC BY-NC-SA 3.0 */ -/** - * @constructor - * @extends KnoinAbstractViewModel - */ -function AdminPaneViewModel() -{ - KnoinAbstractViewModel.call(this, 'Right', 'AdminPane'); +(function (module) { - this.adminDomain = ko.observable(RL.settingsGet('AdminDomain')); - this.version = ko.observable(RL.settingsGet('Version')); + 'use strict'; - this.adminManLoadingVisibility = RL.data().adminManLoadingVisibility; + var + ko = require('../External/ko.js'), - Knoin.constructorEnd(this); -} + Remote = require('../Storages/AdminAjaxRemoteStorage.js'), + + kn = require('../Knoin/Knoin.js'), + KnoinAbstractViewModel = require('../Knoin/KnoinAbstractViewModel.js') + ; -Utils.extendAsViewModel('AdminPaneViewModel', AdminPaneViewModel); + /** + * @constructor + * @extends KnoinAbstractViewModel + */ + function AdminPaneViewModel() + { + KnoinAbstractViewModel.call(this, 'Right', 'AdminPane'); -AdminPaneViewModel.prototype.logoutClick = function () -{ - RL.remote().adminLogout(function () { - RL.loginAndLogoutReload(); - }); -}; \ No newline at end of file + this.adminDomain = ko.observable(RL.settingsGet('AdminDomain')); + this.version = ko.observable(RL.settingsGet('Version')); + + this.adminManLoadingVisibility = RL.data().adminManLoadingVisibility; + + kn.constructorEnd(this); + } + + kn.extendAsViewModel('AdminPaneViewModel', AdminPaneViewModel); + + AdminPaneViewModel.prototype.logoutClick = function () + { + Remote.adminLogout(function () { + RL.loginAndLogoutReload(); + }); + }; + + module.exports = new AdminPaneViewModel(); + +}(module)); \ No newline at end of file diff --git a/dev/ViewModels/LoginViewModel.js b/dev/ViewModels/LoginViewModel.js index c7f2828b0..22c30b669 100644 --- a/dev/ViewModels/LoginViewModel.js +++ b/dev/ViewModels/LoginViewModel.js @@ -1,344 +1,366 @@ /* RainLoop Webmail (c) RainLoop Team | Licensed under CC BY-NC-SA 3.0 */ -/** - * @constructor - * @extends KnoinAbstractViewModel - */ -function LoginViewModel() -{ - KnoinAbstractViewModel.call(this, 'Center', 'Login'); +(function (module) { - var oData = RL.data(); + 'use strict'; - this.email = ko.observable(''); - this.password = ko.observable(''); - this.signMe = ko.observable(false); + var + window = require('../External/window.js'), + $ = require('../External/jquery.js'), + _ = require('../External/underscore.js'), + ko = require('../External/ko.js'), + + Utils = require('../Common/Utils.js'), + Enums = require('../Common/Enums.js'), + LinkBuilder = require('../Common/LinkBuilder.js'), - this.additionalCode = ko.observable(''); - this.additionalCode.error = ko.observable(false); - this.additionalCode.focused = ko.observable(false); - this.additionalCode.visibility = ko.observable(false); - this.additionalCodeSignMe = ko.observable(false); + Remote = require('../Storages/WebMailAjaxRemoteStorage.js'), - this.logoImg = Utils.trim(RL.settingsGet('LoginLogo')); - this.loginDescription = Utils.trim(RL.settingsGet('LoginDescription')); - this.logoCss = Utils.trim(RL.settingsGet('LoginCss')); + kn = require('../Knoin/Knoin.js'), + KnoinAbstractViewModel = require('../Knoin/KnoinAbstractViewModel.js') + ; - this.emailError = ko.observable(false); - this.passwordError = ko.observable(false); + /** + * @constructor + * @extends KnoinAbstractViewModel + */ + function LoginViewModel() + { + KnoinAbstractViewModel.call(this, 'Center', 'Login'); - this.emailFocus = ko.observable(false); - this.submitFocus = ko.observable(false); + var oData = RL.data(); - this.email.subscribe(function () { - this.emailError(false); - this.additionalCode(''); - this.additionalCode.visibility(false); - }, this); + this.email = ko.observable(''); + this.password = ko.observable(''); + this.signMe = ko.observable(false); - this.password.subscribe(function () { - this.passwordError(false); - }, this); + this.additionalCode = ko.observable(''); + this.additionalCode.error = ko.observable(false); + this.additionalCode.focused = ko.observable(false); + this.additionalCode.visibility = ko.observable(false); + this.additionalCodeSignMe = ko.observable(false); - this.additionalCode.subscribe(function () { - this.additionalCode.error(false); - }, this); + this.logoImg = Utils.trim(RL.settingsGet('LoginLogo')); + this.loginDescription = Utils.trim(RL.settingsGet('LoginDescription')); + this.logoCss = Utils.trim(RL.settingsGet('LoginCss')); - this.additionalCode.visibility.subscribe(function () { - this.additionalCode.error(false); - }, this); + this.emailError = ko.observable(false); + this.passwordError = ko.observable(false); - this.submitRequest = ko.observable(false); - this.submitError = ko.observable(''); + this.emailFocus = ko.observable(false); + this.submitFocus = ko.observable(false); - this.allowLanguagesOnLogin = oData.allowLanguagesOnLogin; + this.email.subscribe(function () { + this.emailError(false); + this.additionalCode(''); + this.additionalCode.visibility(false); + }, this); - this.langRequest = ko.observable(false); - this.mainLanguage = oData.mainLanguage; - this.bSendLanguage = false; + this.password.subscribe(function () { + this.passwordError(false); + }, this); - this.mainLanguageFullName = ko.computed(function () { - return Utils.convertLangName(this.mainLanguage()); - }, this); + this.additionalCode.subscribe(function () { + this.additionalCode.error(false); + }, this); - this.signMeType = ko.observable(Enums.LoginSignMeType.Unused); + this.additionalCode.visibility.subscribe(function () { + this.additionalCode.error(false); + }, this); - this.signMeType.subscribe(function (iValue) { - this.signMe(Enums.LoginSignMeType.DefaultOn === iValue); - }, this); + this.submitRequest = ko.observable(false); + this.submitError = ko.observable(''); - this.signMeVisibility = ko.computed(function () { - return Enums.LoginSignMeType.Unused !== this.signMeType(); - }, this); + this.allowLanguagesOnLogin = oData.allowLanguagesOnLogin; - this.submitCommand = Utils.createCommand(this, function () { + this.langRequest = ko.observable(false); + this.mainLanguage = oData.mainLanguage; + this.bSendLanguage = false; - Utils.triggerAutocompleteInputChange(); + this.mainLanguageFullName = ko.computed(function () { + return Utils.convertLangName(this.mainLanguage()); + }, this); - this.emailError('' === Utils.trim(this.email())); - this.passwordError('' === Utils.trim(this.password())); + this.signMeType = ko.observable(Enums.LoginSignMeType.Unused); - if (this.additionalCode.visibility()) - { - this.additionalCode.error('' === Utils.trim(this.additionalCode())); - } + this.signMeType.subscribe(function (iValue) { + this.signMe(Enums.LoginSignMeType.DefaultOn === iValue); + }, this); - if (this.emailError() || this.passwordError() || this.additionalCode.error()) - { - return false; - } + this.signMeVisibility = ko.computed(function () { + return Enums.LoginSignMeType.Unused !== this.signMeType(); + }, this); - this.submitRequest(true); + this.submitCommand = Utils.createCommand(this, function () { - var - sPassword = this.password(), + Utils.triggerAutocompleteInputChange(); - fLoginRequest = _.bind(function (sPassword) { + this.emailError('' === Utils.trim(this.email())); + this.passwordError('' === Utils.trim(this.password())); - RL.remote().login(_.bind(function (sResult, oData) { + if (this.additionalCode.visibility()) + { + this.additionalCode.error('' === Utils.trim(this.additionalCode())); + } - if (Enums.StorageResultType.Success === sResult && oData && 'Login' === oData.Action) - { - if (oData.Result) + if (this.emailError() || this.passwordError() || this.additionalCode.error()) + { + return false; + } + + this.submitRequest(true); + + var + sPassword = this.password(), + + fLoginRequest = _.bind(function (sPassword) { + + Remote.login(_.bind(function (sResult, oData) { + + if (Enums.StorageResultType.Success === sResult && oData && 'Login' === oData.Action) { - if (oData.TwoFactorAuth) + if (oData.Result) { - this.additionalCode(''); - this.additionalCode.visibility(true); - this.additionalCode.focused(true); + if (oData.TwoFactorAuth) + { + this.additionalCode(''); + this.additionalCode.visibility(true); + this.additionalCode.focused(true); + this.submitRequest(false); + } + else + { + RL.loginAndLogoutReload(); + } + } + else if (oData.ErrorCode) + { this.submitRequest(false); + this.submitError(Utils.getNotification(oData.ErrorCode)); + + if ('' === this.submitError()) + { + this.submitError(Utils.getNotification(Enums.Notification.UnknownError)); + } } else { - RL.loginAndLogoutReload(); - } - } - else if (oData.ErrorCode) - { - this.submitRequest(false); - this.submitError(Utils.getNotification(oData.ErrorCode)); - - if ('' === this.submitError()) - { - this.submitError(Utils.getNotification(Enums.Notification.UnknownError)); + this.submitRequest(false); } } else { this.submitRequest(false); + this.submitError(Utils.getNotification(Enums.Notification.UnknownError)); + } + + }, this), this.email(), '', sPassword, !!this.signMe(), + this.bSendLanguage ? this.mainLanguage() : '', + this.additionalCode.visibility() ? this.additionalCode() : '', + this.additionalCode.visibility() ? !!this.additionalCodeSignMe() : false + ); + + }, this) + ; + + if (!!RL.settingsGet('UseRsaEncryption') && Utils.rsaEncode.supported) + { + Remote.getPublicKey(_.bind(function (sResult, oData) { + + var bRequest = false; + if (Enums.StorageResultType.Success === sResult && oData && oData.Result && + Utils.isArray(oData.Result) && oData.Result[0] && oData.Result[1] && oData.Result[2]) + { + var sEncryptedPassword = Utils.rsaEncode(sPassword, oData.Result[0], oData.Result[1], oData.Result[2]); + if (sEncryptedPassword) + { + fLoginRequest(sEncryptedPassword); + bRequest = true; } } - else + + if (!bRequest) { this.submitRequest(false); this.submitError(Utils.getNotification(Enums.Notification.UnknownError)); } - }, this), this.email(), '', sPassword, !!this.signMe(), - this.bSendLanguage ? this.mainLanguage() : '', - this.additionalCode.visibility() ? this.additionalCode() : '', - this.additionalCode.visibility() ? !!this.additionalCodeSignMe() : false - ); - - }, this) - ; - - if (!!RL.settingsGet('UseRsaEncryption') && Utils.rsaEncode.supported) - { - RL.remote().getPublicKey(_.bind(function (sResult, oData) { - - var bRequest = false; - if (Enums.StorageResultType.Success === sResult && oData && oData.Result && - Utils.isArray(oData.Result) && oData.Result[0] && oData.Result[1] && oData.Result[2]) - { - var sEncryptedPassword = Utils.rsaEncode(sPassword, oData.Result[0], oData.Result[1], oData.Result[2]); - if (sEncryptedPassword) - { - fLoginRequest(sEncryptedPassword); - bRequest = true; - } - } - - if (!bRequest) - { - this.submitRequest(false); - this.submitError(Utils.getNotification(Enums.Notification.UnknownError)); - } - - }, this)); - } - else - { - fLoginRequest(sPassword); - } - - return true; - - }, function () { - return !this.submitRequest(); - }); - - this.facebookLoginEnabled = ko.observable(false); - - this.facebookCommand = Utils.createCommand(this, function () { - - window.open(RL.link().socialFacebook(), 'Facebook', 'left=200,top=100,width=650,height=335,menubar=no,status=no,resizable=yes,scrollbars=yes'); - return true; - - }, function () { - return !this.submitRequest() && this.facebookLoginEnabled(); - }); - - this.googleLoginEnabled = ko.observable(false); - - this.googleCommand = Utils.createCommand(this, function () { - - window.open(RL.link().socialGoogle(), 'Google', 'left=200,top=100,width=650,height=335,menubar=no,status=no,resizable=yes,scrollbars=yes'); - return true; - - }, function () { - return !this.submitRequest() && this.googleLoginEnabled(); - }); - - this.twitterLoginEnabled = ko.observable(false); - - this.twitterCommand = Utils.createCommand(this, function () { - - window.open(RL.link().socialTwitter(), 'Twitter', 'left=200,top=100,width=650,height=335,menubar=no,status=no,resizable=yes,scrollbars=yes'); - return true; - - }, function () { - return !this.submitRequest() && this.twitterLoginEnabled(); - }); - - this.socialLoginEnabled = ko.computed(function () { - - var - bF = this.facebookLoginEnabled(), - bG = this.googleLoginEnabled(), - bT = this.twitterLoginEnabled() - ; - - return bF || bG || bT; - }, this); - - Knoin.constructorEnd(this); -} - -Utils.extendAsViewModel('LoginViewModel', LoginViewModel); - -LoginViewModel.prototype.onShow = function () -{ - kn.routeOff(); - - _.delay(_.bind(function () { - if ('' !== this.email() && '' !== this.password()) - { - this.submitFocus(true); - } - else - { - this.emailFocus(true); - } - - if (RL.settingsGet('UserLanguage')) - { - $.cookie('rllang', RL.data().language(), {'expires': 30}); - } - - }, this), 100); -}; - -LoginViewModel.prototype.onHide = function () -{ - this.submitFocus(false); - this.emailFocus(false); -}; - -LoginViewModel.prototype.onBuild = function () -{ - var - self = this, - sJsHash = RL.settingsGet('JsHash'), - fSocial = function (iErrorCode) { - iErrorCode = Utils.pInt(iErrorCode); - if (0 === iErrorCode) - { - self.submitRequest(true); - RL.loginAndLogoutReload(); + }, this)); } else { - self.submitError(Utils.getNotification(iErrorCode)); + fLoginRequest(sPassword); } - } - ; - this.facebookLoginEnabled(!!RL.settingsGet('AllowFacebookSocial')); - this.twitterLoginEnabled(!!RL.settingsGet('AllowTwitterSocial')); - this.googleLoginEnabled(!!RL.settingsGet('AllowGoogleSocial')); + return true; - switch ((RL.settingsGet('SignMe') || 'unused').toLowerCase()) - { - case Enums.LoginSignMeTypeAsString.DefaultOff: - this.signMeType(Enums.LoginSignMeType.DefaultOff); - break; - case Enums.LoginSignMeTypeAsString.DefaultOn: - this.signMeType(Enums.LoginSignMeType.DefaultOn); - break; - default: - case Enums.LoginSignMeTypeAsString.Unused: - this.signMeType(Enums.LoginSignMeType.Unused); - break; - } - - this.email(RL.data().devEmail); - this.password(RL.data().devPassword); - - if (this.googleLoginEnabled()) - { - window['rl_' + sJsHash + '_google_login_service'] = fSocial; - } - - if (this.facebookLoginEnabled()) - { - window['rl_' + sJsHash + '_facebook_login_service'] = fSocial; - } - - if (this.twitterLoginEnabled()) - { - window['rl_' + sJsHash + '_twitter_login_service'] = fSocial; - } - - _.delay(function () { - RL.data().language.subscribe(function (sValue) { - self.langRequest(true); - $.ajax({ - 'url': RL.link().langLink(sValue), - 'dataType': 'script', - 'cache': true - }).done(function() { - self.bSendLanguage = true; - Utils.i18nReload(); - $.cookie('rllang', RL.data().language(), {'expires': 30}); - }).always(function() { - self.langRequest(false); - }); + }, function () { + return !this.submitRequest(); }); - }, 50); - Utils.triggerAutocompleteInputChange(true); + this.facebookLoginEnabled = ko.observable(false); -}; + this.facebookCommand = Utils.createCommand(this, function () { -LoginViewModel.prototype.submitForm = function () -{ - this.submitCommand(); -}; + window.open(LinkBuilder.socialFacebook(), 'Facebook', 'left=200,top=100,width=650,height=335,menubar=no,status=no,resizable=yes,scrollbars=yes'); + return true; -LoginViewModel.prototype.selectLanguage = function () -{ - kn.showScreenPopup(PopupsLanguagesViewModel); -}; + }, function () { + return !this.submitRequest() && this.facebookLoginEnabled(); + }); + this.googleLoginEnabled = ko.observable(false); + + this.googleCommand = Utils.createCommand(this, function () { + + window.open(LinkBuilder.socialGoogle(), 'Google', 'left=200,top=100,width=650,height=335,menubar=no,status=no,resizable=yes,scrollbars=yes'); + return true; + + }, function () { + return !this.submitRequest() && this.googleLoginEnabled(); + }); + + this.twitterLoginEnabled = ko.observable(false); + + this.twitterCommand = Utils.createCommand(this, function () { + + window.open(LinkBuilder.socialTwitter(), 'Twitter', 'left=200,top=100,width=650,height=335,menubar=no,status=no,resizable=yes,scrollbars=yes'); + return true; + + }, function () { + return !this.submitRequest() && this.twitterLoginEnabled(); + }); + + this.socialLoginEnabled = ko.computed(function () { + + var + bF = this.facebookLoginEnabled(), + bG = this.googleLoginEnabled(), + bT = this.twitterLoginEnabled() + ; + + return bF || bG || bT; + }, this); + + kn.constructorEnd(this); + } + + kn.extendAsViewModel('LoginViewModel', LoginViewModel); + + LoginViewModel.prototype.onShow = function () + { + kn.routeOff(); + + _.delay(_.bind(function () { + if ('' !== this.email() && '' !== this.password()) + { + this.submitFocus(true); + } + else + { + this.emailFocus(true); + } + + if (RL.settingsGet('UserLanguage')) + { + $.cookie('rllang', RL.data().language(), {'expires': 30}); + } + + }, this), 100); + }; + + LoginViewModel.prototype.onHide = function () + { + this.submitFocus(false); + this.emailFocus(false); + }; + + LoginViewModel.prototype.onBuild = function () + { + var + self = this, + sJsHash = RL.settingsGet('JsHash'), + fSocial = function (iErrorCode) { + iErrorCode = Utils.pInt(iErrorCode); + if (0 === iErrorCode) + { + self.submitRequest(true); + RL.loginAndLogoutReload(); + } + else + { + self.submitError(Utils.getNotification(iErrorCode)); + } + } + ; + + this.facebookLoginEnabled(!!RL.settingsGet('AllowFacebookSocial')); + this.twitterLoginEnabled(!!RL.settingsGet('AllowTwitterSocial')); + this.googleLoginEnabled(!!RL.settingsGet('AllowGoogleSocial')); + + switch ((RL.settingsGet('SignMe') || 'unused').toLowerCase()) + { + case Enums.LoginSignMeTypeAsString.DefaultOff: + this.signMeType(Enums.LoginSignMeType.DefaultOff); + break; + case Enums.LoginSignMeTypeAsString.DefaultOn: + this.signMeType(Enums.LoginSignMeType.DefaultOn); + break; + default: + case Enums.LoginSignMeTypeAsString.Unused: + this.signMeType(Enums.LoginSignMeType.Unused); + break; + } + + this.email(RL.data().devEmail); + this.password(RL.data().devPassword); + + if (this.googleLoginEnabled()) + { + window['rl_' + sJsHash + '_google_login_service'] = fSocial; + } + + if (this.facebookLoginEnabled()) + { + window['rl_' + sJsHash + '_facebook_login_service'] = fSocial; + } + + if (this.twitterLoginEnabled()) + { + window['rl_' + sJsHash + '_twitter_login_service'] = fSocial; + } + + _.delay(function () { + RL.data().language.subscribe(function (sValue) { + self.langRequest(true); + $.ajax({ + 'url': LinkBuilder.langLink(sValue), + 'dataType': 'script', + 'cache': true + }).done(function() { + self.bSendLanguage = true; + Utils.i18nReload(); + $.cookie('rllang', RL.data().language(), {'expires': 30}); + }).always(function() { + self.langRequest(false); + }); + }); + }, 50); + + Utils.triggerAutocompleteInputChange(true); + }; + + LoginViewModel.prototype.submitForm = function () + { + this.submitCommand(); + }; + + LoginViewModel.prototype.selectLanguage = function () + { + kn.showScreenPopup(PopupsLanguagesViewModel); + }; + + module.exports = new LoginViewModel(); + +}(module)); \ No newline at end of file diff --git a/dev/ViewModels/MailBoxFolderListViewModel.js b/dev/ViewModels/MailBoxFolderListViewModel.js index 9b324dd50..ee60f655a 100644 --- a/dev/ViewModels/MailBoxFolderListViewModel.js +++ b/dev/ViewModels/MailBoxFolderListViewModel.js @@ -1,249 +1,274 @@ /* RainLoop Webmail (c) RainLoop Team | Licensed under CC BY-NC-SA 3.0 */ -/** - * @constructor - * @extends KnoinAbstractViewModel - */ -function MailBoxFolderListViewModel() -{ - KnoinAbstractViewModel.call(this, 'Left', 'MailFolderList'); +(function (module) { - var oData = RL.data(); - - this.oContentVisible = null; - this.oContentScrollable = null; - - this.messageList = oData.messageList; - this.folderList = oData.folderList; - this.folderListSystem = oData.folderListSystem; - this.foldersChanging = oData.foldersChanging; - - this.leftPanelDisabled = oData.leftPanelDisabled; - - this.iDropOverTimer = 0; - - this.allowContacts = !!RL.settingsGet('ContactsIsAllowed'); - - Knoin.constructorEnd(this); -} - -Utils.extendAsViewModel('MailBoxFolderListViewModel', MailBoxFolderListViewModel); - -MailBoxFolderListViewModel.prototype.onBuild = function (oDom) -{ - this.oContentVisible = $('.b-content', oDom); - this.oContentScrollable = $('.content', this.oContentVisible); - - var self = this; - - oDom - .on('click', '.b-folders .e-item .e-link .e-collapsed-sign', function (oEvent) { - - var - oFolder = ko.dataFor(this), - bCollapsed = false - ; - - if (oFolder && oEvent) - { - bCollapsed = oFolder.collapsed(); - Utils.setExpandedFolder(oFolder.fullNameHash, bCollapsed); - - oFolder.collapsed(!bCollapsed); - oEvent.preventDefault(); - oEvent.stopPropagation(); - } - }) - .on('click', '.b-folders .e-item .e-link.selectable', function (oEvent) { - - oEvent.preventDefault(); - - var - oData = RL.data(), - oFolder = ko.dataFor(this) - ; - - if (oFolder) - { - if (Enums.Layout.NoPreview === oData.layout()) - { - oData.message(null); - } - - if (oFolder.fullNameRaw === oData.currentFolderFullNameRaw()) - { - RL.cache().setFolderHash(oFolder.fullNameRaw, ''); - } - - kn.setHash(RL.link().mailBox(oFolder.fullNameHash)); - } - }) - ; - - key('up, down', Enums.KeyState.FolderList, function (event, handler) { - - var - iIndex = -1, - iKeyCode = handler && 'up' === handler.shortcut ? 38 : 40, - $items = $('.b-folders .e-item .e-link:not(.hidden):visible', oDom) - ; - - if (event && $items.length) - { - iIndex = $items.index($items.filter('.focused')); - if (-1 < iIndex) - { - $items.eq(iIndex).removeClass('focused'); - } - - if (iKeyCode === 38 && iIndex > 0) - { - iIndex--; - } - else if (iKeyCode === 40 && iIndex < $items.length - 1) - { - iIndex++; - } - - $items.eq(iIndex).addClass('focused'); - self.scrollToFocused(); - } - - return false; - }); - - key('enter', Enums.KeyState.FolderList, function () { - var $items = $('.b-folders .e-item .e-link:not(.hidden).focused', oDom); - if ($items.length && $items[0]) - { - self.folderList.focused(false); - $items.click(); - } - - return false; - }); - - key('space', Enums.KeyState.FolderList, function () { - var bCollapsed = true, oFolder = null, $items = $('.b-folders .e-item .e-link:not(.hidden).focused', oDom); - if ($items.length && $items[0]) - { - oFolder = ko.dataFor($items[0]); - if (oFolder) - { - bCollapsed = oFolder.collapsed(); - Utils.setExpandedFolder(oFolder.fullNameHash, bCollapsed); - oFolder.collapsed(!bCollapsed); - } - } - - return false; - }); - - key('esc, tab, shift+tab, right', Enums.KeyState.FolderList, function () { - self.folderList.focused(false); - return false; - }); - - self.folderList.focused.subscribe(function (bValue) { - $('.b-folders .e-item .e-link.focused', oDom).removeClass('focused'); - if (bValue) - { - $('.b-folders .e-item .e-link.selected', oDom).addClass('focused'); - } - }); -}; - -MailBoxFolderListViewModel.prototype.messagesDropOver = function (oFolder) -{ - window.clearTimeout(this.iDropOverTimer); - if (oFolder && oFolder.collapsed()) - { - this.iDropOverTimer = window.setTimeout(function () { - oFolder.collapsed(false); - Utils.setExpandedFolder(oFolder.fullNameHash, true); - Utils.windowResize(); - }, 500); - } -}; - -MailBoxFolderListViewModel.prototype.messagesDropOut = function () -{ - window.clearTimeout(this.iDropOverTimer); -}; - -MailBoxFolderListViewModel.prototype.scrollToFocused = function () -{ - if (!this.oContentVisible || !this.oContentScrollable) - { - return false; - } + 'use strict'; var - iOffset = 20, - oFocused = $('.e-item .e-link.focused', this.oContentScrollable), - oPos = oFocused.position(), - iVisibleHeight = this.oContentVisible.height(), - iFocusedHeight = oFocused.outerHeight() + window = require('../External/window.js'), + $ = require('../External/jquery.js'), + ko = require('../External/ko.js'), + key = require('../External/key.js'), + $html = require('../External/$html.js'), + + Utils = require('../Common/Utils.js'), + Enums = require('../Common/Enums.js'), + LinkBuilder = require('../Common/LinkBuilder.js'), + + Cache = require('../Storages/WebMailCacheStorage.js'), + + kn = require('../Knoin/Knoin.js'), + KnoinAbstractViewModel = require('../Knoin/KnoinAbstractViewModel.js') ; - if (oPos && (oPos.top < 0 || oPos.top + iFocusedHeight > iVisibleHeight)) + /** + * @constructor + * @extends KnoinAbstractViewModel + */ + function MailBoxFolderListViewModel() { - if (oPos.top < 0) - { - this.oContentScrollable.scrollTop(this.oContentScrollable.scrollTop() + oPos.top - iOffset); - } - else - { - this.oContentScrollable.scrollTop(this.oContentScrollable.scrollTop() + oPos.top - iVisibleHeight + iFocusedHeight + iOffset); - } + KnoinAbstractViewModel.call(this, 'Left', 'MailFolderList'); - return true; + var oData = RL.data(); + + this.oContentVisible = null; + this.oContentScrollable = null; + + this.messageList = oData.messageList; + this.folderList = oData.folderList; + this.folderListSystem = oData.folderListSystem; + this.foldersChanging = oData.foldersChanging; + + this.leftPanelDisabled = oData.leftPanelDisabled; + + this.iDropOverTimer = 0; + + this.allowContacts = !!RL.settingsGet('ContactsIsAllowed'); + + kn.constructorEnd(this); } - return false; -}; + kn.extendAsViewModel('MailBoxFolderListViewModel', MailBoxFolderListViewModel); -/** - * - * @param {FolderModel} oToFolder - * @param {{helper:jQuery}} oUi - */ -MailBoxFolderListViewModel.prototype.messagesDrop = function (oToFolder, oUi) -{ - if (oToFolder && oUi && oUi.helper) + MailBoxFolderListViewModel.prototype.onBuild = function (oDom) { - var - sFromFolderFullNameRaw = oUi.helper.data('rl-folder'), - bCopy = $html.hasClass('rl-ctrl-key-pressed'), - aUids = oUi.helper.data('rl-uids') + this.oContentVisible = $('.b-content', oDom); + this.oContentScrollable = $('.content', this.oContentVisible); + + var self = this; + + oDom + .on('click', '.b-folders .e-item .e-link .e-collapsed-sign', function (oEvent) { + + var + oFolder = ko.dataFor(this), + bCollapsed = false + ; + + if (oFolder && oEvent) + { + bCollapsed = oFolder.collapsed(); + Utils.setExpandedFolder(oFolder.fullNameHash, bCollapsed); + + oFolder.collapsed(!bCollapsed); + oEvent.preventDefault(); + oEvent.stopPropagation(); + } + }) + .on('click', '.b-folders .e-item .e-link.selectable', function (oEvent) { + + oEvent.preventDefault(); + + var + oData = RL.data(), + oFolder = ko.dataFor(this) + ; + + if (oFolder) + { + if (Enums.Layout.NoPreview === oData.layout()) + { + oData.message(null); + } + + if (oFolder.fullNameRaw === oData.currentFolderFullNameRaw()) + { + Cache.setFolderHash(oFolder.fullNameRaw, ''); + } + + kn.setHash(LinkBuilder.mailBox(oFolder.fullNameHash)); + } + }) ; - if (Utils.isNormal(sFromFolderFullNameRaw) && '' !== sFromFolderFullNameRaw && Utils.isArray(aUids)) - { - RL.moveMessagesToFolder(sFromFolderFullNameRaw, aUids, oToFolder.fullNameRaw, bCopy); - } - } -}; + key('up, down', Enums.KeyState.FolderList, function (event, handler) { -MailBoxFolderListViewModel.prototype.composeClick = function () -{ - kn.showScreenPopup(PopupsComposeViewModel); -}; + var + iIndex = -1, + iKeyCode = handler && 'up' === handler.shortcut ? 38 : 40, + $items = $('.b-folders .e-item .e-link:not(.hidden):visible', oDom) + ; -MailBoxFolderListViewModel.prototype.createFolder = function () -{ - kn.showScreenPopup(PopupsFolderCreateViewModel); -}; + if (event && $items.length) + { + iIndex = $items.index($items.filter('.focused')); + if (-1 < iIndex) + { + $items.eq(iIndex).removeClass('focused'); + } -MailBoxFolderListViewModel.prototype.configureFolders = function () -{ - kn.setHash(RL.link().settings('folders')); -}; + if (iKeyCode === 38 && iIndex > 0) + { + iIndex--; + } + else if (iKeyCode === 40 && iIndex < $items.length - 1) + { + iIndex++; + } -MailBoxFolderListViewModel.prototype.contactsClick = function () -{ - if (this.allowContacts) + $items.eq(iIndex).addClass('focused'); + self.scrollToFocused(); + } + + return false; + }); + + key('enter', Enums.KeyState.FolderList, function () { + var $items = $('.b-folders .e-item .e-link:not(.hidden).focused', oDom); + if ($items.length && $items[0]) + { + self.folderList.focused(false); + $items.click(); + } + + return false; + }); + + key('space', Enums.KeyState.FolderList, function () { + var bCollapsed = true, oFolder = null, $items = $('.b-folders .e-item .e-link:not(.hidden).focused', oDom); + if ($items.length && $items[0]) + { + oFolder = ko.dataFor($items[0]); + if (oFolder) + { + bCollapsed = oFolder.collapsed(); + Utils.setExpandedFolder(oFolder.fullNameHash, bCollapsed); + oFolder.collapsed(!bCollapsed); + } + } + + return false; + }); + + key('esc, tab, shift+tab, right', Enums.KeyState.FolderList, function () { + self.folderList.focused(false); + return false; + }); + + self.folderList.focused.subscribe(function (bValue) { + $('.b-folders .e-item .e-link.focused', oDom).removeClass('focused'); + if (bValue) + { + $('.b-folders .e-item .e-link.selected', oDom).addClass('focused'); + } + }); + }; + + MailBoxFolderListViewModel.prototype.messagesDropOver = function (oFolder) { - kn.showScreenPopup(PopupsContactsViewModel); - } -}; + window.clearTimeout(this.iDropOverTimer); + if (oFolder && oFolder.collapsed()) + { + this.iDropOverTimer = window.setTimeout(function () { + oFolder.collapsed(false); + Utils.setExpandedFolder(oFolder.fullNameHash, true); + Utils.windowResize(); + }, 500); + } + }; + + MailBoxFolderListViewModel.prototype.messagesDropOut = function () + { + window.clearTimeout(this.iDropOverTimer); + }; + + MailBoxFolderListViewModel.prototype.scrollToFocused = function () + { + if (!this.oContentVisible || !this.oContentScrollable) + { + return false; + } + + var + iOffset = 20, + oFocused = $('.e-item .e-link.focused', this.oContentScrollable), + oPos = oFocused.position(), + iVisibleHeight = this.oContentVisible.height(), + iFocusedHeight = oFocused.outerHeight() + ; + + if (oPos && (oPos.top < 0 || oPos.top + iFocusedHeight > iVisibleHeight)) + { + if (oPos.top < 0) + { + this.oContentScrollable.scrollTop(this.oContentScrollable.scrollTop() + oPos.top - iOffset); + } + else + { + this.oContentScrollable.scrollTop(this.oContentScrollable.scrollTop() + oPos.top - iVisibleHeight + iFocusedHeight + iOffset); + } + + return true; + } + + return false; + }; + + /** + * + * @param {FolderModel} oToFolder + * @param {{helper:jQuery}} oUi + */ + MailBoxFolderListViewModel.prototype.messagesDrop = function (oToFolder, oUi) + { + if (oToFolder && oUi && oUi.helper) + { + var + sFromFolderFullNameRaw = oUi.helper.data('rl-folder'), + bCopy = $html.hasClass('rl-ctrl-key-pressed'), + aUids = oUi.helper.data('rl-uids') + ; + + if (Utils.isNormal(sFromFolderFullNameRaw) && '' !== sFromFolderFullNameRaw && Utils.isArray(aUids)) + { + RL.moveMessagesToFolder(sFromFolderFullNameRaw, aUids, oToFolder.fullNameRaw, bCopy); + } + } + }; + + MailBoxFolderListViewModel.prototype.composeClick = function () + { + kn.showScreenPopup(PopupsComposeViewModel); + }; + + MailBoxFolderListViewModel.prototype.createFolder = function () + { + kn.showScreenPopup(PopupsFolderCreateViewModel); + }; + + MailBoxFolderListViewModel.prototype.configureFolders = function () + { + kn.setHash(LinkBuilder.settings('folders')); + }; + + MailBoxFolderListViewModel.prototype.contactsClick = function () + { + if (this.allowContacts) + { + kn.showScreenPopup(PopupsContactsViewModel); + } + }; + + module.exports = new MailBoxFolderListViewModel(); + +}(module)); diff --git a/dev/ViewModels/MailBoxMessageListViewModel.js b/dev/ViewModels/MailBoxMessageListViewModel.js index e0f7c75ef..1d74f8fa7 100644 --- a/dev/ViewModels/MailBoxMessageListViewModel.js +++ b/dev/ViewModels/MailBoxMessageListViewModel.js @@ -1,907 +1,935 @@ /* RainLoop Webmail (c) RainLoop Team | Licensed under CC BY-NC-SA 3.0 */ -/** - * @constructor - * @extends KnoinAbstractViewModel - */ -function MailBoxMessageListViewModel() -{ - KnoinAbstractViewModel.call(this, 'Right', 'MailMessageList'); +(function (module) { - this.sLastUid = null; - this.bPrefetch = false; - this.emptySubjectValue = ''; - - this.hideDangerousActions = !!RL.settingsGet('HideDangerousActions'); - - var oData = RL.data(); - - this.popupVisibility = RL.popupVisibility; - - this.message = oData.message; - this.messageList = oData.messageList; - this.folderList = oData.folderList; - this.currentMessage = oData.currentMessage; - this.isMessageSelected = oData.isMessageSelected; - this.messageListSearch = oData.messageListSearch; - this.messageListError = oData.messageListError; - this.folderMenuForMove = oData.folderMenuForMove; - - this.useCheckboxesInList = oData.useCheckboxesInList; - - this.mainMessageListSearch = oData.mainMessageListSearch; - this.messageListEndFolder = oData.messageListEndFolder; - - this.messageListChecked = oData.messageListChecked; - this.messageListCheckedOrSelected = oData.messageListCheckedOrSelected; - this.messageListCheckedOrSelectedUidsWithSubMails = oData.messageListCheckedOrSelectedUidsWithSubMails; - this.messageListCompleteLoadingThrottle = oData.messageListCompleteLoadingThrottle; - - Utils.initOnStartOrLangChange(function () { - this.emptySubjectValue = Utils.i18n('MESSAGE_LIST/EMPTY_SUBJECT_TEXT'); - }, this); - - this.userQuota = oData.userQuota; - this.userUsageSize = oData.userUsageSize; - this.userUsageProc = oData.userUsageProc; - - this.moveDropdownTrigger = ko.observable(false); - this.moreDropdownTrigger = ko.observable(false); - - // append drag and drop - this.dragOver = ko.observable(false).extend({'throttle': 1}); - this.dragOverEnter = ko.observable(false).extend({'throttle': 1}); - this.dragOverArea = ko.observable(null); - this.dragOverBodyArea = ko.observable(null); - - this.messageListItemTemplate = ko.computed(function () { - return Enums.Layout.NoPreview !== oData.layout() ? - 'MailMessageListItem' : 'MailMessageListItemNoPreviewPane'; - }); - - this.messageListSearchDesc = ko.computed(function () { - var sValue = oData.messageListEndSearch(); - return '' === sValue ? '' : Utils.i18n('MESSAGE_LIST/SEARCH_RESULT_FOR', {'SEARCH': sValue}); - }); - - this.messageListPagenator = ko.computed(Utils.computedPagenatorHelper(oData.messageListPage, oData.messageListPageCount)); - - this.checkAll = ko.computed({ - 'read': function () { - return 0 < RL.data().messageListChecked().length; - }, - - 'write': function (bValue) { - bValue = !!bValue; - _.each(RL.data().messageList(), function (oMessage) { - oMessage.checked(bValue); - }); - } - }); - - this.inputMessageListSearchFocus = ko.observable(false); - - this.sLastSearchValue = ''; - this.inputProxyMessageListSearch = ko.computed({ - 'read': this.mainMessageListSearch, - 'write': function (sValue) { - this.sLastSearchValue = sValue; - }, - 'owner': this - }); - - this.isIncompleteChecked = ko.computed(function () { - var - iM = RL.data().messageList().length, - iC = RL.data().messageListChecked().length - ; - return 0 < iM && 0 < iC && iM > iC; - }, this); - - this.hasMessages = ko.computed(function () { - return 0 < this.messageList().length; - }, this); - - this.hasCheckedOrSelectedLines = ko.computed(function () { - return 0 < this.messageListCheckedOrSelected().length; - }, this); - - this.isSpamFolder = ko.computed(function () { - return oData.spamFolder() === this.messageListEndFolder() && - '' !== oData.spamFolder(); - }, this); - - this.isSpamDisabled = ko.computed(function () { - return Consts.Values.UnuseOptionValue === oData.spamFolder(); - }, this); - - this.isTrashFolder = ko.computed(function () { - return oData.trashFolder() === this.messageListEndFolder() && - '' !== oData.trashFolder(); - }, this); - - this.isDraftFolder = ko.computed(function () { - return oData.draftFolder() === this.messageListEndFolder() && - '' !== oData.draftFolder(); - }, this); - - this.isSentFolder = ko.computed(function () { - return oData.sentFolder() === this.messageListEndFolder() && - '' !== oData.sentFolder(); - }, this); - - this.isArchiveFolder = ko.computed(function () { - return oData.archiveFolder() === this.messageListEndFolder() && - '' !== oData.archiveFolder(); - }, this); - - this.isArchiveDisabled = ko.computed(function () { - return Consts.Values.UnuseOptionValue === RL.data().archiveFolder(); - }, this); - - this.canBeMoved = this.hasCheckedOrSelectedLines; - - this.clearCommand = Utils.createCommand(this, function () { - kn.showScreenPopup(PopupsFolderClearViewModel, [RL.data().currentFolder()]); - }); - - this.multyForwardCommand = Utils.createCommand(this, function () { - kn.showScreenPopup(PopupsComposeViewModel, [Enums.ComposeType.ForwardAsAttachment, RL.data().messageListCheckedOrSelected()]); - }, this.canBeMoved); - - this.deleteWithoutMoveCommand = Utils.createCommand(this, function () { - RL.deleteMessagesFromFolder(Enums.FolderType.Trash, - RL.data().currentFolderFullNameRaw(), - RL.data().messageListCheckedOrSelectedUidsWithSubMails(), false); - }, this.canBeMoved); - - this.deleteCommand = Utils.createCommand(this, function () { - RL.deleteMessagesFromFolder(Enums.FolderType.Trash, - RL.data().currentFolderFullNameRaw(), - RL.data().messageListCheckedOrSelectedUidsWithSubMails(), true); - }, this.canBeMoved); - - this.archiveCommand = Utils.createCommand(this, function () { - RL.deleteMessagesFromFolder(Enums.FolderType.Archive, - RL.data().currentFolderFullNameRaw(), - RL.data().messageListCheckedOrSelectedUidsWithSubMails(), true); - }, this.canBeMoved); - - this.spamCommand = Utils.createCommand(this, function () { - RL.deleteMessagesFromFolder(Enums.FolderType.Spam, - RL.data().currentFolderFullNameRaw(), - RL.data().messageListCheckedOrSelectedUidsWithSubMails(), true); - }, this.canBeMoved); - - this.notSpamCommand = Utils.createCommand(this, function () { - RL.deleteMessagesFromFolder(Enums.FolderType.NotSpam, - RL.data().currentFolderFullNameRaw(), - RL.data().messageListCheckedOrSelectedUidsWithSubMails(), true); - }, this.canBeMoved); - - this.moveCommand = Utils.createCommand(this, Utils.emptyFunction, this.canBeMoved); - - this.reloadCommand = Utils.createCommand(this, function () { - if (!RL.data().messageListCompleteLoadingThrottle()) - { - RL.reloadMessageList(false, true); - } - }); - - this.quotaTooltip = _.bind(this.quotaTooltip, this); - - this.selector = new Selector(this.messageList, this.currentMessage, - '.messageListItem .actionHandle', '.messageListItem.selected', '.messageListItem .checkboxMessage', - '.messageListItem.focused'); - - this.selector.on('onItemSelect', _.bind(function (oMessage) { - if (oMessage) - { - oData.message(oData.staticMessageList.populateByMessageListItem(oMessage)); - this.populateMessageBody(oData.message()); - - if (Enums.Layout.NoPreview === oData.layout()) - { - kn.setHash(RL.link().messagePreview(), true); - oData.message.focused(true); - } - } - else - { - oData.message(null); - } - }, this)); - - this.selector.on('onItemGetUid', function (oMessage) { - return oMessage ? oMessage.generateUid() : ''; - }); - - oData.messageListEndHash.subscribe(function () { - this.selector.scrollToTop(); - }, this); - - oData.layout.subscribe(function (mValue) { - this.selector.autoSelect(Enums.Layout.NoPreview !== mValue); - }, this); - - oData.layout.valueHasMutated(); - - RL - .sub('mailbox.message-list.selector.go-down', function () { - this.selector.goDown(true); - }, this) - .sub('mailbox.message-list.selector.go-up', function () { - this.selector.goUp(true); - }, this) - ; - - Knoin.constructorEnd(this); -} - -Utils.extendAsViewModel('MailBoxMessageListViewModel', MailBoxMessageListViewModel); - -/** - * @type {string} - */ -MailBoxMessageListViewModel.prototype.emptySubjectValue = ''; - -MailBoxMessageListViewModel.prototype.searchEnterAction = function () -{ - this.mainMessageListSearch(this.sLastSearchValue); - this.inputMessageListSearchFocus(false); -}; - -/** - * @returns {string} - */ -MailBoxMessageListViewModel.prototype.printableMessageCountForDeletion = function () -{ - var iCnt = this.messageListCheckedOrSelectedUidsWithSubMails().length; - return 1 < iCnt ? ' (' + (100 > iCnt ? iCnt : '99+') + ')' : ''; -}; - -MailBoxMessageListViewModel.prototype.cancelSearch = function () -{ - this.mainMessageListSearch(''); - this.inputMessageListSearchFocus(false); -}; - -/** - * @param {string} sToFolderFullNameRaw - * @return {boolean} - */ -MailBoxMessageListViewModel.prototype.moveSelectedMessagesToFolder = function (sToFolderFullNameRaw, bCopy) -{ - if (this.canBeMoved()) - { - RL.moveMessagesToFolder( - RL.data().currentFolderFullNameRaw(), - RL.data().messageListCheckedOrSelectedUidsWithSubMails(), sToFolderFullNameRaw, bCopy); - } - - return false; -}; - -MailBoxMessageListViewModel.prototype.dragAndDronHelper = function (oMessageListItem) -{ - if (oMessageListItem) - { - oMessageListItem.checked(true); - } + 'use strict'; var - oEl = Utils.draggeblePlace(), - aUids = RL.data().messageListCheckedOrSelectedUidsWithSubMails() + $ = require('../External/jquery.js'), + _ = require('../External/underscore.js'), + ko = require('../External/ko.js'), + key = require('../External/key.js'), + ifvisible = require('../External/ifvisible.js'), + Jua = require('../External/Jua.js'), + + Utils = require('../Common/Utils.js'), + Enums = require('../Common/Enums.js'), + Consts = require('../Common/Consts.js'), + Globals = require('../Common/Globals.js'), + LinkBuilder = require('../Common/LinkBuilder.js'), + + Cache = require('../Storages/WebMailCacheStorage.js'), + Remote = require('../Storages/WebMailAjaxRemoteStorage.js'), + + kn = require('../Knoin/Knoin.js'), + KnoinAbstractViewModel = require('../Knoin/KnoinAbstractViewModel.js'), + + PopupsComposeViewModel = require('./Popups/PopupsComposeViewModel.js') ; - oEl.data('rl-folder', RL.data().currentFolderFullNameRaw()); - oEl.data('rl-uids', aUids); - oEl.find('.text').text('' + aUids.length); + /** + * @constructor + * @extends KnoinAbstractViewModel + */ + function MailBoxMessageListViewModel() + { + KnoinAbstractViewModel.call(this, 'Right', 'MailMessageList'); - _.defer(function () { - var aUids = RL.data().messageListCheckedOrSelectedUidsWithSubMails(); + this.sLastUid = null; + this.bPrefetch = false; + this.emptySubjectValue = ''; + this.hideDangerousActions = !!RL.settingsGet('HideDangerousActions'); + + var oData = RL.data(); + + this.popupVisibility = RL.popupVisibility; + + this.message = oData.message; + this.messageList = oData.messageList; + this.folderList = oData.folderList; + this.currentMessage = oData.currentMessage; + this.isMessageSelected = oData.isMessageSelected; + this.messageListSearch = oData.messageListSearch; + this.messageListError = oData.messageListError; + this.folderMenuForMove = oData.folderMenuForMove; + + this.useCheckboxesInList = oData.useCheckboxesInList; + + this.mainMessageListSearch = oData.mainMessageListSearch; + this.messageListEndFolder = oData.messageListEndFolder; + + this.messageListChecked = oData.messageListChecked; + this.messageListCheckedOrSelected = oData.messageListCheckedOrSelected; + this.messageListCheckedOrSelectedUidsWithSubMails = oData.messageListCheckedOrSelectedUidsWithSubMails; + this.messageListCompleteLoadingThrottle = oData.messageListCompleteLoadingThrottle; + + Utils.initOnStartOrLangChange(function () { + this.emptySubjectValue = Utils.i18n('MESSAGE_LIST/EMPTY_SUBJECT_TEXT'); + }, this); + + this.userQuota = oData.userQuota; + this.userUsageSize = oData.userUsageSize; + this.userUsageProc = oData.userUsageProc; + + this.moveDropdownTrigger = ko.observable(false); + this.moreDropdownTrigger = ko.observable(false); + + // append drag and drop + this.dragOver = ko.observable(false).extend({'throttle': 1}); + this.dragOverEnter = ko.observable(false).extend({'throttle': 1}); + this.dragOverArea = ko.observable(null); + this.dragOverBodyArea = ko.observable(null); + + this.messageListItemTemplate = ko.computed(function () { + return Enums.Layout.NoPreview !== oData.layout() ? + 'MailMessageListItem' : 'MailMessageListItemNoPreviewPane'; + }); + + this.messageListSearchDesc = ko.computed(function () { + var sValue = oData.messageListEndSearch(); + return '' === sValue ? '' : Utils.i18n('MESSAGE_LIST/SEARCH_RESULT_FOR', {'SEARCH': sValue}); + }); + + this.messageListPagenator = ko.computed(Utils.computedPagenatorHelper(oData.messageListPage, oData.messageListPageCount)); + + this.checkAll = ko.computed({ + 'read': function () { + return 0 < RL.data().messageListChecked().length; + }, + + 'write': function (bValue) { + bValue = !!bValue; + _.each(RL.data().messageList(), function (oMessage) { + oMessage.checked(bValue); + }); + } + }); + + this.inputMessageListSearchFocus = ko.observable(false); + + this.sLastSearchValue = ''; + this.inputProxyMessageListSearch = ko.computed({ + 'read': this.mainMessageListSearch, + 'write': function (sValue) { + this.sLastSearchValue = sValue; + }, + 'owner': this + }); + + this.isIncompleteChecked = ko.computed(function () { + var + iM = RL.data().messageList().length, + iC = RL.data().messageListChecked().length + ; + return 0 < iM && 0 < iC && iM > iC; + }, this); + + this.hasMessages = ko.computed(function () { + return 0 < this.messageList().length; + }, this); + + this.hasCheckedOrSelectedLines = ko.computed(function () { + return 0 < this.messageListCheckedOrSelected().length; + }, this); + + this.isSpamFolder = ko.computed(function () { + return oData.spamFolder() === this.messageListEndFolder() && + '' !== oData.spamFolder(); + }, this); + + this.isSpamDisabled = ko.computed(function () { + return Consts.Values.UnuseOptionValue === oData.spamFolder(); + }, this); + + this.isTrashFolder = ko.computed(function () { + return oData.trashFolder() === this.messageListEndFolder() && + '' !== oData.trashFolder(); + }, this); + + this.isDraftFolder = ko.computed(function () { + return oData.draftFolder() === this.messageListEndFolder() && + '' !== oData.draftFolder(); + }, this); + + this.isSentFolder = ko.computed(function () { + return oData.sentFolder() === this.messageListEndFolder() && + '' !== oData.sentFolder(); + }, this); + + this.isArchiveFolder = ko.computed(function () { + return oData.archiveFolder() === this.messageListEndFolder() && + '' !== oData.archiveFolder(); + }, this); + + this.isArchiveDisabled = ko.computed(function () { + return Consts.Values.UnuseOptionValue === RL.data().archiveFolder(); + }, this); + + this.canBeMoved = this.hasCheckedOrSelectedLines; + + this.clearCommand = Utils.createCommand(this, function () { + kn.showScreenPopup(PopupsFolderClearViewModel, [RL.data().currentFolder()]); + }); + + this.multyForwardCommand = Utils.createCommand(this, function () { + kn.showScreenPopup(PopupsComposeViewModel, [Enums.ComposeType.ForwardAsAttachment, RL.data().messageListCheckedOrSelected()]); + }, this.canBeMoved); + + this.deleteWithoutMoveCommand = Utils.createCommand(this, function () { + RL.deleteMessagesFromFolder(Enums.FolderType.Trash, + RL.data().currentFolderFullNameRaw(), + RL.data().messageListCheckedOrSelectedUidsWithSubMails(), false); + }, this.canBeMoved); + + this.deleteCommand = Utils.createCommand(this, function () { + RL.deleteMessagesFromFolder(Enums.FolderType.Trash, + RL.data().currentFolderFullNameRaw(), + RL.data().messageListCheckedOrSelectedUidsWithSubMails(), true); + }, this.canBeMoved); + + this.archiveCommand = Utils.createCommand(this, function () { + RL.deleteMessagesFromFolder(Enums.FolderType.Archive, + RL.data().currentFolderFullNameRaw(), + RL.data().messageListCheckedOrSelectedUidsWithSubMails(), true); + }, this.canBeMoved); + + this.spamCommand = Utils.createCommand(this, function () { + RL.deleteMessagesFromFolder(Enums.FolderType.Spam, + RL.data().currentFolderFullNameRaw(), + RL.data().messageListCheckedOrSelectedUidsWithSubMails(), true); + }, this.canBeMoved); + + this.notSpamCommand = Utils.createCommand(this, function () { + RL.deleteMessagesFromFolder(Enums.FolderType.NotSpam, + RL.data().currentFolderFullNameRaw(), + RL.data().messageListCheckedOrSelectedUidsWithSubMails(), true); + }, this.canBeMoved); + + this.moveCommand = Utils.createCommand(this, Utils.emptyFunction, this.canBeMoved); + + this.reloadCommand = Utils.createCommand(this, function () { + if (!RL.data().messageListCompleteLoadingThrottle()) + { + RL.reloadMessageList(false, true); + } + }); + + this.quotaTooltip = _.bind(this.quotaTooltip, this); + + this.selector = new Selector(this.messageList, this.currentMessage, + '.messageListItem .actionHandle', '.messageListItem.selected', '.messageListItem .checkboxMessage', + '.messageListItem.focused'); + + this.selector.on('onItemSelect', _.bind(function (oMessage) { + if (oMessage) + { + oData.message(oData.staticMessageList.populateByMessageListItem(oMessage)); + this.populateMessageBody(oData.message()); + + if (Enums.Layout.NoPreview === oData.layout()) + { + kn.setHash(LinkBuilder.messagePreview(), true); + oData.message.focused(true); + } + } + else + { + oData.message(null); + } + }, this)); + + this.selector.on('onItemGetUid', function (oMessage) { + return oMessage ? oMessage.generateUid() : ''; + }); + + oData.messageListEndHash.subscribe(function () { + this.selector.scrollToTop(); + }, this); + + oData.layout.subscribe(function (mValue) { + this.selector.autoSelect(Enums.Layout.NoPreview !== mValue); + }, this); + + oData.layout.valueHasMutated(); + + RL + .sub('mailbox.message-list.selector.go-down', function () { + this.selector.goDown(true); + }, this) + .sub('mailbox.message-list.selector.go-up', function () { + this.selector.goUp(true); + }, this) + ; + + kn.constructorEnd(this); + } + + kn.extendAsViewModel('MailBoxMessageListViewModel', MailBoxMessageListViewModel); + + /** + * @type {string} + */ + MailBoxMessageListViewModel.prototype.emptySubjectValue = ''; + + MailBoxMessageListViewModel.prototype.searchEnterAction = function () + { + this.mainMessageListSearch(this.sLastSearchValue); + this.inputMessageListSearchFocus(false); + }; + + /** + * @returns {string} + */ + MailBoxMessageListViewModel.prototype.printableMessageCountForDeletion = function () + { + var iCnt = this.messageListCheckedOrSelectedUidsWithSubMails().length; + return 1 < iCnt ? ' (' + (100 > iCnt ? iCnt : '99+') + ')' : ''; + }; + + MailBoxMessageListViewModel.prototype.cancelSearch = function () + { + this.mainMessageListSearch(''); + this.inputMessageListSearchFocus(false); + }; + + /** + * @param {string} sToFolderFullNameRaw + * @return {boolean} + */ + MailBoxMessageListViewModel.prototype.moveSelectedMessagesToFolder = function (sToFolderFullNameRaw, bCopy) + { + if (this.canBeMoved()) + { + RL.moveMessagesToFolder( + RL.data().currentFolderFullNameRaw(), + RL.data().messageListCheckedOrSelectedUidsWithSubMails(), sToFolderFullNameRaw, bCopy); + } + + return false; + }; + + MailBoxMessageListViewModel.prototype.dragAndDronHelper = function (oMessageListItem) + { + if (oMessageListItem) + { + oMessageListItem.checked(true); + } + + var + oEl = Utils.draggeblePlace(), + aUids = RL.data().messageListCheckedOrSelectedUidsWithSubMails() + ; + + oEl.data('rl-folder', RL.data().currentFolderFullNameRaw()); oEl.data('rl-uids', aUids); oEl.find('.text').text('' + aUids.length); - }); - return oEl; -}; + _.defer(function () { + var aUids = RL.data().messageListCheckedOrSelectedUidsWithSubMails(); -/** - * @param {string} sResult - * @param {AjaxJsonDefaultResponse} oData - * @param {boolean} bCached - */ -MailBoxMessageListViewModel.prototype.onMessageResponse = function (sResult, oData, bCached) -{ - var oRainLoopData = RL.data(); + oEl.data('rl-uids', aUids); + oEl.find('.text').text('' + aUids.length); + }); - oRainLoopData.hideMessageBodies(); - oRainLoopData.messageLoading(false); + return oEl; + }; - if (Enums.StorageResultType.Success === sResult && oData && oData.Result) + /** + * @param {string} sResult + * @param {AjaxJsonDefaultResponse} oData + * @param {boolean} bCached + */ + MailBoxMessageListViewModel.prototype.onMessageResponse = function (sResult, oData, bCached) { - oRainLoopData.setMessage(oData, bCached); - } - else if (Enums.StorageResultType.Unload === sResult) - { - oRainLoopData.message(null); - oRainLoopData.messageError(''); - } - else if (Enums.StorageResultType.Abort !== sResult) - { - oRainLoopData.message(null); - oRainLoopData.messageError((oData && oData.ErrorCode ? - Utils.getNotification(oData.ErrorCode) : - Utils.getNotification(Enums.Notification.UnknownError))); - } -}; + var oRainLoopData = RL.data(); -MailBoxMessageListViewModel.prototype.populateMessageBody = function (oMessage) -{ - if (oMessage) - { - if (RL.remote().message(this.onMessageResponse, oMessage.folderFullNameRaw, oMessage.uid)) + oRainLoopData.hideMessageBodies(); + oRainLoopData.messageLoading(false); + + if (Enums.StorageResultType.Success === sResult && oData && oData.Result) { - RL.data().messageLoading(true); + oRainLoopData.setMessage(oData, bCached); } - else + else if (Enums.StorageResultType.Unload === sResult) { - Utils.log('Error: Unknown message request: ' + oMessage.folderFullNameRaw + ' ~ ' + oMessage.uid + ' [e-101]'); + oRainLoopData.message(null); + oRainLoopData.messageError(''); } - } -}; + else if (Enums.StorageResultType.Abort !== sResult) + { + oRainLoopData.message(null); + oRainLoopData.messageError((oData && oData.ErrorCode ? + Utils.getNotification(oData.ErrorCode) : + Utils.getNotification(Enums.Notification.UnknownError))); + } + }; -/** - * @param {string} sFolderFullNameRaw - * @param {number} iSetAction - * @param {Array=} aMessages = null - */ -MailBoxMessageListViewModel.prototype.setAction = function (sFolderFullNameRaw, iSetAction, aMessages) -{ - var - aUids = [], - oFolder = null, - oCache = RL.cache(), - iAlreadyUnread = 0 - ; - - if (Utils.isUnd(aMessages)) + MailBoxMessageListViewModel.prototype.populateMessageBody = function (oMessage) { - aMessages = RL.data().messageListChecked(); - } + if (oMessage) + { + if (Remote.message(this.onMessageResponse, oMessage.folderFullNameRaw, oMessage.uid)) + { + RL.data().messageLoading(true); + } + else + { + Utils.log('Error: Unknown message request: ' + oMessage.folderFullNameRaw + ' ~ ' + oMessage.uid + ' [e-101]'); + } + } + }; - aUids = _.map(aMessages, function (oMessage) { - return oMessage.uid; - }); - - if ('' !== sFolderFullNameRaw && 0 < aUids.length) + /** + * @param {string} sFolderFullNameRaw + * @param {number} iSetAction + * @param {Array=} aMessages = null + */ + MailBoxMessageListViewModel.prototype.setAction = function (sFolderFullNameRaw, iSetAction, aMessages) { - switch (iSetAction) { - case Enums.MessageSetAction.SetSeen: - _.each(aMessages, function (oMessage) { - if (oMessage.unseen()) - { - iAlreadyUnread++; - } + var + aUids = [], + oFolder = null, + iAlreadyUnread = 0 + ; - oMessage.unseen(false); - oCache.storeMessageFlagsToCache(oMessage); - }); - - oFolder = oCache.getFolderFromCacheList(sFolderFullNameRaw); - if (oFolder) - { - oFolder.messageCountUnread(oFolder.messageCountUnread() - iAlreadyUnread); - } - - RL.remote().messageSetSeen(Utils.emptyFunction, sFolderFullNameRaw, aUids, true); - break; - case Enums.MessageSetAction.UnsetSeen: - _.each(aMessages, function (oMessage) { - if (oMessage.unseen()) - { - iAlreadyUnread++; - } - - oMessage.unseen(true); - oCache.storeMessageFlagsToCache(oMessage); - }); - - oFolder = oCache.getFolderFromCacheList(sFolderFullNameRaw); - if (oFolder) - { - oFolder.messageCountUnread(oFolder.messageCountUnread() - iAlreadyUnread + aUids.length); - } - RL.remote().messageSetSeen(Utils.emptyFunction, sFolderFullNameRaw, aUids, false); - break; - case Enums.MessageSetAction.SetFlag: - _.each(aMessages, function (oMessage) { - oMessage.flagged(true); - oCache.storeMessageFlagsToCache(oMessage); - }); - RL.remote().messageSetFlagged(Utils.emptyFunction, sFolderFullNameRaw, aUids, true); - break; - case Enums.MessageSetAction.UnsetFlag: - _.each(aMessages, function (oMessage) { - oMessage.flagged(false); - oCache.storeMessageFlagsToCache(oMessage); - }); - RL.remote().messageSetFlagged(Utils.emptyFunction, sFolderFullNameRaw, aUids, false); - break; + if (Utils.isUnd(aMessages)) + { + aMessages = RL.data().messageListChecked(); } - RL.reloadFlagsCurrentMessageListAndMessageFromCache(); - } -}; + aUids = _.map(aMessages, function (oMessage) { + return oMessage.uid; + }); -/** - * @param {string} sFolderFullNameRaw - * @param {number} iSetAction - */ -MailBoxMessageListViewModel.prototype.setActionForAll = function (sFolderFullNameRaw, iSetAction) -{ - var - oFolder = null, - aMessages = RL.data().messageList(), - oCache = RL.cache() - ; - - if ('' !== sFolderFullNameRaw) - { - oFolder = oCache.getFolderFromCacheList(sFolderFullNameRaw); - - if (oFolder) + if ('' !== sFolderFullNameRaw && 0 < aUids.length) { switch (iSetAction) { case Enums.MessageSetAction.SetSeen: - oFolder = oCache.getFolderFromCacheList(sFolderFullNameRaw); + _.each(aMessages, function (oMessage) { + if (oMessage.unseen()) + { + iAlreadyUnread++; + } + + oMessage.unseen(false); + Cache.storeMessageFlagsToCache(oMessage); + }); + + oFolder = Cache.getFolderFromCacheList(sFolderFullNameRaw); if (oFolder) { - _.each(aMessages, function (oMessage) { - oMessage.unseen(false); - }); - - oFolder.messageCountUnread(0); - oCache.clearMessageFlagsFromCacheByFolder(sFolderFullNameRaw); + oFolder.messageCountUnread(oFolder.messageCountUnread() - iAlreadyUnread); } - RL.remote().messageSetSeenToAll(Utils.emptyFunction, sFolderFullNameRaw, true); + Remote.messageSetSeen(Utils.emptyFunction, sFolderFullNameRaw, aUids, true); break; case Enums.MessageSetAction.UnsetSeen: - oFolder = oCache.getFolderFromCacheList(sFolderFullNameRaw); + _.each(aMessages, function (oMessage) { + if (oMessage.unseen()) + { + iAlreadyUnread++; + } + + oMessage.unseen(true); + Cache.storeMessageFlagsToCache(oMessage); + }); + + oFolder = Cache.getFolderFromCacheList(sFolderFullNameRaw); if (oFolder) { - _.each(aMessages, function (oMessage) { - oMessage.unseen(true); - }); - - oFolder.messageCountUnread(oFolder.messageCountAll()); - oCache.clearMessageFlagsFromCacheByFolder(sFolderFullNameRaw); + oFolder.messageCountUnread(oFolder.messageCountUnread() - iAlreadyUnread + aUids.length); } - RL.remote().messageSetSeenToAll(Utils.emptyFunction, sFolderFullNameRaw, false); + Remote.messageSetSeen(Utils.emptyFunction, sFolderFullNameRaw, aUids, false); + break; + case Enums.MessageSetAction.SetFlag: + _.each(aMessages, function (oMessage) { + oMessage.flagged(true); + Cache.storeMessageFlagsToCache(oMessage); + }); + Remote.messageSetFlagged(Utils.emptyFunction, sFolderFullNameRaw, aUids, true); + break; + case Enums.MessageSetAction.UnsetFlag: + _.each(aMessages, function (oMessage) { + oMessage.flagged(false); + Cache.storeMessageFlagsToCache(oMessage); + }); + Remote.messageSetFlagged(Utils.emptyFunction, sFolderFullNameRaw, aUids, false); break; } RL.reloadFlagsCurrentMessageListAndMessageFromCache(); } - } -}; + }; -MailBoxMessageListViewModel.prototype.listSetSeen = function () -{ - this.setAction(RL.data().currentFolderFullNameRaw(), Enums.MessageSetAction.SetSeen, RL.data().messageListCheckedOrSelected()); -}; - -MailBoxMessageListViewModel.prototype.listSetAllSeen = function () -{ - this.setActionForAll(RL.data().currentFolderFullNameRaw(), Enums.MessageSetAction.SetSeen); -}; - -MailBoxMessageListViewModel.prototype.listUnsetSeen = function () -{ - this.setAction(RL.data().currentFolderFullNameRaw(), Enums.MessageSetAction.UnsetSeen, RL.data().messageListCheckedOrSelected()); -}; - -MailBoxMessageListViewModel.prototype.listSetFlags = function () -{ - this.setAction(RL.data().currentFolderFullNameRaw(), Enums.MessageSetAction.SetFlag, RL.data().messageListCheckedOrSelected()); -}; - -MailBoxMessageListViewModel.prototype.listUnsetFlags = function () -{ - this.setAction(RL.data().currentFolderFullNameRaw(), Enums.MessageSetAction.UnsetFlag, RL.data().messageListCheckedOrSelected()); -}; - -MailBoxMessageListViewModel.prototype.flagMessages = function (oCurrentMessage) -{ - var - aChecked = this.messageListCheckedOrSelected(), - aCheckedUids = [] - ; - - if (oCurrentMessage) + /** + * @param {string} sFolderFullNameRaw + * @param {number} iSetAction + */ + MailBoxMessageListViewModel.prototype.setActionForAll = function (sFolderFullNameRaw, iSetAction) { - if (0 < aChecked.length) - { - aCheckedUids = _.map(aChecked, function (oMessage) { - return oMessage.uid; - }); - } - - if (0 < aCheckedUids.length && -1 < Utils.inArray(oCurrentMessage.uid, aCheckedUids)) - { - this.setAction(oCurrentMessage.folderFullNameRaw, oCurrentMessage.flagged() ? - Enums.MessageSetAction.UnsetFlag : Enums.MessageSetAction.SetFlag, aChecked); - } - else - { - this.setAction(oCurrentMessage.folderFullNameRaw, oCurrentMessage.flagged() ? - Enums.MessageSetAction.UnsetFlag : Enums.MessageSetAction.SetFlag, [oCurrentMessage]); - } - } -}; - -MailBoxMessageListViewModel.prototype.flagMessagesFast = function (bFlag) -{ - var - aChecked = this.messageListCheckedOrSelected(), - aFlagged = [] - ; - - if (0 < aChecked.length) - { - aFlagged = _.filter(aChecked, function (oMessage) { - return oMessage.flagged(); - }); - - if (Utils.isUnd(bFlag)) - { - this.setAction(aChecked[0].folderFullNameRaw, - aChecked.length === aFlagged.length ? Enums.MessageSetAction.UnsetFlag : Enums.MessageSetAction.SetFlag, aChecked); - } - else - { - this.setAction(aChecked[0].folderFullNameRaw, - !bFlag ? Enums.MessageSetAction.UnsetFlag : Enums.MessageSetAction.SetFlag, aChecked); - } - } -}; - -MailBoxMessageListViewModel.prototype.seenMessagesFast = function (bSeen) -{ - var - aChecked = this.messageListCheckedOrSelected(), - aUnseen = [] - ; - - if (0 < aChecked.length) - { - aUnseen = _.filter(aChecked, function (oMessage) { - return oMessage.unseen(); - }); - - if (Utils.isUnd(bSeen)) - { - this.setAction(aChecked[0].folderFullNameRaw, - 0 < aUnseen.length ? Enums.MessageSetAction.SetSeen : Enums.MessageSetAction.UnsetSeen, aChecked); - } - else - { - this.setAction(aChecked[0].folderFullNameRaw, - bSeen ? Enums.MessageSetAction.SetSeen : Enums.MessageSetAction.UnsetSeen, aChecked); - } - } -}; - -MailBoxMessageListViewModel.prototype.onBuild = function (oDom) -{ - var - self = this, - oData = RL.data() - ; - - this.oContentVisible = $('.b-content', oDom); - this.oContentScrollable = $('.content', this.oContentVisible); - - this.oContentVisible.on('click', '.fullThreadHandle', function () { var - aList = [], - oMessage = ko.dataFor(this) + oFolder = null, + aMessages = RL.data().messageList() ; - if (oMessage && !oMessage.lastInCollapsedThreadLoading()) + if ('' !== sFolderFullNameRaw) { - RL.data().messageListThreadFolder(oMessage.folderFullNameRaw); + oFolder = Cache.getFolderFromCacheList(sFolderFullNameRaw); - aList = RL.data().messageListThreadUids(); - - if (oMessage.lastInCollapsedThread()) + if (oFolder) { - aList.push(0 < oMessage.parentUid() ? oMessage.parentUid() : oMessage.uid); + switch (iSetAction) { + case Enums.MessageSetAction.SetSeen: + oFolder = Cache.getFolderFromCacheList(sFolderFullNameRaw); + if (oFolder) + { + _.each(aMessages, function (oMessage) { + oMessage.unseen(false); + }); + + oFolder.messageCountUnread(0); + Cache.clearMessageFlagsFromCacheByFolder(sFolderFullNameRaw); + } + + Remote.messageSetSeenToAll(Utils.emptyFunction, sFolderFullNameRaw, true); + break; + case Enums.MessageSetAction.UnsetSeen: + oFolder = Cache.getFolderFromCacheList(sFolderFullNameRaw); + if (oFolder) + { + _.each(aMessages, function (oMessage) { + oMessage.unseen(true); + }); + + oFolder.messageCountUnread(oFolder.messageCountAll()); + Cache.clearMessageFlagsFromCacheByFolder(sFolderFullNameRaw); + } + Remote.messageSetSeenToAll(Utils.emptyFunction, sFolderFullNameRaw, false); + break; + } + + RL.reloadFlagsCurrentMessageListAndMessageFromCache(); + } + } + }; + + MailBoxMessageListViewModel.prototype.listSetSeen = function () + { + this.setAction(RL.data().currentFolderFullNameRaw(), Enums.MessageSetAction.SetSeen, RL.data().messageListCheckedOrSelected()); + }; + + MailBoxMessageListViewModel.prototype.listSetAllSeen = function () + { + this.setActionForAll(RL.data().currentFolderFullNameRaw(), Enums.MessageSetAction.SetSeen); + }; + + MailBoxMessageListViewModel.prototype.listUnsetSeen = function () + { + this.setAction(RL.data().currentFolderFullNameRaw(), Enums.MessageSetAction.UnsetSeen, RL.data().messageListCheckedOrSelected()); + }; + + MailBoxMessageListViewModel.prototype.listSetFlags = function () + { + this.setAction(RL.data().currentFolderFullNameRaw(), Enums.MessageSetAction.SetFlag, RL.data().messageListCheckedOrSelected()); + }; + + MailBoxMessageListViewModel.prototype.listUnsetFlags = function () + { + this.setAction(RL.data().currentFolderFullNameRaw(), Enums.MessageSetAction.UnsetFlag, RL.data().messageListCheckedOrSelected()); + }; + + MailBoxMessageListViewModel.prototype.flagMessages = function (oCurrentMessage) + { + var + aChecked = this.messageListCheckedOrSelected(), + aCheckedUids = [] + ; + + if (oCurrentMessage) + { + if (0 < aChecked.length) + { + aCheckedUids = _.map(aChecked, function (oMessage) { + return oMessage.uid; + }); + } + + if (0 < aCheckedUids.length && -1 < Utils.inArray(oCurrentMessage.uid, aCheckedUids)) + { + this.setAction(oCurrentMessage.folderFullNameRaw, oCurrentMessage.flagged() ? + Enums.MessageSetAction.UnsetFlag : Enums.MessageSetAction.SetFlag, aChecked); } else { - aList = _.without(aList, 0 < oMessage.parentUid() ? oMessage.parentUid() : oMessage.uid); + this.setAction(oCurrentMessage.folderFullNameRaw, oCurrentMessage.flagged() ? + Enums.MessageSetAction.UnsetFlag : Enums.MessageSetAction.SetFlag, [oCurrentMessage]); } - - RL.data().messageListThreadUids(_.uniq(aList)); - - oMessage.lastInCollapsedThreadLoading(true); - oMessage.lastInCollapsedThread(!oMessage.lastInCollapsedThread()); - RL.reloadMessageList(); } + }; - return false; - }); - - this.selector.init(this.oContentVisible, this.oContentScrollable, Enums.KeyState.MessageList); - - oDom - .on('click', '.messageList .b-message-list-wrapper', function () { - if (self.message.focused()) - { - self.message.focused(false); - } - }) - .on('click', '.e-pagenator .e-page', function () { - var oPage = ko.dataFor(this); - if (oPage) - { - kn.setHash(RL.link().mailBox( - oData.currentFolderFullNameHash(), - oPage.value, - oData.messageListSearch() - )); - } - }) - .on('click', '.messageList .checkboxCkeckAll', function () { - self.checkAll(!self.checkAll()); - }) - .on('click', '.messageList .messageListItem .flagParent', function () { - self.flagMessages(ko.dataFor(this)); - }) - ; - - this.initUploaderForAppend(); - this.initShortcuts(); - - if (!Globals.bMobileDevice && RL.capa(Enums.Capa.Prefetch) && ifvisible) + MailBoxMessageListViewModel.prototype.flagMessagesFast = function (bFlag) { - ifvisible.setIdleDuration(10); + var + aChecked = this.messageListCheckedOrSelected(), + aFlagged = [] + ; - ifvisible.idle(function () { - self.prefetchNextTick(); - }); - } -}; - -MailBoxMessageListViewModel.prototype.initShortcuts = function () -{ - var self = this; - - // disable print - key('ctrl+p, command+p', Enums.KeyState.MessageList, function () { - return false; - }); - - // archive (zip) - key('z', [Enums.KeyState.MessageList, Enums.KeyState.MessageView], function () { - self.archiveCommand(); - return false; - }); - - // delete - key('delete, shift+delete, shift+3', Enums.KeyState.MessageList, function (event, handler) { - if (event) + if (0 < aChecked.length) { - if (0 < RL.data().messageListCheckedOrSelected().length) + aFlagged = _.filter(aChecked, function (oMessage) { + return oMessage.flagged(); + }); + + if (Utils.isUnd(bFlag)) { - if (handler && 'shift+delete' === handler.shortcut) - { - self.deleteWithoutMoveCommand(); - } - else - { - self.deleteCommand(); - } + this.setAction(aChecked[0].folderFullNameRaw, + aChecked.length === aFlagged.length ? Enums.MessageSetAction.UnsetFlag : Enums.MessageSetAction.SetFlag, aChecked); + } + else + { + this.setAction(aChecked[0].folderFullNameRaw, + !bFlag ? Enums.MessageSetAction.UnsetFlag : Enums.MessageSetAction.SetFlag, aChecked); } - - return false; } - }); + }; - // check mail - key('ctrl+r, command+r', [Enums.KeyState.FolderList, Enums.KeyState.MessageList, Enums.KeyState.MessageView], function () { - self.reloadCommand(); - return false; - }); + MailBoxMessageListViewModel.prototype.seenMessagesFast = function (bSeen) + { + var + aChecked = this.messageListCheckedOrSelected(), + aUnseen = [] + ; - // check all - key('ctrl+a, command+a', Enums.KeyState.MessageList, function () { - self.checkAll(!(self.checkAll() && !self.isIncompleteChecked())); - return false; - }); - - // write/compose (open compose popup) - key('w,c', [Enums.KeyState.MessageList, Enums.KeyState.MessageView], function () { - kn.showScreenPopup(PopupsComposeViewModel); - return false; - }); - - // important - star/flag messages - key('i', [Enums.KeyState.MessageList, Enums.KeyState.MessageView], function () { - self.flagMessagesFast(); - return false; - }); - - // move - key('m', Enums.KeyState.MessageList, function () { - self.moveDropdownTrigger(true); - return false; - }); - - // read - key('q', [Enums.KeyState.MessageList, Enums.KeyState.MessageView], function () { - self.seenMessagesFast(true); - return false; - }); - - // unread - key('u', [Enums.KeyState.MessageList, Enums.KeyState.MessageView], function () { - self.seenMessagesFast(false); - return false; - }); - - key('shift+f', [Enums.KeyState.MessageList, Enums.KeyState.MessageView], function () { - self.multyForwardCommand(); - return false; - }); - - // search input focus - key('/', [Enums.KeyState.MessageList, Enums.KeyState.MessageView], function () { - self.inputMessageListSearchFocus(true); - return false; - }); - - // cancel search - key('esc', Enums.KeyState.MessageList, function () { - if ('' !== self.messageListSearchDesc()) + if (0 < aChecked.length) { - self.cancelSearch(); - return false; + aUnseen = _.filter(aChecked, function (oMessage) { + return oMessage.unseen(); + }); + + if (Utils.isUnd(bSeen)) + { + this.setAction(aChecked[0].folderFullNameRaw, + 0 < aUnseen.length ? Enums.MessageSetAction.SetSeen : Enums.MessageSetAction.UnsetSeen, aChecked); + } + else + { + this.setAction(aChecked[0].folderFullNameRaw, + bSeen ? Enums.MessageSetAction.SetSeen : Enums.MessageSetAction.UnsetSeen, aChecked); + } } - }); + }; - // change focused state - key('tab, shift+tab, left, right', Enums.KeyState.MessageList, function (event, handler) { - if (event && handler && 'shift+tab' === handler.shortcut || 'left' === handler.shortcut) - { - self.folderList.focused(true); - } - else if (self.message()) - { - self.message.focused(true); - } - - return false; - }); - - // TODO - key('ctrl+left, command+left', Enums.KeyState.MessageView, function () { - return false; - }); - - // TODO - key('ctrl+right, command+right', Enums.KeyState.MessageView, function () { - return false; - }); -}; - -MailBoxMessageListViewModel.prototype.prefetchNextTick = function () -{ - if (!this.bPrefetch && !ifvisible.now() && this.viewModelVisibility()) + MailBoxMessageListViewModel.prototype.onBuild = function (oDom) { var self = this, - oCache = RL.cache(), - oMessage = _.find(this.messageList(), function (oMessage) { - return oMessage && - !oCache.hasRequestedMessage(oMessage.folderFullNameRaw, oMessage.uid); - }) + oData = RL.data() ; - if (oMessage) - { - this.bPrefetch = true; + this.oContentVisible = $('.b-content', oDom); + this.oContentScrollable = $('.content', this.oContentVisible); - RL.cache().addRequestedMessage(oMessage.folderFullNameRaw, oMessage.uid); + this.oContentVisible.on('click', '.fullThreadHandle', function () { + var + aList = [], + oMessage = ko.dataFor(this) + ; - RL.remote().message(function (sResult, oData) { - - var bNext = !!(Enums.StorageResultType.Success === sResult && oData && oData.Result); - - _.delay(function () { - self.bPrefetch = false; - if (bNext) - { - self.prefetchNextTick(); - } - }, 1000); - - }, oMessage.folderFullNameRaw, oMessage.uid); - } - } -}; - -MailBoxMessageListViewModel.prototype.composeClick = function () -{ - kn.showScreenPopup(PopupsComposeViewModel); -}; - -MailBoxMessageListViewModel.prototype.advancedSearchClick = function () -{ - kn.showScreenPopup(PopupsAdvancedSearchViewModel); -}; - -MailBoxMessageListViewModel.prototype.quotaTooltip = function () -{ - return Utils.i18n('MESSAGE_LIST/QUOTA_SIZE', { - 'SIZE': Utils.friendlySize(this.userUsageSize()), - 'PROC': this.userUsageProc(), - 'LIMIT': Utils.friendlySize(this.userQuota()) - }); -}; - -MailBoxMessageListViewModel.prototype.initUploaderForAppend = function () -{ - if (!RL.settingsGet('AllowAppendMessage') || !this.dragOverArea()) - { - return false; - } - - var oJua = new Jua({ - 'action': RL.link().append(), - 'name': 'AppendFile', - 'queueSize': 1, - 'multipleSizeLimit': 1, - 'disableFolderDragAndDrop': true, - 'hidden': { - 'Folder': function () { - return RL.data().currentFolderFullNameRaw(); - } - }, - 'dragAndDropElement': this.dragOverArea(), - 'dragAndDropBodyElement': this.dragOverBodyArea() - }); - - oJua - .on('onDragEnter', _.bind(function () { - this.dragOverEnter(true); - }, this)) - .on('onDragLeave', _.bind(function () { - this.dragOverEnter(false); - }, this)) - .on('onBodyDragEnter', _.bind(function () { - this.dragOver(true); - }, this)) - .on('onBodyDragLeave', _.bind(function () { - this.dragOver(false); - }, this)) - .on('onSelect', _.bind(function (sUid, oData) { - if (sUid && oData && 'message/rfc822' === oData['Type']) + if (oMessage && !oMessage.lastInCollapsedThreadLoading()) { - RL.data().messageListLoading(true); - return true; + RL.data().messageListThreadFolder(oMessage.folderFullNameRaw); + + aList = RL.data().messageListThreadUids(); + + if (oMessage.lastInCollapsedThread()) + { + aList.push(0 < oMessage.parentUid() ? oMessage.parentUid() : oMessage.uid); + } + else + { + aList = _.without(aList, 0 < oMessage.parentUid() ? oMessage.parentUid() : oMessage.uid); + } + + RL.data().messageListThreadUids(_.uniq(aList)); + + oMessage.lastInCollapsedThreadLoading(true); + oMessage.lastInCollapsedThread(!oMessage.lastInCollapsedThread()); + RL.reloadMessageList(); } return false; - }, this)) - .on('onComplete', _.bind(function () { - RL.reloadMessageList(true, true); - }, this)) - ; + }); - return !!oJua; -}; \ No newline at end of file + this.selector.init(this.oContentVisible, this.oContentScrollable, Enums.KeyState.MessageList); + + oDom + .on('click', '.messageList .b-message-list-wrapper', function () { + if (self.message.focused()) + { + self.message.focused(false); + } + }) + .on('click', '.e-pagenator .e-page', function () { + var oPage = ko.dataFor(this); + if (oPage) + { + kn.setHash(LinkBuilder.mailBox( + oData.currentFolderFullNameHash(), + oPage.value, + oData.messageListSearch() + )); + } + }) + .on('click', '.messageList .checkboxCkeckAll', function () { + self.checkAll(!self.checkAll()); + }) + .on('click', '.messageList .messageListItem .flagParent', function () { + self.flagMessages(ko.dataFor(this)); + }) + ; + + this.initUploaderForAppend(); + this.initShortcuts(); + + if (!Globals.bMobileDevice && RL.capa(Enums.Capa.Prefetch) && ifvisible) + { + ifvisible.setIdleDuration(10); + + ifvisible.idle(function () { + self.prefetchNextTick(); + }); + } + }; + + MailBoxMessageListViewModel.prototype.initShortcuts = function () + { + var self = this; + + // disable print + key('ctrl+p, command+p', Enums.KeyState.MessageList, function () { + return false; + }); + + // archive (zip) + key('z', [Enums.KeyState.MessageList, Enums.KeyState.MessageView], function () { + self.archiveCommand(); + return false; + }); + + // delete + key('delete, shift+delete, shift+3', Enums.KeyState.MessageList, function (event, handler) { + if (event) + { + if (0 < RL.data().messageListCheckedOrSelected().length) + { + if (handler && 'shift+delete' === handler.shortcut) + { + self.deleteWithoutMoveCommand(); + } + else + { + self.deleteCommand(); + } + } + + return false; + } + }); + + // check mail + key('ctrl+r, command+r', [Enums.KeyState.FolderList, Enums.KeyState.MessageList, Enums.KeyState.MessageView], function () { + self.reloadCommand(); + return false; + }); + + // check all + key('ctrl+a, command+a', Enums.KeyState.MessageList, function () { + self.checkAll(!(self.checkAll() && !self.isIncompleteChecked())); + return false; + }); + + // write/compose (open compose popup) + key('w,c', [Enums.KeyState.MessageList, Enums.KeyState.MessageView], function () { + kn.showScreenPopup(PopupsComposeViewModel); + return false; + }); + + // important - star/flag messages + key('i', [Enums.KeyState.MessageList, Enums.KeyState.MessageView], function () { + self.flagMessagesFast(); + return false; + }); + + // move + key('m', Enums.KeyState.MessageList, function () { + self.moveDropdownTrigger(true); + return false; + }); + + // read + key('q', [Enums.KeyState.MessageList, Enums.KeyState.MessageView], function () { + self.seenMessagesFast(true); + return false; + }); + + // unread + key('u', [Enums.KeyState.MessageList, Enums.KeyState.MessageView], function () { + self.seenMessagesFast(false); + return false; + }); + + key('shift+f', [Enums.KeyState.MessageList, Enums.KeyState.MessageView], function () { + self.multyForwardCommand(); + return false; + }); + + // search input focus + key('/', [Enums.KeyState.MessageList, Enums.KeyState.MessageView], function () { + self.inputMessageListSearchFocus(true); + return false; + }); + + // cancel search + key('esc', Enums.KeyState.MessageList, function () { + if ('' !== self.messageListSearchDesc()) + { + self.cancelSearch(); + return false; + } + }); + + // change focused state + key('tab, shift+tab, left, right', Enums.KeyState.MessageList, function (event, handler) { + if (event && handler && 'shift+tab' === handler.shortcut || 'left' === handler.shortcut) + { + self.folderList.focused(true); + } + else if (self.message()) + { + self.message.focused(true); + } + + return false; + }); + + // TODO + key('ctrl+left, command+left', Enums.KeyState.MessageView, function () { + return false; + }); + + // TODO + key('ctrl+right, command+right', Enums.KeyState.MessageView, function () { + return false; + }); + }; + + MailBoxMessageListViewModel.prototype.prefetchNextTick = function () + { + if (!this.bPrefetch && !ifvisible.now() && this.viewModelVisibility()) + { + var + self = this, + oMessage = _.find(this.messageList(), function (oMessage) { + return oMessage && + !Cache.hasRequestedMessage(oMessage.folderFullNameRaw, oMessage.uid); + }) + ; + + if (oMessage) + { + this.bPrefetch = true; + + Cache.addRequestedMessage(oMessage.folderFullNameRaw, oMessage.uid); + + Remote.message(function (sResult, oData) { + + var bNext = !!(Enums.StorageResultType.Success === sResult && oData && oData.Result); + + _.delay(function () { + self.bPrefetch = false; + if (bNext) + { + self.prefetchNextTick(); + } + }, 1000); + + }, oMessage.folderFullNameRaw, oMessage.uid); + } + } + }; + + MailBoxMessageListViewModel.prototype.composeClick = function () + { + kn.showScreenPopup(PopupsComposeViewModel); + }; + + MailBoxMessageListViewModel.prototype.advancedSearchClick = function () + { + kn.showScreenPopup(PopupsAdvancedSearchViewModel); + }; + + MailBoxMessageListViewModel.prototype.quotaTooltip = function () + { + return Utils.i18n('MESSAGE_LIST/QUOTA_SIZE', { + 'SIZE': Utils.friendlySize(this.userUsageSize()), + 'PROC': this.userUsageProc(), + 'LIMIT': Utils.friendlySize(this.userQuota()) + }); + }; + + MailBoxMessageListViewModel.prototype.initUploaderForAppend = function () + { + if (!RL.settingsGet('AllowAppendMessage') || !this.dragOverArea()) + { + return false; + } + + var oJua = new Jua({ + 'action': LinkBuilder.append(), + 'name': 'AppendFile', + 'queueSize': 1, + 'multipleSizeLimit': 1, + 'disableFolderDragAndDrop': true, + 'hidden': { + 'Folder': function () { + return RL.data().currentFolderFullNameRaw(); + } + }, + 'dragAndDropElement': this.dragOverArea(), + 'dragAndDropBodyElement': this.dragOverBodyArea() + }); + + oJua + .on('onDragEnter', _.bind(function () { + this.dragOverEnter(true); + }, this)) + .on('onDragLeave', _.bind(function () { + this.dragOverEnter(false); + }, this)) + .on('onBodyDragEnter', _.bind(function () { + this.dragOver(true); + }, this)) + .on('onBodyDragLeave', _.bind(function () { + this.dragOver(false); + }, this)) + .on('onSelect', _.bind(function (sUid, oData) { + if (sUid && oData && 'message/rfc822' === oData['Type']) + { + RL.data().messageListLoading(true); + return true; + } + + return false; + }, this)) + .on('onComplete', _.bind(function () { + RL.reloadMessageList(true, true); + }, this)) + ; + + return !!oJua; + }; + + module.exports = new MailBoxMessageListViewModel(); + +}(module)); diff --git a/dev/ViewModels/MailBoxMessageViewViewModel.js b/dev/ViewModels/MailBoxMessageViewViewModel.js index 02f59df50..42da72d63 100644 --- a/dev/ViewModels/MailBoxMessageViewViewModel.js +++ b/dev/ViewModels/MailBoxMessageViewViewModel.js @@ -8,9 +8,14 @@ ko = require('../External/ko.js'), key = require('../External/key.js'), $html = require('../External/$html.js'), + Consts = require('../Common/Consts.js'), Enums = require('../Common/Enums.js'), Utils = require('../Common/Utils.js'), + + Cache = require('../Storages/WebMailCacheStorage.js'), + Remote = require('../Storages/WebMailAjaxRemoteStorage.js'), + kn = require('../Knoin/Knoin.js'), KnoinAbstractViewModel = require('../Knoin/KnoinAbstractViewModel.js') ; @@ -188,7 +193,7 @@ this.viewDownloadLink(oMessage.downloadLink()); sLastEmail = oMessage.fromAsSingleEmail(); - RL.cache().getUserPic(sLastEmail, function (sPic, $sEmail) { + Cache.getUserPic(sLastEmail, function (sPic, $sEmail) { if (sPic !== self.viewUserPic() && sLastEmail === $sEmail) { self.viewUserPicVisible(false); @@ -240,7 +245,7 @@ kn.constructorEnd(this); } - Utils.extendAsViewModel('MailBoxMessageViewViewModel', MailBoxMessageViewViewModel); + kn.extendAsViewModel('MailBoxMessageViewViewModel', MailBoxMessageViewViewModel); MailBoxMessageViewViewModel.prototype.isPgpActionVisible = function () { @@ -695,14 +700,14 @@ { if (oMessage && '' !== oMessage.readReceipt()) { - RL.remote().sendReadReceiptMessage(Utils.emptyFunction, oMessage.folderFullNameRaw, oMessage.uid, + Remote.sendReadReceiptMessage(Utils.emptyFunction, oMessage.folderFullNameRaw, oMessage.uid, oMessage.readReceipt(), Utils.i18n('READ_RECEIPT/SUBJECT', {'SUBJECT': oMessage.subject()}), Utils.i18n('READ_RECEIPT/BODY', {'READ-RECEIPT': RL.data().accountEmail()})); oMessage.isReadReceipt(true); - RL.cache().storeMessageFlagsToCache(oMessage); + Cache.storeMessageFlagsToCache(oMessage); RL.reloadFlagsCurrentMessageListAndMessageFromCache(); } }; diff --git a/dev/ViewModels/MailBoxSystemDropDownViewModel.js b/dev/ViewModels/MailBoxSystemDropDownViewModel.js index 0ed5aa0bf..f520a7fa8 100644 --- a/dev/ViewModels/MailBoxSystemDropDownViewModel.js +++ b/dev/ViewModels/MailBoxSystemDropDownViewModel.js @@ -20,7 +20,7 @@ kn.constructorEnd(this); } - Utils.extendAsViewModel('MailBoxSystemDropDownViewModel', MailBoxSystemDropDownViewModel, AbstractSystemDropDownViewModel); + kn.extendAsViewModel('MailBoxSystemDropDownViewModel', MailBoxSystemDropDownViewModel, AbstractSystemDropDownViewModel); module.exports = MailBoxSystemDropDownViewModel; diff --git a/dev/ViewModels/Popups/PopupsActivateViewModel.js b/dev/ViewModels/Popups/PopupsActivateViewModel.js index d81770d9e..c24a4355a 100644 --- a/dev/ViewModels/Popups/PopupsActivateViewModel.js +++ b/dev/ViewModels/Popups/PopupsActivateViewModel.js @@ -1,118 +1,138 @@ /* RainLoop Webmail (c) RainLoop Team | Licensed under CC BY-NC-SA 3.0 */ -/** - * @constructor - * @extends KnoinAbstractViewModel - */ -function PopupsActivateViewModel() -{ - KnoinAbstractViewModel.call(this, 'Popups', 'PopupsActivate'); +(function (module) { - var self = this; + 'use strict'; - this.domain = ko.observable(''); - this.key = ko.observable(''); - this.key.focus = ko.observable(false); - this.activationSuccessed = ko.observable(false); + var + ko = require('../../External/ko.js'), + Enums = require('../../Common/Enums.js'), + Utils = require('../../Common/Utils.js'), - this.licenseTrigger = RL.data().licenseTrigger; - - this.activateProcess = ko.observable(false); - this.activateText = ko.observable(''); - this.activateText.isError = ko.observable(false); + Data = require('../../Storages/AdminDataStorage.js'), + Remote = require('../../Storages/AdminAjaxRemoteStorage.js'), + + kn = require('../../Knoin/Knoin.js'), + KnoinAbstractViewModel = require('../../Knoin/KnoinAbstractViewModel.js') + ; - this.key.subscribe(function () { - this.activateText(''); - this.activateText.isError(false); - }, this); + /** + * @constructor + * @extends KnoinAbstractViewModel + */ + function PopupsActivateViewModel() + { + KnoinAbstractViewModel.call(this, 'Popups', 'PopupsActivate'); - this.activationSuccessed.subscribe(function (bValue) { - if (bValue) - { - this.licenseTrigger(!this.licenseTrigger()); - } - }, this); + var self = this; - this.activateCommand = Utils.createCommand(this, function () { + this.domain = ko.observable(''); + this.key = ko.observable(''); + this.key.focus = ko.observable(false); + this.activationSuccessed = ko.observable(false); - this.activateProcess(true); - if (this.validateSubscriptionKey()) - { - RL.remote().licensingActivate(function (sResult, oData) { + this.licenseTrigger = Data.licenseTrigger; - self.activateProcess(false); - if (Enums.StorageResultType.Success === sResult && oData.Result) - { - if (true === oData.Result) + this.activateProcess = ko.observable(false); + this.activateText = ko.observable(''); + this.activateText.isError = ko.observable(false); + + this.key.subscribe(function () { + this.activateText(''); + this.activateText.isError(false); + }, this); + + this.activationSuccessed.subscribe(function (bValue) { + if (bValue) + { + this.licenseTrigger(!this.licenseTrigger()); + } + }, this); + + this.activateCommand = Utils.createCommand(this, function () { + + this.activateProcess(true); + if (this.validateSubscriptionKey()) + { + Remote.licensingActivate(function (sResult, oData) { + + self.activateProcess(false); + if (Enums.StorageResultType.Success === sResult && oData.Result) { - self.activationSuccessed(true); - self.activateText('Subscription Key Activated Successfully'); - self.activateText.isError(false); + if (true === oData.Result) + { + self.activationSuccessed(true); + self.activateText('Subscription Key Activated Successfully'); + self.activateText.isError(false); + } + else + { + self.activateText(oData.Result); + self.activateText.isError(true); + self.key.focus(true); + } } - else + else if (oData.ErrorCode) { - self.activateText(oData.Result); + self.activateText(Utils.getNotification(oData.ErrorCode)); + self.activateText.isError(true); + self.key.focus(true); + } + else + { + self.activateText(Utils.getNotification(Enums.Notification.UnknownError)); self.activateText.isError(true); self.key.focus(true); } - } - else if (oData.ErrorCode) - { - self.activateText(Utils.getNotification(oData.ErrorCode)); - self.activateText.isError(true); - self.key.focus(true); - } - else - { - self.activateText(Utils.getNotification(Enums.Notification.UnknownError)); - self.activateText.isError(true); - self.key.focus(true); - } - }, this.domain(), this.key()); - } - else + }, this.domain(), this.key()); + } + else + { + this.activateProcess(false); + this.activateText('Invalid Subscription Key'); + this.activateText.isError(true); + this.key.focus(true); + } + + }, function () { + return !this.activateProcess() && '' !== this.domain() && '' !== this.key() && !this.activationSuccessed(); + }); + + kn.constructorEnd(this); + } + + kn.extendAsViewModel('PopupsActivateViewModel', PopupsActivateViewModel); + + PopupsActivateViewModel.prototype.onShow = function () + { + this.domain(RL.settingsGet('AdminDomain')); + if (!this.activateProcess()) + { + this.key(''); + this.activateText(''); + this.activateText.isError(false); + this.activationSuccessed(false); + } + }; + + PopupsActivateViewModel.prototype.onFocus = function () + { + if (!this.activateProcess()) { - this.activateProcess(false); - this.activateText('Invalid Subscription Key'); - this.activateText.isError(true); this.key.focus(true); } + }; - }, function () { - return !this.activateProcess() && '' !== this.domain() && '' !== this.key() && !this.activationSuccessed(); - }); - - Knoin.constructorEnd(this); -} - -Utils.extendAsViewModel('PopupsActivateViewModel', PopupsActivateViewModel); - -PopupsActivateViewModel.prototype.onShow = function () -{ - this.domain(RL.settingsGet('AdminDomain')); - if (!this.activateProcess()) + /** + * @returns {boolean} + */ + PopupsActivateViewModel.prototype.validateSubscriptionKey = function () { - this.key(''); - this.activateText(''); - this.activateText.isError(false); - this.activationSuccessed(false); - } -}; + var sValue = this.key(); + return '' === sValue || !!/^RL[\d]+-[A-Z0-9\-]+Z$/.test(Utils.trim(sValue)); + }; + + module.exports = new PopupsActivateViewModel(); -PopupsActivateViewModel.prototype.onFocus = function () -{ - if (!this.activateProcess()) - { - this.key.focus(true); - } -}; - -/** - * @returns {boolean} - */ -PopupsActivateViewModel.prototype.validateSubscriptionKey = function () -{ - var sValue = this.key(); - return '' === sValue || !!/^RL[\d]+-[A-Z0-9\-]+Z$/.test(Utils.trim(sValue)); -}; \ No newline at end of file +}(module)); \ No newline at end of file diff --git a/dev/ViewModels/Popups/PopupsAddAccountViewModel.js b/dev/ViewModels/Popups/PopupsAddAccountViewModel.js index 83e364010..4882f62ee 100644 --- a/dev/ViewModels/Popups/PopupsAddAccountViewModel.js +++ b/dev/ViewModels/Popups/PopupsAddAccountViewModel.js @@ -1,95 +1,115 @@ /* RainLoop Webmail (c) RainLoop Team | Licensed under CC BY-NC-SA 3.0 */ -/** - * @constructor - * @extends KnoinAbstractViewModel - */ -function PopupsAddAccountViewModel() -{ - KnoinAbstractViewModel.call(this, 'Popups', 'PopupsAddAccount'); +(function (module) { - this.email = ko.observable(''); - this.password = ko.observable(''); + 'use strict'; - this.emailError = ko.observable(false); - this.passwordError = ko.observable(false); + var + ko = require('../../External/ko.js'), + + Enums = require('../../Common/Enums.js'), + Utils = require('../../Common/Utils.js'), + + Remote = require('../../Storages/WebMailAjaxRemoteStorage.js'), + + kn = require('../../Knoin/Knoin.js'), + KnoinAbstractViewModel = require('../../Knoin/KnoinAbstractViewModel.js') + ; + + /** + * @constructor + * @extends KnoinAbstractViewModel + */ + function PopupsAddAccountViewModel() + { + KnoinAbstractViewModel.call(this, 'Popups', 'PopupsAddAccount'); + + this.email = ko.observable(''); + this.password = ko.observable(''); + + this.emailError = ko.observable(false); + this.passwordError = ko.observable(false); + + this.email.subscribe(function () { + this.emailError(false); + }, this); + + this.password.subscribe(function () { + this.passwordError(false); + }, this); + + this.submitRequest = ko.observable(false); + this.submitError = ko.observable(''); + + this.emailFocus = ko.observable(false); + + this.addAccountCommand = Utils.createCommand(this, function () { + + this.emailError('' === Utils.trim(this.email())); + this.passwordError('' === Utils.trim(this.password())); + + if (this.emailError() || this.passwordError()) + { + return false; + } + + this.submitRequest(true); + + Remote.accountAdd(_.bind(function (sResult, oData) { + + this.submitRequest(false); + if (Enums.StorageResultType.Success === sResult && oData && 'AccountAdd' === oData.Action) + { + if (oData.Result) + { + RL.accountsAndIdentities(); + this.cancelCommand(); + } + else if (oData.ErrorCode) + { + this.submitError(Utils.getNotification(oData.ErrorCode)); + } + } + else + { + this.submitError(Utils.getNotification(Enums.Notification.UnknownError)); + } + + }, this), this.email(), '', this.password()); + + return true; + + }, function () { + return !this.submitRequest(); + }); + + kn.constructorEnd(this); + } + + kn.extendAsViewModel('PopupsAddAccountViewModel', PopupsAddAccountViewModel); + + PopupsAddAccountViewModel.prototype.clearPopup = function () + { + this.email(''); + this.password(''); - this.email.subscribe(function () { this.emailError(false); - }, this); - - this.password.subscribe(function () { this.passwordError(false); - }, this); - this.submitRequest = ko.observable(false); - this.submitError = ko.observable(''); + this.submitRequest(false); + this.submitError(''); + }; - this.emailFocus = ko.observable(false); + PopupsAddAccountViewModel.prototype.onShow = function () + { + this.clearPopup(); + }; - this.addAccountCommand = Utils.createCommand(this, function () { + PopupsAddAccountViewModel.prototype.onFocus = function () + { + this.emailFocus(true); + }; - this.emailError('' === Utils.trim(this.email())); - this.passwordError('' === Utils.trim(this.password())); + module.exports = new PopupsAddAccountViewModel(); - if (this.emailError() || this.passwordError()) - { - return false; - } - - this.submitRequest(true); - - RL.remote().accountAdd(_.bind(function (sResult, oData) { - - this.submitRequest(false); - if (Enums.StorageResultType.Success === sResult && oData && 'AccountAdd' === oData.Action) - { - if (oData.Result) - { - RL.accountsAndIdentities(); - this.cancelCommand(); - } - else if (oData.ErrorCode) - { - this.submitError(Utils.getNotification(oData.ErrorCode)); - } - } - else - { - this.submitError(Utils.getNotification(Enums.Notification.UnknownError)); - } - - }, this), this.email(), '', this.password()); - - return true; - - }, function () { - return !this.submitRequest(); - }); - - Knoin.constructorEnd(this); -} - -Utils.extendAsViewModel('PopupsAddAccountViewModel', PopupsAddAccountViewModel); - -PopupsAddAccountViewModel.prototype.clearPopup = function () -{ - this.email(''); - this.password(''); - - this.emailError(false); - this.passwordError(false); - - this.submitRequest(false); - this.submitError(''); -}; - -PopupsAddAccountViewModel.prototype.onShow = function () -{ - this.clearPopup(); -}; - -PopupsAddAccountViewModel.prototype.onFocus = function () -{ - this.emailFocus(true); -}; +}(module)); \ No newline at end of file diff --git a/dev/ViewModels/Popups/PopupsAddOpenPgpKeyViewModel.js b/dev/ViewModels/Popups/PopupsAddOpenPgpKeyViewModel.js index 30049d829..fccb0a134 100644 --- a/dev/ViewModels/Popups/PopupsAddOpenPgpKeyViewModel.js +++ b/dev/ViewModels/Popups/PopupsAddOpenPgpKeyViewModel.js @@ -1,90 +1,109 @@ /* RainLoop Webmail (c) RainLoop Team | Licensed under CC BY-NC-SA 3.0 */ -/** - * @constructor - * @extends KnoinAbstractViewModel - */ -function PopupsAddOpenPgpKeyViewModel() -{ - KnoinAbstractViewModel.call(this, 'Popups', 'PopupsAddOpenPgpKey'); +(function (module) { - this.key = ko.observable(''); - this.key.error = ko.observable(false); - this.key.focus = ko.observable(false); + 'use strict'; - this.key.subscribe(function () { + var + ko = require('../../External/ko.js'), + + Utils = require('../../Common/Utils.js'), + + Data = require('../../Storages/WebMailDataStorage.js'), + + kn = require('../../Knoin/Knoin.js'), + KnoinAbstractViewModel = require('../../Knoin/KnoinAbstractViewModel.js') + ; + + /** + * @constructor + * @extends KnoinAbstractViewModel + */ + function PopupsAddOpenPgpKeyViewModel() + { + KnoinAbstractViewModel.call(this, 'Popups', 'PopupsAddOpenPgpKey'); + + this.key = ko.observable(''); + this.key.error = ko.observable(false); + this.key.focus = ko.observable(false); + + this.key.subscribe(function () { + this.key.error(false); + }, this); + + this.addOpenPgpKeyCommand = Utils.createCommand(this, function () { + + var + iCount = 30, + aMatch = null, + sKey = Utils.trim(this.key()), + oReg = /[\-]{3,6}BEGIN[\s]PGP[\s](PRIVATE|PUBLIC)[\s]KEY[\s]BLOCK[\-]{3,6}[\s\S]+?[\-]{3,6}END[\s]PGP[\s](PRIVATE|PUBLIC)[\s]KEY[\s]BLOCK[\-]{3,6}/gi, + oOpenpgpKeyring = Data.openpgpKeyring + ; + + sKey = sKey.replace(/[\r\n]([a-zA-Z0-9]{2,}:[^\r\n]+)[\r\n]+([a-zA-Z0-9\/\\+=]{10,})/g, '\n$1!-!N!-!$2') + .replace(/[\n\r]+/g, '\n').replace(/!-!N!-!/g, '\n\n'); + + this.key.error('' === sKey); + + if (!oOpenpgpKeyring || this.key.error()) + { + return false; + } + + do + { + aMatch = oReg.exec(sKey); + if (!aMatch || 0 > iCount) + { + break; + } + + if (aMatch[0] && aMatch[1] && aMatch[2] && aMatch[1] === aMatch[2]) + { + if ('PRIVATE' === aMatch[1]) + { + oOpenpgpKeyring.privateKeys.importKey(aMatch[0]); + } + else if ('PUBLIC' === aMatch[1]) + { + oOpenpgpKeyring.publicKeys.importKey(aMatch[0]); + } + } + + iCount--; + } + while (true); + + oOpenpgpKeyring.store(); + + RL.reloadOpenPgpKeys(); + Utils.delegateRun(this, 'cancelCommand'); + + return true; + }); + + kn.constructorEnd(this); + } + + kn.extendAsViewModel('PopupsAddOpenPgpKeyViewModel', PopupsAddOpenPgpKeyViewModel); + + PopupsAddOpenPgpKeyViewModel.prototype.clearPopup = function () + { + this.key(''); this.key.error(false); - }, this); + }; - this.addOpenPgpKeyCommand = Utils.createCommand(this, function () { + PopupsAddOpenPgpKeyViewModel.prototype.onShow = function () + { + this.clearPopup(); + }; - var - iCount = 30, - aMatch = null, - sKey = Utils.trim(this.key()), - oReg = /[\-]{3,6}BEGIN[\s]PGP[\s](PRIVATE|PUBLIC)[\s]KEY[\s]BLOCK[\-]{3,6}[\s\S]+?[\-]{3,6}END[\s]PGP[\s](PRIVATE|PUBLIC)[\s]KEY[\s]BLOCK[\-]{3,6}/gi, - oOpenpgpKeyring = RL.data().openpgpKeyring - ; + PopupsAddOpenPgpKeyViewModel.prototype.onFocus = function () + { + this.key.focus(true); + }; - sKey = sKey.replace(/[\r\n]([a-zA-Z0-9]{2,}:[^\r\n]+)[\r\n]+([a-zA-Z0-9\/\\+=]{10,})/g, '\n$1!-!N!-!$2') - .replace(/[\n\r]+/g, '\n').replace(/!-!N!-!/g, '\n\n'); + module.exports = new PopupsAddOpenPgpKeyViewModel(); - this.key.error('' === sKey); - - if (!oOpenpgpKeyring || this.key.error()) - { - return false; - } - - do - { - aMatch = oReg.exec(sKey); - if (!aMatch || 0 > iCount) - { - break; - } - - if (aMatch[0] && aMatch[1] && aMatch[2] && aMatch[1] === aMatch[2]) - { - if ('PRIVATE' === aMatch[1]) - { - oOpenpgpKeyring.privateKeys.importKey(aMatch[0]); - } - else if ('PUBLIC' === aMatch[1]) - { - oOpenpgpKeyring.publicKeys.importKey(aMatch[0]); - } - } - - iCount--; - } - while (true); - - oOpenpgpKeyring.store(); - - RL.reloadOpenPgpKeys(); - Utils.delegateRun(this, 'cancelCommand'); - - return true; - }); - - Knoin.constructorEnd(this); -} - -Utils.extendAsViewModel('PopupsAddOpenPgpKeyViewModel', PopupsAddOpenPgpKeyViewModel); - -PopupsAddOpenPgpKeyViewModel.prototype.clearPopup = function () -{ - this.key(''); - this.key.error(false); -}; - -PopupsAddOpenPgpKeyViewModel.prototype.onShow = function () -{ - this.clearPopup(); -}; - -PopupsAddOpenPgpKeyViewModel.prototype.onFocus = function () -{ - this.key.focus(true); -}; +}(module)); \ No newline at end of file diff --git a/dev/ViewModels/Popups/PopupsAdvancedSearchViewModel.js b/dev/ViewModels/Popups/PopupsAdvancedSearchViewModel.js index 87a809951..f83ebc53d 100644 --- a/dev/ViewModels/Popups/PopupsAdvancedSearchViewModel.js +++ b/dev/ViewModels/Popups/PopupsAdvancedSearchViewModel.js @@ -1,137 +1,157 @@ /* RainLoop Webmail (c) RainLoop Team | Licensed under CC BY-NC-SA 3.0 */ -/** - * @constructor - * @extends KnoinAbstractViewModel - */ -function PopupsAdvancedSearchViewModel() -{ - KnoinAbstractViewModel.call(this, 'Popups', 'PopupsAdvancedSearch'); +(function (module) { - this.fromFocus = ko.observable(false); - - this.from = ko.observable(''); - this.to = ko.observable(''); - this.subject = ko.observable(''); - this.text = ko.observable(''); - this.selectedDateValue = ko.observable(-1); + 'use strict'; - this.hasAttachment = ko.observable(false); - this.starred = ko.observable(false); - this.unseen = ko.observable(false); - - this.searchCommand = Utils.createCommand(this, function () { - - var sSearch = this.buildSearchString(); - if ('' !== sSearch) - { - RL.data().mainMessageListSearch(sSearch); - } - - this.cancelCommand(); - }); - - Knoin.constructorEnd(this); -} - -Utils.extendAsViewModel('PopupsAdvancedSearchViewModel', PopupsAdvancedSearchViewModel); - -PopupsAdvancedSearchViewModel.prototype.buildSearchStringValue = function (sValue) -{ - if (-1 < sValue.indexOf(' ')) - { - sValue = '"' + sValue + '"'; - } - - return sValue; -}; - -PopupsAdvancedSearchViewModel.prototype.buildSearchString = function () -{ var - aResult = [], - sFrom = Utils.trim(this.from()), - sTo = Utils.trim(this.to()), - sSubject = Utils.trim(this.subject()), - sText = Utils.trim(this.text()), - aIs = [], - aHas = [] + ko = require('../../External/ko.js'), + moment = require('../../External/moment.js'), + + Utils = require('../../Common/Utils.js'), + + Data = require('../../Storages/WebMailDataStorage.js'), + + kn = require('../../Knoin/Knoin.js'), + KnoinAbstractViewModel = require('../../Knoin/KnoinAbstractViewModel.js') ; - if (sFrom && '' !== sFrom) + /** + * @constructor + * @extends KnoinAbstractViewModel + */ + function PopupsAdvancedSearchViewModel() { - aResult.push('from:' + this.buildSearchStringValue(sFrom)); - } - - if (sTo && '' !== sTo) - { - aResult.push('to:' + this.buildSearchStringValue(sTo)); + KnoinAbstractViewModel.call(this, 'Popups', 'PopupsAdvancedSearch'); + + this.fromFocus = ko.observable(false); + + this.from = ko.observable(''); + this.to = ko.observable(''); + this.subject = ko.observable(''); + this.text = ko.observable(''); + this.selectedDateValue = ko.observable(-1); + + this.hasAttachment = ko.observable(false); + this.starred = ko.observable(false); + this.unseen = ko.observable(false); + + this.searchCommand = Utils.createCommand(this, function () { + + var sSearch = this.buildSearchString(); + if ('' !== sSearch) + { + Data.mainMessageListSearch(sSearch); + } + + this.cancelCommand(); + }); + + kn.constructorEnd(this); } - if (sSubject && '' !== sSubject) + kn.extendAsViewModel('PopupsAdvancedSearchViewModel', PopupsAdvancedSearchViewModel); + + PopupsAdvancedSearchViewModel.prototype.buildSearchStringValue = function (sValue) { - aResult.push('subject:' + this.buildSearchStringValue(sSubject)); - } - - if (this.hasAttachment()) + if (-1 < sValue.indexOf(' ')) + { + sValue = '"' + sValue + '"'; + } + + return sValue; + }; + + PopupsAdvancedSearchViewModel.prototype.buildSearchString = function () { - aHas.push('attachment'); - } - - if (this.unseen()) + var + aResult = [], + sFrom = Utils.trim(this.from()), + sTo = Utils.trim(this.to()), + sSubject = Utils.trim(this.subject()), + sText = Utils.trim(this.text()), + aIs = [], + aHas = [] + ; + + if (sFrom && '' !== sFrom) + { + aResult.push('from:' + this.buildSearchStringValue(sFrom)); + } + + if (sTo && '' !== sTo) + { + aResult.push('to:' + this.buildSearchStringValue(sTo)); + } + + if (sSubject && '' !== sSubject) + { + aResult.push('subject:' + this.buildSearchStringValue(sSubject)); + } + + if (this.hasAttachment()) + { + aHas.push('attachment'); + } + + if (this.unseen()) + { + aIs.push('unseen'); + } + + if (this.starred()) + { + aIs.push('flagged'); + } + + if (0 < aHas.length) + { + aResult.push('has:' + aHas.join(',')); + } + + if (0 < aIs.length) + { + aResult.push('is:' + aIs.join(',')); + } + + if (-1 < this.selectedDateValue()) + { + aResult.push('date:' + moment().subtract('days', this.selectedDateValue()).format('YYYY.MM.DD') + '/'); + } + + if (sText && '' !== sText) + { + aResult.push('text:' + this.buildSearchStringValue(sText)); + } + + return Utils.trim(aResult.join(' ')); + }; + + PopupsAdvancedSearchViewModel.prototype.clearPopup = function () { - aIs.push('unseen'); - } + this.from(''); + this.to(''); + this.subject(''); + this.text(''); - if (this.starred()) + this.selectedDateValue(-1); + this.hasAttachment(false); + this.starred(false); + this.unseen(false); + + this.fromFocus(true); + }; + + PopupsAdvancedSearchViewModel.prototype.onShow = function () { - aIs.push('flagged'); - } + this.clearPopup(); + }; - if (0 < aHas.length) + PopupsAdvancedSearchViewModel.prototype.onFocus = function () { - aResult.push('has:' + aHas.join(',')); - } + this.fromFocus(true); + }; - if (0 < aIs.length) - { - aResult.push('is:' + aIs.join(',')); - } + module.exports = new PopupsAdvancedSearchViewModel(); - if (-1 < this.selectedDateValue()) - { - aResult.push('date:' + moment().subtract('days', this.selectedDateValue()).format('YYYY.MM.DD') + '/'); - } - - if (sText && '' !== sText) - { - aResult.push('text:' + this.buildSearchStringValue(sText)); - } - - return Utils.trim(aResult.join(' ')); -}; - -PopupsAdvancedSearchViewModel.prototype.clearPopup = function () -{ - this.from(''); - this.to(''); - this.subject(''); - this.text(''); - - this.selectedDateValue(-1); - this.hasAttachment(false); - this.starred(false); - this.unseen(false); - - this.fromFocus(true); -}; - -PopupsAdvancedSearchViewModel.prototype.onShow = function () -{ - this.clearPopup(); -}; - -PopupsAdvancedSearchViewModel.prototype.onFocus = function () -{ - this.fromFocus(true); -}; +}(module)); \ No newline at end of file diff --git a/dev/ViewModels/Popups/PopupsAskViewModel.js b/dev/ViewModels/Popups/PopupsAskViewModel.js index 42f1fa704..2bad36503 100644 --- a/dev/ViewModels/Popups/PopupsAskViewModel.js +++ b/dev/ViewModels/Popups/PopupsAskViewModel.js @@ -1,112 +1,128 @@ /* RainLoop Webmail (c) RainLoop Team | Licensed under CC BY-NC-SA 3.0 */ -/** - * @constructor - * @extends KnoinAbstractViewModel - */ -function PopupsAskViewModel() -{ - KnoinAbstractViewModel.call(this, 'Popups', 'PopupsAsk'); +(function (module) { - this.askDesc = ko.observable(''); - this.yesButton = ko.observable(''); - this.noButton = ko.observable(''); + 'use strict'; - this.yesFocus = ko.observable(false); - this.noFocus = ko.observable(false); + var + ko = require('../../External/ko.js'), + key = require('../../External/key.js'), + Enums = require('../../Common/Enums.js'), + Utils = require('../../Common/Utils.js'), + kn = require('../../Knoin/Knoin.js'), + KnoinAbstractViewModel = require('../../Knoin/KnoinAbstractViewModel.js') + ; - this.fYesAction = null; - this.fNoAction = null; - - this.bDisabeCloseOnEsc = true; - this.sDefaultKeyScope = Enums.KeyState.PopupAsk; - - Knoin.constructorEnd(this); -} - -Utils.extendAsViewModel('PopupsAskViewModel', PopupsAskViewModel); - -PopupsAskViewModel.prototype.clearPopup = function () -{ - this.askDesc(''); - this.yesButton(Utils.i18n('POPUPS_ASK/BUTTON_YES')); - this.noButton(Utils.i18n('POPUPS_ASK/BUTTON_NO')); - - this.yesFocus(false); - this.noFocus(false); - - this.fYesAction = null; - this.fNoAction = null; -}; - -PopupsAskViewModel.prototype.yesClick = function () -{ - this.cancelCommand(); - - if (Utils.isFunc(this.fYesAction)) + /** + * @constructor + * @extends KnoinAbstractViewModel + */ + function PopupsAskViewModel() { - this.fYesAction.call(null); - } -}; + KnoinAbstractViewModel.call(this, 'Popups', 'PopupsAsk'); -PopupsAskViewModel.prototype.noClick = function () -{ - this.cancelCommand(); + this.askDesc = ko.observable(''); + this.yesButton = ko.observable(''); + this.noButton = ko.observable(''); - if (Utils.isFunc(this.fNoAction)) - { - this.fNoAction.call(null); - } -}; + this.yesFocus = ko.observable(false); + this.noFocus = ko.observable(false); -/** - * @param {string} sAskDesc - * @param {Function=} fYesFunc - * @param {Function=} fNoFunc - * @param {string=} sYesButton - * @param {string=} sNoButton - */ -PopupsAskViewModel.prototype.onShow = function (sAskDesc, fYesFunc, fNoFunc, sYesButton, sNoButton) -{ - this.clearPopup(); - - this.fYesAction = fYesFunc || null; - this.fNoAction = fNoFunc || null; + this.fYesAction = null; + this.fNoAction = null; - this.askDesc(sAskDesc || ''); - if (sYesButton) - { - this.yesButton(sYesButton); + this.bDisabeCloseOnEsc = true; + this.sDefaultKeyScope = Enums.KeyState.PopupAsk; + + kn.constructorEnd(this); } - if (sYesButton) + kn.extendAsViewModel('PopupsAskViewModel', PopupsAskViewModel); + + PopupsAskViewModel.prototype.clearPopup = function () { - this.yesButton(sNoButton); - } -}; + this.askDesc(''); + this.yesButton(Utils.i18n('POPUPS_ASK/BUTTON_YES')); + this.noButton(Utils.i18n('POPUPS_ASK/BUTTON_NO')); -PopupsAskViewModel.prototype.onFocus = function () -{ - this.yesFocus(true); -}; + this.yesFocus(false); + this.noFocus(false); -PopupsAskViewModel.prototype.onBuild = function () -{ - key('tab, shift+tab, right, left', Enums.KeyState.PopupAsk, _.bind(function () { - if (this.yesFocus()) + this.fYesAction = null; + this.fNoAction = null; + }; + + PopupsAskViewModel.prototype.yesClick = function () + { + this.cancelCommand(); + + if (Utils.isFunc(this.fYesAction)) { - this.noFocus(true); + this.fYesAction.call(null); } - else + }; + + PopupsAskViewModel.prototype.noClick = function () + { + this.cancelCommand(); + + if (Utils.isFunc(this.fNoAction)) { - this.yesFocus(true); + this.fNoAction.call(null); } - return false; - }, this)); + }; - key('esc', Enums.KeyState.PopupAsk, _.bind(function () { - this.noClick(); - return false; - }, this)); -}; + /** + * @param {string} sAskDesc + * @param {Function=} fYesFunc + * @param {Function=} fNoFunc + * @param {string=} sYesButton + * @param {string=} sNoButton + */ + PopupsAskViewModel.prototype.onShow = function (sAskDesc, fYesFunc, fNoFunc, sYesButton, sNoButton) + { + this.clearPopup(); + this.fYesAction = fYesFunc || null; + this.fNoAction = fNoFunc || null; + + this.askDesc(sAskDesc || ''); + if (sYesButton) + { + this.yesButton(sYesButton); + } + + if (sYesButton) + { + this.yesButton(sNoButton); + } + }; + + PopupsAskViewModel.prototype.onFocus = function () + { + this.yesFocus(true); + }; + + PopupsAskViewModel.prototype.onBuild = function () + { + key('tab, shift+tab, right, left', Enums.KeyState.PopupAsk, _.bind(function () { + if (this.yesFocus()) + { + this.noFocus(true); + } + else + { + this.yesFocus(true); + } + return false; + }, this)); + + key('esc', Enums.KeyState.PopupAsk, _.bind(function () { + this.noClick(); + return false; + }, this)); + }; + + module.exports = new PopupsAskViewModel(); + +}(module)); \ No newline at end of file diff --git a/dev/ViewModels/Popups/PopupsComposeOpenPgpViewModel.js b/dev/ViewModels/Popups/PopupsComposeOpenPgpViewModel.js index 65a6895b4..a3740f407 100644 --- a/dev/ViewModels/Popups/PopupsComposeOpenPgpViewModel.js +++ b/dev/ViewModels/Popups/PopupsComposeOpenPgpViewModel.js @@ -1,241 +1,262 @@ /* RainLoop Webmail (c) RainLoop Team | Licensed under CC BY-NC-SA 3.0 */ -/** - * @constructor - * @extends KnoinAbstractViewModel - */ -function PopupsComposeOpenPgpViewModel() -{ - KnoinAbstractViewModel.call(this, 'Popups', 'PopupsComposeOpenPgp'); +(function (module) { - this.notification = ko.observable(''); - - this.sign = ko.observable(true); - this.encrypt = ko.observable(true); - - this.password = ko.observable(''); - this.password.focus = ko.observable(false); - this.buttonFocus = ko.observable(false); - - this.from = ko.observable(''); - this.to = ko.observableArray([]); - this.text = ko.observable(''); - - this.resultCallback = null; - - this.submitRequest = ko.observable(false); - - // commands - this.doCommand = Utils.createCommand(this, function () { - - var - self = this, - bResult = true, - oData = RL.data(), - oPrivateKey = null, - aPublicKeys = [] - ; - - this.submitRequest(true); - - if (bResult && this.sign() && '' === this.from()) - { - this.notification(Utils.i18n('PGP_NOTIFICATIONS/SPECIFY_FROM_EMAIL')); - bResult = false; - } - - if (bResult && this.sign()) - { - oPrivateKey = oData.findPrivateKeyByEmail(this.from(), this.password()); - if (!oPrivateKey) - { - this.notification(Utils.i18n('PGP_NOTIFICATIONS/NO_PRIVATE_KEY_FOUND_FOR', { - 'EMAIL': this.from() - })); - - bResult = false; - } - } - - if (bResult && this.encrypt() && 0 === this.to().length) - { - this.notification(Utils.i18n('PGP_NOTIFICATIONS/SPECIFY_AT_LEAST_ONE_RECIPIENT')); - bResult = false; - } - - if (bResult && this.encrypt()) - { - aPublicKeys = []; - _.each(this.to(), function (sEmail) { - var aKeys = oData.findPublicKeysByEmail(sEmail); - if (0 === aKeys.length && bResult) - { - self.notification(Utils.i18n('PGP_NOTIFICATIONS/NO_PUBLIC_KEYS_FOUND_FOR', { - 'EMAIL': sEmail - })); - - bResult = false; - } - - aPublicKeys = aPublicKeys.concat(aKeys); - }); - - if (bResult && (0 === aPublicKeys.length || this.to().length !== aPublicKeys.length)) - { - bResult = false; - } - } - - _.delay(function () { - - if (self.resultCallback && bResult) - { - try { - - if (oPrivateKey && 0 === aPublicKeys.length) - { - self.resultCallback( - window.openpgp.signClearMessage([oPrivateKey], self.text()) - ); - } - else if (oPrivateKey && 0 < aPublicKeys.length) - { - self.resultCallback( - window.openpgp.signAndEncryptMessage(aPublicKeys, oPrivateKey, self.text()) - ); - } - else if (!oPrivateKey && 0 < aPublicKeys.length) - { - self.resultCallback( - window.openpgp.encryptMessage(aPublicKeys, self.text()) - ); - } - } - catch (e) - { - self.notification(Utils.i18n('PGP_NOTIFICATIONS/PGP_ERROR', { - 'ERROR': '' + e - })); - - bResult = false; - } - } - - if (bResult) - { - self.cancelCommand(); - } - - self.submitRequest(false); - - }, 10); - - }, function () { - return !this.submitRequest() && (this.sign() || this.encrypt()); - }); - - this.sDefaultKeyScope = Enums.KeyState.PopupComposeOpenPGP; - - Knoin.constructorEnd(this); -} - -Utils.extendAsViewModel('PopupsComposeOpenPgpViewModel', PopupsComposeOpenPgpViewModel); - -PopupsComposeOpenPgpViewModel.prototype.clearPopup = function () -{ - this.notification(''); - - this.password(''); - this.password.focus(false); - this.buttonFocus(false); - - this.from(''); - this.to([]); - this.text(''); - - this.submitRequest(false); - - this.resultCallback = null; -}; - -PopupsComposeOpenPgpViewModel.prototype.onBuild = function () -{ - key('tab,shift+tab', Enums.KeyState.PopupComposeOpenPGP, _.bind(function () { - - switch (true) - { - case this.password.focus(): - this.buttonFocus(true); - break; - case this.buttonFocus(): - this.password.focus(true); - break; - } - - return false; - - }, this)); -}; - -PopupsComposeOpenPgpViewModel.prototype.onHide = function () -{ - this.clearPopup(); -}; - -PopupsComposeOpenPgpViewModel.prototype.onFocus = function () -{ - if (this.sign()) - { - this.password.focus(true); - } - else - { - this.buttonFocus(true); - } -}; - -PopupsComposeOpenPgpViewModel.prototype.onShow = function (fCallback, sText, sFromEmail, sTo, sCc, sBcc) -{ - this.clearPopup(); + 'use strict'; var - oEmail = new EmailModel(), - sResultFromEmail = '', - aRec = [] + window = require('../../External/window.js'), + ko = require('../../External/ko.js'), + key = require('../../External/key.js'), + + Utils = require('../../Common/Utils.js'), + Enums = require('../../Common/Enums.js'), + + Data = require('../../Storages/WebMailDataStorage.js'), + + kn = require('../../Knoin/Knoin.js'), + KnoinAbstractViewModel = require('../../Knoin/KnoinAbstractViewModel.js') ; - - this.resultCallback = fCallback; - - oEmail.clear(); - oEmail.mailsoParse(sFromEmail); - if ('' !== oEmail.email) - { - sResultFromEmail = oEmail.email; - } - - if ('' !== sTo) - { - aRec.push(sTo); - } - if ('' !== sCc) + /** + * @constructor + * @extends KnoinAbstractViewModel + */ + function PopupsComposeOpenPgpViewModel() { - aRec.push(sCc); + KnoinAbstractViewModel.call(this, 'Popups', 'PopupsComposeOpenPgp'); + + this.notification = ko.observable(''); + + this.sign = ko.observable(true); + this.encrypt = ko.observable(true); + + this.password = ko.observable(''); + this.password.focus = ko.observable(false); + this.buttonFocus = ko.observable(false); + + this.from = ko.observable(''); + this.to = ko.observableArray([]); + this.text = ko.observable(''); + + this.resultCallback = null; + + this.submitRequest = ko.observable(false); + + // commands + this.doCommand = Utils.createCommand(this, function () { + + var + self = this, + bResult = true, + oPrivateKey = null, + aPublicKeys = [] + ; + + this.submitRequest(true); + + if (bResult && this.sign() && '' === this.from()) + { + this.notification(Utils.i18n('PGP_NOTIFICATIONS/SPECIFY_FROM_EMAIL')); + bResult = false; + } + + if (bResult && this.sign()) + { + oPrivateKey = Data.findPrivateKeyByEmail(this.from(), this.password()); + if (!oPrivateKey) + { + this.notification(Utils.i18n('PGP_NOTIFICATIONS/NO_PRIVATE_KEY_FOUND_FOR', { + 'EMAIL': this.from() + })); + + bResult = false; + } + } + + if (bResult && this.encrypt() && 0 === this.to().length) + { + this.notification(Utils.i18n('PGP_NOTIFICATIONS/SPECIFY_AT_LEAST_ONE_RECIPIENT')); + bResult = false; + } + + if (bResult && this.encrypt()) + { + aPublicKeys = []; + _.each(this.to(), function (sEmail) { + var aKeys = Data.findPublicKeysByEmail(sEmail); + if (0 === aKeys.length && bResult) + { + self.notification(Utils.i18n('PGP_NOTIFICATIONS/NO_PUBLIC_KEYS_FOUND_FOR', { + 'EMAIL': sEmail + })); + + bResult = false; + } + + aPublicKeys = aPublicKeys.concat(aKeys); + }); + + if (bResult && (0 === aPublicKeys.length || this.to().length !== aPublicKeys.length)) + { + bResult = false; + } + } + + _.delay(function () { + + if (self.resultCallback && bResult) + { + try { + + if (oPrivateKey && 0 === aPublicKeys.length) + { + self.resultCallback( + window.openpgp.signClearMessage([oPrivateKey], self.text()) + ); + } + else if (oPrivateKey && 0 < aPublicKeys.length) + { + self.resultCallback( + window.openpgp.signAndEncryptMessage(aPublicKeys, oPrivateKey, self.text()) + ); + } + else if (!oPrivateKey && 0 < aPublicKeys.length) + { + self.resultCallback( + window.openpgp.encryptMessage(aPublicKeys, self.text()) + ); + } + } + catch (e) + { + self.notification(Utils.i18n('PGP_NOTIFICATIONS/PGP_ERROR', { + 'ERROR': '' + e + })); + + bResult = false; + } + } + + if (bResult) + { + self.cancelCommand(); + } + + self.submitRequest(false); + + }, 10); + + }, function () { + return !this.submitRequest() && (this.sign() || this.encrypt()); + }); + + this.sDefaultKeyScope = Enums.KeyState.PopupComposeOpenPGP; + + kn.constructorEnd(this); } - if ('' !== sBcc) - { - aRec.push(sBcc); - } + kn.extendAsViewModel('PopupsComposeOpenPgpViewModel', PopupsComposeOpenPgpViewModel); + + PopupsComposeOpenPgpViewModel.prototype.clearPopup = function () + { + this.notification(''); + + this.password(''); + this.password.focus(false); + this.buttonFocus(false); + + this.from(''); + this.to([]); + this.text(''); + + this.submitRequest(false); + + this.resultCallback = null; + }; + + PopupsComposeOpenPgpViewModel.prototype.onBuild = function () + { + key('tab,shift+tab', Enums.KeyState.PopupComposeOpenPGP, _.bind(function () { + + switch (true) + { + case this.password.focus(): + this.buttonFocus(true); + break; + case this.buttonFocus(): + this.password.focus(true); + break; + } + + return false; + + }, this)); + }; + + PopupsComposeOpenPgpViewModel.prototype.onHide = function () + { + this.clearPopup(); + }; + + PopupsComposeOpenPgpViewModel.prototype.onFocus = function () + { + if (this.sign()) + { + this.password.focus(true); + } + else + { + this.buttonFocus(true); + } + }; + + PopupsComposeOpenPgpViewModel.prototype.onShow = function (fCallback, sText, sFromEmail, sTo, sCc, sBcc) + { + this.clearPopup(); + + var + oEmail = new EmailModel(), + sResultFromEmail = '', + aRec = [] + ; + + this.resultCallback = fCallback; - aRec = aRec.join(', ').split(','); - aRec = _.compact(_.map(aRec, function (sValue) { oEmail.clear(); - oEmail.mailsoParse(Utils.trim(sValue)); - return '' === oEmail.email ? false : oEmail.email; - })); + oEmail.mailsoParse(sFromEmail); + if ('' !== oEmail.email) + { + sResultFromEmail = oEmail.email; + } - this.from(sResultFromEmail); - this.to(aRec); - this.text(sText); -}; + if ('' !== sTo) + { + aRec.push(sTo); + } + + if ('' !== sCc) + { + aRec.push(sCc); + } + + if ('' !== sBcc) + { + aRec.push(sBcc); + } + + aRec = aRec.join(', ').split(','); + aRec = _.compact(_.map(aRec, function (sValue) { + oEmail.clear(); + oEmail.mailsoParse(Utils.trim(sValue)); + return '' === oEmail.email ? false : oEmail.email; + })); + + this.from(sResultFromEmail); + this.to(aRec); + this.text(sText); + }; + + module.exports = new PopupsComposeOpenPgpViewModel(); + +}(module)); \ No newline at end of file diff --git a/dev/ViewModels/Popups/PopupsComposeViewModel.js b/dev/ViewModels/Popups/PopupsComposeViewModel.js index 45aca02af..ec782c908 100644 --- a/dev/ViewModels/Popups/PopupsComposeViewModel.js +++ b/dev/ViewModels/Popups/PopupsComposeViewModel.js @@ -1,262 +1,321 @@ /* RainLoop Webmail (c) RainLoop Team | Licensed under CC BY-NC-SA 3.0 */ -/** - * @constructor - * @extends KnoinAbstractViewModel - */ -function PopupsComposeViewModel() -{ - KnoinAbstractViewModel.call(this, 'Popups', 'PopupsCompose'); +(function (module) { - this.oEditor = null; - this.aDraftInfo = null; - this.sInReplyTo = ''; - this.bFromDraft = false; - this.bSkipNext = false; - this.sReferences = ''; - - this.bCapaAdditionalIdentities = RL.capa(Enums.Capa.AdditionalIdentities); + 'use strict'; var - self = this, - oRainLoopData = RL.data(), - fCcAndBccCheckHelper = function (aValue) { - if (false === self.showCcAndBcc() && 0 < aValue.length) - { - self.showCcAndBcc(true); - } - } + $ = require('../../External/jquery.js'), + _ = require('../../External/underscore.js'), + ko = require('../../External/ko.js'), + moment = require('../../External/moment.js'), + + Enums = require('../../Common/Enums.js'), + Consts = require('../../Common/Consts.js'), + Utils = require('../../Common/Utils.js'), + LinkBuilder = require('../Common/LinkBuilder.js'), + + Data = require('../../Storages/WebMailDataStorage.js'), + Cache = require('../../Storages/WebMailCacheStorage.js'), + Remote = require('../../Storages/WebMailAjaxRemoteStorage.js'), + + kn = require('../../Knoin/Knoin.js'), + KnoinAbstractViewModel = require('../../Knoin/KnoinAbstractViewModel.js') ; - this.capaOpenPGP = oRainLoopData.capaOpenPGP; + /** + * @constructor + * @extends KnoinAbstractViewModel + */ + function PopupsComposeViewModel() + { + KnoinAbstractViewModel.call(this, 'Popups', 'PopupsCompose'); - this.resizer = ko.observable(false).extend({'throttle': 50}); + this.oEditor = null; + this.aDraftInfo = null; + this.sInReplyTo = ''; + this.bFromDraft = false; + this.bSkipNext = false; + this.sReferences = ''; - this.identitiesDropdownTrigger = ko.observable(false); + this.bCapaAdditionalIdentities = RL.capa(Enums.Capa.AdditionalIdentities); - this.to = ko.observable(''); - this.to.focusTrigger = ko.observable(false); - this.cc = ko.observable(''); - this.bcc = ko.observable(''); + var + self = this, + fCcAndBccCheckHelper = function (aValue) { + if (false === self.showCcAndBcc() && 0 < aValue.length) + { + self.showCcAndBcc(true); + } + } + ; - this.replyTo = ko.observable(''); - this.subject = ko.observable(''); - this.isHtml = ko.observable(false); + this.capaOpenPGP = Data.capaOpenPGP; - this.requestReadReceipt = ko.observable(false); + this.resizer = ko.observable(false).extend({'throttle': 50}); - this.sendError = ko.observable(false); - this.sendSuccessButSaveError = ko.observable(false); - this.savedError = ko.observable(false); + this.identitiesDropdownTrigger = ko.observable(false); - this.savedTime = ko.observable(0); - this.savedOrSendingText = ko.observable(''); + this.to = ko.observable(''); + this.to.focusTrigger = ko.observable(false); + this.cc = ko.observable(''); + this.bcc = ko.observable(''); - this.emptyToError = ko.observable(false); - this.attachmentsInProcessError = ko.observable(false); - this.showCcAndBcc = ko.observable(false); + this.replyTo = ko.observable(''); + this.subject = ko.observable(''); + this.isHtml = ko.observable(false); - this.cc.subscribe(fCcAndBccCheckHelper, this); - this.bcc.subscribe(fCcAndBccCheckHelper, this); + this.requestReadReceipt = ko.observable(false); - this.draftFolder = ko.observable(''); - this.draftUid = ko.observable(''); - this.sending = ko.observable(false); - this.saving = ko.observable(false); - this.attachments = ko.observableArray([]); + this.sendError = ko.observable(false); + this.sendSuccessButSaveError = ko.observable(false); + this.savedError = ko.observable(false); - this.attachmentsInProcess = this.attachments.filter(function (oItem) { - return oItem && '' === oItem.tempName(); - }); + this.savedTime = ko.observable(0); + this.savedOrSendingText = ko.observable(''); - this.attachmentsInReady = this.attachments.filter(function (oItem) { - return oItem && '' !== oItem.tempName(); - }); + this.emptyToError = ko.observable(false); + this.attachmentsInProcessError = ko.observable(false); + this.showCcAndBcc = ko.observable(false); - this.attachments.subscribe(function () { - this.triggerForResize(); - }, this); + this.cc.subscribe(fCcAndBccCheckHelper, this); + this.bcc.subscribe(fCcAndBccCheckHelper, this); - this.isDraftFolderMessage = ko.computed(function () { - return '' !== this.draftFolder() && '' !== this.draftUid(); - }, this); + this.draftFolder = ko.observable(''); + this.draftUid = ko.observable(''); + this.sending = ko.observable(false); + this.saving = ko.observable(false); + this.attachments = ko.observableArray([]); - this.composeUploaderButton = ko.observable(null); - this.composeUploaderDropPlace = ko.observable(null); - this.dragAndDropEnabled = ko.observable(false); - this.dragAndDropOver = ko.observable(false).extend({'throttle': 1}); - this.dragAndDropVisible = ko.observable(false).extend({'throttle': 1}); - this.attacheMultipleAllowed = ko.observable(false); - this.addAttachmentEnabled = ko.observable(false); - - this.composeEditorArea = ko.observable(null); - - this.identities = RL.data().identities; - this.defaultIdentityID = RL.data().defaultIdentityID; - this.currentIdentityID = ko.observable(''); - - this.currentIdentityString = ko.observable(''); - this.currentIdentityResultEmail = ko.observable(''); - - this.identitiesOptions = ko.computed(function () { - - var aList = [{ - 'optValue': oRainLoopData.accountEmail(), - 'optText': this.formattedFrom(false) - }]; - - _.each(oRainLoopData.identities(), function (oItem) { - aList.push({ - 'optValue': oItem.id, - 'optText': oItem.formattedNameForCompose() - }); + this.attachmentsInProcess = this.attachments.filter(function (oItem) { + return oItem && '' === oItem.tempName(); }); - return aList; + this.attachmentsInReady = this.attachments.filter(function (oItem) { + return oItem && '' !== oItem.tempName(); + }); - }, this); + this.attachments.subscribe(function () { + this.triggerForResize(); + }, this); - ko.computed(function () { + this.isDraftFolderMessage = ko.computed(function () { + return '' !== this.draftFolder() && '' !== this.draftUid(); + }, this); - var - sResult = '', - sResultEmail = '', - oItem = null, - aList = this.identities(), - sID = this.currentIdentityID() - ; + this.composeUploaderButton = ko.observable(null); + this.composeUploaderDropPlace = ko.observable(null); + this.dragAndDropEnabled = ko.observable(false); + this.dragAndDropOver = ko.observable(false).extend({'throttle': 1}); + this.dragAndDropVisible = ko.observable(false).extend({'throttle': 1}); + this.attacheMultipleAllowed = ko.observable(false); + this.addAttachmentEnabled = ko.observable(false); - if (this.bCapaAdditionalIdentities && sID && sID !== RL.data().accountEmail()) - { - oItem = _.find(aList, function (oItem) { - return oItem && sID === oItem['id']; + this.composeEditorArea = ko.observable(null); + + this.identities = Data.identities; + this.defaultIdentityID = Data.defaultIdentityID; + this.currentIdentityID = ko.observable(''); + + this.currentIdentityString = ko.observable(''); + this.currentIdentityResultEmail = ko.observable(''); + + this.identitiesOptions = ko.computed(function () { + + var aList = [{ + 'optValue': Data.accountEmail(), + 'optText': this.formattedFrom(false) + }]; + + _.each(Data.identities(), function (oItem) { + aList.push({ + 'optValue': oItem.id, + 'optText': oItem.formattedNameForCompose() + }); }); - sResult = oItem ? oItem.formattedNameForCompose() : ''; - sResultEmail = oItem ? oItem.formattedNameForEmail() : ''; + return aList; - if ('' === sResult && aList[0]) + }, this); + + ko.computed(function () { + + var + sResult = '', + sResultEmail = '', + oItem = null, + aList = this.identities(), + sID = this.currentIdentityID() + ; + + if (this.bCapaAdditionalIdentities && sID && sID !== Data.accountEmail()) { - this.currentIdentityID(aList[0]['id']); - return ''; - } - } + oItem = _.find(aList, function (oItem) { + return oItem && sID === oItem['id']; + }); - if ('' === sResult) - { - sResult = this.formattedFrom(false); - sResultEmail = this.formattedFrom(true); - } + sResult = oItem ? oItem.formattedNameForCompose() : ''; + sResultEmail = oItem ? oItem.formattedNameForEmail() : ''; - this.currentIdentityString(sResult); - this.currentIdentityResultEmail(sResultEmail); - - return sResult; - - }, this); - - this.to.subscribe(function (sValue) { - if (this.emptyToError() && 0 < sValue.length) - { - this.emptyToError(false); - } - }, this); - - this.attachmentsInProcess.subscribe(function (aValue) { - if (this.attachmentsInProcessError() && Utils.isArray(aValue) && 0 === aValue.length) - { - this.attachmentsInProcessError(false); - } - }, this); - - this.editorResizeThrottle = _.throttle(_.bind(this.editorResize, this), 100); - - this.resizer.subscribe(function () { - this.editorResizeThrottle(); - }, this); - - this.canBeSendedOrSaved = ko.computed(function () { - return !this.sending() && !this.saving(); - }, this); - - this.deleteCommand = Utils.createCommand(this, function () { - - RL.deleteMessagesFromFolderWithoutCheck(this.draftFolder(), [this.draftUid()]); - kn.hideScreenPopup(PopupsComposeViewModel); - - }, function () { - return this.isDraftFolderMessage(); - }); - - this.sendMessageResponse = _.bind(this.sendMessageResponse, this); - this.saveMessageResponse = _.bind(this.saveMessageResponse, this); - - this.sendCommand = Utils.createCommand(this, function () { - var - sTo = Utils.trim(this.to()), - sSentFolder = RL.data().sentFolder(), - aFlagsCache = [] - ; - - if (0 < this.attachmentsInProcess().length) - { - this.attachmentsInProcessError(true); - } - else if (0 === sTo.length) - { - this.emptyToError(true); - } - else - { - if (RL.data().replySameFolder()) - { - if (Utils.isArray(this.aDraftInfo) && 3 === this.aDraftInfo.length && Utils.isNormal(this.aDraftInfo[2]) && 0 < this.aDraftInfo[2].length) + if ('' === sResult && aList[0]) { - sSentFolder = this.aDraftInfo[2]; + this.currentIdentityID(aList[0]['id']); + return ''; } } - if ('' === sSentFolder) + if ('' === sResult) { - kn.showScreenPopup(PopupsFolderSystemViewModel, [Enums.SetSystemFoldersNotification.Sent]); + sResult = this.formattedFrom(false); + sResultEmail = this.formattedFrom(true); + } + + this.currentIdentityString(sResult); + this.currentIdentityResultEmail(sResultEmail); + + return sResult; + + }, this); + + this.to.subscribe(function (sValue) { + if (this.emptyToError() && 0 < sValue.length) + { + this.emptyToError(false); + } + }, this); + + this.attachmentsInProcess.subscribe(function (aValue) { + if (this.attachmentsInProcessError() && Utils.isArray(aValue) && 0 === aValue.length) + { + this.attachmentsInProcessError(false); + } + }, this); + + this.editorResizeThrottle = _.throttle(_.bind(this.editorResize, this), 100); + + this.resizer.subscribe(function () { + this.editorResizeThrottle(); + }, this); + + this.canBeSendedOrSaved = ko.computed(function () { + return !this.sending() && !this.saving(); + }, this); + + this.deleteCommand = Utils.createCommand(this, function () { + + RL.deleteMessagesFromFolderWithoutCheck(this.draftFolder(), [this.draftUid()]); + kn.hideScreenPopup(PopupsComposeViewModel); + + }, function () { + return this.isDraftFolderMessage(); + }); + + this.sendMessageResponse = _.bind(this.sendMessageResponse, this); + this.saveMessageResponse = _.bind(this.saveMessageResponse, this); + + this.sendCommand = Utils.createCommand(this, function () { + var + sTo = Utils.trim(this.to()), + sSentFolder = Data.sentFolder(), + aFlagsCache = [] + ; + + if (0 < this.attachmentsInProcess().length) + { + this.attachmentsInProcessError(true); + } + else if (0 === sTo.length) + { + this.emptyToError(true); } else { - this.sendError(false); - this.sending(true); - - if (Utils.isArray(this.aDraftInfo) && 3 === this.aDraftInfo.length) + if (Data.replySameFolder()) { - aFlagsCache = RL.cache().getMessageFlagsFromCache(this.aDraftInfo[2], this.aDraftInfo[1]); - if (aFlagsCache) + if (Utils.isArray(this.aDraftInfo) && 3 === this.aDraftInfo.length && Utils.isNormal(this.aDraftInfo[2]) && 0 < this.aDraftInfo[2].length) { - if ('forward' === this.aDraftInfo[0]) - { - aFlagsCache[3] = true; - } - else - { - aFlagsCache[2] = true; - } - - RL.cache().setMessageFlagsToCache(this.aDraftInfo[2], this.aDraftInfo[1], aFlagsCache); - RL.reloadFlagsCurrentMessageListAndMessageFromCache(); - RL.cache().setFolderHash(this.aDraftInfo[2], ''); + sSentFolder = this.aDraftInfo[2]; } } - sSentFolder = Consts.Values.UnuseOptionValue === sSentFolder ? '' : sSentFolder; + if ('' === sSentFolder) + { + kn.showScreenPopup(PopupsFolderSystemViewModel, [Enums.SetSystemFoldersNotification.Sent]); + } + else + { + this.sendError(false); + this.sending(true); - RL.cache().setFolderHash(this.draftFolder(), ''); - RL.cache().setFolderHash(sSentFolder, ''); + if (Utils.isArray(this.aDraftInfo) && 3 === this.aDraftInfo.length) + { + aFlagsCache = Cache.getMessageFlagsFromCache(this.aDraftInfo[2], this.aDraftInfo[1]); + if (aFlagsCache) + { + if ('forward' === this.aDraftInfo[0]) + { + aFlagsCache[3] = true; + } + else + { + aFlagsCache[2] = true; + } - RL.remote().sendMessage( - this.sendMessageResponse, + Cache.setMessageFlagsToCache(this.aDraftInfo[2], this.aDraftInfo[1], aFlagsCache); + RL.reloadFlagsCurrentMessageListAndMessageFromCache(); + Cache.setFolderHash(this.aDraftInfo[2], ''); + } + } + + sSentFolder = Consts.Values.UnuseOptionValue === sSentFolder ? '' : sSentFolder; + + Cache.setFolderHash(this.draftFolder(), ''); + Cache.setFolderHash(sSentFolder, ''); + + Remote.sendMessage( + this.sendMessageResponse, + this.draftFolder(), + this.draftUid(), + sSentFolder, + this.currentIdentityResultEmail(), + sTo, + this.cc(), + this.bcc(), + this.subject(), + this.oEditor ? this.oEditor.isHtml() : false, + this.oEditor ? this.oEditor.getData(true) : '', + this.prepearAttachmentsForSendOrSave(), + this.aDraftInfo, + this.sInReplyTo, + this.sReferences, + this.requestReadReceipt() + ); + } + } + }, this.canBeSendedOrSaved); + + this.saveCommand = Utils.createCommand(this, function () { + + if (Data.draftFolderNotEnabled()) + { + kn.showScreenPopup(PopupsFolderSystemViewModel, [Enums.SetSystemFoldersNotification.Draft]); + } + else + { + this.savedError(false); + this.saving(true); + + this.bSkipNext = true; + + Cache.setFolderHash(Data.draftFolder(), ''); + + Remote.saveMessage( + this.saveMessageResponse, this.draftFolder(), this.draftUid(), - sSentFolder, + Data.draftFolder(), this.currentIdentityResultEmail(), - sTo, + this.to(), this.cc(), this.bcc(), this.subject(), @@ -265,1467 +324,1433 @@ function PopupsComposeViewModel() this.prepearAttachmentsForSendOrSave(), this.aDraftInfo, this.sInReplyTo, - this.sReferences, - this.requestReadReceipt() + this.sReferences ); } - } - }, this.canBeSendedOrSaved); - this.saveCommand = Utils.createCommand(this, function () { + }, this.canBeSendedOrSaved); - if (RL.data().draftFolderNotEnabled()) + RL.sub('interval.1m', function () { + if (this.modalVisibility() && !Data.draftFolderNotEnabled() && !this.isEmptyForm(false) && + !this.bSkipNext && !this.saving() && !this.sending() && !this.savedError()) + { + this.bSkipNext = false; + this.saveCommand(); + } + }, this); + + this.showCcAndBcc.subscribe(function () { + this.triggerForResize(); + }, this); + + this.dropboxEnabled = ko.observable(!!RL.settingsGet('DropboxApiKey')); + + this.dropboxCommand = Utils.createCommand(this, function () { + + if (window.Dropbox) + { + window.Dropbox.choose({ + //'iframe': true, + 'success': function(aFiles) { + + if (aFiles && aFiles[0] && aFiles[0]['link']) + { + self.addDropboxAttachment(aFiles[0]); + } + }, + 'linkType': "direct", + 'multiselect': false + }); + } + + return true; + + }, function () { + return this.dropboxEnabled(); + }); + + this.driveEnabled = ko.observable(Globals.bXMLHttpRequestSupported && + !!RL.settingsGet('GoogleClientID') && !!RL.settingsGet('GoogleApiKey')); + + this.driveVisible = ko.observable(false); + + this.driveCommand = Utils.createCommand(this, function () { + + this.driveOpenPopup(); + return true; + + }, function () { + return this.driveEnabled(); + }); + + this.driveCallback = _.bind(this.driveCallback, this); + + this.bDisabeCloseOnEsc = true; + this.sDefaultKeyScope = Enums.KeyState.Compose; + + this.tryToClosePopup = _.debounce(_.bind(this.tryToClosePopup, this), 200); + + kn.constructorEnd(this); + } + + kn.extendAsViewModel('PopupsComposeViewModel', PopupsComposeViewModel); + + PopupsComposeViewModel.prototype.openOpenPgpPopup = function () + { + if (this.capaOpenPGP() && this.oEditor && !this.oEditor.isHtml()) { - kn.showScreenPopup(PopupsFolderSystemViewModel, [Enums.SetSystemFoldersNotification.Draft]); - } - else - { - this.savedError(false); - this.saving(true); - - this.bSkipNext = true; - - RL.cache().setFolderHash(RL.data().draftFolder(), ''); - - RL.remote().saveMessage( - this.saveMessageResponse, - this.draftFolder(), - this.draftUid(), - RL.data().draftFolder(), + var self = this; + kn.showScreenPopup(PopupsComposeOpenPgpViewModel, [ + function (sResult) { + self.editor(function (oEditor) { + oEditor.setPlain(sResult); + }); + }, + this.oEditor.getData(), this.currentIdentityResultEmail(), this.to(), this.cc(), - this.bcc(), - this.subject(), - this.oEditor ? this.oEditor.isHtml() : false, - this.oEditor ? this.oEditor.getData(true) : '', - this.prepearAttachmentsForSendOrSave(), - this.aDraftInfo, - this.sInReplyTo, - this.sReferences - ); + this.bcc() + ]); } + }; - }, this.canBeSendedOrSaved); - - RL.sub('interval.1m', function () { - if (this.modalVisibility() && !RL.data().draftFolderNotEnabled() && !this.isEmptyForm(false) && - !this.bSkipNext && !this.saving() && !this.sending() && !this.savedError()) + PopupsComposeViewModel.prototype.reloadDraftFolder = function () + { + var sDraftFolder = Data.draftFolder(); + if ('' !== sDraftFolder) { - this.bSkipNext = false; - this.saveCommand(); + Cache.setFolderHash(sDraftFolder, ''); + if (Data.currentFolderFullNameRaw() === sDraftFolder) + { + RL.reloadMessageList(true); + } + else + { + RL.folderInformation(sDraftFolder); + } } - }, this); + }; - this.showCcAndBcc.subscribe(function () { - this.triggerForResize(); - }, this); + PopupsComposeViewModel.prototype.findIdentityIdByMessage = function (sComposeType, oMessage) + { + var + oIDs = {}, + sResult = '', + fFindHelper = function (oItem) { + if (oItem && oItem.email && oIDs[oItem.email]) + { + sResult = oIDs[oItem.email]; + return true; + } - this.dropboxEnabled = ko.observable(!!RL.settingsGet('DropboxApiKey')); + return false; + } + ; - this.dropboxCommand = Utils.createCommand(this, function () { - - if (window.Dropbox) + if (this.bCapaAdditionalIdentities) { - window.Dropbox.choose({ - //'iframe': true, - 'success': function(aFiles) { - - if (aFiles && aFiles[0] && aFiles[0]['link']) - { - self.addDropboxAttachment(aFiles[0]); - } - }, - 'linkType': "direct", - 'multiselect': false + _.each(this.identities(), function (oItem) { + oIDs[oItem.email()] = oItem['id']; }); } - return true; + oIDs[Data.accountEmail()] = Data.accountEmail(); - }, function () { - return this.dropboxEnabled(); - }); - - this.driveEnabled = ko.observable(Globals.bXMLHttpRequestSupported && - !!RL.settingsGet('GoogleClientID') && !!RL.settingsGet('GoogleApiKey')); - - this.driveVisible = ko.observable(false); - - this.driveCommand = Utils.createCommand(this, function () { - - this.driveOpenPopup(); - return true; - - }, function () { - return this.driveEnabled(); - }); - - this.driveCallback = _.bind(this.driveCallback, this); - - this.bDisabeCloseOnEsc = true; - this.sDefaultKeyScope = Enums.KeyState.Compose; - - this.tryToClosePopup = _.debounce(_.bind(this.tryToClosePopup, this), 200); - - Knoin.constructorEnd(this); -} - -Utils.extendAsViewModel('PopupsComposeViewModel', PopupsComposeViewModel); - -PopupsComposeViewModel.prototype.openOpenPgpPopup = function () -{ - if (this.capaOpenPGP() && this.oEditor && !this.oEditor.isHtml()) - { - var self = this; - kn.showScreenPopup(PopupsComposeOpenPgpViewModel, [ - function (sResult) { - self.editor(function (oEditor) { - oEditor.setPlain(sResult); - }); - }, - this.oEditor.getData(), - this.currentIdentityResultEmail(), - this.to(), - this.cc(), - this.bcc() - ]); - } -}; - -PopupsComposeViewModel.prototype.reloadDraftFolder = function () -{ - var sDraftFolder = RL.data().draftFolder(); - if ('' !== sDraftFolder) - { - RL.cache().setFolderHash(sDraftFolder, ''); - if (RL.data().currentFolderFullNameRaw() === sDraftFolder) + if (oMessage) { - RL.reloadMessageList(true); - } - else - { - RL.folderInformation(sDraftFolder); - } - } -}; - -PopupsComposeViewModel.prototype.findIdentityIdByMessage = function (sComposeType, oMessage) -{ - var - oIDs = {}, - sResult = '', - fFindHelper = function (oItem) { - if (oItem && oItem.email && oIDs[oItem.email]) + switch (sComposeType) { - sResult = oIDs[oItem.email]; - return true; - } - - return false; - } - ; - - if (this.bCapaAdditionalIdentities) - { - _.each(this.identities(), function (oItem) { - oIDs[oItem.email()] = oItem['id']; - }); - } - - oIDs[RL.data().accountEmail()] = RL.data().accountEmail(); - - if (oMessage) - { - switch (sComposeType) - { - case Enums.ComposeType.Empty: - break; - case Enums.ComposeType.Reply: - case Enums.ComposeType.ReplyAll: - case Enums.ComposeType.Forward: - case Enums.ComposeType.ForwardAsAttachment: - _.find(_.union(oMessage.to, oMessage.cc, oMessage.bcc, oMessage.deliveredTo), fFindHelper); - break; - case Enums.ComposeType.Draft: - _.find(_.union(oMessage.from, oMessage.replyTo), fFindHelper); - break; - } - } - - if ('' === sResult) - { - sResult = this.defaultIdentityID(); - } - - if ('' === sResult) - { - sResult = RL.data().accountEmail(); - } - - return sResult; -}; - -PopupsComposeViewModel.prototype.selectIdentity = function (oIdentity) -{ - if (oIdentity) - { - this.currentIdentityID(oIdentity.optValue); - } -}; - -/** - * - * @param {boolean=} bHeaderResult = false - * @returns {string} - */ -PopupsComposeViewModel.prototype.formattedFrom = function (bHeaderResult) -{ - var - sDisplayName = RL.data().displayName(), - sEmail = RL.data().accountEmail() - ; - - return '' === sDisplayName ? sEmail : - ((Utils.isUnd(bHeaderResult) ? false : !!bHeaderResult) ? - '"' + Utils.quoteName(sDisplayName) + '" <' + sEmail + '>' : - sDisplayName + ' (' + sEmail + ')') - ; -}; - -PopupsComposeViewModel.prototype.sendMessageResponse = function (sResult, oData) -{ - var - bResult = false, - sMessage = '' - ; - - this.sending(false); - - if (Enums.StorageResultType.Success === sResult && oData && oData.Result) - { - bResult = true; - if (this.modalVisibility()) - { - Utils.delegateRun(this, 'closeCommand'); - } - } - - if (this.modalVisibility() && !bResult) - { - if (oData && Enums.Notification.CantSaveMessage === oData.ErrorCode) - { - this.sendSuccessButSaveError(true); - window.alert(Utils.trim(Utils.i18n('COMPOSE/SAVED_ERROR_ON_SEND'))); - } - else - { - sMessage = Utils.getNotification(oData && oData.ErrorCode ? oData.ErrorCode : Enums.Notification.CantSendMessage, - oData && oData.ErrorMessage ? oData.ErrorMessage : ''); - - this.sendError(true); - window.alert(sMessage || Utils.getNotification(Enums.Notification.CantSendMessage)); - } - } - - this.reloadDraftFolder(); -}; - -PopupsComposeViewModel.prototype.saveMessageResponse = function (sResult, oData) -{ - var - bResult = false, - oMessage = null - ; - - this.saving(false); - - if (Enums.StorageResultType.Success === sResult && oData && oData.Result) - { - if (oData.Result.NewFolder && oData.Result.NewUid) - { - if (this.bFromDraft) - { - oMessage = RL.data().message(); - if (oMessage && this.draftFolder() === oMessage.folderFullNameRaw && this.draftUid() === oMessage.uid) - { - RL.data().message(null); - } - } - - this.draftFolder(oData.Result.NewFolder); - this.draftUid(oData.Result.NewUid); - - if (this.modalVisibility()) - { - this.savedTime(Math.round((new window.Date()).getTime() / 1000)); - - this.savedOrSendingText( - 0 < this.savedTime() ? Utils.i18n('COMPOSE/SAVED_TIME', { - 'TIME': moment.unix(this.savedTime() - 1).format('LT') - }) : '' - ); - - bResult = true; - - if (this.bFromDraft) - { - RL.cache().setFolderHash(this.draftFolder(), ''); - } - } - } - } - - if (!this.modalVisibility() && !bResult) - { - this.savedError(true); - this.savedOrSendingText(Utils.getNotification(Enums.Notification.CantSaveMessage)); - } - - this.reloadDraftFolder(); -}; - -PopupsComposeViewModel.prototype.onHide = function () -{ - this.reset(); - kn.routeOn(); -}; - -/** - * @param {string} sSignature - * @param {string=} sFrom - * @param {string=} sData - * @param {string=} sComposeType - * @return {string} - */ -PopupsComposeViewModel.prototype.convertSignature = function (sSignature, sFrom, sData, sComposeType) -{ - var bHtml = false, bData = false; - if ('' !== sSignature) - { - if (':HTML:' === sSignature.substr(0, 6)) - { - bHtml = true; - sSignature = sSignature.substr(6); - } - - sSignature = sSignature.replace(/[\r]/, ''); - - sFrom = Utils.pString(sFrom); - if ('' !== sFrom) - { - sSignature = sSignature.replace(/{{FROM}}/, sFrom); - } - - sSignature = sSignature.replace(/[\s]{1,2}{{FROM}}/, '{{FROM}}'); - - sSignature = sSignature.replace(/{{FROM}}/, ''); - sSignature = sSignature.replace(/{{DATE}}/, moment().format('llll')); - - if (sData && Enums.ComposeType.Empty === sComposeType && - -1 < sSignature.indexOf('{{DATA}}')) - { - bData = true; - sSignature = sSignature.replace('{{DATA}}', sData); - } - - sSignature = sSignature.replace(/{{DATA}}/, ''); - - if (!bHtml) - { - sSignature = Utils.convertPlainTextToHtml(sSignature); - } - } - - if (sData && !bData) - { - switch (sComposeType) - { - case Enums.ComposeType.Empty: - sSignature = sData + '
' + sSignature; - break; - default: - sSignature = sSignature + '
' + sData; - break; - } - } - - return sSignature; -}; - -PopupsComposeViewModel.prototype.editor = function (fOnInit) -{ - if (fOnInit) - { - var self = this; - if (!this.oEditor && this.composeEditorArea()) - { - _.delay(function () { - self.oEditor = new NewHtmlEditorWrapper(self.composeEditorArea(), null, function () { - fOnInit(self.oEditor); - }, function (bHtml) { - self.isHtml(!!bHtml); - }); - }, 300); - } - else if (this.oEditor) - { - fOnInit(this.oEditor); - } - } -}; - -/** - * @param {string=} sType = Enums.ComposeType.Empty - * @param {?MessageModel|Array=} oMessageOrArray = null - * @param {Array=} aToEmails = null - * @param {string=} sCustomSubject = null - * @param {string=} sCustomPlainText = null - */ -PopupsComposeViewModel.prototype.onShow = function (sType, oMessageOrArray, aToEmails, sCustomSubject, sCustomPlainText) -{ - kn.routeOff(); - - var - self = this, - sFrom = '', - sTo = '', - sCc = '', - sDate = '', - sSubject = '', - oText = null, - oSubText = null, - sText = '', - sReplyTitle = '', - aResplyAllParts = [], - oExcludeEmail = {}, - mEmail = RL.data().accountEmail(), - sSignature = RL.data().signature(), - bSignatureToAll = RL.data().signatureToAll(), - aDownloads = [], - aDraftInfo = null, - oMessage = null, - sComposeType = sType || Enums.ComposeType.Empty, - fEmailArrayToStringLineHelper = function (aList, bFriendly) { - - var - iIndex = 0, - iLen = aList.length, - aResult = [] - ; - - for (; iIndex < iLen; iIndex++) - { - aResult.push(aList[iIndex].toLine(!!bFriendly)); - } - - return aResult.join(', '); - } - ; - - oMessageOrArray = oMessageOrArray || null; - if (oMessageOrArray && Utils.isNormal(oMessageOrArray)) - { - oMessage = Utils.isArray(oMessageOrArray) && 1 === oMessageOrArray.length ? oMessageOrArray[0] : - (!Utils.isArray(oMessageOrArray) ? oMessageOrArray : null); - } - - if (null !== mEmail) - { - oExcludeEmail[mEmail] = true; - } - - this.currentIdentityID(this.findIdentityIdByMessage(sComposeType, oMessage)); - this.reset(); - - if (Utils.isNonEmptyArray(aToEmails)) - { - this.to(fEmailArrayToStringLineHelper(aToEmails)); - } - - if ('' !== sComposeType && oMessage) - { - sDate = oMessage.fullFormatDateValue(); - sSubject = oMessage.subject(); - aDraftInfo = oMessage.aDraftInfo; - - oText = $(oMessage.body).clone(); - Utils.removeBlockquoteSwitcher(oText); - - oSubText = oText.find('[data-html-editor-font-wrapper=true]'); - sText = oSubText && oSubText[0] ? oSubText.html() : oText.html(); - - switch (sComposeType) - { - case Enums.ComposeType.Empty: - break; - - case Enums.ComposeType.Reply: - this.to(fEmailArrayToStringLineHelper(oMessage.replyEmails(oExcludeEmail))); - this.subject(Utils.replySubjectAdd('Re', sSubject)); - this.prepearMessageAttachments(oMessage, sComposeType); - this.aDraftInfo = ['reply', oMessage.uid, oMessage.folderFullNameRaw]; - this.sInReplyTo = oMessage.sMessageId; - this.sReferences = Utils.trim(this.sInReplyTo + ' ' + oMessage.sReferences); - break; - - case Enums.ComposeType.ReplyAll: - aResplyAllParts = oMessage.replyAllEmails(oExcludeEmail); - this.to(fEmailArrayToStringLineHelper(aResplyAllParts[0])); - this.cc(fEmailArrayToStringLineHelper(aResplyAllParts[1])); - this.subject(Utils.replySubjectAdd('Re', sSubject)); - this.prepearMessageAttachments(oMessage, sComposeType); - this.aDraftInfo = ['reply', oMessage.uid, oMessage.folderFullNameRaw]; - this.sInReplyTo = oMessage.sMessageId; - this.sReferences = Utils.trim(this.sInReplyTo + ' ' + oMessage.references()); - break; - - case Enums.ComposeType.Forward: - this.subject(Utils.replySubjectAdd('Fwd', sSubject)); - this.prepearMessageAttachments(oMessage, sComposeType); - this.aDraftInfo = ['forward', oMessage.uid, oMessage.folderFullNameRaw]; - this.sInReplyTo = oMessage.sMessageId; - this.sReferences = Utils.trim(this.sInReplyTo + ' ' + oMessage.sReferences); - break; - - case Enums.ComposeType.ForwardAsAttachment: - this.subject(Utils.replySubjectAdd('Fwd', sSubject)); - this.prepearMessageAttachments(oMessage, sComposeType); - this.aDraftInfo = ['forward', oMessage.uid, oMessage.folderFullNameRaw]; - this.sInReplyTo = oMessage.sMessageId; - this.sReferences = Utils.trim(this.sInReplyTo + ' ' + oMessage.sReferences); - break; - - case Enums.ComposeType.Draft: - this.to(fEmailArrayToStringLineHelper(oMessage.to)); - this.cc(fEmailArrayToStringLineHelper(oMessage.cc)); - this.bcc(fEmailArrayToStringLineHelper(oMessage.bcc)); - - this.bFromDraft = true; - - this.draftFolder(oMessage.folderFullNameRaw); - this.draftUid(oMessage.uid); - - this.subject(sSubject); - this.prepearMessageAttachments(oMessage, sComposeType); - - this.aDraftInfo = Utils.isNonEmptyArray(aDraftInfo) && 3 === aDraftInfo.length ? aDraftInfo : null; - this.sInReplyTo = oMessage.sInReplyTo; - this.sReferences = oMessage.sReferences; - break; - - case Enums.ComposeType.EditAsNew: - this.to(fEmailArrayToStringLineHelper(oMessage.to)); - this.cc(fEmailArrayToStringLineHelper(oMessage.cc)); - this.bcc(fEmailArrayToStringLineHelper(oMessage.bcc)); - - this.subject(sSubject); - this.prepearMessageAttachments(oMessage, sComposeType); - - this.aDraftInfo = Utils.isNonEmptyArray(aDraftInfo) && 3 === aDraftInfo.length ? aDraftInfo : null; - this.sInReplyTo = oMessage.sInReplyTo; - this.sReferences = oMessage.sReferences; - break; - } - - switch (sComposeType) - { - case Enums.ComposeType.Reply: - case Enums.ComposeType.ReplyAll: - sFrom = oMessage.fromToLine(false, true); - sReplyTitle = Utils.i18n('COMPOSE/REPLY_MESSAGE_TITLE', { - 'DATETIME': sDate, - 'EMAIL': sFrom - }); - - sText = '

' + sReplyTitle + ':' + - '

' + sText + '

'; - - break; - - case Enums.ComposeType.Forward: - sFrom = oMessage.fromToLine(false, true); - sTo = oMessage.toToLine(false, true); - sCc = oMessage.ccToLine(false, true); - sText = '


' + Utils.i18n('COMPOSE/FORWARD_MESSAGE_TOP_TITLE') + - '
' + Utils.i18n('COMPOSE/FORWARD_MESSAGE_TOP_FROM') + ': ' + sFrom + - '
' + Utils.i18n('COMPOSE/FORWARD_MESSAGE_TOP_TO') + ': ' + sTo + - (0 < sCc.length ? '
' + Utils.i18n('COMPOSE/FORWARD_MESSAGE_TOP_CC') + ': ' + sCc : '') + - '
' + Utils.i18n('COMPOSE/FORWARD_MESSAGE_TOP_SENT') + ': ' + Utils.encodeHtml(sDate) + - '
' + Utils.i18n('COMPOSE/FORWARD_MESSAGE_TOP_SUBJECT') + ': ' + Utils.encodeHtml(sSubject) + - '

' + sText; - break; - case Enums.ComposeType.ForwardAsAttachment: - sText = ''; - break; - } - - if (bSignatureToAll && '' !== sSignature && - Enums.ComposeType.EditAsNew !== sComposeType && Enums.ComposeType.Draft !== sComposeType) - { - sText = this.convertSignature(sSignature, fEmailArrayToStringLineHelper(oMessage.from, true), sText, sComposeType); - } - - this.editor(function (oEditor) { - oEditor.setHtml(sText, false); - if (!oMessage.isHtml()) - { - oEditor.modeToggle(false); - } - }); - } - else if (Enums.ComposeType.Empty === sComposeType) - { - this.subject(Utils.isNormal(sCustomSubject) ? '' + sCustomSubject : ''); - - sText = Utils.isNormal(sCustomPlainText) ? '' + sCustomPlainText : ''; - if (bSignatureToAll && '' !== sSignature) - { - sText = this.convertSignature(sSignature, '', - Utils.convertPlainTextToHtml(sText), sComposeType); - } - - this.editor(function (oEditor) { - oEditor.setHtml(sText, false); - if (Enums.EditorDefaultType.Html !== RL.data().editorDefaultType()) - { - oEditor.modeToggle(false); - } - }); - } - else if (Utils.isNonEmptyArray(oMessageOrArray)) - { - _.each(oMessageOrArray, function (oMessage) { - self.addMessageAsAttachment(oMessage); - }); - } - - aDownloads = this.getAttachmentsDownloadsForUpload(); - if (Utils.isNonEmptyArray(aDownloads)) - { - RL.remote().messageUploadAttachments(function (sResult, oData) { - - if (Enums.StorageResultType.Success === sResult && oData && oData.Result) - { - var - oAttachment = null, - sTempName = '' - ; - - if (!self.viewModelVisibility()) - { - for (sTempName in oData.Result) - { - if (oData.Result.hasOwnProperty(sTempName)) - { - oAttachment = self.getAttachmentById(oData.Result[sTempName]); - if (oAttachment) - { - oAttachment.tempName(sTempName); - } - } - } - } - } - else - { - self.setMessageAttachmentFailedDowbloadText(); - } - - }, aDownloads); - } - - this.triggerForResize(); -}; - -PopupsComposeViewModel.prototype.onFocus = function () -{ - if ('' === this.to()) - { - this.to.focusTrigger(!this.to.focusTrigger()); - } - else if (this.oEditor) - { - this.oEditor.focus(); - } - - this.triggerForResize(); -}; - -PopupsComposeViewModel.prototype.editorResize = function () -{ - if (this.oEditor) - { - this.oEditor.resize(); - } -}; - -PopupsComposeViewModel.prototype.tryToClosePopup = function () -{ - var self = this; - if (!kn.isPopupVisible(PopupsAskViewModel)) - { - kn.showScreenPopup(PopupsAskViewModel, [Utils.i18n('POPUPS_ASK/DESC_WANT_CLOSE_THIS_WINDOW'), function () { - if (self.modalVisibility()) - { - Utils.delegateRun(self, 'closeCommand'); - } - }]); - } -}; - -PopupsComposeViewModel.prototype.onBuild = function () -{ - this.initUploader(); - - var - self = this, - oScript = null - ; - - key('ctrl+q, command+q', Enums.KeyState.Compose, function () { - self.identitiesDropdownTrigger(true); - return false; - }); - - key('ctrl+s, command+s', Enums.KeyState.Compose, function () { - self.saveCommand(); - return false; - }); - - key('ctrl+enter, command+enter', Enums.KeyState.Compose, function () { - self.sendCommand(); - return false; - }); - - key('esc', Enums.KeyState.Compose, function () { - if (self.modalVisibility()) - { - self.tryToClosePopup(); - } - return false; - }); - - $window.on('resize', function () { - self.triggerForResize(); - }); - - if (this.dropboxEnabled()) - { - oScript = document.createElement('script'); - oScript.type = 'text/javascript'; - oScript.src = 'https://www.dropbox.com/static/api/1/dropins.js'; - $(oScript).attr('id', 'dropboxjs').attr('data-app-key', RL.settingsGet('DropboxApiKey')); - - document.body.appendChild(oScript); - } - - if (this.driveEnabled()) - { - $.getScript('https://apis.google.com/js/api.js', function () { - if (window.gapi) - { - self.driveVisible(true); - } - }); - } -}; - -PopupsComposeViewModel.prototype.driveCallback = function (sAccessToken, oData) -{ - if (oData && window.XMLHttpRequest && window.google && - oData[window.google.picker.Response.ACTION] === window.google.picker.Action.PICKED && - oData[window.google.picker.Response.DOCUMENTS] && oData[window.google.picker.Response.DOCUMENTS][0] && - oData[window.google.picker.Response.DOCUMENTS][0]['id']) - { - var - self = this, - oRequest = new window.XMLHttpRequest() - ; - - oRequest.open('GET', 'https://www.googleapis.com/drive/v2/files/' + oData[window.google.picker.Response.DOCUMENTS][0]['id']); - oRequest.setRequestHeader('Authorization', 'Bearer ' + sAccessToken); - oRequest.addEventListener('load', function() { - if (oRequest && oRequest.responseText) - { - var oItem = JSON.parse(oRequest.responseText), fExport = function (oItem, sMimeType, sExt) { - if (oItem && oItem['exportLinks']) - { - if (oItem['exportLinks'][sMimeType]) - { - oItem['downloadUrl'] = oItem['exportLinks'][sMimeType]; - oItem['title'] = oItem['title'] + '.' + sExt; - oItem['mimeType'] = sMimeType; - } - else if (oItem['exportLinks']['application/pdf']) - { - oItem['downloadUrl'] = oItem['exportLinks']['application/pdf']; - oItem['title'] = oItem['title'] + '.pdf'; - oItem['mimeType'] = 'application/pdf'; - } - } - }; - - if (oItem && !oItem['downloadUrl'] && oItem['mimeType'] && oItem['exportLinks']) - { - switch (oItem['mimeType'].toString().toLowerCase()) - { - case 'application/vnd.google-apps.document': - fExport(oItem, 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', 'docx'); - break; - case 'application/vnd.google-apps.spreadsheet': - fExport(oItem, 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', 'xlsx'); - break; - case 'application/vnd.google-apps.drawing': - fExport(oItem, 'image/png', 'png'); - break; - case 'application/vnd.google-apps.presentation': - fExport(oItem, 'application/vnd.openxmlformats-officedocument.presentationml.presentation', 'pptx'); - break; - default: - fExport(oItem, 'application/pdf', 'pdf'); - break; - } - } - - if (oItem && oItem['downloadUrl']) - { - self.addDriveAttachment(oItem, sAccessToken); - } - } - }); - - oRequest.send(); - } -}; - -PopupsComposeViewModel.prototype.driveCreatePiker = function (oOauthToken) -{ - if (window.gapi && oOauthToken && oOauthToken.access_token) - { - var self = this; - - window.gapi.load('picker', {'callback': function () { - - if (window.google && window.google.picker) - { - var drivePicker = new window.google.picker.PickerBuilder() - .addView( - new window.google.picker.DocsView() - .setIncludeFolders(true) - ) - .setAppId(RL.settingsGet('GoogleClientID')) - .setOAuthToken(oOauthToken.access_token) - .setCallback(_.bind(self.driveCallback, self, oOauthToken.access_token)) - .enableFeature(window.google.picker.Feature.NAV_HIDDEN) - .build() - ; - - drivePicker.setVisible(true); - } - }}); - } -}; - -PopupsComposeViewModel.prototype.driveOpenPopup = function () -{ - if (window.gapi) - { - var self = this; - - window.gapi.load('auth', {'callback': function () { - - var oAuthToken = window.gapi.auth.getToken(); - if (!oAuthToken) - { - window.gapi.auth.authorize({ - 'client_id': RL.settingsGet('GoogleClientID'), - 'scope': 'https://www.googleapis.com/auth/drive.readonly', - 'immediate': true - }, function (oAuthResult) { - if (oAuthResult && !oAuthResult.error) - { - var oAuthToken = window.gapi.auth.getToken(); - if (oAuthToken) - { - self.driveCreatePiker(oAuthToken); - } - } - else - { - window.gapi.auth.authorize({ - 'client_id': RL.settingsGet('GoogleClientID'), - 'scope': 'https://www.googleapis.com/auth/drive.readonly', - 'immediate': false - }, function (oAuthResult) { - if (oAuthResult && !oAuthResult.error) - { - var oAuthToken = window.gapi.auth.getToken(); - if (oAuthToken) - { - self.driveCreatePiker(oAuthToken); - } - } - }); - } - }); - } - else - { - self.driveCreatePiker(oAuthToken); - } - }}); - } -}; - -/** - * @param {string} sId - * @return {?Object} - */ -PopupsComposeViewModel.prototype.getAttachmentById = function (sId) -{ - var - aAttachments = this.attachments(), - iIndex = 0, - iLen = aAttachments.length - ; - - for (; iIndex < iLen; iIndex++) - { - if (aAttachments[iIndex] && sId === aAttachments[iIndex].id) - { - return aAttachments[iIndex]; - } - } - - return null; -}; - -PopupsComposeViewModel.prototype.initUploader = function () -{ - if (this.composeUploaderButton()) - { - var - oUploadCache = {}, - iAttachmentSizeLimit = Utils.pInt(RL.settingsGet('AttachmentLimit')), - oJua = new Jua({ - 'action': RL.link().upload(), - 'name': 'uploader', - 'queueSize': 2, - 'multipleSizeLimit': 50, - 'disableFolderDragAndDrop': false, - 'clickElement': this.composeUploaderButton(), - 'dragAndDropElement': this.composeUploaderDropPlace() - }) - ; - - if (oJua) - { - oJua -// .on('onLimitReached', function (iLimit) { -// alert(iLimit); -// }) - .on('onDragEnter', _.bind(function () { - this.dragAndDropOver(true); - }, this)) - .on('onDragLeave', _.bind(function () { - this.dragAndDropOver(false); - }, this)) - .on('onBodyDragEnter', _.bind(function () { - this.dragAndDropVisible(true); - }, this)) - .on('onBodyDragLeave', _.bind(function () { - this.dragAndDropVisible(false); - }, this)) - .on('onProgress', _.bind(function (sId, iLoaded, iTotal) { - var oItem = null; - if (Utils.isUnd(oUploadCache[sId])) - { - oItem = this.getAttachmentById(sId); - if (oItem) - { - oUploadCache[sId] = oItem; - } - } - else - { - oItem = oUploadCache[sId]; - } - - if (oItem) - { - oItem.progress(' - ' + Math.floor(iLoaded / iTotal * 100) + '%'); - } - - }, this)) - .on('onSelect', _.bind(function (sId, oData) { - - this.dragAndDropOver(false); - - var - that = this, - sFileName = Utils.isUnd(oData.FileName) ? '' : oData.FileName.toString(), - mSize = Utils.isNormal(oData.Size) ? Utils.pInt(oData.Size) : null, - oAttachment = new ComposeAttachmentModel(sId, sFileName, mSize) - ; - - oAttachment.cancel = (function (sId) { - - return function () { - that.attachments.remove(function (oItem) { - return oItem && oItem.id === sId; - }); - - if (oJua) - { - oJua.cancel(sId); - } - }; - - }(sId)); - - this.attachments.push(oAttachment); - - if (0 < mSize && 0 < iAttachmentSizeLimit && iAttachmentSizeLimit < mSize) - { - oAttachment.error(Utils.i18n('UPLOAD/ERROR_FILE_IS_TOO_BIG')); - return false; - } - - return true; - - }, this)) - .on('onStart', _.bind(function (sId) { - - var - oItem = null - ; - - if (Utils.isUnd(oUploadCache[sId])) - { - oItem = this.getAttachmentById(sId); - if (oItem) - { - oUploadCache[sId] = oItem; - } - } - else - { - oItem = oUploadCache[sId]; - } - - if (oItem) - { - oItem.waiting(false); - oItem.uploading(true); - } - - }, this)) - .on('onComplete', _.bind(function (sId, bResult, oData) { - - var - sError = '', - mErrorCode = null, - oAttachmentJson = null, - oAttachment = this.getAttachmentById(sId) - ; - - oAttachmentJson = bResult && oData && oData.Result && oData.Result.Attachment ? oData.Result.Attachment : null; - mErrorCode = oData && oData.Result && oData.Result.ErrorCode ? oData.Result.ErrorCode : null; - - if (null !== mErrorCode) - { - sError = Utils.getUploadErrorDescByCode(mErrorCode); - } - else if (!oAttachmentJson) - { - sError = Utils.i18n('UPLOAD/ERROR_UNKNOWN'); - } - - if (oAttachment) - { - if ('' !== sError && 0 < sError.length) - { - oAttachment - .waiting(false) - .uploading(false) - .error(sError) - ; - } - else if (oAttachmentJson) - { - oAttachment - .waiting(false) - .uploading(false) - ; - - oAttachment.initByUploadJson(oAttachmentJson); - } - - if (Utils.isUnd(oUploadCache[sId])) - { - delete (oUploadCache[sId]); - } - } - - }, this)) - ; - - this - .addAttachmentEnabled(true) - .dragAndDropEnabled(oJua.isDragAndDropSupported()) - ; - } - else - { - this - .addAttachmentEnabled(false) - .dragAndDropEnabled(false) - ; - } - } -}; - -/** - * @return {Object} - */ -PopupsComposeViewModel.prototype.prepearAttachmentsForSendOrSave = function () -{ - var oResult = {}; - _.each(this.attachmentsInReady(), function (oItem) { - if (oItem && '' !== oItem.tempName() && oItem.enabled()) - { - oResult[oItem.tempName()] = [ - oItem.fileName(), - oItem.isInline ? '1' : '0', - oItem.CID, - oItem.contentLocation - ]; - } - }); - - return oResult; -}; - -/** - * @param {MessageModel} oMessage - */ -PopupsComposeViewModel.prototype.addMessageAsAttachment = function (oMessage) -{ - if (oMessage) - { - var - self = this, - oAttachment = null, - sTemp = oMessage.subject(), - fCancelFunc = function (sId) { - return function () { - self.attachments.remove(function (oItem) { - return oItem && oItem.id === sId; - }); - }; - } - ; - - sTemp = '.eml' === sTemp.substr(-4).toLowerCase() ? sTemp : sTemp + '.eml'; - oAttachment = new ComposeAttachmentModel( - oMessage.requestHash, sTemp, oMessage.size() - ); - - oAttachment.fromMessage = true; - oAttachment.cancel = fCancelFunc(oMessage.requestHash); - oAttachment.waiting(false).uploading(true); - - this.attachments.push(oAttachment); - } -}; - -/** - * @param {Object} oDropboxFile - * @return {boolean} - */ -PopupsComposeViewModel.prototype.addDropboxAttachment = function (oDropboxFile) -{ - var - self = this, - oAttachment = null, - fCancelFunc = function (sId) { - return function () { - self.attachments.remove(function (oItem) { - return oItem && oItem.id === sId; - }); - }; - }, - iAttachmentSizeLimit = Utils.pInt(RL.settingsGet('AttachmentLimit')), - mSize = oDropboxFile['bytes'] - ; - - oAttachment = new ComposeAttachmentModel( - oDropboxFile['link'], oDropboxFile['name'], mSize - ); - - oAttachment.fromMessage = false; - oAttachment.cancel = fCancelFunc(oDropboxFile['link']); - oAttachment.waiting(false).uploading(true); - - this.attachments.push(oAttachment); - - if (0 < mSize && 0 < iAttachmentSizeLimit && iAttachmentSizeLimit < mSize) - { - oAttachment.uploading(false); - oAttachment.error(Utils.i18n('UPLOAD/ERROR_FILE_IS_TOO_BIG')); - return false; - } - - RL.remote().composeUploadExternals(function (sResult, oData) { - - var bResult = false; - oAttachment.uploading(false); - - if (Enums.StorageResultType.Success === sResult && oData && oData.Result) - { - if (oData.Result[oAttachment.id]) - { - bResult = true; - oAttachment.tempName(oData.Result[oAttachment.id]); - } - } - - if (!bResult) - { - oAttachment.error(Utils.getUploadErrorDescByCode(Enums.UploadErrorCode.FileNoUploaded)); - } - - }, [oDropboxFile['link']]); - - return true; -}; - -/** - * @param {Object} oDriveFile - * @param {string} sAccessToken - * @return {boolean} - */ -PopupsComposeViewModel.prototype.addDriveAttachment = function (oDriveFile, sAccessToken) -{ - var - self = this, - fCancelFunc = function (sId) { - return function () { - self.attachments.remove(function (oItem) { - return oItem && oItem.id === sId; - }); - }; - }, - iAttachmentSizeLimit = Utils.pInt(RL.settingsGet('AttachmentLimit')), - oAttachment = null, - mSize = oDriveFile['fileSize'] ? Utils.pInt(oDriveFile['fileSize']) : 0 - ; - - oAttachment = new ComposeAttachmentModel( - oDriveFile['downloadUrl'], oDriveFile['title'], mSize - ); - - oAttachment.fromMessage = false; - oAttachment.cancel = fCancelFunc(oDriveFile['downloadUrl']); - oAttachment.waiting(false).uploading(true); - - this.attachments.push(oAttachment); - - if (0 < mSize && 0 < iAttachmentSizeLimit && iAttachmentSizeLimit < mSize) - { - oAttachment.uploading(false); - oAttachment.error(Utils.i18n('UPLOAD/ERROR_FILE_IS_TOO_BIG')); - return false; - } - - RL.remote().composeUploadDrive(function (sResult, oData) { - - var bResult = false; - oAttachment.uploading(false); - - if (Enums.StorageResultType.Success === sResult && oData && oData.Result) - { - if (oData.Result[oAttachment.id]) - { - bResult = true; - oAttachment.tempName(oData.Result[oAttachment.id][0]); - oAttachment.size(Utils.pInt(oData.Result[oAttachment.id][1])); - } - } - - if (!bResult) - { - oAttachment.error(Utils.getUploadErrorDescByCode(Enums.UploadErrorCode.FileNoUploaded)); - } - - }, oDriveFile['downloadUrl'], sAccessToken); - - return true; -}; - -/** - * @param {MessageModel} oMessage - * @param {string} sType - */ -PopupsComposeViewModel.prototype.prepearMessageAttachments = function (oMessage, sType) -{ - if (oMessage) - { - var - self = this, - aAttachments = Utils.isNonEmptyArray(oMessage.attachments()) ? oMessage.attachments() : [], - iIndex = 0, - iLen = aAttachments.length, - oAttachment = null, - oItem = null, - bAdd = false, - fCancelFunc = function (sId) { - return function () { - self.attachments.remove(function (oItem) { - return oItem && oItem.id === sId; - }); - }; - } - ; - - if (Enums.ComposeType.ForwardAsAttachment === sType) - { - this.addMessageAsAttachment(oMessage); - } - else - { - for (; iIndex < iLen; iIndex++) - { - oItem = aAttachments[iIndex]; - - bAdd = false; - switch (sType) { + case Enums.ComposeType.Empty: + break; case Enums.ComposeType.Reply: case Enums.ComposeType.ReplyAll: - bAdd = oItem.isLinked; + case Enums.ComposeType.Forward: + case Enums.ComposeType.ForwardAsAttachment: + _.find(_.union(oMessage.to, oMessage.cc, oMessage.bcc, oMessage.deliveredTo), fFindHelper); + break; + case Enums.ComposeType.Draft: + _.find(_.union(oMessage.from, oMessage.replyTo), fFindHelper); + break; + } + } + + if ('' === sResult) + { + sResult = this.defaultIdentityID(); + } + + if ('' === sResult) + { + sResult = Data.accountEmail(); + } + + return sResult; + }; + + PopupsComposeViewModel.prototype.selectIdentity = function (oIdentity) + { + if (oIdentity) + { + this.currentIdentityID(oIdentity.optValue); + } + }; + + /** + * + * @param {boolean=} bHeaderResult = false + * @returns {string} + */ + PopupsComposeViewModel.prototype.formattedFrom = function (bHeaderResult) + { + var + sDisplayName = Data.displayName(), + sEmail = Data.accountEmail() + ; + + return '' === sDisplayName ? sEmail : + ((Utils.isUnd(bHeaderResult) ? false : !!bHeaderResult) ? + '"' + Utils.quoteName(sDisplayName) + '" <' + sEmail + '>' : + sDisplayName + ' (' + sEmail + ')') + ; + }; + + PopupsComposeViewModel.prototype.sendMessageResponse = function (sResult, oData) + { + var + bResult = false, + sMessage = '' + ; + + this.sending(false); + + if (Enums.StorageResultType.Success === sResult && oData && oData.Result) + { + bResult = true; + if (this.modalVisibility()) + { + Utils.delegateRun(this, 'closeCommand'); + } + } + + if (this.modalVisibility() && !bResult) + { + if (oData && Enums.Notification.CantSaveMessage === oData.ErrorCode) + { + this.sendSuccessButSaveError(true); + window.alert(Utils.trim(Utils.i18n('COMPOSE/SAVED_ERROR_ON_SEND'))); + } + else + { + sMessage = Utils.getNotification(oData && oData.ErrorCode ? oData.ErrorCode : Enums.Notification.CantSendMessage, + oData && oData.ErrorMessage ? oData.ErrorMessage : ''); + + this.sendError(true); + window.alert(sMessage || Utils.getNotification(Enums.Notification.CantSendMessage)); + } + } + + this.reloadDraftFolder(); + }; + + PopupsComposeViewModel.prototype.saveMessageResponse = function (sResult, oData) + { + var + bResult = false, + oMessage = null + ; + + this.saving(false); + + if (Enums.StorageResultType.Success === sResult && oData && oData.Result) + { + if (oData.Result.NewFolder && oData.Result.NewUid) + { + if (this.bFromDraft) + { + oMessage = Data.message(); + if (oMessage && this.draftFolder() === oMessage.folderFullNameRaw && this.draftUid() === oMessage.uid) + { + Data.message(null); + } + } + + this.draftFolder(oData.Result.NewFolder); + this.draftUid(oData.Result.NewUid); + + if (this.modalVisibility()) + { + this.savedTime(window.Math.round((new window.Date()).getTime() / 1000)); + + this.savedOrSendingText( + 0 < this.savedTime() ? Utils.i18n('COMPOSE/SAVED_TIME', { + 'TIME': moment.unix(this.savedTime() - 1).format('LT') + }) : '' + ); + + bResult = true; + + if (this.bFromDraft) + { + Cache.setFolderHash(this.draftFolder(), ''); + } + } + } + } + + if (!this.modalVisibility() && !bResult) + { + this.savedError(true); + this.savedOrSendingText(Utils.getNotification(Enums.Notification.CantSaveMessage)); + } + + this.reloadDraftFolder(); + }; + + PopupsComposeViewModel.prototype.onHide = function () + { + this.reset(); + kn.routeOn(); + }; + + /** + * @param {string} sSignature + * @param {string=} sFrom + * @param {string=} sData + * @param {string=} sComposeType + * @return {string} + */ + PopupsComposeViewModel.prototype.convertSignature = function (sSignature, sFrom, sData, sComposeType) + { + var bHtml = false, bData = false; + if ('' !== sSignature) + { + if (':HTML:' === sSignature.substr(0, 6)) + { + bHtml = true; + sSignature = sSignature.substr(6); + } + + sSignature = sSignature.replace(/[\r]/, ''); + + sFrom = Utils.pString(sFrom); + if ('' !== sFrom) + { + sSignature = sSignature.replace(/{{FROM}}/, sFrom); + } + + sSignature = sSignature.replace(/[\s]{1,2}{{FROM}}/, '{{FROM}}'); + + sSignature = sSignature.replace(/{{FROM}}/, ''); + sSignature = sSignature.replace(/{{DATE}}/, moment().format('llll')); + + if (sData && Enums.ComposeType.Empty === sComposeType && + -1 < sSignature.indexOf('{{DATA}}')) + { + bData = true; + sSignature = sSignature.replace('{{DATA}}', sData); + } + + sSignature = sSignature.replace(/{{DATA}}/, ''); + + if (!bHtml) + { + sSignature = Utils.convertPlainTextToHtml(sSignature); + } + } + + if (sData && !bData) + { + switch (sComposeType) + { + case Enums.ComposeType.Empty: + sSignature = sData + '
' + sSignature; + break; + default: + sSignature = sSignature + '
' + sData; + break; + } + } + + return sSignature; + }; + + PopupsComposeViewModel.prototype.editor = function (fOnInit) + { + if (fOnInit) + { + var self = this; + if (!this.oEditor && this.composeEditorArea()) + { + _.delay(function () { + self.oEditor = new NewHtmlEditorWrapper(self.composeEditorArea(), null, function () { + fOnInit(self.oEditor); + }, function (bHtml) { + self.isHtml(!!bHtml); + }); + }, 300); + } + else if (this.oEditor) + { + fOnInit(this.oEditor); + } + } + }; + + /** + * @param {string=} sType = Enums.ComposeType.Empty + * @param {?MessageModel|Array=} oMessageOrArray = null + * @param {Array=} aToEmails = null + * @param {string=} sCustomSubject = null + * @param {string=} sCustomPlainText = null + */ + PopupsComposeViewModel.prototype.onShow = function (sType, oMessageOrArray, aToEmails, sCustomSubject, sCustomPlainText) + { + kn.routeOff(); + + var + self = this, + sFrom = '', + sTo = '', + sCc = '', + sDate = '', + sSubject = '', + oText = null, + oSubText = null, + sText = '', + sReplyTitle = '', + aResplyAllParts = [], + oExcludeEmail = {}, + mEmail = Data.accountEmail(), + sSignature = Data.signature(), + bSignatureToAll = Data.signatureToAll(), + aDownloads = [], + aDraftInfo = null, + oMessage = null, + sComposeType = sType || Enums.ComposeType.Empty, + fEmailArrayToStringLineHelper = function (aList, bFriendly) { + + var + iIndex = 0, + iLen = aList.length, + aResult = [] + ; + + for (; iIndex < iLen; iIndex++) + { + aResult.push(aList[iIndex].toLine(!!bFriendly)); + } + + return aResult.join(', '); + } + ; + + oMessageOrArray = oMessageOrArray || null; + if (oMessageOrArray && Utils.isNormal(oMessageOrArray)) + { + oMessage = Utils.isArray(oMessageOrArray) && 1 === oMessageOrArray.length ? oMessageOrArray[0] : + (!Utils.isArray(oMessageOrArray) ? oMessageOrArray : null); + } + + if (null !== mEmail) + { + oExcludeEmail[mEmail] = true; + } + + this.currentIdentityID(this.findIdentityIdByMessage(sComposeType, oMessage)); + this.reset(); + + if (Utils.isNonEmptyArray(aToEmails)) + { + this.to(fEmailArrayToStringLineHelper(aToEmails)); + } + + if ('' !== sComposeType && oMessage) + { + sDate = oMessage.fullFormatDateValue(); + sSubject = oMessage.subject(); + aDraftInfo = oMessage.aDraftInfo; + + oText = $(oMessage.body).clone(); + Utils.removeBlockquoteSwitcher(oText); + + oSubText = oText.find('[data-html-editor-font-wrapper=true]'); + sText = oSubText && oSubText[0] ? oSubText.html() : oText.html(); + + switch (sComposeType) + { + case Enums.ComposeType.Empty: + break; + + case Enums.ComposeType.Reply: + this.to(fEmailArrayToStringLineHelper(oMessage.replyEmails(oExcludeEmail))); + this.subject(Utils.replySubjectAdd('Re', sSubject)); + this.prepearMessageAttachments(oMessage, sComposeType); + this.aDraftInfo = ['reply', oMessage.uid, oMessage.folderFullNameRaw]; + this.sInReplyTo = oMessage.sMessageId; + this.sReferences = Utils.trim(this.sInReplyTo + ' ' + oMessage.sReferences); + break; + + case Enums.ComposeType.ReplyAll: + aResplyAllParts = oMessage.replyAllEmails(oExcludeEmail); + this.to(fEmailArrayToStringLineHelper(aResplyAllParts[0])); + this.cc(fEmailArrayToStringLineHelper(aResplyAllParts[1])); + this.subject(Utils.replySubjectAdd('Re', sSubject)); + this.prepearMessageAttachments(oMessage, sComposeType); + this.aDraftInfo = ['reply', oMessage.uid, oMessage.folderFullNameRaw]; + this.sInReplyTo = oMessage.sMessageId; + this.sReferences = Utils.trim(this.sInReplyTo + ' ' + oMessage.references()); break; case Enums.ComposeType.Forward: - case Enums.ComposeType.Draft: - case Enums.ComposeType.EditAsNew: - bAdd = true; + this.subject(Utils.replySubjectAdd('Fwd', sSubject)); + this.prepearMessageAttachments(oMessage, sComposeType); + this.aDraftInfo = ['forward', oMessage.uid, oMessage.folderFullNameRaw]; + this.sInReplyTo = oMessage.sMessageId; + this.sReferences = Utils.trim(this.sInReplyTo + ' ' + oMessage.sReferences); break; + + case Enums.ComposeType.ForwardAsAttachment: + this.subject(Utils.replySubjectAdd('Fwd', sSubject)); + this.prepearMessageAttachments(oMessage, sComposeType); + this.aDraftInfo = ['forward', oMessage.uid, oMessage.folderFullNameRaw]; + this.sInReplyTo = oMessage.sMessageId; + this.sReferences = Utils.trim(this.sInReplyTo + ' ' + oMessage.sReferences); + break; + + case Enums.ComposeType.Draft: + this.to(fEmailArrayToStringLineHelper(oMessage.to)); + this.cc(fEmailArrayToStringLineHelper(oMessage.cc)); + this.bcc(fEmailArrayToStringLineHelper(oMessage.bcc)); + + this.bFromDraft = true; + + this.draftFolder(oMessage.folderFullNameRaw); + this.draftUid(oMessage.uid); + + this.subject(sSubject); + this.prepearMessageAttachments(oMessage, sComposeType); + + this.aDraftInfo = Utils.isNonEmptyArray(aDraftInfo) && 3 === aDraftInfo.length ? aDraftInfo : null; + this.sInReplyTo = oMessage.sInReplyTo; + this.sReferences = oMessage.sReferences; + break; + + case Enums.ComposeType.EditAsNew: + this.to(fEmailArrayToStringLineHelper(oMessage.to)); + this.cc(fEmailArrayToStringLineHelper(oMessage.cc)); + this.bcc(fEmailArrayToStringLineHelper(oMessage.bcc)); + + this.subject(sSubject); + this.prepearMessageAttachments(oMessage, sComposeType); + + this.aDraftInfo = Utils.isNonEmptyArray(aDraftInfo) && 3 === aDraftInfo.length ? aDraftInfo : null; + this.sInReplyTo = oMessage.sInReplyTo; + this.sReferences = oMessage.sReferences; + break; + } + + switch (sComposeType) + { + case Enums.ComposeType.Reply: + case Enums.ComposeType.ReplyAll: + sFrom = oMessage.fromToLine(false, true); + sReplyTitle = Utils.i18n('COMPOSE/REPLY_MESSAGE_TITLE', { + 'DATETIME': sDate, + 'EMAIL': sFrom + }); + + sText = '

' + sReplyTitle + ':' + + '

' + sText + '

'; + + break; + + case Enums.ComposeType.Forward: + sFrom = oMessage.fromToLine(false, true); + sTo = oMessage.toToLine(false, true); + sCc = oMessage.ccToLine(false, true); + sText = '


' + Utils.i18n('COMPOSE/FORWARD_MESSAGE_TOP_TITLE') + + '
' + Utils.i18n('COMPOSE/FORWARD_MESSAGE_TOP_FROM') + ': ' + sFrom + + '
' + Utils.i18n('COMPOSE/FORWARD_MESSAGE_TOP_TO') + ': ' + sTo + + (0 < sCc.length ? '
' + Utils.i18n('COMPOSE/FORWARD_MESSAGE_TOP_CC') + ': ' + sCc : '') + + '
' + Utils.i18n('COMPOSE/FORWARD_MESSAGE_TOP_SENT') + ': ' + Utils.encodeHtml(sDate) + + '
' + Utils.i18n('COMPOSE/FORWARD_MESSAGE_TOP_SUBJECT') + ': ' + Utils.encodeHtml(sSubject) + + '

' + sText; + break; + case Enums.ComposeType.ForwardAsAttachment: + sText = ''; + break; + } + + if (bSignatureToAll && '' !== sSignature && + Enums.ComposeType.EditAsNew !== sComposeType && Enums.ComposeType.Draft !== sComposeType) + { + sText = this.convertSignature(sSignature, fEmailArrayToStringLineHelper(oMessage.from, true), sText, sComposeType); + } + + this.editor(function (oEditor) { + oEditor.setHtml(sText, false); + if (!oMessage.isHtml()) + { + oEditor.modeToggle(false); + } + }); + } + else if (Enums.ComposeType.Empty === sComposeType) + { + this.subject(Utils.isNormal(sCustomSubject) ? '' + sCustomSubject : ''); + + sText = Utils.isNormal(sCustomPlainText) ? '' + sCustomPlainText : ''; + if (bSignatureToAll && '' !== sSignature) + { + sText = this.convertSignature(sSignature, '', + Utils.convertPlainTextToHtml(sText), sComposeType); + } + + this.editor(function (oEditor) { + oEditor.setHtml(sText, false); + if (Enums.EditorDefaultType.Html !== Data.editorDefaultType()) + { + oEditor.modeToggle(false); + } + }); + } + else if (Utils.isNonEmptyArray(oMessageOrArray)) + { + _.each(oMessageOrArray, function (oMessage) { + self.addMessageAsAttachment(oMessage); + }); + } + + aDownloads = this.getAttachmentsDownloadsForUpload(); + if (Utils.isNonEmptyArray(aDownloads)) + { + Remote.messageUploadAttachments(function (sResult, oData) { + + if (Enums.StorageResultType.Success === sResult && oData && oData.Result) + { + var + oAttachment = null, + sTempName = '' + ; + + if (!self.viewModelVisibility()) + { + for (sTempName in oData.Result) + { + if (oData.Result.hasOwnProperty(sTempName)) + { + oAttachment = self.getAttachmentById(oData.Result[sTempName]); + if (oAttachment) + { + oAttachment.tempName(sTempName); + } + } + } + } + } + else + { + self.setMessageAttachmentFailedDowbloadText(); } - if (bAdd) + }, aDownloads); + } + + this.triggerForResize(); + }; + + PopupsComposeViewModel.prototype.onFocus = function () + { + if ('' === this.to()) + { + this.to.focusTrigger(!this.to.focusTrigger()); + } + else if (this.oEditor) + { + this.oEditor.focus(); + } + + this.triggerForResize(); + }; + + PopupsComposeViewModel.prototype.editorResize = function () + { + if (this.oEditor) + { + this.oEditor.resize(); + } + }; + + PopupsComposeViewModel.prototype.tryToClosePopup = function () + { + var self = this; + if (!kn.isPopupVisible(PopupsAskViewModel)) + { + kn.showScreenPopup(PopupsAskViewModel, [Utils.i18n('POPUPS_ASK/DESC_WANT_CLOSE_THIS_WINDOW'), function () { + if (self.modalVisibility()) { - oAttachment = new ComposeAttachmentModel( - oItem.download, oItem.fileName, oItem.estimatedSize, - oItem.isInline, oItem.isLinked, oItem.cid, oItem.contentLocation - ); + Utils.delegateRun(self, 'closeCommand'); + } + }]); + } + }; - oAttachment.fromMessage = true; - oAttachment.cancel = fCancelFunc(oItem.download); - oAttachment.waiting(false).uploading(true); + PopupsComposeViewModel.prototype.onBuild = function () + { + this.initUploader(); - this.attachments.push(oAttachment); + var + self = this, + oScript = null + ; + + key('ctrl+q, command+q', Enums.KeyState.Compose, function () { + self.identitiesDropdownTrigger(true); + return false; + }); + + key('ctrl+s, command+s', Enums.KeyState.Compose, function () { + self.saveCommand(); + return false; + }); + + key('ctrl+enter, command+enter', Enums.KeyState.Compose, function () { + self.sendCommand(); + return false; + }); + + key('esc', Enums.KeyState.Compose, function () { + if (self.modalVisibility()) + { + self.tryToClosePopup(); + } + return false; + }); + + $window.on('resize', function () { + self.triggerForResize(); + }); + + if (this.dropboxEnabled()) + { + oScript = document.createElement('script'); + oScript.type = 'text/javascript'; + oScript.src = 'https://www.dropbox.com/static/api/1/dropins.js'; + $(oScript).attr('id', 'dropboxjs').attr('data-app-key', RL.settingsGet('DropboxApiKey')); + + document.body.appendChild(oScript); + } + + if (this.driveEnabled()) + { + $.getScript('https://apis.google.com/js/api.js', function () { + if (window.gapi) + { + self.driveVisible(true); + } + }); + } + }; + + PopupsComposeViewModel.prototype.driveCallback = function (sAccessToken, oData) + { + if (oData && window.XMLHttpRequest && window.google && + oData[window.google.picker.Response.ACTION] === window.google.picker.Action.PICKED && + oData[window.google.picker.Response.DOCUMENTS] && oData[window.google.picker.Response.DOCUMENTS][0] && + oData[window.google.picker.Response.DOCUMENTS][0]['id']) + { + var + self = this, + oRequest = new window.XMLHttpRequest() + ; + + oRequest.open('GET', 'https://www.googleapis.com/drive/v2/files/' + oData[window.google.picker.Response.DOCUMENTS][0]['id']); + oRequest.setRequestHeader('Authorization', 'Bearer ' + sAccessToken); + oRequest.addEventListener('load', function() { + if (oRequest && oRequest.responseText) + { + var oItem = JSON.parse(oRequest.responseText), fExport = function (oItem, sMimeType, sExt) { + if (oItem && oItem['exportLinks']) + { + if (oItem['exportLinks'][sMimeType]) + { + oItem['downloadUrl'] = oItem['exportLinks'][sMimeType]; + oItem['title'] = oItem['title'] + '.' + sExt; + oItem['mimeType'] = sMimeType; + } + else if (oItem['exportLinks']['application/pdf']) + { + oItem['downloadUrl'] = oItem['exportLinks']['application/pdf']; + oItem['title'] = oItem['title'] + '.pdf'; + oItem['mimeType'] = 'application/pdf'; + } + } + }; + + if (oItem && !oItem['downloadUrl'] && oItem['mimeType'] && oItem['exportLinks']) + { + switch (oItem['mimeType'].toString().toLowerCase()) + { + case 'application/vnd.google-apps.document': + fExport(oItem, 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', 'docx'); + break; + case 'application/vnd.google-apps.spreadsheet': + fExport(oItem, 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', 'xlsx'); + break; + case 'application/vnd.google-apps.drawing': + fExport(oItem, 'image/png', 'png'); + break; + case 'application/vnd.google-apps.presentation': + fExport(oItem, 'application/vnd.openxmlformats-officedocument.presentationml.presentation', 'pptx'); + break; + default: + fExport(oItem, 'application/pdf', 'pdf'); + break; + } + } + + if (oItem && oItem['downloadUrl']) + { + self.addDriveAttachment(oItem, sAccessToken); + } + } + }); + + oRequest.send(); + } + }; + + PopupsComposeViewModel.prototype.driveCreatePiker = function (oOauthToken) + { + if (window.gapi && oOauthToken && oOauthToken.access_token) + { + var self = this; + + window.gapi.load('picker', {'callback': function () { + + if (window.google && window.google.picker) + { + var drivePicker = new window.google.picker.PickerBuilder() + .addView( + new window.google.picker.DocsView() + .setIncludeFolders(true) + ) + .setAppId(RL.settingsGet('GoogleClientID')) + .setOAuthToken(oOauthToken.access_token) + .setCallback(_.bind(self.driveCallback, self, oOauthToken.access_token)) + .enableFeature(window.google.picker.Feature.NAV_HIDDEN) + .build() + ; + + drivePicker.setVisible(true); + } + }}); + } + }; + + PopupsComposeViewModel.prototype.driveOpenPopup = function () + { + if (window.gapi) + { + var self = this; + + window.gapi.load('auth', {'callback': function () { + + var oAuthToken = window.gapi.auth.getToken(); + if (!oAuthToken) + { + window.gapi.auth.authorize({ + 'client_id': RL.settingsGet('GoogleClientID'), + 'scope': 'https://www.googleapis.com/auth/drive.readonly', + 'immediate': true + }, function (oAuthResult) { + if (oAuthResult && !oAuthResult.error) + { + var oAuthToken = window.gapi.auth.getToken(); + if (oAuthToken) + { + self.driveCreatePiker(oAuthToken); + } + } + else + { + window.gapi.auth.authorize({ + 'client_id': RL.settingsGet('GoogleClientID'), + 'scope': 'https://www.googleapis.com/auth/drive.readonly', + 'immediate': false + }, function (oAuthResult) { + if (oAuthResult && !oAuthResult.error) + { + var oAuthToken = window.gapi.auth.getToken(); + if (oAuthToken) + { + self.driveCreatePiker(oAuthToken); + } + } + }); + } + }); + } + else + { + self.driveCreatePiker(oAuthToken); + } + }}); + } + }; + + /** + * @param {string} sId + * @return {?Object} + */ + PopupsComposeViewModel.prototype.getAttachmentById = function (sId) + { + var + aAttachments = this.attachments(), + iIndex = 0, + iLen = aAttachments.length + ; + + for (; iIndex < iLen; iIndex++) + { + if (aAttachments[iIndex] && sId === aAttachments[iIndex].id) + { + return aAttachments[iIndex]; + } + } + + return null; + }; + + PopupsComposeViewModel.prototype.initUploader = function () + { + if (this.composeUploaderButton()) + { + var + oUploadCache = {}, + iAttachmentSizeLimit = Utils.pInt(RL.settingsGet('AttachmentLimit')), + oJua = new Jua({ + 'action': LinkBuilder.upload(), + 'name': 'uploader', + 'queueSize': 2, + 'multipleSizeLimit': 50, + 'disableFolderDragAndDrop': false, + 'clickElement': this.composeUploaderButton(), + 'dragAndDropElement': this.composeUploaderDropPlace() + }) + ; + + if (oJua) + { + oJua + // .on('onLimitReached', function (iLimit) { + // alert(iLimit); + // }) + .on('onDragEnter', _.bind(function () { + this.dragAndDropOver(true); + }, this)) + .on('onDragLeave', _.bind(function () { + this.dragAndDropOver(false); + }, this)) + .on('onBodyDragEnter', _.bind(function () { + this.dragAndDropVisible(true); + }, this)) + .on('onBodyDragLeave', _.bind(function () { + this.dragAndDropVisible(false); + }, this)) + .on('onProgress', _.bind(function (sId, iLoaded, iTotal) { + var oItem = null; + if (Utils.isUnd(oUploadCache[sId])) + { + oItem = this.getAttachmentById(sId); + if (oItem) + { + oUploadCache[sId] = oItem; + } + } + else + { + oItem = oUploadCache[sId]; + } + + if (oItem) + { + oItem.progress(' - ' + Math.floor(iLoaded / iTotal * 100) + '%'); + } + + }, this)) + .on('onSelect', _.bind(function (sId, oData) { + + this.dragAndDropOver(false); + + var + that = this, + sFileName = Utils.isUnd(oData.FileName) ? '' : oData.FileName.toString(), + mSize = Utils.isNormal(oData.Size) ? Utils.pInt(oData.Size) : null, + oAttachment = new ComposeAttachmentModel(sId, sFileName, mSize) + ; + + oAttachment.cancel = (function (sId) { + + return function () { + that.attachments.remove(function (oItem) { + return oItem && oItem.id === sId; + }); + + if (oJua) + { + oJua.cancel(sId); + } + }; + + }(sId)); + + this.attachments.push(oAttachment); + + if (0 < mSize && 0 < iAttachmentSizeLimit && iAttachmentSizeLimit < mSize) + { + oAttachment.error(Utils.i18n('UPLOAD/ERROR_FILE_IS_TOO_BIG')); + return false; + } + + return true; + + }, this)) + .on('onStart', _.bind(function (sId) { + + var + oItem = null + ; + + if (Utils.isUnd(oUploadCache[sId])) + { + oItem = this.getAttachmentById(sId); + if (oItem) + { + oUploadCache[sId] = oItem; + } + } + else + { + oItem = oUploadCache[sId]; + } + + if (oItem) + { + oItem.waiting(false); + oItem.uploading(true); + } + + }, this)) + .on('onComplete', _.bind(function (sId, bResult, oData) { + + var + sError = '', + mErrorCode = null, + oAttachmentJson = null, + oAttachment = this.getAttachmentById(sId) + ; + + oAttachmentJson = bResult && oData && oData.Result && oData.Result.Attachment ? oData.Result.Attachment : null; + mErrorCode = oData && oData.Result && oData.Result.ErrorCode ? oData.Result.ErrorCode : null; + + if (null !== mErrorCode) + { + sError = Utils.getUploadErrorDescByCode(mErrorCode); + } + else if (!oAttachmentJson) + { + sError = Utils.i18n('UPLOAD/ERROR_UNKNOWN'); + } + + if (oAttachment) + { + if ('' !== sError && 0 < sError.length) + { + oAttachment + .waiting(false) + .uploading(false) + .error(sError) + ; + } + else if (oAttachmentJson) + { + oAttachment + .waiting(false) + .uploading(false) + ; + + oAttachment.initByUploadJson(oAttachmentJson); + } + + if (Utils.isUnd(oUploadCache[sId])) + { + delete (oUploadCache[sId]); + } + } + + }, this)) + ; + + this + .addAttachmentEnabled(true) + .dragAndDropEnabled(oJua.isDragAndDropSupported()) + ; + } + else + { + this + .addAttachmentEnabled(false) + .dragAndDropEnabled(false) + ; + } + } + }; + + /** + * @return {Object} + */ + PopupsComposeViewModel.prototype.prepearAttachmentsForSendOrSave = function () + { + var oResult = {}; + _.each(this.attachmentsInReady(), function (oItem) { + if (oItem && '' !== oItem.tempName() && oItem.enabled()) + { + oResult[oItem.tempName()] = [ + oItem.fileName(), + oItem.isInline ? '1' : '0', + oItem.CID, + oItem.contentLocation + ]; + } + }); + + return oResult; + }; + + /** + * @param {MessageModel} oMessage + */ + PopupsComposeViewModel.prototype.addMessageAsAttachment = function (oMessage) + { + if (oMessage) + { + var + self = this, + oAttachment = null, + sTemp = oMessage.subject(), + fCancelFunc = function (sId) { + return function () { + self.attachments.remove(function (oItem) { + return oItem && oItem.id === sId; + }); + }; + } + ; + + sTemp = '.eml' === sTemp.substr(-4).toLowerCase() ? sTemp : sTemp + '.eml'; + oAttachment = new ComposeAttachmentModel( + oMessage.requestHash, sTemp, oMessage.size() + ); + + oAttachment.fromMessage = true; + oAttachment.cancel = fCancelFunc(oMessage.requestHash); + oAttachment.waiting(false).uploading(true); + + this.attachments.push(oAttachment); + } + }; + + /** + * @param {Object} oDropboxFile + * @return {boolean} + */ + PopupsComposeViewModel.prototype.addDropboxAttachment = function (oDropboxFile) + { + var + self = this, + oAttachment = null, + fCancelFunc = function (sId) { + return function () { + self.attachments.remove(function (oItem) { + return oItem && oItem.id === sId; + }); + }; + }, + iAttachmentSizeLimit = Utils.pInt(RL.settingsGet('AttachmentLimit')), + mSize = oDropboxFile['bytes'] + ; + + oAttachment = new ComposeAttachmentModel( + oDropboxFile['link'], oDropboxFile['name'], mSize + ); + + oAttachment.fromMessage = false; + oAttachment.cancel = fCancelFunc(oDropboxFile['link']); + oAttachment.waiting(false).uploading(true); + + this.attachments.push(oAttachment); + + if (0 < mSize && 0 < iAttachmentSizeLimit && iAttachmentSizeLimit < mSize) + { + oAttachment.uploading(false); + oAttachment.error(Utils.i18n('UPLOAD/ERROR_FILE_IS_TOO_BIG')); + return false; + } + + Remote.composeUploadExternals(function (sResult, oData) { + + var bResult = false; + oAttachment.uploading(false); + + if (Enums.StorageResultType.Success === sResult && oData && oData.Result) + { + if (oData.Result[oAttachment.id]) + { + bResult = true; + oAttachment.tempName(oData.Result[oAttachment.id]); + } + } + + if (!bResult) + { + oAttachment.error(Utils.getUploadErrorDescByCode(Enums.UploadErrorCode.FileNoUploaded)); + } + + }, [oDropboxFile['link']]); + + return true; + }; + + /** + * @param {Object} oDriveFile + * @param {string} sAccessToken + * @return {boolean} + */ + PopupsComposeViewModel.prototype.addDriveAttachment = function (oDriveFile, sAccessToken) + { + var + self = this, + fCancelFunc = function (sId) { + return function () { + self.attachments.remove(function (oItem) { + return oItem && oItem.id === sId; + }); + }; + }, + iAttachmentSizeLimit = Utils.pInt(RL.settingsGet('AttachmentLimit')), + oAttachment = null, + mSize = oDriveFile['fileSize'] ? Utils.pInt(oDriveFile['fileSize']) : 0 + ; + + oAttachment = new ComposeAttachmentModel( + oDriveFile['downloadUrl'], oDriveFile['title'], mSize + ); + + oAttachment.fromMessage = false; + oAttachment.cancel = fCancelFunc(oDriveFile['downloadUrl']); + oAttachment.waiting(false).uploading(true); + + this.attachments.push(oAttachment); + + if (0 < mSize && 0 < iAttachmentSizeLimit && iAttachmentSizeLimit < mSize) + { + oAttachment.uploading(false); + oAttachment.error(Utils.i18n('UPLOAD/ERROR_FILE_IS_TOO_BIG')); + return false; + } + + Remote.composeUploadDrive(function (sResult, oData) { + + var bResult = false; + oAttachment.uploading(false); + + if (Enums.StorageResultType.Success === sResult && oData && oData.Result) + { + if (oData.Result[oAttachment.id]) + { + bResult = true; + oAttachment.tempName(oData.Result[oAttachment.id][0]); + oAttachment.size(Utils.pInt(oData.Result[oAttachment.id][1])); + } + } + + if (!bResult) + { + oAttachment.error(Utils.getUploadErrorDescByCode(Enums.UploadErrorCode.FileNoUploaded)); + } + + }, oDriveFile['downloadUrl'], sAccessToken); + + return true; + }; + + /** + * @param {MessageModel} oMessage + * @param {string} sType + */ + PopupsComposeViewModel.prototype.prepearMessageAttachments = function (oMessage, sType) + { + if (oMessage) + { + var + self = this, + aAttachments = Utils.isNonEmptyArray(oMessage.attachments()) ? oMessage.attachments() : [], + iIndex = 0, + iLen = aAttachments.length, + oAttachment = null, + oItem = null, + bAdd = false, + fCancelFunc = function (sId) { + return function () { + self.attachments.remove(function (oItem) { + return oItem && oItem.id === sId; + }); + }; + } + ; + + if (Enums.ComposeType.ForwardAsAttachment === sType) + { + this.addMessageAsAttachment(oMessage); + } + else + { + for (; iIndex < iLen; iIndex++) + { + oItem = aAttachments[iIndex]; + + bAdd = false; + switch (sType) { + case Enums.ComposeType.Reply: + case Enums.ComposeType.ReplyAll: + bAdd = oItem.isLinked; + break; + + case Enums.ComposeType.Forward: + case Enums.ComposeType.Draft: + case Enums.ComposeType.EditAsNew: + bAdd = true; + break; + } + + if (bAdd) + { + oAttachment = new ComposeAttachmentModel( + oItem.download, oItem.fileName, oItem.estimatedSize, + oItem.isInline, oItem.isLinked, oItem.cid, oItem.contentLocation + ); + + oAttachment.fromMessage = true; + oAttachment.cancel = fCancelFunc(oItem.download); + oAttachment.waiting(false).uploading(true); + + this.attachments.push(oAttachment); + } } } } - } -}; + }; -PopupsComposeViewModel.prototype.removeLinkedAttachments = function () -{ - this.attachments.remove(function (oItem) { - return oItem && oItem.isLinked; - }); -}; - -PopupsComposeViewModel.prototype.setMessageAttachmentFailedDowbloadText = function () -{ - _.each(this.attachments(), function(oAttachment) { - if (oAttachment && oAttachment.fromMessage) - { - oAttachment - .waiting(false) - .uploading(false) - .error(Utils.getUploadErrorDescByCode(Enums.UploadErrorCode.FileNoUploaded)) - ; - } - }, this); -}; - -/** - * @param {boolean=} bIncludeAttachmentInProgress = true - * @return {boolean} - */ -PopupsComposeViewModel.prototype.isEmptyForm = function (bIncludeAttachmentInProgress) -{ - bIncludeAttachmentInProgress = Utils.isUnd(bIncludeAttachmentInProgress) ? true : !!bIncludeAttachmentInProgress; - var bAttach = bIncludeAttachmentInProgress ? - 0 === this.attachments().length : 0 === this.attachmentsInReady().length; - - return 0 === this.to().length && - 0 === this.cc().length && - 0 === this.bcc().length && - 0 === this.subject().length && - bAttach && - (!this.oEditor || '' === this.oEditor.getData()) - ; -}; - -PopupsComposeViewModel.prototype.reset = function () -{ - this.to(''); - this.cc(''); - this.bcc(''); - this.replyTo(''); - this.subject(''); - - this.requestReadReceipt(false); - - this.aDraftInfo = null; - this.sInReplyTo = ''; - this.bFromDraft = false; - this.sReferences = ''; - - this.sendError(false); - this.sendSuccessButSaveError(false); - this.savedError(false); - this.savedTime(0); - this.savedOrSendingText(''); - this.emptyToError(false); - this.attachmentsInProcessError(false); - this.showCcAndBcc(false); - - this.attachments([]); - this.dragAndDropOver(false); - this.dragAndDropVisible(false); - - this.draftFolder(''); - this.draftUid(''); - - this.sending(false); - this.saving(false); - - if (this.oEditor) + PopupsComposeViewModel.prototype.removeLinkedAttachments = function () { - this.oEditor.clear(false); - } -}; + this.attachments.remove(function (oItem) { + return oItem && oItem.isLinked; + }); + }; -/** - * @return {Array} - */ -PopupsComposeViewModel.prototype.getAttachmentsDownloadsForUpload = function () -{ - return _.map(_.filter(this.attachments(), function (oItem) { - return oItem && '' === oItem.tempName(); - }), function (oItem) { - return oItem.id; - }); -}; + PopupsComposeViewModel.prototype.setMessageAttachmentFailedDowbloadText = function () + { + _.each(this.attachments(), function(oAttachment) { + if (oAttachment && oAttachment.fromMessage) + { + oAttachment + .waiting(false) + .uploading(false) + .error(Utils.getUploadErrorDescByCode(Enums.UploadErrorCode.FileNoUploaded)) + ; + } + }, this); + }; -PopupsComposeViewModel.prototype.triggerForResize = function () -{ - this.resizer(!this.resizer()); - this.editorResizeThrottle(); -}; + /** + * @param {boolean=} bIncludeAttachmentInProgress = true + * @return {boolean} + */ + PopupsComposeViewModel.prototype.isEmptyForm = function (bIncludeAttachmentInProgress) + { + bIncludeAttachmentInProgress = Utils.isUnd(bIncludeAttachmentInProgress) ? true : !!bIncludeAttachmentInProgress; + var bAttach = bIncludeAttachmentInProgress ? + 0 === this.attachments().length : 0 === this.attachmentsInReady().length; + return 0 === this.to().length && + 0 === this.cc().length && + 0 === this.bcc().length && + 0 === this.subject().length && + bAttach && + (!this.oEditor || '' === this.oEditor.getData()) + ; + }; + + PopupsComposeViewModel.prototype.reset = function () + { + this.to(''); + this.cc(''); + this.bcc(''); + this.replyTo(''); + this.subject(''); + + this.requestReadReceipt(false); + + this.aDraftInfo = null; + this.sInReplyTo = ''; + this.bFromDraft = false; + this.sReferences = ''; + + this.sendError(false); + this.sendSuccessButSaveError(false); + this.savedError(false); + this.savedTime(0); + this.savedOrSendingText(''); + this.emptyToError(false); + this.attachmentsInProcessError(false); + this.showCcAndBcc(false); + + this.attachments([]); + this.dragAndDropOver(false); + this.dragAndDropVisible(false); + + this.draftFolder(''); + this.draftUid(''); + + this.sending(false); + this.saving(false); + + if (this.oEditor) + { + this.oEditor.clear(false); + } + }; + + /** + * @return {Array} + */ + PopupsComposeViewModel.prototype.getAttachmentsDownloadsForUpload = function () + { + return _.map(_.filter(this.attachments(), function (oItem) { + return oItem && '' === oItem.tempName(); + }), function (oItem) { + return oItem.id; + }); + }; + + PopupsComposeViewModel.prototype.triggerForResize = function () + { + this.resizer(!this.resizer()); + this.editorResizeThrottle(); + }; + + module.exports = new PopupsComposeViewModel(); + +}(module)); \ No newline at end of file diff --git a/dev/ViewModels/Popups/PopupsContactsViewModel.js b/dev/ViewModels/Popups/PopupsContactsViewModel.js index 69b9f2a45..39388837c 100644 --- a/dev/ViewModels/Popups/PopupsContactsViewModel.js +++ b/dev/ViewModels/Popups/PopupsContactsViewModel.js @@ -1,743 +1,768 @@ /* RainLoop Webmail (c) RainLoop Team | Licensed under CC BY-NC-SA 3.0 */ -/** - * @constructor - * @extends KnoinAbstractViewModel - */ -function PopupsContactsViewModel() -{ - KnoinAbstractViewModel.call(this, 'Popups', 'PopupsContacts'); +(function (module) { + + 'use strict'; var - self = this, - fFastClearEmptyListHelper = function (aList) { - if (aList && 0 < aList.length) { - self.viewProperties.removeAll(aList); - } - } + window = require('../../External/window.js'), + $ = require('../../External/jquery.js'), + _ = require('../../External/underscore.js'), + ko = require('../../External/ko.js'), + key = require('../../External/key.js'), + + Enums = require('../../Common/Enums.js'), + Consts = require('../../Common/Consts.js'), + Globals = require('../../Common/Globals.js'), + Utils = require('../../Common/Utils.js'), + LinkBuilder = require('../Common/LinkBuilder.js'), + + Data = require('../../Storages/WebMailDataStorage.js'), + Remote = require('../../Storages/WebMailAjaxRemoteStorage.js'), + + kn = require('../../Knoin/Knoin.js'), + KnoinAbstractViewModel = require('../../Knoin/KnoinAbstractViewModel.js') ; - this.allowContactsSync = RL.data().allowContactsSync; - this.enableContactsSync = RL.data().enableContactsSync; - this.allowExport = !Globals.bMobileDevice; + /** + * @constructor + * @extends KnoinAbstractViewModel + */ + function PopupsContactsViewModel() + { + KnoinAbstractViewModel.call(this, 'Popups', 'PopupsContacts'); - this.search = ko.observable(''); - this.contactsCount = ko.observable(0); - this.contacts = RL.data().contacts; - this.contactTags = RL.data().contactTags; + var + self = this, + fFastClearEmptyListHelper = function (aList) { + if (aList && 0 < aList.length) { + self.viewProperties.removeAll(aList); + } + } + ; - this.currentContact = ko.observable(null); + this.allowContactsSync = Data.allowContactsSync; + this.enableContactsSync = Data.enableContactsSync; + this.allowExport = !Globals.bMobileDevice; - this.importUploaderButton = ko.observable(null); + this.search = ko.observable(''); + this.contactsCount = ko.observable(0); + this.contacts = Data.contacts; + this.contactTags = Data.contactTags; - this.contactsPage = ko.observable(1); - this.contactsPageCount = ko.computed(function () { - var iPage = Math.ceil(this.contactsCount() / Consts.Defaults.ContactsPerPage); - return 0 >= iPage ? 1 : iPage; - }, this); + this.currentContact = ko.observable(null); - this.contactsPagenator = ko.computed(Utils.computedPagenatorHelper(this.contactsPage, this.contactsPageCount)); + this.importUploaderButton = ko.observable(null); - this.emptySelection = ko.observable(true); - this.viewClearSearch = ko.observable(false); + this.contactsPage = ko.observable(1); + this.contactsPageCount = ko.computed(function () { + var iPage = window.Math.ceil(this.contactsCount() / Consts.Defaults.ContactsPerPage); + return 0 >= iPage ? 1 : iPage; + }, this); - this.viewID = ko.observable(''); - this.viewReadOnly = ko.observable(false); - this.viewProperties = ko.observableArray([]); + this.contactsPagenator = ko.computed(Utils.computedPagenatorHelper(this.contactsPage, this.contactsPageCount)); - this.viewTags = ko.observable(''); - this.viewTags.visibility = ko.observable(false); - this.viewTags.focusTrigger = ko.observable(false); + this.emptySelection = ko.observable(true); + this.viewClearSearch = ko.observable(false); - this.viewTags.focusTrigger.subscribe(function (bValue) { - if (!bValue && '' === this.viewTags()) - { - this.viewTags.visibility(false); - } - else if (bValue) - { - this.viewTags.visibility(true); - } - }, this); + this.viewID = ko.observable(''); + this.viewReadOnly = ko.observable(false); + this.viewProperties = ko.observableArray([]); - this.viewSaveTrigger = ko.observable(Enums.SaveSettingsStep.Idle); + this.viewTags = ko.observable(''); + this.viewTags.visibility = ko.observable(false); + this.viewTags.focusTrigger = ko.observable(false); - this.viewPropertiesNames = this.viewProperties.filter(function(oProperty) { - return -1 < Utils.inArray(oProperty.type(), [ - Enums.ContactPropertyType.FirstName, Enums.ContactPropertyType.LastName - ]); - }); + this.viewTags.focusTrigger.subscribe(function (bValue) { + if (!bValue && '' === this.viewTags()) + { + this.viewTags.visibility(false); + } + else if (bValue) + { + this.viewTags.visibility(true); + } + }, this); - this.viewPropertiesOther = this.viewProperties.filter(function(oProperty) { - return -1 < Utils.inArray(oProperty.type(), [ - Enums.ContactPropertyType.Note - ]); - }); + this.viewSaveTrigger = ko.observable(Enums.SaveSettingsStep.Idle); - this.viewPropertiesOther = ko.computed(function () { - - var aList = _.filter(this.viewProperties(), function (oProperty) { + this.viewPropertiesNames = this.viewProperties.filter(function(oProperty) { return -1 < Utils.inArray(oProperty.type(), [ - Enums.ContactPropertyType.Nick + Enums.ContactPropertyType.FirstName, Enums.ContactPropertyType.LastName ]); }); - return _.sortBy(aList, function (oProperty) { - return oProperty.type(); + this.viewPropertiesOther = this.viewProperties.filter(function(oProperty) { + return -1 < Utils.inArray(oProperty.type(), [ + Enums.ContactPropertyType.Note + ]); }); - }, this); + this.viewPropertiesOther = ko.computed(function () { - this.viewPropertiesEmails = this.viewProperties.filter(function(oProperty) { - return Enums.ContactPropertyType.Email === oProperty.type(); - }); + var aList = _.filter(this.viewProperties(), function (oProperty) { + return -1 < Utils.inArray(oProperty.type(), [ + Enums.ContactPropertyType.Nick + ]); + }); - this.viewPropertiesWeb = this.viewProperties.filter(function(oProperty) { - return Enums.ContactPropertyType.Web === oProperty.type(); - }); + return _.sortBy(aList, function (oProperty) { + return oProperty.type(); + }); - this.viewHasNonEmptyRequaredProperties = ko.computed(function() { + }, this); - var - aNames = this.viewPropertiesNames(), - aEmail = this.viewPropertiesEmails(), - fHelper = function (oProperty) { - return '' !== Utils.trim(oProperty.value()); - } - ; + this.viewPropertiesEmails = this.viewProperties.filter(function(oProperty) { + return Enums.ContactPropertyType.Email === oProperty.type(); + }); - return !!(_.find(aNames, fHelper) || _.find(aEmail, fHelper)); - }, this); + this.viewPropertiesWeb = this.viewProperties.filter(function(oProperty) { + return Enums.ContactPropertyType.Web === oProperty.type(); + }); - this.viewPropertiesPhones = this.viewProperties.filter(function(oProperty) { - return Enums.ContactPropertyType.Phone === oProperty.type(); - }); + this.viewHasNonEmptyRequaredProperties = ko.computed(function() { - this.viewPropertiesEmailsNonEmpty = this.viewPropertiesNames.filter(function(oProperty) { - return '' !== Utils.trim(oProperty.value()); - }); + var + aNames = this.viewPropertiesNames(), + aEmail = this.viewPropertiesEmails(), + fHelper = function (oProperty) { + return '' !== Utils.trim(oProperty.value()); + } + ; - this.viewPropertiesEmailsEmptyAndOnFocused = this.viewPropertiesEmails.filter(function(oProperty) { - var bF = oProperty.focused(); - return '' === Utils.trim(oProperty.value()) && !bF; - }); + return !!(_.find(aNames, fHelper) || _.find(aEmail, fHelper)); + }, this); - this.viewPropertiesPhonesEmptyAndOnFocused = this.viewPropertiesPhones.filter(function(oProperty) { - var bF = oProperty.focused(); - return '' === Utils.trim(oProperty.value()) && !bF; - }); + this.viewPropertiesPhones = this.viewProperties.filter(function(oProperty) { + return Enums.ContactPropertyType.Phone === oProperty.type(); + }); - this.viewPropertiesWebEmptyAndOnFocused = this.viewPropertiesWeb.filter(function(oProperty) { - var bF = oProperty.focused(); - return '' === Utils.trim(oProperty.value()) && !bF; - }); + this.viewPropertiesEmailsNonEmpty = this.viewPropertiesNames.filter(function(oProperty) { + return '' !== Utils.trim(oProperty.value()); + }); - this.viewPropertiesOtherEmptyAndOnFocused = ko.computed(function () { - return _.filter(this.viewPropertiesOther(), function (oProperty) { + this.viewPropertiesEmailsEmptyAndOnFocused = this.viewPropertiesEmails.filter(function(oProperty) { var bF = oProperty.focused(); return '' === Utils.trim(oProperty.value()) && !bF; }); - }, this); - this.viewPropertiesEmailsEmptyAndOnFocused.subscribe(function(aList) { - fFastClearEmptyListHelper(aList); - }); - - this.viewPropertiesPhonesEmptyAndOnFocused.subscribe(function(aList) { - fFastClearEmptyListHelper(aList); - }); - - this.viewPropertiesWebEmptyAndOnFocused.subscribe(function(aList) { - fFastClearEmptyListHelper(aList); - }); - - this.viewPropertiesOtherEmptyAndOnFocused.subscribe(function(aList) { - fFastClearEmptyListHelper(aList); - }); - - this.viewSaving = ko.observable(false); - - this.useCheckboxesInList = RL.data().useCheckboxesInList; - - this.search.subscribe(function () { - this.reloadContactList(); - }, this); - - this.contacts.subscribe(function () { - Utils.windowResize(); - }, this); - - this.viewProperties.subscribe(function () { - Utils.windowResize(); - }, this); - - this.contactsChecked = ko.computed(function () { - return _.filter(this.contacts(), function (oItem) { - return oItem.checked(); + this.viewPropertiesPhonesEmptyAndOnFocused = this.viewPropertiesPhones.filter(function(oProperty) { + var bF = oProperty.focused(); + return '' === Utils.trim(oProperty.value()) && !bF; }); - }, this); - this.contactsCheckedOrSelected = ko.computed(function () { - - var - aChecked = this.contactsChecked(), - oSelected = this.currentContact() - ; - - return _.union(aChecked, oSelected ? [oSelected] : []); - - }, this); - - this.contactsCheckedOrSelectedUids = ko.computed(function () { - return _.map(this.contactsCheckedOrSelected(), function (oContact) { - return oContact.idContact; + this.viewPropertiesWebEmptyAndOnFocused = this.viewPropertiesWeb.filter(function(oProperty) { + var bF = oProperty.focused(); + return '' === Utils.trim(oProperty.value()) && !bF; }); - }, this); - this.selector = new Selector(this.contacts, this.currentContact, - '.e-contact-item .actionHandle', '.e-contact-item.selected', '.e-contact-item .checkboxItem', - '.e-contact-item.focused'); + this.viewPropertiesOtherEmptyAndOnFocused = ko.computed(function () { + return _.filter(this.viewPropertiesOther(), function (oProperty) { + var bF = oProperty.focused(); + return '' === Utils.trim(oProperty.value()) && !bF; + }); + }, this); - this.selector.on('onItemSelect', _.bind(function (oContact) { - this.populateViewContact(oContact ? oContact : null); - if (!oContact) - { + this.viewPropertiesEmailsEmptyAndOnFocused.subscribe(function(aList) { + fFastClearEmptyListHelper(aList); + }); + + this.viewPropertiesPhonesEmptyAndOnFocused.subscribe(function(aList) { + fFastClearEmptyListHelper(aList); + }); + + this.viewPropertiesWebEmptyAndOnFocused.subscribe(function(aList) { + fFastClearEmptyListHelper(aList); + }); + + this.viewPropertiesOtherEmptyAndOnFocused.subscribe(function(aList) { + fFastClearEmptyListHelper(aList); + }); + + this.viewSaving = ko.observable(false); + + this.useCheckboxesInList = Data.useCheckboxesInList; + + this.search.subscribe(function () { + this.reloadContactList(); + }, this); + + this.contacts.subscribe(function () { + Utils.windowResize(); + }, this); + + this.viewProperties.subscribe(function () { + Utils.windowResize(); + }, this); + + this.contactsChecked = ko.computed(function () { + return _.filter(this.contacts(), function (oItem) { + return oItem.checked(); + }); + }, this); + + this.contactsCheckedOrSelected = ko.computed(function () { + + var + aChecked = this.contactsChecked(), + oSelected = this.currentContact() + ; + + return _.union(aChecked, oSelected ? [oSelected] : []); + + }, this); + + this.contactsCheckedOrSelectedUids = ko.computed(function () { + return _.map(this.contactsCheckedOrSelected(), function (oContact) { + return oContact.idContact; + }); + }, this); + + this.selector = new Selector(this.contacts, this.currentContact, + '.e-contact-item .actionHandle', '.e-contact-item.selected', '.e-contact-item .checkboxItem', + '.e-contact-item.focused'); + + this.selector.on('onItemSelect', _.bind(function (oContact) { + this.populateViewContact(oContact ? oContact : null); + if (!oContact) + { + this.emptySelection(true); + } + }, this)); + + this.selector.on('onItemGetUid', function (oContact) { + return oContact ? oContact.generateUid() : ''; + }); + + this.newCommand = Utils.createCommand(this, function () { + this.populateViewContact(null); + this.currentContact(null); + }); + + this.deleteCommand = Utils.createCommand(this, function () { + this.deleteSelectedContacts(); this.emptySelection(true); - } - }, this)); + }, function () { + return 0 < this.contactsCheckedOrSelected().length; + }); - this.selector.on('onItemGetUid', function (oContact) { - return oContact ? oContact.generateUid() : ''; - }); - - this.newCommand = Utils.createCommand(this, function () { - this.populateViewContact(null); - this.currentContact(null); - }); - - this.deleteCommand = Utils.createCommand(this, function () { - this.deleteSelectedContacts(); - this.emptySelection(true); - }, function () { - return 0 < this.contactsCheckedOrSelected().length; - }); - - this.newMessageCommand = Utils.createCommand(this, function () { - var aC = this.contactsCheckedOrSelected(), aE = []; - if (Utils.isNonEmptyArray(aC)) - { - aE = _.map(aC, function (oItem) { - if (oItem) - { - var - aData = oItem.getNameAndEmailHelper(), - oEmail = aData ? new EmailModel(aData[0], aData[1]) : null - ; - - if (oEmail && oEmail.validate()) + this.newMessageCommand = Utils.createCommand(this, function () { + var aC = this.contactsCheckedOrSelected(), aE = []; + if (Utils.isNonEmptyArray(aC)) + { + aE = _.map(aC, function (oItem) { + if (oItem) { - return oEmail; - } - } + var + aData = oItem.getNameAndEmailHelper(), + oEmail = aData ? new EmailModel(aData[0], aData[1]) : null + ; - return null; + if (oEmail && oEmail.validate()) + { + return oEmail; + } + } + + return null; + }); + + aE = _.compact(aE); + } + + if (Utils.isNonEmptyArray(aE)) + { + kn.hideScreenPopup(PopupsContactsViewModel); + kn.showScreenPopup(PopupsComposeViewModel, [Enums.ComposeType.Empty, null, aE]); + } + + }, function () { + return 0 < this.contactsCheckedOrSelected().length; + }); + + this.clearCommand = Utils.createCommand(this, function () { + this.search(''); + }); + + this.saveCommand = Utils.createCommand(this, function () { + + this.viewSaving(true); + this.viewSaveTrigger(Enums.SaveSettingsStep.Animate); + + var + sRequestUid = Utils.fakeMd5(), + aProperties = [] + ; + + _.each(this.viewProperties(), function (oItem) { + if (oItem.type() && '' !== Utils.trim(oItem.value())) + { + aProperties.push([oItem.type(), oItem.value(), oItem.typeStr()]); + } }); - aE = _.compact(aE); - } + Remote.contactSave(function (sResult, oData) { - if (Utils.isNonEmptyArray(aE)) - { - kn.hideScreenPopup(PopupsContactsViewModel); - kn.showScreenPopup(PopupsComposeViewModel, [Enums.ComposeType.Empty, null, aE]); - } + var bRes = false; + self.viewSaving(false); - }, function () { - return 0 < this.contactsCheckedOrSelected().length; - }); - - this.clearCommand = Utils.createCommand(this, function () { - this.search(''); - }); - - this.saveCommand = Utils.createCommand(this, function () { - - this.viewSaving(true); - this.viewSaveTrigger(Enums.SaveSettingsStep.Animate); - - var - sRequestUid = Utils.fakeMd5(), - aProperties = [] - ; - - _.each(this.viewProperties(), function (oItem) { - if (oItem.type() && '' !== Utils.trim(oItem.value())) - { - aProperties.push([oItem.type(), oItem.value(), oItem.typeStr()]); - } - }); - - RL.remote().contactSave(function (sResult, oData) { - - var bRes = false; - self.viewSaving(false); - - if (Enums.StorageResultType.Success === sResult && oData && oData.Result && - oData.Result.RequestUid === sRequestUid && 0 < Utils.pInt(oData.Result.ResultID)) - { - if ('' === self.viewID()) + if (Enums.StorageResultType.Success === sResult && oData && oData.Result && + oData.Result.RequestUid === sRequestUid && 0 < Utils.pInt(oData.Result.ResultID)) { - self.viewID(Utils.pInt(oData.Result.ResultID)); + if ('' === self.viewID()) + { + self.viewID(Utils.pInt(oData.Result.ResultID)); + } + + self.reloadContactList(); + bRes = true; } - self.reloadContactList(); - bRes = true; + _.delay(function () { + self.viewSaveTrigger(bRes ? Enums.SaveSettingsStep.TrueResult : Enums.SaveSettingsStep.FalseResult); + }, 300); + + if (bRes) + { + self.watchDirty(false); + + _.delay(function () { + self.viewSaveTrigger(Enums.SaveSettingsStep.Idle); + }, 1000); + } + + }, sRequestUid, this.viewID(), this.viewTags(), aProperties); + + }, function () { + var + bV = this.viewHasNonEmptyRequaredProperties(), + bReadOnly = this.viewReadOnly() + ; + return !this.viewSaving() && bV && !bReadOnly; + }); + + this.syncCommand = Utils.createCommand(this, function () { + + var self = this; + RL.contactsSync(function (sResult, oData) { + if (Enums.StorageResultType.Success !== sResult || !oData || !oData.Result) + { + window.alert(Utils.getNotification( + oData && oData.ErrorCode ? oData.ErrorCode : Enums.Notification.ContactsSyncError)); + } + + self.reloadContactList(true); + }); + + }, function () { + return !this.contacts.syncing() && !this.contacts.importing(); + }); + + this.bDropPageAfterDelete = false; + + this.watchDirty = ko.observable(false); + this.watchHash = ko.observable(false); + + this.viewHash = ko.computed(function () { + return '' + self.viewTags() + '|' + _.map(self.viewProperties(), function (oItem) { + return oItem.value(); + }).join(''); + }); + + // this.saveCommandDebounce = _.debounce(_.bind(this.saveCommand, this), 1000); + + this.viewHash.subscribe(function () { + if (this.watchHash() && !this.viewReadOnly() && !this.watchDirty()) + { + this.watchDirty(true); + } + }, this); + + this.sDefaultKeyScope = Enums.KeyState.ContactList; + + kn.constructorEnd(this); + } + + kn.extendAsViewModel('PopupsContactsViewModel', PopupsContactsViewModel); + + PopupsContactsViewModel.prototype.getPropertyPlceholder = function (sType) + { + var sResult = ''; + switch (sType) + { + case Enums.ContactPropertyType.LastName: + sResult = 'CONTACTS/PLACEHOLDER_ENTER_LAST_NAME'; + break; + case Enums.ContactPropertyType.FirstName: + sResult = 'CONTACTS/PLACEHOLDER_ENTER_FIRST_NAME'; + break; + case Enums.ContactPropertyType.Nick: + sResult = 'CONTACTS/PLACEHOLDER_ENTER_NICK_NAME'; + break; + } + + return sResult; + }; + + PopupsContactsViewModel.prototype.addNewProperty = function (sType, sTypeStr) + { + this.viewProperties.push(new ContactPropertyModel(sType, sTypeStr || '', '', true, this.getPropertyPlceholder(sType))); + }; + + PopupsContactsViewModel.prototype.addNewOrFocusProperty = function (sType, sTypeStr) + { + var oItem = _.find(this.viewProperties(), function (oItem) { + return sType === oItem.type(); + }); + + if (oItem) + { + oItem.focused(true); + } + else + { + this.addNewProperty(sType, sTypeStr); + } + }; + + PopupsContactsViewModel.prototype.addNewTag = function () + { + this.viewTags.visibility(true); + this.viewTags.focusTrigger(true); + }; + + PopupsContactsViewModel.prototype.addNewEmail = function () + { + this.addNewProperty(Enums.ContactPropertyType.Email, 'Home'); + }; + + PopupsContactsViewModel.prototype.addNewPhone = function () + { + this.addNewProperty(Enums.ContactPropertyType.Phone, 'Mobile'); + }; + + PopupsContactsViewModel.prototype.addNewWeb = function () + { + this.addNewProperty(Enums.ContactPropertyType.Web); + }; + + PopupsContactsViewModel.prototype.addNewNickname = function () + { + this.addNewOrFocusProperty(Enums.ContactPropertyType.Nick); + }; + + PopupsContactsViewModel.prototype.addNewNotes = function () + { + this.addNewOrFocusProperty(Enums.ContactPropertyType.Note); + }; + + PopupsContactsViewModel.prototype.addNewBirthday = function () + { + this.addNewOrFocusProperty(Enums.ContactPropertyType.Birthday); + }; + + //PopupsContactsViewModel.prototype.addNewAddress = function () + //{ + //}; + + PopupsContactsViewModel.prototype.exportVcf = function () + { + RL.download(LinkBuilder.exportContactsVcf()); + }; + + PopupsContactsViewModel.prototype.exportCsv = function () + { + RL.download(LinkBuilder.exportContactsCsv()); + }; + + PopupsContactsViewModel.prototype.initUploader = function () + { + if (this.importUploaderButton()) + { + var + oJua = new Jua({ + 'action': LinkBuilder.uploadContacts(), + 'name': 'uploader', + 'queueSize': 1, + 'multipleSizeLimit': 1, + 'disableFolderDragAndDrop': true, + 'disableDragAndDrop': true, + 'disableMultiple': true, + 'disableDocumentDropPrevent': true, + 'clickElement': this.importUploaderButton() + }) + ; + + if (oJua) + { + oJua + .on('onStart', _.bind(function () { + this.contacts.importing(true); + }, this)) + .on('onComplete', _.bind(function (sId, bResult, oData) { + + this.contacts.importing(false); + this.reloadContactList(); + + if (!sId || !bResult || !oData || !oData.Result) + { + window.alert(Utils.i18n('CONTACTS/ERROR_IMPORT_FILE')); + } + + }, this)) + ; + } + } + }; + + PopupsContactsViewModel.prototype.removeCheckedOrSelectedContactsFromList = function () + { + var + self = this, + oKoContacts = this.contacts, + oCurrentContact = this.currentContact(), + iCount = this.contacts().length, + aContacts = this.contactsCheckedOrSelected() + ; + + if (0 < aContacts.length) + { + _.each(aContacts, function (oContact) { + + if (oCurrentContact && oCurrentContact.idContact === oContact.idContact) + { + oCurrentContact = null; + self.currentContact(null); + } + + oContact.deleted(true); + iCount--; + }); + + if (iCount <= 0) + { + this.bDropPageAfterDelete = true; } _.delay(function () { - self.viewSaveTrigger(bRes ? Enums.SaveSettingsStep.TrueResult : Enums.SaveSettingsStep.FalseResult); - }, 300); - if (bRes) + _.each(aContacts, function (oContact) { + oKoContacts.remove(oContact); + }); + + }, 500); + } + }; + + PopupsContactsViewModel.prototype.deleteSelectedContacts = function () + { + if (0 < this.contactsCheckedOrSelected().length) + { + Remote.contactsDelete( + _.bind(this.deleteResponse, this), + this.contactsCheckedOrSelectedUids() + ); + + this.removeCheckedOrSelectedContactsFromList(); + } + }; + + /** + * @param {string} sResult + * @param {AjaxJsonDefaultResponse} oData + */ + PopupsContactsViewModel.prototype.deleteResponse = function (sResult, oData) + { + if (500 < (Enums.StorageResultType.Success === sResult && oData && oData.Time ? Utils.pInt(oData.Time) : 0)) + { + this.reloadContactList(this.bDropPageAfterDelete); + } + else + { + _.delay((function (self) { + return function () { + self.reloadContactList(self.bDropPageAfterDelete); + }; + }(this)), 500); + } + }; + + PopupsContactsViewModel.prototype.removeProperty = function (oProp) + { + this.viewProperties.remove(oProp); + }; + + /** + * @param {?ContactModel} oContact + */ + PopupsContactsViewModel.prototype.populateViewContact = function (oContact) + { + var + sId = '', + sLastName = '', + sFirstName = '', + aList = [] + ; + + this.watchHash(false); + + this.emptySelection(false); + this.viewReadOnly(false); + this.viewTags(''); + + if (oContact) + { + sId = oContact.idContact; + if (Utils.isNonEmptyArray(oContact.properties)) { - self.watchDirty(false); - - _.delay(function () { - self.viewSaveTrigger(Enums.SaveSettingsStep.Idle); - }, 1000); + _.each(oContact.properties, function (aProperty) { + if (aProperty && aProperty[0]) + { + if (Enums.ContactPropertyType.LastName === aProperty[0]) + { + sLastName = aProperty[1]; + } + else if (Enums.ContactPropertyType.FirstName === aProperty[0]) + { + sFirstName = aProperty[1]; + } + else + { + aList.push(new ContactPropertyModel(aProperty[0], aProperty[2] || '', aProperty[1])); + } + } + }); } - }, sRequestUid, this.viewID(), this.viewTags(), aProperties); + this.viewTags(oContact.tags); - }, function () { + this.viewReadOnly(!!oContact.readOnly); + } + + this.viewTags.focusTrigger.valueHasMutated(); + this.viewTags.visibility('' !== this.viewTags()); + + aList.unshift(new ContactPropertyModel(Enums.ContactPropertyType.LastName, '', sLastName, false, + this.getPropertyPlceholder(Enums.ContactPropertyType.LastName))); + + aList.unshift(new ContactPropertyModel(Enums.ContactPropertyType.FirstName, '', sFirstName, !oContact, + this.getPropertyPlceholder(Enums.ContactPropertyType.FirstName))); + + this.viewID(sId); + this.viewProperties([]); + this.viewProperties(aList); + + this.watchDirty(false); + this.watchHash(true); + }; + + /** + * @param {boolean=} bDropPagePosition = false + */ + PopupsContactsViewModel.prototype.reloadContactList = function (bDropPagePosition) + { var - bV = this.viewHasNonEmptyRequaredProperties(), - bReadOnly = this.viewReadOnly() + self = this, + iOffset = (this.contactsPage() - 1) * Consts.Defaults.ContactsPerPage ; - return !this.viewSaving() && bV && !bReadOnly; - }); - this.syncCommand = Utils.createCommand(this, function () { + this.bDropPageAfterDelete = false; + + if (Utils.isUnd(bDropPagePosition) ? false : !!bDropPagePosition) + { + this.contactsPage(1); + iOffset = 0; + } + + this.contacts.loading(true); + Remote.contacts(function (sResult, oData) { + var + iCount = 0, + aList = [], + aTagsList = [] + ; + + if (Enums.StorageResultType.Success === sResult && oData && oData.Result && oData.Result.List) + { + if (Utils.isNonEmptyArray(oData.Result.List)) + { + aList = _.map(oData.Result.List, function (oItem) { + var oContact = new ContactModel(); + return oContact.parse(oItem) ? oContact : null; + }); + + aList = _.compact(aList); + + iCount = Utils.pInt(oData.Result.Count); + iCount = 0 < iCount ? iCount : 0; + } + + if (Utils.isNonEmptyArray(oData.Result.Tags)) + { + aTagsList = _.map(oData.Result.Tags, function (oItem) { + var oContactTag = new ContactTagModel(); + return oContactTag.parse(oItem) ? oContactTag : null; + }); + + aTagsList = _.compact(aTagsList); + } + } + + self.contactsCount(iCount); + + self.contacts(aList); + self.contacts.loading(false); + self.contactTags(aTagsList); + + self.viewClearSearch('' !== self.search()); + + }, iOffset, Consts.Defaults.ContactsPerPage, this.search()); + }; + + PopupsContactsViewModel.prototype.onBuild = function (oDom) + { + this.oContentVisible = $('.b-list-content', oDom); + this.oContentScrollable = $('.content', this.oContentVisible); + + this.selector.init(this.oContentVisible, this.oContentScrollable, Enums.KeyState.ContactList); var self = this; - RL.contactsSync(function (sResult, oData) { - if (Enums.StorageResultType.Success !== sResult || !oData || !oData.Result) - { - window.alert(Utils.getNotification( - oData && oData.ErrorCode ? oData.ErrorCode : Enums.Notification.ContactsSyncError)); - } - self.reloadContactList(true); + key('delete', Enums.KeyState.ContactList, function () { + self.deleteCommand(); + return false; }); - }, function () { - return !this.contacts.syncing() && !this.contacts.importing(); - }); - - this.bDropPageAfterDelete = false; - - this.watchDirty = ko.observable(false); - this.watchHash = ko.observable(false); - - this.viewHash = ko.computed(function () { - return '' + self.viewTags() + '|' + _.map(self.viewProperties(), function (oItem) { - return oItem.value(); - }).join(''); - }); - -// this.saveCommandDebounce = _.debounce(_.bind(this.saveCommand, this), 1000); - - this.viewHash.subscribe(function () { - if (this.watchHash() && !this.viewReadOnly() && !this.watchDirty()) - { - this.watchDirty(true); - } - }, this); - - this.sDefaultKeyScope = Enums.KeyState.ContactList; - - Knoin.constructorEnd(this); -} - -Utils.extendAsViewModel('PopupsContactsViewModel', PopupsContactsViewModel); - -PopupsContactsViewModel.prototype.getPropertyPlceholder = function (sType) -{ - var sResult = ''; - switch (sType) - { - case Enums.ContactPropertyType.LastName: - sResult = 'CONTACTS/PLACEHOLDER_ENTER_LAST_NAME'; - break; - case Enums.ContactPropertyType.FirstName: - sResult = 'CONTACTS/PLACEHOLDER_ENTER_FIRST_NAME'; - break; - case Enums.ContactPropertyType.Nick: - sResult = 'CONTACTS/PLACEHOLDER_ENTER_NICK_NAME'; - break; - } - - return sResult; -}; - -PopupsContactsViewModel.prototype.addNewProperty = function (sType, sTypeStr) -{ - this.viewProperties.push(new ContactPropertyModel(sType, sTypeStr || '', '', true, this.getPropertyPlceholder(sType))); -}; - -PopupsContactsViewModel.prototype.addNewOrFocusProperty = function (sType, sTypeStr) -{ - var oItem = _.find(this.viewProperties(), function (oItem) { - return sType === oItem.type(); - }); - - if (oItem) - { - oItem.focused(true); - } - else - { - this.addNewProperty(sType, sTypeStr); - } -}; - -PopupsContactsViewModel.prototype.addNewTag = function () -{ - this.viewTags.visibility(true); - this.viewTags.focusTrigger(true); -}; - -PopupsContactsViewModel.prototype.addNewEmail = function () -{ - this.addNewProperty(Enums.ContactPropertyType.Email, 'Home'); -}; - -PopupsContactsViewModel.prototype.addNewPhone = function () -{ - this.addNewProperty(Enums.ContactPropertyType.Phone, 'Mobile'); -}; - -PopupsContactsViewModel.prototype.addNewWeb = function () -{ - this.addNewProperty(Enums.ContactPropertyType.Web); -}; - -PopupsContactsViewModel.prototype.addNewNickname = function () -{ - this.addNewOrFocusProperty(Enums.ContactPropertyType.Nick); -}; - -PopupsContactsViewModel.prototype.addNewNotes = function () -{ - this.addNewOrFocusProperty(Enums.ContactPropertyType.Note); -}; - -PopupsContactsViewModel.prototype.addNewBirthday = function () -{ - this.addNewOrFocusProperty(Enums.ContactPropertyType.Birthday); -}; - -//PopupsContactsViewModel.prototype.addNewAddress = function () -//{ -//}; - -PopupsContactsViewModel.prototype.exportVcf = function () -{ - RL.download(RL.link().exportContactsVcf()); -}; - -PopupsContactsViewModel.prototype.exportCsv = function () -{ - RL.download(RL.link().exportContactsCsv()); -}; - -PopupsContactsViewModel.prototype.initUploader = function () -{ - if (this.importUploaderButton()) - { - var - oJua = new Jua({ - 'action': RL.link().uploadContacts(), - 'name': 'uploader', - 'queueSize': 1, - 'multipleSizeLimit': 1, - 'disableFolderDragAndDrop': true, - 'disableDragAndDrop': true, - 'disableMultiple': true, - 'disableDocumentDropPrevent': true, - 'clickElement': this.importUploaderButton() + oDom + .on('click', '.e-pagenator .e-page', function () { + var oPage = ko.dataFor(this); + if (oPage) + { + self.contactsPage(Utils.pInt(oPage.value)); + self.reloadContactList(); + } }) ; - if (oJua) - { - oJua - .on('onStart', _.bind(function () { - this.contacts.importing(true); - }, this)) - .on('onComplete', _.bind(function (sId, bResult, oData) { + this.initUploader(); + }; - this.contacts.importing(false); - this.reloadContactList(); - - if (!sId || !bResult || !oData || !oData.Result) - { - window.alert(Utils.i18n('CONTACTS/ERROR_IMPORT_FILE')); - } - - }, this)) - ; - } - } -}; - -PopupsContactsViewModel.prototype.removeCheckedOrSelectedContactsFromList = function () -{ - var - self = this, - oKoContacts = this.contacts, - oCurrentContact = this.currentContact(), - iCount = this.contacts().length, - aContacts = this.contactsCheckedOrSelected() - ; - - if (0 < aContacts.length) + PopupsContactsViewModel.prototype.onShow = function () { - _.each(aContacts, function (oContact) { + kn.routeOff(); + this.reloadContactList(true); + }; - if (oCurrentContact && oCurrentContact.idContact === oContact.idContact) - { - oCurrentContact = null; - self.currentContact(null); - } - - oContact.deleted(true); - iCount--; - }); - - if (iCount <= 0) - { - this.bDropPageAfterDelete = true; - } - - _.delay(function () { - - _.each(aContacts, function (oContact) { - oKoContacts.remove(oContact); - }); - - }, 500); - } -}; - -PopupsContactsViewModel.prototype.deleteSelectedContacts = function () -{ - if (0 < this.contactsCheckedOrSelected().length) + PopupsContactsViewModel.prototype.onHide = function () { - RL.remote().contactsDelete( - _.bind(this.deleteResponse, this), - this.contactsCheckedOrSelectedUids() - ); + kn.routeOn(); + this.currentContact(null); + this.emptySelection(true); + this.search(''); + this.contactsCount(0); + this.contacts([]); + }; - this.removeCheckedOrSelectedContactsFromList(); - } -}; + module.exports = new PopupsContactsViewModel(); -/** - * @param {string} sResult - * @param {AjaxJsonDefaultResponse} oData - */ -PopupsContactsViewModel.prototype.deleteResponse = function (sResult, oData) -{ - if (500 < (Enums.StorageResultType.Success === sResult && oData && oData.Time ? Utils.pInt(oData.Time) : 0)) - { - this.reloadContactList(this.bDropPageAfterDelete); - } - else - { - _.delay((function (self) { - return function () { - self.reloadContactList(self.bDropPageAfterDelete); - }; - }(this)), 500); - } -}; - -PopupsContactsViewModel.prototype.removeProperty = function (oProp) -{ - this.viewProperties.remove(oProp); -}; - -/** - * @param {?ContactModel} oContact - */ -PopupsContactsViewModel.prototype.populateViewContact = function (oContact) -{ - var - sId = '', - sLastName = '', - sFirstName = '', - aList = [] - ; - - this.watchHash(false); - - this.emptySelection(false); - this.viewReadOnly(false); - this.viewTags(''); - - if (oContact) - { - sId = oContact.idContact; - if (Utils.isNonEmptyArray(oContact.properties)) - { - _.each(oContact.properties, function (aProperty) { - if (aProperty && aProperty[0]) - { - if (Enums.ContactPropertyType.LastName === aProperty[0]) - { - sLastName = aProperty[1]; - } - else if (Enums.ContactPropertyType.FirstName === aProperty[0]) - { - sFirstName = aProperty[1]; - } - else - { - aList.push(new ContactPropertyModel(aProperty[0], aProperty[2] || '', aProperty[1])); - } - } - }); - } - - this.viewTags(oContact.tags); - - this.viewReadOnly(!!oContact.readOnly); - } - - this.viewTags.focusTrigger.valueHasMutated(); - this.viewTags.visibility('' !== this.viewTags()); - - aList.unshift(new ContactPropertyModel(Enums.ContactPropertyType.LastName, '', sLastName, false, - this.getPropertyPlceholder(Enums.ContactPropertyType.LastName))); - - aList.unshift(new ContactPropertyModel(Enums.ContactPropertyType.FirstName, '', sFirstName, !oContact, - this.getPropertyPlceholder(Enums.ContactPropertyType.FirstName))); - - this.viewID(sId); - this.viewProperties([]); - this.viewProperties(aList); - - this.watchDirty(false); - this.watchHash(true); -}; - -/** - * @param {boolean=} bDropPagePosition = false - */ -PopupsContactsViewModel.prototype.reloadContactList = function (bDropPagePosition) -{ - var - self = this, - iOffset = (this.contactsPage() - 1) * Consts.Defaults.ContactsPerPage - ; - - this.bDropPageAfterDelete = false; - - if (Utils.isUnd(bDropPagePosition) ? false : !!bDropPagePosition) - { - this.contactsPage(1); - iOffset = 0; - } - - this.contacts.loading(true); - RL.remote().contacts(function (sResult, oData) { - var - iCount = 0, - aList = [], - aTagsList = [] - ; - - if (Enums.StorageResultType.Success === sResult && oData && oData.Result && oData.Result.List) - { - if (Utils.isNonEmptyArray(oData.Result.List)) - { - aList = _.map(oData.Result.List, function (oItem) { - var oContact = new ContactModel(); - return oContact.parse(oItem) ? oContact : null; - }); - - aList = _.compact(aList); - - iCount = Utils.pInt(oData.Result.Count); - iCount = 0 < iCount ? iCount : 0; - } - - if (Utils.isNonEmptyArray(oData.Result.Tags)) - { - aTagsList = _.map(oData.Result.Tags, function (oItem) { - var oContactTag = new ContactTagModel(); - return oContactTag.parse(oItem) ? oContactTag : null; - }); - - aTagsList = _.compact(aTagsList); - } - } - - self.contactsCount(iCount); - - self.contacts(aList); - self.contacts.loading(false); - self.contactTags(aTagsList); - - self.viewClearSearch('' !== self.search()); - - }, iOffset, Consts.Defaults.ContactsPerPage, this.search()); -}; - -PopupsContactsViewModel.prototype.onBuild = function (oDom) -{ - this.oContentVisible = $('.b-list-content', oDom); - this.oContentScrollable = $('.content', this.oContentVisible); - - this.selector.init(this.oContentVisible, this.oContentScrollable, Enums.KeyState.ContactList); - - var self = this; - - key('delete', Enums.KeyState.ContactList, function () { - self.deleteCommand(); - return false; - }); - - oDom - .on('click', '.e-pagenator .e-page', function () { - var oPage = ko.dataFor(this); - if (oPage) - { - self.contactsPage(Utils.pInt(oPage.value)); - self.reloadContactList(); - } - }) - ; - - this.initUploader(); -}; - -PopupsContactsViewModel.prototype.onShow = function () -{ - kn.routeOff(); - this.reloadContactList(true); -}; - -PopupsContactsViewModel.prototype.onHide = function () -{ - kn.routeOn(); - this.currentContact(null); - this.emptySelection(true); - this.search(''); - this.contactsCount(0); - this.contacts([]); -// _.each(this.contacts(), function (oItem) { -// oItem.checked(false); -// }); -}; +}(module)); \ No newline at end of file diff --git a/dev/ViewModels/Popups/PopupsDomainViewModel.js b/dev/ViewModels/Popups/PopupsDomainViewModel.js index cf329f106..6c6b3b38e 100644 --- a/dev/ViewModels/Popups/PopupsDomainViewModel.js +++ b/dev/ViewModels/Popups/PopupsDomainViewModel.js @@ -1,296 +1,318 @@ /* RainLoop Webmail (c) RainLoop Team | Licensed under CC BY-NC-SA 3.0 */ -/** - * @constructor - * @extends KnoinAbstractViewModel - */ -function PopupsDomainViewModel() -{ - KnoinAbstractViewModel.call(this, 'Popups', 'PopupsDomain'); +(function (module) { - this.edit = ko.observable(false); - this.saving = ko.observable(false); - this.savingError = ko.observable(''); - this.whiteListPage = ko.observable(false); + 'use strict'; - this.testing = ko.observable(false); - this.testingDone = ko.observable(false); - this.testingImapError = ko.observable(false); - this.testingSmtpError = ko.observable(false); - this.testingImapErrorDesc = ko.observable(''); - this.testingSmtpErrorDesc = ko.observable(''); + var + _ = require('../../External/underscore.js'), + ko = require('../../External/ko.js'), + + Enums = require('../../Common/Enums.js'), + Consts = require('../../Common/Consts.js'), + Utils = require('../../Common/Utils.js'), - this.testingImapError.subscribe(function (bValue) { - if (!bValue) + Remote = require('../../Storages/AdminAjaxRemoteStorage.js'), + + kn = require('../../Knoin/Knoin.js'), + KnoinAbstractViewModel = require('../../Knoin/KnoinAbstractViewModel.js') + ; + + /** + * @constructor + * @extends KnoinAbstractViewModel + */ + function PopupsDomainViewModel() + { + KnoinAbstractViewModel.call(this, 'Popups', 'PopupsDomain'); + + this.edit = ko.observable(false); + this.saving = ko.observable(false); + this.savingError = ko.observable(''); + this.whiteListPage = ko.observable(false); + + this.testing = ko.observable(false); + this.testingDone = ko.observable(false); + this.testingImapError = ko.observable(false); + this.testingSmtpError = ko.observable(false); + this.testingImapErrorDesc = ko.observable(''); + this.testingSmtpErrorDesc = ko.observable(''); + + this.testingImapError.subscribe(function (bValue) { + if (!bValue) + { + this.testingImapErrorDesc(''); + } + }, this); + + this.testingSmtpError.subscribe(function (bValue) { + if (!bValue) + { + this.testingSmtpErrorDesc(''); + } + }, this); + + this.testingImapErrorDesc = ko.observable(''); + this.testingSmtpErrorDesc = ko.observable(''); + + this.imapServerFocus = ko.observable(false); + this.smtpServerFocus = ko.observable(false); + + this.name = ko.observable(''); + this.name.focused = ko.observable(false); + + this.imapServer = ko.observable(''); + this.imapPort = ko.observable('' + Consts.Values.ImapDefaulPort); + this.imapSecure = ko.observable(Enums.ServerSecure.None); + this.imapShortLogin = ko.observable(false); + this.smtpServer = ko.observable(''); + this.smtpPort = ko.observable('' + Consts.Values.SmtpDefaulPort); + this.smtpSecure = ko.observable(Enums.ServerSecure.None); + this.smtpShortLogin = ko.observable(false); + this.smtpAuth = ko.observable(true); + this.whiteList = ko.observable(''); + + this.headerText = ko.computed(function () { + var sName = this.name(); + return this.edit() ? 'Edit Domain "' + sName + '"' : + 'Add Domain' + ('' === sName ? '' : ' "' + sName + '"'); + }, this); + + this.domainIsComputed = ko.computed(function () { + return '' !== this.name() && + '' !== this.imapServer() && + '' !== this.imapPort() && + '' !== this.smtpServer() && + '' !== this.smtpPort(); + }, this); + + this.canBeTested = ko.computed(function () { + return !this.testing() && this.domainIsComputed(); + }, this); + + this.canBeSaved = ko.computed(function () { + return !this.saving() && this.domainIsComputed(); + }, this); + + this.createOrAddCommand = Utils.createCommand(this, function () { + this.saving(true); + Remote.createOrUpdateDomain( + _.bind(this.onDomainCreateOrSaveResponse, this), + !this.edit(), + this.name(), + this.imapServer(), + Utils.pInt(this.imapPort()), + this.imapSecure(), + this.imapShortLogin(), + this.smtpServer(), + Utils.pInt(this.smtpPort()), + this.smtpSecure(), + this.smtpShortLogin(), + this.smtpAuth(), + this.whiteList() + ); + }, this.canBeSaved); + + this.testConnectionCommand = Utils.createCommand(this, function () { + this.whiteListPage(false); + this.testingDone(false); + this.testingImapError(false); + this.testingSmtpError(false); + this.testing(true); + Remote.testConnectionForDomain( + _.bind(this.onTestConnectionResponse, this), + this.name(), + this.imapServer(), + Utils.pInt(this.imapPort()), + this.imapSecure(), + this.smtpServer(), + Utils.pInt(this.smtpPort()), + this.smtpSecure(), + this.smtpAuth() + ); + }, this.canBeTested); + + this.whiteListCommand = Utils.createCommand(this, function () { + this.whiteListPage(!this.whiteListPage()); + }); + + // smart form improvements + this.imapServerFocus.subscribe(function (bValue) { + if (bValue && '' !== this.name() && '' === this.imapServer()) + { + this.imapServer(this.name().replace(/[.]?[*][.]?/g, '')); + } + }, this); + + this.smtpServerFocus.subscribe(function (bValue) { + if (bValue && '' !== this.imapServer() && '' === this.smtpServer()) + { + this.smtpServer(this.imapServer().replace(/imap/ig, 'smtp')); + } + }, this); + + this.imapSecure.subscribe(function (sValue) { + var iPort = Utils.pInt(this.imapPort()); + sValue = Utils.pString(sValue); + switch (sValue) + { + case '0': + if (993 === iPort) + { + this.imapPort('143'); + } + break; + case '1': + if (143 === iPort) + { + this.imapPort('993'); + } + break; + } + }, this); + + this.smtpSecure.subscribe(function (sValue) { + var iPort = Utils.pInt(this.smtpPort()); + sValue = Utils.pString(sValue); + switch (sValue) + { + case '0': + if (465 === iPort || 587 === iPort) + { + this.smtpPort('25'); + } + break; + case '1': + if (25 === iPort || 587 === iPort) + { + this.smtpPort('465'); + } + break; + case '2': + if (25 === iPort || 465 === iPort) + { + this.smtpPort('587'); + } + break; + } + }, this); + + kn.constructorEnd(this); + } + + kn.extendAsViewModel('PopupsDomainViewModel', PopupsDomainViewModel); + + PopupsDomainViewModel.prototype.onTestConnectionResponse = function (sResult, oData) + { + this.testing(false); + if (Enums.StorageResultType.Success === sResult && oData.Result) { - this.testingImapErrorDesc(''); - } - }, this); + this.testingDone(true); + this.testingImapError(true !== oData.Result.Imap); + this.testingSmtpError(true !== oData.Result.Smtp); - this.testingSmtpError.subscribe(function (bValue) { - if (!bValue) + if (this.testingImapError() && oData.Result.Imap) + { + this.testingImapErrorDesc(oData.Result.Imap); + } + + if (this.testingSmtpError() && oData.Result.Smtp) + { + this.testingSmtpErrorDesc(oData.Result.Smtp); + } + } + else { - this.testingSmtpErrorDesc(''); + this.testingImapError(true); + this.testingSmtpError(true); } - }, this); + }; - this.testingImapErrorDesc = ko.observable(''); - this.testingSmtpErrorDesc = ko.observable(''); + PopupsDomainViewModel.prototype.onDomainCreateOrSaveResponse = function (sResult, oData) + { + this.saving(false); + if (Enums.StorageResultType.Success === sResult && oData) + { + if (oData.Result) + { + RL.reloadDomainList(); + this.closeCommand(); + } + else if (Enums.Notification.DomainAlreadyExists === oData.ErrorCode) + { + this.savingError('Domain already exists'); + } + } + else + { + this.savingError('Unknown error'); + } + }; - this.imapServerFocus = ko.observable(false); - this.smtpServerFocus = ko.observable(false); - - this.name = ko.observable(''); - this.name.focused = ko.observable(false); - - this.imapServer = ko.observable(''); - this.imapPort = ko.observable('' + Consts.Values.ImapDefaulPort); - this.imapSecure = ko.observable(Enums.ServerSecure.None); - this.imapShortLogin = ko.observable(false); - this.smtpServer = ko.observable(''); - this.smtpPort = ko.observable('' + Consts.Values.SmtpDefaulPort); - this.smtpSecure = ko.observable(Enums.ServerSecure.None); - this.smtpShortLogin = ko.observable(false); - this.smtpAuth = ko.observable(true); - this.whiteList = ko.observable(''); - - this.headerText = ko.computed(function () { - var sName = this.name(); - return this.edit() ? 'Edit Domain "' + sName + '"' : - 'Add Domain' + ('' === sName ? '' : ' "' + sName + '"'); - }, this); - - this.domainIsComputed = ko.computed(function () { - return '' !== this.name() && - '' !== this.imapServer() && - '' !== this.imapPort() && - '' !== this.smtpServer() && - '' !== this.smtpPort(); - }, this); - - this.canBeTested = ko.computed(function () { - return !this.testing() && this.domainIsComputed(); - }, this); - - this.canBeSaved = ko.computed(function () { - return !this.saving() && this.domainIsComputed(); - }, this); - - this.createOrAddCommand = Utils.createCommand(this, function () { - this.saving(true); - RL.remote().createOrUpdateDomain( - _.bind(this.onDomainCreateOrSaveResponse, this), - !this.edit(), - this.name(), - this.imapServer(), - Utils.pInt(this.imapPort()), - this.imapSecure(), - this.imapShortLogin(), - this.smtpServer(), - Utils.pInt(this.smtpPort()), - this.smtpSecure(), - this.smtpShortLogin(), - this.smtpAuth(), - this.whiteList() - ); - }, this.canBeSaved); - - this.testConnectionCommand = Utils.createCommand(this, function () { + PopupsDomainViewModel.prototype.onHide = function () + { this.whiteListPage(false); + }; + + PopupsDomainViewModel.prototype.onShow = function (oDomain) + { + this.saving(false); + this.whiteListPage(false); + + this.testing(false); this.testingDone(false); this.testingImapError(false); this.testingSmtpError(false); - this.testing(true); - RL.remote().testConnectionForDomain( - _.bind(this.onTestConnectionResponse, this), - this.name(), - this.imapServer(), - Utils.pInt(this.imapPort()), - this.imapSecure(), - this.smtpServer(), - Utils.pInt(this.smtpPort()), - this.smtpSecure(), - this.smtpAuth() - ); - }, this.canBeTested); - this.whiteListCommand = Utils.createCommand(this, function () { - this.whiteListPage(!this.whiteListPage()); - }); - - // smart form improvements - this.imapServerFocus.subscribe(function (bValue) { - if (bValue && '' !== this.name() && '' === this.imapServer()) + this.clearForm(); + if (oDomain) { - this.imapServer(this.name().replace(/[.]?[*][.]?/g, '')); + this.edit(true); + + this.name(Utils.trim(oDomain.Name)); + this.imapServer(Utils.trim(oDomain.IncHost)); + this.imapPort('' + Utils.pInt(oDomain.IncPort)); + this.imapSecure(Utils.trim(oDomain.IncSecure)); + this.imapShortLogin(!!oDomain.IncShortLogin); + this.smtpServer(Utils.trim(oDomain.OutHost)); + this.smtpPort('' + Utils.pInt(oDomain.OutPort)); + this.smtpSecure(Utils.trim(oDomain.OutSecure)); + this.smtpShortLogin(!!oDomain.OutShortLogin); + this.smtpAuth(!!oDomain.OutAuth); + this.whiteList(Utils.trim(oDomain.WhiteList)); } - }, this); + }; - this.smtpServerFocus.subscribe(function (bValue) { - if (bValue && '' !== this.imapServer() && '' === this.smtpServer()) - { - this.smtpServer(this.imapServer().replace(/imap/ig, 'smtp')); - } - }, this); - - this.imapSecure.subscribe(function (sValue) { - var iPort = Utils.pInt(this.imapPort()); - sValue = Utils.pString(sValue); - switch (sValue) - { - case '0': - if (993 === iPort) - { - this.imapPort('143'); - } - break; - case '1': - if (143 === iPort) - { - this.imapPort('993'); - } - break; - } - }, this); - - this.smtpSecure.subscribe(function (sValue) { - var iPort = Utils.pInt(this.smtpPort()); - sValue = Utils.pString(sValue); - switch (sValue) - { - case '0': - if (465 === iPort || 587 === iPort) - { - this.smtpPort('25'); - } - break; - case '1': - if (25 === iPort || 587 === iPort) - { - this.smtpPort('465'); - } - break; - case '2': - if (25 === iPort || 465 === iPort) - { - this.smtpPort('587'); - } - break; - } - }, this); - - Knoin.constructorEnd(this); -} - -Utils.extendAsViewModel('PopupsDomainViewModel', PopupsDomainViewModel); - -PopupsDomainViewModel.prototype.onTestConnectionResponse = function (sResult, oData) -{ - this.testing(false); - if (Enums.StorageResultType.Success === sResult && oData.Result) + PopupsDomainViewModel.prototype.onFocus = function () { - this.testingDone(true); - this.testingImapError(true !== oData.Result.Imap); - this.testingSmtpError(true !== oData.Result.Smtp); - - if (this.testingImapError() && oData.Result.Imap) + if ('' === this.name()) { - this.testingImapErrorDesc(oData.Result.Imap); + this.name.focused(true); } + }; - if (this.testingSmtpError() && oData.Result.Smtp) - { - this.testingSmtpErrorDesc(oData.Result.Smtp); - } - } - else + PopupsDomainViewModel.prototype.clearForm = function () { - this.testingImapError(true); - this.testingSmtpError(true); - } -}; + this.edit(false); + this.whiteListPage(false); -PopupsDomainViewModel.prototype.onDomainCreateOrSaveResponse = function (sResult, oData) -{ - this.saving(false); - if (Enums.StorageResultType.Success === sResult && oData) - { - if (oData.Result) - { - RL.reloadDomainList(); - this.closeCommand(); - } - else if (Enums.Notification.DomainAlreadyExists === oData.ErrorCode) - { - this.savingError('Domain already exists'); - } - } - else - { - this.savingError('Unknown error'); - } -}; + this.savingError(''); -PopupsDomainViewModel.prototype.onHide = function () -{ - this.whiteListPage(false); -}; + this.name(''); + this.name.focused(false); -PopupsDomainViewModel.prototype.onShow = function (oDomain) -{ - this.saving(false); - this.whiteListPage(false); + this.imapServer(''); + this.imapPort('' + Consts.Values.ImapDefaulPort); + this.imapSecure(Enums.ServerSecure.None); + this.imapShortLogin(false); + this.smtpServer(''); + this.smtpPort('' + Consts.Values.SmtpDefaulPort); + this.smtpSecure(Enums.ServerSecure.None); + this.smtpShortLogin(false); + this.smtpAuth(true); + this.whiteList(''); + }; - this.testing(false); - this.testingDone(false); - this.testingImapError(false); - this.testingSmtpError(false); + module.exports = new PopupsDomainViewModel(); - this.clearForm(); - if (oDomain) - { - this.edit(true); - - this.name(Utils.trim(oDomain.Name)); - this.imapServer(Utils.trim(oDomain.IncHost)); - this.imapPort('' + Utils.pInt(oDomain.IncPort)); - this.imapSecure(Utils.trim(oDomain.IncSecure)); - this.imapShortLogin(!!oDomain.IncShortLogin); - this.smtpServer(Utils.trim(oDomain.OutHost)); - this.smtpPort('' + Utils.pInt(oDomain.OutPort)); - this.smtpSecure(Utils.trim(oDomain.OutSecure)); - this.smtpShortLogin(!!oDomain.OutShortLogin); - this.smtpAuth(!!oDomain.OutAuth); - this.whiteList(Utils.trim(oDomain.WhiteList)); - } -}; - -PopupsDomainViewModel.prototype.onFocus = function () -{ - if ('' === this.name()) - { - this.name.focused(true); - } -}; - -PopupsDomainViewModel.prototype.clearForm = function () -{ - this.edit(false); - this.whiteListPage(false); - - this.savingError(''); - - this.name(''); - this.name.focused(false); - - this.imapServer(''); - this.imapPort('' + Consts.Values.ImapDefaulPort); - this.imapSecure(Enums.ServerSecure.None); - this.imapShortLogin(false); - this.smtpServer(''); - this.smtpPort('' + Consts.Values.SmtpDefaulPort); - this.smtpSecure(Enums.ServerSecure.None); - this.smtpShortLogin(false); - this.smtpAuth(true); - this.whiteList(''); -}; +}(module)); \ No newline at end of file diff --git a/dev/ViewModels/Popups/PopupsFiterViewModel.js b/dev/ViewModels/Popups/PopupsFiterViewModel.js index 367547152..b56737b65 100644 --- a/dev/ViewModels/Popups/PopupsFiterViewModel.js +++ b/dev/ViewModels/Popups/PopupsFiterViewModel.js @@ -1,37 +1,57 @@ /* RainLoop Webmail (c) RainLoop Team | Licensed under CC BY-NC-SA 3.0 */ -/** - * @constructor - * @extends KnoinAbstractViewModel - */ -function PopupsFilterViewModel() -{ - KnoinAbstractViewModel.call(this, 'Popups', 'PopupsFilter'); +(function (module) { - this.filter = ko.observable(null); + 'use strict'; - this.selectedFolderValue = ko.observable(Consts.Values.UnuseOptionValue); - this.folderSelectList = RL.data().folderMenuForMove; - this.defautOptionsAfterRender = Utils.defautOptionsAfterRender; + var + ko = require('../../External/ko.js'), + + Consts = require('../../Common/Consts.js'), + Utils = require('../../Common/Utils.js'), - Knoin.constructorEnd(this); -} + Data = require('../../Storages/WebMailDataStorage.js'), -Utils.extendAsViewModel('PopupsFilterViewModel', PopupsFilterViewModel); + kn = require('../../Knoin/Knoin.js'), + KnoinAbstractViewModel = require('../../Knoin/KnoinAbstractViewModel.js') + ; -PopupsFilterViewModel.prototype.clearPopup = function () -{ + /** + * @constructor + * @extends KnoinAbstractViewModel + */ + function PopupsFilterViewModel() + { + KnoinAbstractViewModel.call(this, 'Popups', 'PopupsFilter'); -}; + this.filter = ko.observable(null); -PopupsFilterViewModel.prototype.onShow = function (oFilter) -{ - this.clearPopup(); + this.selectedFolderValue = ko.observable(Consts.Values.UnuseOptionValue); + this.folderSelectList = Data.folderMenuForMove; + this.defautOptionsAfterRender = Utils.defautOptionsAfterRender; - this.filter(oFilter); -}; + kn.constructorEnd(this); + } -PopupsFilterViewModel.prototype.onFocus = function () -{ + kn.extendAsViewModel('PopupsFilterViewModel', PopupsFilterViewModel); -}; + PopupsFilterViewModel.prototype.clearPopup = function () + { + // TODO + }; + + PopupsFilterViewModel.prototype.onShow = function (oFilter) + { + this.clearPopup(); + + this.filter(oFilter); + }; + +// PopupsFilterViewModel.prototype.onFocus = function () +// { +// +// }; + + module.exports = new PopupsFilterViewModel(); + +}(module)); \ No newline at end of file diff --git a/dev/ViewModels/Popups/PopupsFolderClearViewModel.js b/dev/ViewModels/Popups/PopupsFolderClearViewModel.js index f894bf94c..f0b1a2839 100644 --- a/dev/ViewModels/Popups/PopupsFolderClearViewModel.js +++ b/dev/ViewModels/Popups/PopupsFolderClearViewModel.js @@ -1,97 +1,120 @@ /* RainLoop Webmail (c) RainLoop Team | Licensed under CC BY-NC-SA 3.0 */ -/** - * @constructor - * @extends KnoinAbstractViewModel - */ -function PopupsFolderClearViewModel() -{ - KnoinAbstractViewModel.call(this, 'Popups', 'PopupsFolderClear'); - - this.selectedFolder = ko.observable(null); - this.clearingProcess = ko.observable(false); - this.clearingError = ko.observable(''); +(function (module) { - this.folderFullNameForClear = ko.computed(function () { - var oFolder = this.selectedFolder(); - return oFolder ? oFolder.printableFullName() : ''; - }, this); + 'use strict'; - this.folderNameForClear = ko.computed(function () { - var oFolder = this.selectedFolder(); - return oFolder ? oFolder.localName() : ''; - }, this); - - this.dangerDescHtml = ko.computed(function () { - return Utils.i18n('POPUPS_CLEAR_FOLDER/DANGER_DESC_HTML_1', { - 'FOLDER': this.folderNameForClear() - }); - }, this); + var + ko = require('../../External/ko.js'), + + Enums = require('../../Common/Enums.js'), + Utils = require('../../Common/Utils.js'), - this.clearCommand = Utils.createCommand(this, function () { - var - self = this, - oFolderToClear = this.selectedFolder() - ; + Data = require('../../Storages/WebMailDataStorage.js'), + Cache = require('../../Storages/WebMailCacheStorage.js'), + Remote = require('../../Storages/WebMailAjaxRemoteStorage.js'), - if (oFolderToClear) - { - RL.data().message(null); - RL.data().messageList([]); + kn = require('../../Knoin/Knoin.js'), + KnoinAbstractViewModel = require('../../Knoin/KnoinAbstractViewModel.js') + ; - this.clearingProcess(true); + /** + * @constructor + * @extends KnoinAbstractViewModel + */ + function PopupsFolderClearViewModel() + { + KnoinAbstractViewModel.call(this, 'Popups', 'PopupsFolderClear'); - RL.cache().setFolderHash(oFolderToClear.fullNameRaw, ''); - RL.remote().folderClear(function (sResult, oData) { - - self.clearingProcess(false); - if (Enums.StorageResultType.Success === sResult && oData && oData.Result) - { - RL.reloadMessageList(true); - self.cancelCommand(); - } - else - { - if (oData && oData.ErrorCode) + this.selectedFolder = ko.observable(null); + this.clearingProcess = ko.observable(false); + this.clearingError = ko.observable(''); + + this.folderFullNameForClear = ko.computed(function () { + var oFolder = this.selectedFolder(); + return oFolder ? oFolder.printableFullName() : ''; + }, this); + + this.folderNameForClear = ko.computed(function () { + var oFolder = this.selectedFolder(); + return oFolder ? oFolder.localName() : ''; + }, this); + + this.dangerDescHtml = ko.computed(function () { + return Utils.i18n('POPUPS_CLEAR_FOLDER/DANGER_DESC_HTML_1', { + 'FOLDER': this.folderNameForClear() + }); + }, this); + + this.clearCommand = Utils.createCommand(this, function () { + + var + self = this, + oFolderToClear = this.selectedFolder() + ; + + if (oFolderToClear) + { + Data.message(null); + Data.messageList([]); + + this.clearingProcess(true); + + Cache.setFolderHash(oFolderToClear.fullNameRaw, ''); + Remote.folderClear(function (sResult, oData) { + + self.clearingProcess(false); + if (Enums.StorageResultType.Success === sResult && oData && oData.Result) { - self.clearingError(Utils.getNotification(oData.ErrorCode)); + RL.reloadMessageList(true); + self.cancelCommand(); } else { - self.clearingError(Utils.getNotification(Enums.Notification.MailServerError)); + if (oData && oData.ErrorCode) + { + self.clearingError(Utils.getNotification(oData.ErrorCode)); + } + else + { + self.clearingError(Utils.getNotification(Enums.Notification.MailServerError)); + } } - } - }, oFolderToClear.fullNameRaw); - } + }, oFolderToClear.fullNameRaw); + } - }, function () { + }, function () { - var - oFolder = this.selectedFolder(), - bIsClearing = this.clearingProcess() - ; + var + oFolder = this.selectedFolder(), + bIsClearing = this.clearingProcess() + ; - return !bIsClearing && null !== oFolder; + return !bIsClearing && null !== oFolder; - }); + }); - Knoin.constructorEnd(this); -} - -Utils.extendAsViewModel('PopupsFolderClearViewModel', PopupsFolderClearViewModel); - -PopupsFolderClearViewModel.prototype.clearPopup = function () -{ - this.clearingProcess(false); - this.selectedFolder(null); -}; - -PopupsFolderClearViewModel.prototype.onShow = function (oFolder) -{ - this.clearPopup(); - if (oFolder) - { - this.selectedFolder(oFolder); + kn.constructorEnd(this); } -}; + + kn.extendAsViewModel('PopupsFolderClearViewModel', PopupsFolderClearViewModel); + + PopupsFolderClearViewModel.prototype.clearPopup = function () + { + this.clearingProcess(false); + this.selectedFolder(null); + }; + + PopupsFolderClearViewModel.prototype.onShow = function (oFolder) + { + this.clearPopup(); + if (oFolder) + { + this.selectedFolder(oFolder); + } + }; + + module.exports = new PopupsFolderClearViewModel(); + +}(module)); diff --git a/dev/ViewModels/Popups/PopupsFolderCreateViewModel.js b/dev/ViewModels/Popups/PopupsFolderCreateViewModel.js index 5b8137f81..f659c4fe3 100644 --- a/dev/ViewModels/Popups/PopupsFolderCreateViewModel.js +++ b/dev/ViewModels/Popups/PopupsFolderCreateViewModel.js @@ -1,111 +1,128 @@ /* RainLoop Webmail (c) RainLoop Team | Licensed under CC BY-NC-SA 3.0 */ -/** - * @constructor - * @extends KnoinAbstractViewModel - */ -function PopupsFolderCreateViewModel() -{ - KnoinAbstractViewModel.call(this, 'Popups', 'PopupsFolderCreate'); +(function (module) { - Utils.initOnStartOrLangChange(function () { - this.sNoParentText = Utils.i18n('POPUPS_CREATE_FOLDER/SELECT_NO_PARENT'); - }, this); + 'use strict'; - this.folderName = ko.observable(''); - this.folderName.focused = ko.observable(false); - - this.selectedParentValue = ko.observable(Consts.Values.UnuseOptionValue); - - this.parentFolderSelectList = ko.computed(function () { - - var - oData = RL.data(), - aTop = [], - fDisableCallback = null, - fVisibleCallback = null, - aList = oData.folderList(), - fRenameCallback = function (oItem) { - return oItem ? (oItem.isSystemFolder() ? oItem.name() + ' ' + oItem.manageFolderSystemName() : oItem.name()) : ''; - } - ; - - aTop.push(['', this.sNoParentText]); + var + ko = require('../../External/ko.js'), - if ('' !== oData.namespace) - { - fDisableCallback = function (oItem) + Enums = require('../../Common/Enums.js'), + Consts = require('../../Common/Consts.js'), + Utils = require('../../Common/Utils.js'), + + Data = require('../../Storages/WebMailDataStorage.js'), + Remote = require('../../Storages/WebMailAjaxRemoteStorage.js'), + + kn = require('../../Knoin/Knoin.js'), + KnoinAbstractViewModel = require('../../Knoin/KnoinAbstractViewModel.js') + ; + + /** + * @constructor + * @extends KnoinAbstractViewModel + */ + function PopupsFolderCreateViewModel() + { + KnoinAbstractViewModel.call(this, 'Popups', 'PopupsFolderCreate'); + + Utils.initOnStartOrLangChange(function () { + this.sNoParentText = Utils.i18n('POPUPS_CREATE_FOLDER/SELECT_NO_PARENT'); + }, this); + + this.folderName = ko.observable(''); + this.folderName.focused = ko.observable(false); + + this.selectedParentValue = ko.observable(Consts.Values.UnuseOptionValue); + + this.parentFolderSelectList = ko.computed(function () { + + var + aTop = [], + fDisableCallback = null, + fVisibleCallback = null, + aList = Data.folderList(), + fRenameCallback = function (oItem) { + return oItem ? (oItem.isSystemFolder() ? oItem.name() + ' ' + oItem.manageFolderSystemName() : oItem.name()) : ''; + } + ; + + aTop.push(['', this.sNoParentText]); + + if ('' !== Data.namespace) { - return oData.namespace !== oItem.fullNameRaw.substr(0, oData.namespace.length); - }; - } - - return RL.folderListOptionsBuilder([], aList, [], aTop, null, fDisableCallback, fVisibleCallback, fRenameCallback); - - }, this); - - // commands - this.createFolder = Utils.createCommand(this, function () { - - var - oData = RL.data(), - sParentFolderName = this.selectedParentValue() - ; - - if ('' === sParentFolderName && 1 < oData.namespace.length) - { - sParentFolderName = oData.namespace.substr(0, oData.namespace.length - 1); - } - - oData.foldersCreating(true); - RL.remote().folderCreate(function (sResult, oData) { - - RL.data().foldersCreating(false); - if (Enums.StorageResultType.Success === sResult && oData && oData.Result) - { - RL.folders(); + fDisableCallback = function (oItem) + { + return Data.namespace !== oItem.fullNameRaw.substr(0, Data.namespace.length); + }; } - else + + return RL.folderListOptionsBuilder([], aList, [], aTop, null, fDisableCallback, fVisibleCallback, fRenameCallback); + + }, this); + + // commands + this.createFolder = Utils.createCommand(this, function () { + + var sParentFolderName = this.selectedParentValue(); + if ('' === sParentFolderName && 1 < Data.namespace.length) { - RL.data().foldersListError( - oData && oData.ErrorCode ? Utils.getNotification(oData.ErrorCode) : Utils.i18n('NOTIFICATIONS/CANT_CREATE_FOLDER')); + sParentFolderName = Data.namespace.substr(0, Data.namespace.length - 1); } - - }, this.folderName(), sParentFolderName); - - this.cancelCommand(); - }, function () { - return this.simpleFolderNameValidation(this.folderName()); - }); + Data.foldersCreating(true); + Remote.folderCreate(function (sResult, oData) { - this.defautOptionsAfterRender = Utils.defautOptionsAfterRender; + Data.foldersCreating(false); + if (Enums.StorageResultType.Success === sResult && oData && oData.Result) + { + RL.folders(); + } + else + { + Data.foldersListError( + oData && oData.ErrorCode ? Utils.getNotification(oData.ErrorCode) : Utils.i18n('NOTIFICATIONS/CANT_CREATE_FOLDER')); + } - Knoin.constructorEnd(this); -} + }, this.folderName(), sParentFolderName); -Utils.extendAsViewModel('PopupsFolderCreateViewModel', PopupsFolderCreateViewModel); + this.cancelCommand(); -PopupsFolderCreateViewModel.prototype.sNoParentText = ''; + }, function () { + return this.simpleFolderNameValidation(this.folderName()); + }); -PopupsFolderCreateViewModel.prototype.simpleFolderNameValidation = function (sName) -{ - return (/^[^\\\/]+$/g).test(Utils.trim(sName)); -}; + this.defautOptionsAfterRender = Utils.defautOptionsAfterRender; -PopupsFolderCreateViewModel.prototype.clearPopup = function () -{ - this.folderName(''); - this.selectedParentValue(''); - this.folderName.focused(false); -}; + kn.constructorEnd(this); + } -PopupsFolderCreateViewModel.prototype.onShow = function () -{ - this.clearPopup(); -}; + kn.extendAsViewModel('PopupsFolderCreateViewModel', PopupsFolderCreateViewModel); -PopupsFolderCreateViewModel.prototype.onFocus = function () -{ - this.folderName.focused(true); -}; + PopupsFolderCreateViewModel.prototype.sNoParentText = ''; + + PopupsFolderCreateViewModel.prototype.simpleFolderNameValidation = function (sName) + { + return (/^[^\\\/]+$/g).test(Utils.trim(sName)); + }; + + PopupsFolderCreateViewModel.prototype.clearPopup = function () + { + this.folderName(''); + this.selectedParentValue(''); + this.folderName.focused(false); + }; + + PopupsFolderCreateViewModel.prototype.onShow = function () + { + this.clearPopup(); + }; + + PopupsFolderCreateViewModel.prototype.onFocus = function () + { + this.folderName.focused(true); + }; + + module.exports = new PopupsFolderCreateViewModel(); + +}(module)); \ No newline at end of file diff --git a/dev/ViewModels/Popups/PopupsFolderSystemViewModel.js b/dev/ViewModels/Popups/PopupsFolderSystemViewModel.js index 4be574caf..ead50695e 100644 --- a/dev/ViewModels/Popups/PopupsFolderSystemViewModel.js +++ b/dev/ViewModels/Popups/PopupsFolderSystemViewModel.js @@ -1,114 +1,134 @@ /* RainLoop Webmail (c) RainLoop Team | Licensed under CC BY-NC-SA 3.0 */ -/** - * @constructor - * @extends KnoinAbstractViewModel - */ -function PopupsFolderSystemViewModel() -{ - KnoinAbstractViewModel.call(this, 'Popups', 'PopupsFolderSystem'); +(function (module) { - Utils.initOnStartOrLangChange(function () { - this.sChooseOnText = Utils.i18n('POPUPS_SYSTEM_FOLDERS/SELECT_CHOOSE_ONE'); - this.sUnuseText = Utils.i18n('POPUPS_SYSTEM_FOLDERS/SELECT_UNUSE_NAME'); - }, this); + 'use strict'; - this.notification = ko.observable(''); - - this.folderSelectList = ko.computed(function () { - return RL.folderListOptionsBuilder([], RL.data().folderList(), RL.data().folderListSystemNames(), [ - ['', this.sChooseOnText], - [Consts.Values.UnuseOptionValue, this.sUnuseText] - ]); - }, this); - var - oData = RL.data(), - self = this, - fSaveSystemFolders = null, - fCallback = null + ko = require('../../External/ko.js'), + + Enums = require('../../Common/Enums.js'), + Consts = require('../../Common/Consts.js'), + Utils = require('../../Common/Utils.js'), + + Data = require('../../Storages/WebMailDataStorage.js'), + Remote = require('../../Storages/WebMailAjaxRemoteStorage.js'), + + kn = require('../../Knoin/Knoin.js'), + KnoinAbstractViewModel = require('../../Knoin/KnoinAbstractViewModel.js') ; - - this.sentFolder = oData.sentFolder; - this.draftFolder = oData.draftFolder; - this.spamFolder = oData.spamFolder; - this.trashFolder = oData.trashFolder; - this.archiveFolder = oData.archiveFolder; - - fSaveSystemFolders = _.debounce(function () { - RL.settingsSet('SentFolder', self.sentFolder()); - RL.settingsSet('DraftFolder', self.draftFolder()); - RL.settingsSet('SpamFolder', self.spamFolder()); - RL.settingsSet('TrashFolder', self.trashFolder()); - RL.settingsSet('ArchiveFolder', self.archiveFolder()); - - RL.remote().saveSystemFolders(Utils.emptyFunction, { - 'SentFolder': self.sentFolder(), - 'DraftFolder': self.draftFolder(), - 'SpamFolder': self.spamFolder(), - 'TrashFolder': self.trashFolder(), - 'ArchiveFolder': self.archiveFolder(), - 'NullFolder': 'NullFolder' - }); - - }, 1000); - - fCallback = function () { - - RL.settingsSet('SentFolder', self.sentFolder()); - RL.settingsSet('DraftFolder', self.draftFolder()); - RL.settingsSet('SpamFolder', self.spamFolder()); - RL.settingsSet('TrashFolder', self.trashFolder()); - RL.settingsSet('ArchiveFolder', self.archiveFolder()); - - fSaveSystemFolders(); - }; - - this.sentFolder.subscribe(fCallback); - this.draftFolder.subscribe(fCallback); - this.spamFolder.subscribe(fCallback); - this.trashFolder.subscribe(fCallback); - this.archiveFolder.subscribe(fCallback); - - this.defautOptionsAfterRender = Utils.defautOptionsAfterRender; - - Knoin.constructorEnd(this); -} - -Utils.extendAsViewModel('PopupsFolderSystemViewModel', PopupsFolderSystemViewModel); - -PopupsFolderSystemViewModel.prototype.sChooseOnText = ''; -PopupsFolderSystemViewModel.prototype.sUnuseText = ''; - -/** - * @param {number=} iNotificationType = Enums.SetSystemFoldersNotification.None - */ -PopupsFolderSystemViewModel.prototype.onShow = function (iNotificationType) -{ - var sNotification = ''; - - iNotificationType = Utils.isUnd(iNotificationType) ? Enums.SetSystemFoldersNotification.None : iNotificationType; - - switch (iNotificationType) + /** + * @constructor + * @extends KnoinAbstractViewModel + */ + function PopupsFolderSystemViewModel() { - case Enums.SetSystemFoldersNotification.Sent: - sNotification = Utils.i18n('POPUPS_SYSTEM_FOLDERS/NOTIFICATION_SENT'); - break; - case Enums.SetSystemFoldersNotification.Draft: - sNotification = Utils.i18n('POPUPS_SYSTEM_FOLDERS/NOTIFICATION_DRAFTS'); - break; - case Enums.SetSystemFoldersNotification.Spam: - sNotification = Utils.i18n('POPUPS_SYSTEM_FOLDERS/NOTIFICATION_SPAM'); - break; - case Enums.SetSystemFoldersNotification.Trash: - sNotification = Utils.i18n('POPUPS_SYSTEM_FOLDERS/NOTIFICATION_TRASH'); - break; - case Enums.SetSystemFoldersNotification.Archive: - sNotification = Utils.i18n('POPUPS_SYSTEM_FOLDERS/NOTIFICATION_ARCHIVE'); - break; + KnoinAbstractViewModel.call(this, 'Popups', 'PopupsFolderSystem'); + + Utils.initOnStartOrLangChange(function () { + this.sChooseOnText = Utils.i18n('POPUPS_SYSTEM_FOLDERS/SELECT_CHOOSE_ONE'); + this.sUnuseText = Utils.i18n('POPUPS_SYSTEM_FOLDERS/SELECT_UNUSE_NAME'); + }, this); + + this.notification = ko.observable(''); + + this.folderSelectList = ko.computed(function () { + return RL.folderListOptionsBuilder([], Data.folderList(), Data.folderListSystemNames(), [ + ['', this.sChooseOnText], + [Consts.Values.UnuseOptionValue, this.sUnuseText] + ]); + }, this); + + var + self = this, + fSaveSystemFolders = null, + fCallback = null + ; + + this.sentFolder = Data.sentFolder; + this.draftFolder = Data.draftFolder; + this.spamFolder = Data.spamFolder; + this.trashFolder = Data.trashFolder; + this.archiveFolder = Data.archiveFolder; + + fSaveSystemFolders = _.debounce(function () { + + RL.settingsSet('SentFolder', self.sentFolder()); + RL.settingsSet('DraftFolder', self.draftFolder()); + RL.settingsSet('SpamFolder', self.spamFolder()); + RL.settingsSet('TrashFolder', self.trashFolder()); + RL.settingsSet('ArchiveFolder', self.archiveFolder()); + + Remote.saveSystemFolders(Utils.emptyFunction, { + 'SentFolder': self.sentFolder(), + 'DraftFolder': self.draftFolder(), + 'SpamFolder': self.spamFolder(), + 'TrashFolder': self.trashFolder(), + 'ArchiveFolder': self.archiveFolder(), + 'NullFolder': 'NullFolder' + }); + + }, 1000); + + fCallback = function () { + + RL.settingsSet('SentFolder', self.sentFolder()); + RL.settingsSet('DraftFolder', self.draftFolder()); + RL.settingsSet('SpamFolder', self.spamFolder()); + RL.settingsSet('TrashFolder', self.trashFolder()); + RL.settingsSet('ArchiveFolder', self.archiveFolder()); + + fSaveSystemFolders(); + }; + + this.sentFolder.subscribe(fCallback); + this.draftFolder.subscribe(fCallback); + this.spamFolder.subscribe(fCallback); + this.trashFolder.subscribe(fCallback); + this.archiveFolder.subscribe(fCallback); + + this.defautOptionsAfterRender = Utils.defautOptionsAfterRender; + + kn.constructorEnd(this); } - this.notification(sNotification); -}; + kn.extendAsViewModel('PopupsFolderSystemViewModel', PopupsFolderSystemViewModel); + PopupsFolderSystemViewModel.prototype.sChooseOnText = ''; + PopupsFolderSystemViewModel.prototype.sUnuseText = ''; + + /** + * @param {number=} iNotificationType = Enums.SetSystemFoldersNotification.None + */ + PopupsFolderSystemViewModel.prototype.onShow = function (iNotificationType) + { + var sNotification = ''; + + iNotificationType = Utils.isUnd(iNotificationType) ? Enums.SetSystemFoldersNotification.None : iNotificationType; + + switch (iNotificationType) + { + case Enums.SetSystemFoldersNotification.Sent: + sNotification = Utils.i18n('POPUPS_SYSTEM_FOLDERS/NOTIFICATION_SENT'); + break; + case Enums.SetSystemFoldersNotification.Draft: + sNotification = Utils.i18n('POPUPS_SYSTEM_FOLDERS/NOTIFICATION_DRAFTS'); + break; + case Enums.SetSystemFoldersNotification.Spam: + sNotification = Utils.i18n('POPUPS_SYSTEM_FOLDERS/NOTIFICATION_SPAM'); + break; + case Enums.SetSystemFoldersNotification.Trash: + sNotification = Utils.i18n('POPUPS_SYSTEM_FOLDERS/NOTIFICATION_TRASH'); + break; + case Enums.SetSystemFoldersNotification.Archive: + sNotification = Utils.i18n('POPUPS_SYSTEM_FOLDERS/NOTIFICATION_ARCHIVE'); + break; + } + + this.notification(sNotification); + }; + + module.exports = new PopupsFolderSystemViewModel(); + +}(module)); \ No newline at end of file diff --git a/dev/ViewModels/Popups/PopupsGenerateNewOpenPgpKeyViewModel.js b/dev/ViewModels/Popups/PopupsGenerateNewOpenPgpKeyViewModel.js index b49ba3b22..b4f3f8e06 100644 --- a/dev/ViewModels/Popups/PopupsGenerateNewOpenPgpKeyViewModel.js +++ b/dev/ViewModels/Popups/PopupsGenerateNewOpenPgpKeyViewModel.js @@ -1,95 +1,115 @@ /* RainLoop Webmail (c) RainLoop Team | Licensed under CC BY-NC-SA 3.0 */ -/** - * @constructor - * @extends KnoinAbstractViewModel - */ -function PopupsGenerateNewOpenPgpKeyViewModel() -{ - KnoinAbstractViewModel.call(this, 'Popups', 'PopupsGenerateNewOpenPgpKey'); +(function (module) { - this.email = ko.observable(''); - this.email.focus = ko.observable(''); - this.email.error = ko.observable(false); - - this.name = ko.observable(''); - this.password = ko.observable(''); - this.keyBitLength = ko.observable(2048); + 'use strict'; - this.submitRequest = ko.observable(false); + var + window = require('../../External/window.js'), + ko = require('../../External/ko.js'), + + Utils = require('../../Common/Utils.js'), - this.email.subscribe(function () { - this.email.error(false); - }, this); + Data = require('../../Storages/WebMailDataStorage.js'), - this.generateOpenPgpKeyCommand = Utils.createCommand(this, function () { + kn = require('../../Knoin/Knoin.js'), + KnoinAbstractViewModel = require('../../Knoin/KnoinAbstractViewModel.js') + ; - var - self = this, - sUserID = '', - mKeyPair = null, - oOpenpgpKeyring = RL.data().openpgpKeyring - ; + /** + * @constructor + * @extends KnoinAbstractViewModel + */ + function PopupsGenerateNewOpenPgpKeyViewModel() + { + KnoinAbstractViewModel.call(this, 'Popups', 'PopupsGenerateNewOpenPgpKey'); - this.email.error('' === Utils.trim(this.email())); - if (!oOpenpgpKeyring || this.email.error()) - { - return false; - } + this.email = ko.observable(''); + this.email.focus = ko.observable(''); + this.email.error = ko.observable(false); - sUserID = this.email(); - if ('' !== this.name()) - { - sUserID = this.name() + ' <' + sUserID + '>'; - } + this.name = ko.observable(''); + this.password = ko.observable(''); + this.keyBitLength = ko.observable(2048); - this.submitRequest(true); + this.submitRequest = ko.observable(false); - _.delay(function () { -// mKeyPair = window.openpgp.generateKeyPair(1, Utils.pInt(self.keyBitLength()), sUserID, Utils.trim(self.password())); - mKeyPair = window.openpgp.generateKeyPair({ - 'userId': sUserID, - 'numBits': Utils.pInt(self.keyBitLength()), - 'passphrase': Utils.trim(self.password()) - }); - - if (mKeyPair && mKeyPair.privateKeyArmored) + this.email.subscribe(function () { + this.email.error(false); + }, this); + + this.generateOpenPgpKeyCommand = Utils.createCommand(this, function () { + + var + self = this, + sUserID = '', + mKeyPair = null, + oOpenpgpKeyring = Data.openpgpKeyring + ; + + this.email.error('' === Utils.trim(this.email())); + if (!oOpenpgpKeyring || this.email.error()) { - oOpenpgpKeyring.privateKeys.importKey(mKeyPair.privateKeyArmored); - oOpenpgpKeyring.publicKeys.importKey(mKeyPair.publicKeyArmored); - oOpenpgpKeyring.store(); - - RL.reloadOpenPgpKeys(); - Utils.delegateRun(self, 'cancelCommand'); + return false; } - self.submitRequest(false); - }, 100); + sUserID = this.email(); + if ('' !== this.name()) + { + sUserID = this.name() + ' <' + sUserID + '>'; + } - return true; - }); + this.submitRequest(true); - Knoin.constructorEnd(this); -} + _.delay(function () { + // mKeyPair = window.openpgp.generateKeyPair(1, Utils.pInt(self.keyBitLength()), sUserID, Utils.trim(self.password())); + mKeyPair = window.openpgp.generateKeyPair({ + 'userId': sUserID, + 'numBits': Utils.pInt(self.keyBitLength()), + 'passphrase': Utils.trim(self.password()) + }); -Utils.extendAsViewModel('PopupsGenerateNewOpenPgpKeyViewModel', PopupsGenerateNewOpenPgpKeyViewModel); + if (mKeyPair && mKeyPair.privateKeyArmored) + { + oOpenpgpKeyring.privateKeys.importKey(mKeyPair.privateKeyArmored); + oOpenpgpKeyring.publicKeys.importKey(mKeyPair.publicKeyArmored); + oOpenpgpKeyring.store(); -PopupsGenerateNewOpenPgpKeyViewModel.prototype.clearPopup = function () -{ - this.name(''); - this.password(''); - - this.email(''); - this.email.error(false); - this.keyBitLength(2048); -}; + RL.reloadOpenPgpKeys(); + Utils.delegateRun(self, 'cancelCommand'); + } -PopupsGenerateNewOpenPgpKeyViewModel.prototype.onShow = function () -{ - this.clearPopup(); -}; + self.submitRequest(false); + }, 100); -PopupsGenerateNewOpenPgpKeyViewModel.prototype.onFocus = function () -{ - this.email.focus(true); -}; + return true; + }); + + kn.constructorEnd(this); + } + + kn.extendAsViewModel('PopupsGenerateNewOpenPgpKeyViewModel', PopupsGenerateNewOpenPgpKeyViewModel); + + PopupsGenerateNewOpenPgpKeyViewModel.prototype.clearPopup = function () + { + this.name(''); + this.password(''); + + this.email(''); + this.email.error(false); + this.keyBitLength(2048); + }; + + PopupsGenerateNewOpenPgpKeyViewModel.prototype.onShow = function () + { + this.clearPopup(); + }; + + PopupsGenerateNewOpenPgpKeyViewModel.prototype.onFocus = function () + { + this.email.focus(true); + }; + + module.exports = new PopupsGenerateNewOpenPgpKeyViewModel(); + +}(module)); \ No newline at end of file diff --git a/dev/ViewModels/Popups/PopupsIdentityViewModel.js b/dev/ViewModels/Popups/PopupsIdentityViewModel.js index cf7386be3..d9b9cf283 100644 --- a/dev/ViewModels/Popups/PopupsIdentityViewModel.js +++ b/dev/ViewModels/Popups/PopupsIdentityViewModel.js @@ -1,149 +1,170 @@ /* RainLoop Webmail (c) RainLoop Team | Licensed under CC BY-NC-SA 3.0 */ -/** - * @constructor - * @extends KnoinAbstractViewModel - */ -function PopupsIdentityViewModel() -{ - KnoinAbstractViewModel.call(this, 'Popups', 'PopupsIdentity'); +(function (module) { - this.id = ''; - this.edit = ko.observable(false); - this.owner = ko.observable(false); - - this.email = ko.observable('').validateEmail(); - this.email.focused = ko.observable(false); - this.name = ko.observable(''); - this.name.focused = ko.observable(false); - this.replyTo = ko.observable('').validateSimpleEmail(); - this.replyTo.focused = ko.observable(false); - this.bcc = ko.observable('').validateSimpleEmail(); - this.bcc.focused = ko.observable(false); + 'use strict'; -// this.email.subscribe(function () { -// this.email.hasError(false); -// }, this); - - this.submitRequest = ko.observable(false); - this.submitError = ko.observable(''); - - this.addOrEditIdentityCommand = Utils.createCommand(this, function () { - - if (!this.email.hasError()) - { - this.email.hasError('' === Utils.trim(this.email())); - } - - if (this.email.hasError()) - { - if (!this.owner()) - { - this.email.focused(true); - } - - return false; - } - - if (this.replyTo.hasError()) - { - this.replyTo.focused(true); - return false; - } - - if (this.bcc.hasError()) - { - this.bcc.focused(true); - return false; - } + var + ko = require('../../External/ko.js'), - this.submitRequest(true); + Enums = require('../../Common/Enums.js'), + Utils = require('../../Common/Utils.js'), + kn = require('../../Knoin/Knoin.js'), - RL.remote().identityUpdate(_.bind(function (sResult, oData) { + Remote = require('../../Storages/WebMailAjaxRemoteStorage.js'), + Data = require('../../Storages/WebMailDataStorage.js'), - this.submitRequest(false); - if (Enums.StorageResultType.Success === sResult && oData) + KnoinAbstractViewModel = require('../../Knoin/KnoinAbstractViewModel.js') + ; + + /** + * @constructor + * @extends KnoinAbstractViewModel + */ + function PopupsIdentityViewModel() + { + KnoinAbstractViewModel.call(this, 'Popups', 'PopupsIdentity'); + + this.id = ''; + this.edit = ko.observable(false); + this.owner = ko.observable(false); + + this.email = ko.observable('').validateEmail(); + this.email.focused = ko.observable(false); + this.name = ko.observable(''); + this.name.focused = ko.observable(false); + this.replyTo = ko.observable('').validateSimpleEmail(); + this.replyTo.focused = ko.observable(false); + this.bcc = ko.observable('').validateSimpleEmail(); + this.bcc.focused = ko.observable(false); + + // this.email.subscribe(function () { + // this.email.hasError(false); + // }, this); + + this.submitRequest = ko.observable(false); + this.submitError = ko.observable(''); + + this.addOrEditIdentityCommand = Utils.createCommand(this, function () { + + if (!this.email.hasError()) { - if (oData.Result) - { - RL.accountsAndIdentities(); - this.cancelCommand(); - } - else if (oData.ErrorCode) - { - this.submitError(Utils.getNotification(oData.ErrorCode)); - } - } - else - { - this.submitError(Utils.getNotification(Enums.Notification.UnknownError)); + this.email.hasError('' === Utils.trim(this.email())); } - }, this), this.id, this.email(), this.name(), this.replyTo(), this.bcc()); + if (this.email.hasError()) + { + if (!this.owner()) + { + this.email.focused(true); + } - return true; + return false; + } - }, function () { - return !this.submitRequest(); - }); + if (this.replyTo.hasError()) + { + this.replyTo.focused(true); + return false; + } - this.label = ko.computed(function () { - return Utils.i18n('POPUPS_IDENTITIES/' + (this.edit() ? 'TITLE_UPDATE_IDENTITY': 'TITLE_ADD_IDENTITY')); - }, this); + if (this.bcc.hasError()) + { + this.bcc.focused(true); + return false; + } - this.button = ko.computed(function () { - return Utils.i18n('POPUPS_IDENTITIES/' + (this.edit() ? 'BUTTON_UPDATE_IDENTITY': 'BUTTON_ADD_IDENTITY')); - }, this); + this.submitRequest(true); - Knoin.constructorEnd(this); -} + Remote.identityUpdate(_.bind(function (sResult, oData) { -Utils.extendAsViewModel('PopupsIdentityViewModel', PopupsIdentityViewModel); + this.submitRequest(false); + if (Enums.StorageResultType.Success === sResult && oData) + { + if (oData.Result) + { + RL.accountsAndIdentities(); + this.cancelCommand(); + } + else if (oData.ErrorCode) + { + this.submitError(Utils.getNotification(oData.ErrorCode)); + } + } + else + { + this.submitError(Utils.getNotification(Enums.Notification.UnknownError)); + } -PopupsIdentityViewModel.prototype.clearPopup = function () -{ - this.id = ''; - this.edit(false); - this.owner(false); + }, this), this.id, this.email(), this.name(), this.replyTo(), this.bcc()); - this.name(''); - this.email(''); - this.replyTo(''); - this.bcc(''); + return true; - this.email.hasError(false); - this.replyTo.hasError(false); - this.bcc.hasError(false); + }, function () { + return !this.submitRequest(); + }); - this.submitRequest(false); - this.submitError(''); -}; + this.label = ko.computed(function () { + return Utils.i18n('POPUPS_IDENTITIES/' + (this.edit() ? 'TITLE_UPDATE_IDENTITY': 'TITLE_ADD_IDENTITY')); + }, this); -/** - * @param {?IdentityModel} oIdentity - */ -PopupsIdentityViewModel.prototype.onShow = function (oIdentity) -{ - this.clearPopup(); + this.button = ko.computed(function () { + return Utils.i18n('POPUPS_IDENTITIES/' + (this.edit() ? 'BUTTON_UPDATE_IDENTITY': 'BUTTON_ADD_IDENTITY')); + }, this); - if (oIdentity) - { - this.edit(true); - - this.id = oIdentity.id; - this.name(oIdentity.name()); - this.email(oIdentity.email()); - this.replyTo(oIdentity.replyTo()); - this.bcc(oIdentity.bcc()); - - this.owner(this.id === RL.data().accountEmail()); + kn.constructorEnd(this); } -}; -PopupsIdentityViewModel.prototype.onFocus = function () -{ - if (!this.owner()) + kn.extendAsViewModel('PopupsIdentityViewModel', PopupsIdentityViewModel); + + PopupsIdentityViewModel.prototype.clearPopup = function () { - this.email.focused(true); - } -}; + this.id = ''; + this.edit(false); + this.owner(false); + + this.name(''); + this.email(''); + this.replyTo(''); + this.bcc(''); + + this.email.hasError(false); + this.replyTo.hasError(false); + this.bcc.hasError(false); + + this.submitRequest(false); + this.submitError(''); + }; + + /** + * @param {?IdentityModel} oIdentity + */ + PopupsIdentityViewModel.prototype.onShow = function (oIdentity) + { + this.clearPopup(); + + if (oIdentity) + { + this.edit(true); + + this.id = oIdentity.id; + this.name(oIdentity.name()); + this.email(oIdentity.email()); + this.replyTo(oIdentity.replyTo()); + this.bcc(oIdentity.bcc()); + + this.owner(this.id === Data.accountEmail()); + } + }; + + PopupsIdentityViewModel.prototype.onFocus = function () + { + if (!this.owner()) + { + this.email.focused(true); + } + }; + + module.exports = new PopupsIdentityViewModel(); + +}(module)); \ No newline at end of file diff --git a/dev/ViewModels/Popups/PopupsKeyboardShortcutsHelpViewModel.js b/dev/ViewModels/Popups/PopupsKeyboardShortcutsHelpViewModel.js index 6656bbe0d..5cbb2a9f2 100644 --- a/dev/ViewModels/Popups/PopupsKeyboardShortcutsHelpViewModel.js +++ b/dev/ViewModels/Popups/PopupsKeyboardShortcutsHelpViewModel.js @@ -1,46 +1,63 @@ /* RainLoop Webmail (c) RainLoop Team | Licensed under CC BY-NC-SA 3.0 */ -/** - * @constructor - * @extends KnoinAbstractViewModel - */ -function PopupsKeyboardShortcutsHelpViewModel() -{ - KnoinAbstractViewModel.call(this, 'Popups', 'PopupsKeyboardShortcutsHelp'); +(function (module) { - this.sDefaultKeyScope = Enums.KeyState.PopupKeyboardShortcutsHelp; + 'use strict'; - Knoin.constructorEnd(this); -} + var + _ = require('../../External/underscore.js'), + key = require('../../External/key.js'), + Enums = require('../../Common/Enums.js'), + Utils = require('../../Common/Utils.js'), + kn = require('../../Knoin/Knoin.js'), + KnoinAbstractViewModel = require('../../Knoin/KnoinAbstractViewModel.js') + ; -Utils.extendAsViewModel('PopupsKeyboardShortcutsHelpViewModel', PopupsKeyboardShortcutsHelpViewModel); + /** + * @constructor + * @extends KnoinAbstractViewModel + */ + function PopupsKeyboardShortcutsHelpViewModel() + { + KnoinAbstractViewModel.call(this, 'Popups', 'PopupsKeyboardShortcutsHelp'); -PopupsKeyboardShortcutsHelpViewModel.prototype.onBuild = function (oDom) -{ - key('tab, shift+tab, left, right', Enums.KeyState.PopupKeyboardShortcutsHelp, _.bind(function (event, handler) { - if (event && handler) - { - var - $tabs = oDom.find('.nav.nav-tabs > li'), - bNext = handler && ('tab' === handler.shortcut || 'right' === handler.shortcut), - iIndex = $tabs.index($tabs.filter('.active')) - ; + this.sDefaultKeyScope = Enums.KeyState.PopupKeyboardShortcutsHelp; - if (!bNext && iIndex > 0) + kn.constructorEnd(this); + } + + kn.extendAsViewModel('PopupsKeyboardShortcutsHelpViewModel', PopupsKeyboardShortcutsHelpViewModel); + + PopupsKeyboardShortcutsHelpViewModel.prototype.onBuild = function (oDom) + { + key('tab, shift+tab, left, right', Enums.KeyState.PopupKeyboardShortcutsHelp, _.bind(function (event, handler) { + if (event && handler) { - iIndex--; - } - else if (bNext && iIndex < $tabs.length - 1) - { - iIndex++; - } - else - { - iIndex = bNext ? 0 : $tabs.length - 1; - } + var + $tabs = oDom.find('.nav.nav-tabs > li'), + bNext = handler && ('tab' === handler.shortcut || 'right' === handler.shortcut), + iIndex = $tabs.index($tabs.filter('.active')) + ; - $tabs.eq(iIndex).find('a[data-toggle="tab"]').tab('show'); - return false; - } - }, this)); -}; + if (!bNext && iIndex > 0) + { + iIndex--; + } + else if (bNext && iIndex < $tabs.length - 1) + { + iIndex++; + } + else + { + iIndex = bNext ? 0 : $tabs.length - 1; + } + + $tabs.eq(iIndex).find('a[data-toggle="tab"]').tab('show'); + return false; + } + }, this)); + }; + + module.exports = new AdminPaneViewModel(); + +}(module)); \ No newline at end of file diff --git a/dev/ViewModels/Popups/PopupsLanguagesViewModel.js b/dev/ViewModels/Popups/PopupsLanguagesViewModel.js index 993056089..b64d0c9d9 100644 --- a/dev/ViewModels/Popups/PopupsLanguagesViewModel.js +++ b/dev/ViewModels/Popups/PopupsLanguagesViewModel.js @@ -1,61 +1,81 @@ /* RainLoop Webmail (c) RainLoop Team | Licensed under CC BY-NC-SA 3.0 */ -/** - * @constructor - * @extends KnoinAbstractViewModel - */ -function PopupsLanguagesViewModel() -{ - KnoinAbstractViewModel.call(this, 'Popups', 'PopupsLanguages'); +(function (module) { - this.exp = ko.observable(false); + 'use strict'; - this.languages = ko.computed(function () { - return _.map(RL.data().languages(), function (sLanguage) { - return { - 'key': sLanguage, - 'selected': ko.observable(false), - 'fullName': Utils.convertLangName(sLanguage) - }; + var + _ = require('../../External/underscore.js'), + ko = require('../../External/ko.js'), + + Utils = require('../../Common/Utils.js'), + + Data = require('../../Storages/WebMailDataStorage.js'), + + kn = require('../../Knoin/Knoin.js'), + KnoinAbstractViewModel = require('../../Knoin/KnoinAbstractViewModel.js') + ; + + /** + * @constructor + * @extends KnoinAbstractViewModel + */ + function PopupsLanguagesViewModel() + { + KnoinAbstractViewModel.call(this, 'Popups', 'PopupsLanguages'); + + this.exp = ko.observable(false); + + this.languages = ko.computed(function () { + return _.map(Data.languages(), function (sLanguage) { + return { + 'key': sLanguage, + 'selected': ko.observable(false), + 'fullName': Utils.convertLangName(sLanguage) + }; + }); }); - }); - RL.data().mainLanguage.subscribe(function () { + Data.mainLanguage.subscribe(function () { + this.resetMainLanguage(); + }, this); + + kn.constructorEnd(this); + } + + kn.extendAsViewModel('PopupsLanguagesViewModel', PopupsLanguagesViewModel); + + PopupsLanguagesViewModel.prototype.languageEnName = function (sLanguage) + { + return Utils.convertLangName(sLanguage, true); + }; + + PopupsLanguagesViewModel.prototype.resetMainLanguage = function () + { + var sCurrent = Data.mainLanguage(); + _.each(this.languages(), function (oItem) { + oItem['selected'](oItem['key'] === sCurrent); + }); + }; + + PopupsLanguagesViewModel.prototype.onShow = function () + { + this.exp(true); + this.resetMainLanguage(); - }, this); + }; - Knoin.constructorEnd(this); -} + PopupsLanguagesViewModel.prototype.onHide = function () + { + this.exp(false); + }; -Utils.extendAsViewModel('PopupsLanguagesViewModel', PopupsLanguagesViewModel); + PopupsLanguagesViewModel.prototype.changeLanguage = function (sLang) + { + Data.mainLanguage(sLang); + this.cancelCommand(); + }; -PopupsLanguagesViewModel.prototype.languageEnName = function (sLanguage) -{ - return Utils.convertLangName(sLanguage, true); -}; + module.exports = new PopupsLanguagesViewModel(); -PopupsLanguagesViewModel.prototype.resetMainLanguage = function () -{ - var sCurrent = RL.data().mainLanguage(); - _.each(this.languages(), function (oItem) { - oItem['selected'](oItem['key'] === sCurrent); - }); -}; - -PopupsLanguagesViewModel.prototype.onShow = function () -{ - this.exp(true); - - this.resetMainLanguage(); -}; - -PopupsLanguagesViewModel.prototype.onHide = function () -{ - this.exp(false); -}; - -PopupsLanguagesViewModel.prototype.changeLanguage = function (sLang) -{ - RL.data().mainLanguage(sLang); - this.cancelCommand(); -}; +}(module)); \ No newline at end of file diff --git a/dev/ViewModels/Popups/PopupsPluginViewModel.js b/dev/ViewModels/Popups/PopupsPluginViewModel.js index cb57d325b..3921a156b 100644 --- a/dev/ViewModels/Popups/PopupsPluginViewModel.js +++ b/dev/ViewModels/Popups/PopupsPluginViewModel.js @@ -1,143 +1,165 @@ /* RainLoop Webmail (c) RainLoop Team | Licensed under CC BY-NC-SA 3.0 */ -/** - * @constructor - * @extends KnoinAbstractViewModel - */ -function PopupsPluginViewModel() -{ - KnoinAbstractViewModel.call(this, 'Popups', 'PopupsPlugin'); +(function (module) { - var self = this; - - this.onPluginSettingsUpdateResponse = _.bind(this.onPluginSettingsUpdateResponse, this); - - this.saveError = ko.observable(''); - - this.name = ko.observable(''); - this.readme = ko.observable(''); - - this.configures = ko.observableArray([]); + 'use strict'; - this.hasReadme = ko.computed(function () { - return '' !== this.readme(); - }, this); - - this.hasConfiguration = ko.computed(function () { - return 0 < this.configures().length; - }, this); + var + _ = require('../../External/underscore.js'), + ko = require('../../External/ko.js'), + key = require('../../External/key.js'), + + Enums = require('../../Common/Enums.js'), + Utils = require('../../Common/Utils.js'), - this.readmePopoverConf = { - 'placement': 'top', - 'trigger': 'hover', - 'title': 'About', - 'content': function () { - return self.readme(); - } - }; - - this.saveCommand = Utils.createCommand(this, function () { - - var oList = {}; - - oList['Name'] = this.name(); - - _.each(this.configures(), function (oItem) { - - var mValue = oItem.value(); - if (false === mValue || true === mValue) - { - mValue = mValue ? '1' : '0'; - } - - oList['_' + oItem['Name']] = mValue; - + Remote = require('../../Storages/AdminAjaxRemoteStorage.js'), + + kn = require('../../Knoin/Knoin.js'), + KnoinAbstractViewModel = require('../../Knoin/KnoinAbstractViewModel.js') + ; + + /** + * @constructor + * @extends KnoinAbstractViewModel + */ + function PopupsPluginViewModel() + { + KnoinAbstractViewModel.call(this, 'Popups', 'PopupsPlugin'); + + var self = this; + + this.onPluginSettingsUpdateResponse = _.bind(this.onPluginSettingsUpdateResponse, this); + + this.saveError = ko.observable(''); + + this.name = ko.observable(''); + this.readme = ko.observable(''); + + this.configures = ko.observableArray([]); + + this.hasReadme = ko.computed(function () { + return '' !== this.readme(); }, this); - - this.saveError(''); - RL.remote().pluginSettingsUpdate(this.onPluginSettingsUpdateResponse, oList); - - }, this.hasConfiguration); - this.bDisabeCloseOnEsc = true; - this.sDefaultKeyScope = Enums.KeyState.All; + this.hasConfiguration = ko.computed(function () { + return 0 < this.configures().length; + }, this); - this.tryToClosePopup = _.debounce(_.bind(this.tryToClosePopup, this), 200); + this.readmePopoverConf = { + 'placement': 'top', + 'trigger': 'hover', + 'title': 'About', + 'content': function () { + return self.readme(); + } + }; - Knoin.constructorEnd(this); -} + this.saveCommand = Utils.createCommand(this, function () { -Utils.extendAsViewModel('PopupsPluginViewModel', PopupsPluginViewModel); + var oList = {}; -PopupsPluginViewModel.prototype.onPluginSettingsUpdateResponse = function (sResult, oData) -{ - if (Enums.StorageResultType.Success === sResult && oData && oData.Result) - { - this.cancelCommand(); + oList['Name'] = this.name(); + + _.each(this.configures(), function (oItem) { + + var mValue = oItem.value(); + if (false === mValue || true === mValue) + { + mValue = mValue ? '1' : '0'; + } + + oList['_' + oItem['Name']] = mValue; + + }, this); + + this.saveError(''); + Remote.pluginSettingsUpdate(this.onPluginSettingsUpdateResponse, oList); + + }, this.hasConfiguration); + + this.bDisabeCloseOnEsc = true; + this.sDefaultKeyScope = Enums.KeyState.All; + + this.tryToClosePopup = _.debounce(_.bind(this.tryToClosePopup, this), 200); + + kn.constructorEnd(this); } - else + + kn.extendAsViewModel('PopupsPluginViewModel', PopupsPluginViewModel); + + PopupsPluginViewModel.prototype.onPluginSettingsUpdateResponse = function (sResult, oData) { - this.saveError(''); - if (oData && oData.ErrorCode) + if (Enums.StorageResultType.Success === sResult && oData && oData.Result) { - this.saveError(Utils.getNotification(oData.ErrorCode)); + this.cancelCommand(); } else { - this.saveError(Utils.getNotification(Enums.Notification.CantSavePluginSettings)); - } - } -}; - -PopupsPluginViewModel.prototype.onShow = function (oPlugin) -{ - this.name(); - this.readme(); - this.configures([]); - - if (oPlugin) - { - this.name(oPlugin['Name']); - this.readme(oPlugin['Readme']); - - var aConfig = oPlugin['Config']; - if (Utils.isNonEmptyArray(aConfig)) - { - this.configures(_.map(aConfig, function (aItem) { - return { - 'value': ko.observable(aItem[0]), - 'Name': aItem[1], - 'Type': aItem[2], - 'Label': aItem[3], - 'Default': aItem[4], - 'Desc': aItem[5] - }; - })); - } - } -}; - -PopupsPluginViewModel.prototype.tryToClosePopup = function () -{ - var self = this; - if (!kn.isPopupVisible(PopupsAskViewModel)) - { - kn.showScreenPopup(PopupsAskViewModel, [Utils.i18n('POPUPS_ASK/DESC_WANT_CLOSE_THIS_WINDOW'), function () { - if (self.modalVisibility()) + this.saveError(''); + if (oData && oData.ErrorCode) { - Utils.delegateRun(self, 'cancelCommand'); + this.saveError(Utils.getNotification(oData.ErrorCode)); + } + else + { + this.saveError(Utils.getNotification(Enums.Notification.CantSavePluginSettings)); } - }]); - } -}; - -PopupsPluginViewModel.prototype.onBuild = function () -{ - key('esc', Enums.KeyState.All, _.bind(function () { - if (this.modalVisibility()) - { - this.tryToClosePopup(); } - return false; - }, this)); -}; + }; + + PopupsPluginViewModel.prototype.onShow = function (oPlugin) + { + this.name(); + this.readme(); + this.configures([]); + + if (oPlugin) + { + this.name(oPlugin['Name']); + this.readme(oPlugin['Readme']); + + var aConfig = oPlugin['Config']; + if (Utils.isNonEmptyArray(aConfig)) + { + this.configures(_.map(aConfig, function (aItem) { + return { + 'value': ko.observable(aItem[0]), + 'Name': aItem[1], + 'Type': aItem[2], + 'Label': aItem[3], + 'Default': aItem[4], + 'Desc': aItem[5] + }; + })); + } + } + }; + + PopupsPluginViewModel.prototype.tryToClosePopup = function () + { + var self = this; + if (!kn.isPopupVisible(PopupsAskViewModel)) + { + kn.showScreenPopup(PopupsAskViewModel, [Utils.i18n('POPUPS_ASK/DESC_WANT_CLOSE_THIS_WINDOW'), function () { + if (self.modalVisibility()) + { + Utils.delegateRun(self, 'cancelCommand'); + } + }]); + } + }; + + PopupsPluginViewModel.prototype.onBuild = function () + { + key('esc', Enums.KeyState.All, _.bind(function () { + if (this.modalVisibility()) + { + this.tryToClosePopup(); + } + return false; + }, this)); + }; + + module.exports = new PopupsPluginViewModel(); + +}(module)); \ No newline at end of file diff --git a/dev/ViewModels/Popups/PopupsTwoFactorTestViewModel.js b/dev/ViewModels/Popups/PopupsTwoFactorTestViewModel.js index 08a20b7a8..603e9d5e0 100644 --- a/dev/ViewModels/Popups/PopupsTwoFactorTestViewModel.js +++ b/dev/ViewModels/Popups/PopupsTwoFactorTestViewModel.js @@ -1,55 +1,75 @@ /* RainLoop Webmail (c) RainLoop Team | Licensed under CC BY-NC-SA 3.0 */ -/** - * @constructor - * @extends KnoinAbstractViewModel - */ -function PopupsTwoFactorTestViewModel() -{ - KnoinAbstractViewModel.call(this, 'Popups', 'PopupsTwoFactorTest'); +(function (module) { - var self = this; + 'use strict'; - this.code = ko.observable(''); - this.code.focused = ko.observable(false); - this.code.status = ko.observable(null); - - this.testing = ko.observable(false); - - // commands - this.testCode = Utils.createCommand(this, function () { - - this.testing(true); - RL.remote().testTwoFactor(function (sResult, oData) { - - self.testing(false); - self.code.status(Enums.StorageResultType.Success === sResult && oData && oData.Result ? true : false); - - }, this.code()); + var + ko = require('../../External/ko.js'), - }, function () { - return '' !== this.code() && !this.testing(); - }); + Enums = require('../../Common/Enums.js'), + Utils = require('../../Common/Utils.js'), - Knoin.constructorEnd(this); -} + Remote = require('../../Storages/WebMailAjaxRemoteStorage.js'), -Utils.extendAsViewModel('PopupsTwoFactorTestViewModel', PopupsTwoFactorTestViewModel); + kn = require('../../Knoin/Knoin.js'), + KnoinAbstractViewModel = require('../../Knoin/KnoinAbstractViewModel.js') + ; + + /** + * @constructor + * @extends KnoinAbstractViewModel + */ + function PopupsTwoFactorTestViewModel() + { + KnoinAbstractViewModel.call(this, 'Popups', 'PopupsTwoFactorTest'); -PopupsTwoFactorTestViewModel.prototype.clearPopup = function () -{ - this.code(''); - this.code.focused(false); - this.code.status(null); - this.testing(false); -}; + var self = this; -PopupsTwoFactorTestViewModel.prototype.onShow = function () -{ - this.clearPopup(); -}; + this.code = ko.observable(''); + this.code.focused = ko.observable(false); + this.code.status = ko.observable(null); -PopupsTwoFactorTestViewModel.prototype.onFocus = function () -{ - this.code.focused(true); -}; + this.testing = ko.observable(false); + + // commands + this.testCode = Utils.createCommand(this, function () { + + this.testing(true); + Remote.testTwoFactor(function (sResult, oData) { + + self.testing(false); + self.code.status(Enums.StorageResultType.Success === sResult && oData && oData.Result ? true : false); + + }, this.code()); + + }, function () { + return '' !== this.code() && !this.testing(); + }); + + kn.constructorEnd(this); + } + + kn.extendAsViewModel('PopupsTwoFactorTestViewModel', PopupsTwoFactorTestViewModel); + + PopupsTwoFactorTestViewModel.prototype.clearPopup = function () + { + this.code(''); + this.code.focused(false); + this.code.status(null); + this.testing(false); + }; + + PopupsTwoFactorTestViewModel.prototype.onShow = function () + { + this.clearPopup(); + }; + + PopupsTwoFactorTestViewModel.prototype.onFocus = function () + { + this.code.focused(true); + }; + + module.exports = new PopupsTwoFactorTestViewModel(); + +}(module)); \ No newline at end of file diff --git a/dev/ViewModels/Popups/PopupsViewOpenPgpKeyViewModel.js b/dev/ViewModels/Popups/PopupsViewOpenPgpKeyViewModel.js index 0506d652c..c3732ba5f 100644 --- a/dev/ViewModels/Popups/PopupsViewOpenPgpKeyViewModel.js +++ b/dev/ViewModels/Popups/PopupsViewOpenPgpKeyViewModel.js @@ -1,41 +1,56 @@ /* RainLoop Webmail (c) RainLoop Team | Licensed under CC BY-NC-SA 3.0 */ -/** - * @constructor - * @extends KnoinAbstractViewModel - */ -function PopupsViewOpenPgpKeyViewModel() -{ - KnoinAbstractViewModel.call(this, 'Popups', 'PopupsViewOpenPgpKey'); +(function (module) { - this.key = ko.observable(''); - this.keyDom = ko.observable(null); - - Knoin.constructorEnd(this); -} + 'use strict'; -Utils.extendAsViewModel('PopupsViewOpenPgpKeyViewModel', PopupsViewOpenPgpKeyViewModel); + var + ko = require('../../External/ko.js'), + Utils = require('../../Common/Utils.js'), + kn = require('../../Knoin/Knoin.js'), + KnoinAbstractViewModel = require('../../Knoin/KnoinAbstractViewModel.js') + ; -PopupsViewOpenPgpKeyViewModel.prototype.clearPopup = function () -{ - this.key(''); -}; - -PopupsViewOpenPgpKeyViewModel.prototype.selectKey = function () -{ - var oEl = this.keyDom(); - if (oEl) + /** + * @constructor + * @extends KnoinAbstractViewModel + */ + function PopupsViewOpenPgpKeyViewModel() { - Utils.selectElement(oEl); + KnoinAbstractViewModel.call(this, 'Popups', 'PopupsViewOpenPgpKey'); + + this.key = ko.observable(''); + this.keyDom = ko.observable(null); + + kn.constructorEnd(this); } -}; -PopupsViewOpenPgpKeyViewModel.prototype.onShow = function (oOpenPgpKey) -{ - this.clearPopup(); + kn.extendAsViewModel('PopupsViewOpenPgpKeyViewModel', PopupsViewOpenPgpKeyViewModel); - if (oOpenPgpKey) + PopupsViewOpenPgpKeyViewModel.prototype.clearPopup = function () { - this.key(oOpenPgpKey.armor); - } -}; + this.key(''); + }; + + PopupsViewOpenPgpKeyViewModel.prototype.selectKey = function () + { + var oEl = this.keyDom(); + if (oEl) + { + Utils.selectElement(oEl); + } + }; + + PopupsViewOpenPgpKeyViewModel.prototype.onShow = function (oOpenPgpKey) + { + this.clearPopup(); + + if (oOpenPgpKey) + { + this.key(oOpenPgpKey.armor); + } + }; + + module.exports = new PopupsViewOpenPgpKeyViewModel(); + +}(module)); \ No newline at end of file diff --git a/dev/ViewModels/SettingsMenuViewModel.js b/dev/ViewModels/SettingsMenuViewModel.js index fd6fc8cab..7529c9a2a 100644 --- a/dev/ViewModels/SettingsMenuViewModel.js +++ b/dev/ViewModels/SettingsMenuViewModel.js @@ -5,7 +5,10 @@ 'use strict'; var - Utils = require('../Common/Utils.js'), + LinkBuilder = require('../Common/LinkBuilder.js'), + + Data = require('../Storages/WebMailDataStorage.js'), + kn = require('../Knoin/Knoin.js'), KnoinAbstractViewModel = require('../Knoin/KnoinAbstractViewModel.js') ; @@ -20,23 +23,23 @@ { KnoinAbstractViewModel.call(this, 'Left', 'SettingsMenu'); - this.leftPanelDisabled = RL.data().leftPanelDisabled; // TODO cjs + this.leftPanelDisabled = Data.leftPanelDisabled; this.menu = oScreen.menu; kn.constructorEnd(this); } - Utils.extendAsViewModel('SettingsMenuViewModel', SettingsMenuViewModel); + kn.extendAsViewModel('SettingsMenuViewModel', SettingsMenuViewModel); SettingsMenuViewModel.prototype.link = function (sRoute) { - return RL.link().settings(sRoute);// TODO cjs + return LinkBuilder.settings(sRoute); }; SettingsMenuViewModel.prototype.backToMailBoxClick = function () { - kn.setHash(RL.link().inbox()); // TODO cjs + kn.setHash(LinkBuilder.inbox()); }; module.exports = SettingsMenuViewModel; diff --git a/dev/ViewModels/SettingsPaneViewModel.js b/dev/ViewModels/SettingsPaneViewModel.js index 6653ec34a..776342e4a 100644 --- a/dev/ViewModels/SettingsPaneViewModel.js +++ b/dev/ViewModels/SettingsPaneViewModel.js @@ -6,8 +6,12 @@ var key = require('../External/key.js'), + Enums = require('../Common/Enums.js'), - Utils = require('../Common/Utils.js'), + LinkBuilder = require('../Common/LinkBuilder.js'), + + Data = require('../Storages/WebMailDataStorage.js'), + kn = require('../Knoin/Knoin.js'), KnoinAbstractViewModel = require('../Knoin/KnoinAbstractViewModel.js') ; @@ -23,7 +27,7 @@ kn.constructorEnd(this); } - Utils.extendAsViewModel('SettingsPaneViewModel', SettingsPaneViewModel); + kn.extendAsViewModel('SettingsPaneViewModel', SettingsPaneViewModel); SettingsPaneViewModel.prototype.onBuild = function () { @@ -35,12 +39,12 @@ SettingsPaneViewModel.prototype.onShow = function () { - RL.data().message(null); // TODO cjs + Data.message(null); }; SettingsPaneViewModel.prototype.backToMailBoxClick = function () { - kn.setHash(RL.link().inbox()); // TODO cjs + kn.setHash(LinkBuilder.inbox()); }; module.exports = SettingsPaneViewModel; diff --git a/dev/ViewModels/SettingsSystemDropDownViewModel.js b/dev/ViewModels/SettingsSystemDropDownViewModel.js index 2e6c74b78..43039cb46 100644 --- a/dev/ViewModels/SettingsSystemDropDownViewModel.js +++ b/dev/ViewModels/SettingsSystemDropDownViewModel.js @@ -5,7 +5,6 @@ 'use strict'; var - Utils = require('../Common/Utils.js'), kn = require('./Knoin/Knoin.js'), AbstractSystemDropDownViewModel = require('./AbstractSystemDropDownViewModel.js') ; @@ -20,7 +19,7 @@ kn.constructorEnd(this); } - Utils.extendAsViewModel('SettingsSystemDropDownViewModel', SettingsSystemDropDownViewModel, AbstractSystemDropDownViewModel); + kn.extendAsViewModel('SettingsSystemDropDownViewModel', SettingsSystemDropDownViewModel, AbstractSystemDropDownViewModel); module.exports = SettingsSystemDropDownViewModel; diff --git a/rainloop/v/0.0.0/static/js/bro.js b/rainloop/v/0.0.0/static/js/bro.js index 005e2b372..774c92e5f 100644 --- a/rainloop/v/0.0.0/static/js/bro.js +++ b/rainloop/v/0.0.0/static/js/bro.js @@ -5,11 +5,12 @@ var kn = require('./Knoin/Knoin.js'), - RL = require('./Boots/RainLoopApp.js') + RL = require('./Boots/RainLoopApp.js'), + Remote = require('./Storages/WebMailAjaxRemoteStorage.js') ; -kn.bootstart(RL); -},{"./Boots/RainLoopApp.js":3,"./Knoin/Knoin.js":21}],2:[function(require,module,exports){ +kn.bootstart(RL, Remote); +},{"./Boots/RainLoopApp.js":3,"./Knoin/Knoin.js":26,"./Storages/WebMailAjaxRemoteStorage.js":39}],2:[function(require,module,exports){ /* RainLoop Webmail (c) RainLoop Team | Licensed under CC BY-NC-SA 3.0 */ (function (module) { @@ -17,6 +18,7 @@ kn.bootstart(RL); 'use strict'; var + $ = require('../External/jquery.js'), _ = require('../External/underscore.js'), ko = require('../External/ko.js'), window = require('../External/window.js'), @@ -24,8 +26,15 @@ kn.bootstart(RL); $window = require('../External/$window.js'), $doc = require('../External/$doc.js'), AppData = require('../External/AppData.js'), + Globals = require('../Common/Globals.js'), Utils = require('../Common/Utils.js'), + Plugins = require('../Common/Plugins.js'), + LinkBuilder = require('../Common/LinkBuilder.js'), + + Remote = require('../Remote.js'), + + kn = require('../Knoin/Knoin.js'), KnoinAbstractBoot = require('../Knoin/KnoinAbstractBoot.js') ; @@ -59,8 +68,7 @@ kn.bootstart(RL); 'Script error.', 'Uncaught Error: Error calling method on NPObject.' ])) { - // TODO cjs - RL.remote().jsError( + Remote().jsError( Utils.emptyFunction, oEvent.originalEvent.message, oEvent.originalEvent.filename, @@ -136,32 +144,6 @@ kn.bootstart(RL); return true; }; - /** - * @return {LinkBuilder} - */ - AbstractApp.prototype.link = function () - { - if (null === this.oLink) - { - this.oLink = new LinkBuilder(); // TODO cjs - } - - return this.oLink; - }; - - /** - * @return {LocalStorage} - */ - AbstractApp.prototype.local = function () - { - if (null === this.oLocal) - { - this.oLocal = new LocalStorage(); // TODO cjs - } - - return this.oLocal; - }; - /** * @param {string} sName * @return {?} @@ -193,7 +175,7 @@ kn.bootstart(RL); AbstractApp.prototype.setTitle = function (sTitle) { sTitle = ((Utils.isNormal(sTitle) && 0 < sTitle.length) ? sTitle + ' - ' : '') + - RL.settingsGet('Title') || ''; // TODO cjs + this.settingsGet('Title') || ''; window.document.title = '_'; window.document.title = sTitle; @@ -206,12 +188,10 @@ kn.bootstart(RL); AbstractApp.prototype.loginAndLogoutReload = function (bLogout, bClose) { var - sCustomLogoutLink = Utils.pString(RL.settingsGet('CustomLogoutLink')), - bInIframe = !!RL.settingsGet('InIframe') + sCustomLogoutLink = Utils.pString(this.settingsGet('CustomLogoutLink')), + bInIframe = !!this.settingsGet('InIframe') ; - // TODO cjs - bLogout = Utils.isUnd(bLogout) ? false : !!bLogout; bClose = Utils.isUnd(bClose) ? false : !!bClose; @@ -236,7 +216,7 @@ kn.bootstart(RL); else { kn.routeOff(); - kn.setHash(RL.link().root(), true); + kn.setHash(LinkBuilder.root(), true); kn.routeOff(); _.delay(function () { @@ -317,7 +297,10 @@ kn.bootstart(RL); AbstractApp.prototype.bootstart = function () { - var ssm = require('../External/ssm.js'); + var + self = this, + ssm = require('../External/ssm.js') + ; Utils.initOnStartOrLangChange(function () { Utils.initNotificationLanguage(); @@ -332,11 +315,11 @@ kn.bootstart(RL); 'maxWidth': 767, 'onEnter': function() { $html.addClass('ssm-state-mobile'); - RL.pub('ssm.mobile-enter'); + self.pub('ssm.mobile-enter'); }, 'onLeave': function() { $html.removeClass('ssm-state-mobile'); - RL.pub('ssm.mobile-leave'); + self.pub('ssm.mobile-leave'); } }); @@ -375,12 +358,12 @@ kn.bootstart(RL); } }); - RL.sub('ssm.mobile-enter', function () { // TODO cjs - RL.data().leftPanelDisabled(true); + this.sub('ssm.mobile-enter', function () { + RL.data().leftPanelDisabled(true); // TODO cjs }); - RL.sub('ssm.mobile-leave', function () { // TODO cjs - RL.data().leftPanelDisabled(false); + this.sub('ssm.mobile-leave', function () { + RL.data().leftPanelDisabled(false); // TODO cjs }); RL.data().leftPanelDisabled.subscribe(function (bValue) { // TODO cjs @@ -393,7 +376,7 @@ kn.bootstart(RL); module.exports = AbstractApp; }(module)); -},{"../Common/Globals.js":6,"../Common/Utils.js":8,"../External/$doc.js":9,"../External/$html.js":10,"../External/$window.js":11,"../External/AppData.js":12,"../External/ko.js":17,"../External/ssm.js":18,"../External/underscore.js":19,"../External/window.js":20,"../Knoin/KnoinAbstractBoot.js":22}],3:[function(require,module,exports){ +},{"../Common/Globals.js":6,"../Common/LinkBuilder.js":7,"../Common/Plugins.js":8,"../Common/Utils.js":9,"../External/$doc.js":11,"../External/$html.js":12,"../External/$window.js":13,"../External/AppData.js":14,"../External/jquery.js":19,"../External/ko.js":21,"../External/ssm.js":23,"../External/underscore.js":24,"../External/window.js":25,"../Knoin/Knoin.js":26,"../Knoin/KnoinAbstractBoot.js":27,"../Remote.js":33}],3:[function(require,module,exports){ /* RainLoop Webmail (c) RainLoop Team | Licensed under CC BY-NC-SA 3.0 */ (function (module) { @@ -404,12 +387,24 @@ kn.bootstart(RL); window = require('../External/window.js'), $ = require('../External/jquery.js'), _ = require('../External/underscore.js'), + moment = require('../External/moment.js'), + Enums = require('../Common/Enums.js'), Globals = require('../Common/Globals.js'), Consts = require('../Common/Consts.js'), Plugins = require('../Common/Plugins.js'), Utils = require('../Common/Utils.js'), + LinkBuilder = require('../Common/LinkBuilder.js'), + kn = require('../Knoin/Knoin.js'), + + Data = require('../Storages/WebMailDataStorage.js'), + Cache = require('../Storages/WebMailCacheStorage.js'), + Remote = require('../Storages/WebMailAjaxRemoteStorage.js'), + + PopupsFolderSystemViewModel = require('../ViewModels/Popups/PopupsAskViewModel.js'), + PopupsAskViewModel = require('../ViewModels/Popups/PopupsAskViewModel.js'), + AbstractApp = require('./AbstractApp.js') ; @@ -462,7 +457,7 @@ kn.bootstart(RL); }, 60000 * 5); $.wakeUp(function () { - RL.remote().jsVersion(function (sResult, oData) { + Remote.jsVersion(function (sResult, oData) { if (Enums.StorageResultType.Success === sResult && oData && !oData.Result) { if (window.parent && !!RL.settingsGet('InIframe')) @@ -510,27 +505,13 @@ kn.bootstart(RL); return this.oRemote; }; - /** - * @return {WebMailCacheStorage} - */ - RainLoopApp.prototype.cache = function () - { - if (null === this.oCache) - { - this.oCache = new WebMailCacheStorage(); - } - - return this.oCache; - }; - RainLoopApp.prototype.reloadFlagsCurrentMessageListAndMessageFromCache = function () { - var oCache = RL.cache(); - _.each(RL.data().messageList(), function (oMessage) { - oCache.initMessageFlagsFromCache(oMessage); + _.each(Data.messageList(), function (oMessage) { + Cache.initMessageFlagsFromCache(oMessage); }); - oCache.initMessageFlagsFromCache(RL.data().message()); + Cache.initMessageFlagsFromCache(Data.message()); }; /** @@ -540,50 +521,49 @@ kn.bootstart(RL); RainLoopApp.prototype.reloadMessageList = function (bDropPagePosition, bDropCurrenFolderCache) { var - oRLData = RL.data(), - iOffset = (oRLData.messageListPage() - 1) * oRLData.messagesPerPage() + iOffset = (Data.messageListPage() - 1) * Data.messagesPerPage() ; if (Utils.isUnd(bDropCurrenFolderCache) ? false : !!bDropCurrenFolderCache) { - RL.cache().setFolderHash(oRLData.currentFolderFullNameRaw(), ''); + Cache.setFolderHash(Data.currentFolderFullNameRaw(), ''); } if (Utils.isUnd(bDropPagePosition) ? false : !!bDropPagePosition) { - oRLData.messageListPage(1); + Data.messageListPage(1); iOffset = 0; } - oRLData.messageListLoading(true); - RL.remote().messageList(function (sResult, oData, bCached) { + Data.messageListLoading(true); + Remote.messageList(function (sResult, oData, bCached) { if (Enums.StorageResultType.Success === sResult && oData && oData.Result) { - oRLData.messageListError(''); - oRLData.messageListLoading(false); - oRLData.setMessageList(oData, bCached); + Data.messageListError(''); + Data.messageListLoading(false); + Data.setMessageList(oData, bCached); } else if (Enums.StorageResultType.Unload === sResult) { - oRLData.messageListError(''); - oRLData.messageListLoading(false); + Data.messageListError(''); + Data.messageListLoading(false); } else if (Enums.StorageResultType.Abort !== sResult) { - oRLData.messageList([]); - oRLData.messageListLoading(false); - oRLData.messageListError(oData && oData.ErrorCode ? + Data.messageList([]); + Data.messageListLoading(false); + Data.messageListError(oData && oData.ErrorCode ? Utils.getNotification(oData.ErrorCode) : Utils.i18n('NOTIFICATIONS/CANT_GET_MESSAGE_LIST') ); } - }, oRLData.currentFolderFullNameRaw(), iOffset, oRLData.messagesPerPage(), oRLData.messageListSearch()); + }, Data.currentFolderFullNameRaw(), iOffset, Data.messagesPerPage(), Data.messageListSearch()); }; RainLoopApp.prototype.recacheInboxMessageList = function () { - RL.remote().messageList(Utils.emptyFunction, 'INBOX', 0, RL.data().messagesPerPage(), '', true); + Remote.messageList(Utils.emptyFunction, 'INBOX', 0, Data.messagesPerPage(), '', true); }; RainLoopApp.prototype.reloadMessageListHelper = function (bEmptyList) @@ -597,15 +577,15 @@ kn.bootstart(RL); */ RainLoopApp.prototype.contactsSync = function (fResultFunc) { - var oContacts = RL.data().contacts; - if (oContacts.importing() || oContacts.syncing() || !RL.data().enableContactsSync() || !RL.data().allowContactsSync()) + var oContacts = Data.contacts; + if (oContacts.importing() || oContacts.syncing() || !Data.enableContactsSync() || !Data.allowContactsSync()) { return false; } oContacts.syncing(true); - RL.remote().contactsSync(function (sResult, oData) { + Remote.contactsSync(function (sResult, oData) { oContacts.syncing(false); @@ -622,7 +602,7 @@ kn.bootstart(RL); { var self = this, - sSpamFolder = RL.data().spamFolder() + sSpamFolder = Data.spamFolder() ; _.each(this.oMoveCache, function (oItem) { @@ -632,7 +612,7 @@ kn.bootstart(RL); bHam = !bSpam && sSpamFolder === oItem['From'] && 'INBOX' === oItem['To'] ; - RL.remote().messagesMove(self.moveOrDeleteResponseHelper, oItem['From'], oItem['To'], oItem['Uid'], + Remote.messagesMove(self.moveOrDeleteResponseHelper, oItem['From'], oItem['To'], oItem['Uid'], bSpam ? 'SPAM' : (bHam ? 'HAM' : '')); }); @@ -657,7 +637,7 @@ kn.bootstart(RL); RainLoopApp.prototype.messagesCopyHelper = function (sFromFolderFullNameRaw, sToFolderFullNameRaw, aUidForCopy) { - RL.remote().messagesCopy( + Remote.messagesCopy( this.moveOrDeleteResponseHelper, sFromFolderFullNameRaw, sToFolderFullNameRaw, @@ -667,7 +647,7 @@ kn.bootstart(RL); RainLoopApp.prototype.messagesDeleteHelper = function (sFromFolderFullNameRaw, aUidForRemove) { - RL.remote().messagesDelete( + Remote.messagesDelete( this.moveOrDeleteResponseHelper, sFromFolderFullNameRaw, aUidForRemove @@ -676,15 +656,15 @@ kn.bootstart(RL); RainLoopApp.prototype.moveOrDeleteResponseHelper = function (sResult, oData) { - if (Enums.StorageResultType.Success === sResult && RL.data().currentFolder()) + if (Enums.StorageResultType.Success === sResult && Data.currentFolder()) { if (oData && Utils.isArray(oData.Result) && 2 === oData.Result.length) { - RL.cache().setFolderHash(oData.Result[0], oData.Result[1]); + Cache.setFolderHash(oData.Result[0], oData.Result[1]); } else { - RL.cache().setFolderHash(RL.data().currentFolderFullNameRaw(), ''); + Cache.setFolderHash(Data.currentFolderFullNameRaw(), ''); if (oData && -1 < Utils.inArray(oData.ErrorCode, [Enums.Notification.CantMoveMessage, Enums.Notification.CantCopyMessage])) @@ -693,7 +673,7 @@ kn.bootstart(RL); } } - RL.reloadMessageListHelper(0 === RL.data().messageList().length); + RL.reloadMessageListHelper(0 === Data.messageList().length); RL.quotaDebounce(); } }; @@ -705,7 +685,7 @@ kn.bootstart(RL); RainLoopApp.prototype.deleteMessagesFromFolderWithoutCheck = function (sFromFolderFullNameRaw, aUidForRemove) { this.messagesDeleteHelper(sFromFolderFullNameRaw, aUidForRemove); - RL.data().removeMessagesFromList(sFromFolderFullNameRaw, aUidForRemove); + Data.removeMessagesFromList(sFromFolderFullNameRaw, aUidForRemove); }; /** @@ -718,8 +698,6 @@ kn.bootstart(RL); { var self = this, - oData = RL.data(), - oCache = RL.cache(), oMoveFolder = null, nSetSystemFoldersNotification = null ; @@ -727,18 +705,18 @@ kn.bootstart(RL); switch (iDeleteType) { case Enums.FolderType.Spam: - oMoveFolder = oCache.getFolderFromCacheList(oData.spamFolder()); + oMoveFolder = Cache.getFolderFromCacheList(Data.spamFolder()); nSetSystemFoldersNotification = Enums.SetSystemFoldersNotification.Spam; break; case Enums.FolderType.NotSpam: - oMoveFolder = oCache.getFolderFromCacheList('INBOX'); + oMoveFolder = Cache.getFolderFromCacheList('INBOX'); break; case Enums.FolderType.Trash: - oMoveFolder = oCache.getFolderFromCacheList(oData.trashFolder()); + oMoveFolder = Cache.getFolderFromCacheList(Data.trashFolder()); nSetSystemFoldersNotification = Enums.SetSystemFoldersNotification.Trash; break; case Enums.FolderType.Archive: - oMoveFolder = oCache.getFolderFromCacheList(oData.archiveFolder()); + oMoveFolder = Cache.getFolderFromCacheList(Data.archiveFolder()); nSetSystemFoldersNotification = Enums.SetSystemFoldersNotification.Archive; break; } @@ -746,9 +724,9 @@ kn.bootstart(RL); bUseFolder = Utils.isUnd(bUseFolder) ? true : !!bUseFolder; if (bUseFolder) { - if ((Enums.FolderType.Spam === iDeleteType && Consts.Values.UnuseOptionValue === oData.spamFolder()) || - (Enums.FolderType.Trash === iDeleteType && Consts.Values.UnuseOptionValue === oData.trashFolder()) || - (Enums.FolderType.Archive === iDeleteType && Consts.Values.UnuseOptionValue === oData.archiveFolder())) + if ((Enums.FolderType.Spam === iDeleteType && Consts.Values.UnuseOptionValue === Data.spamFolder()) || + (Enums.FolderType.Trash === iDeleteType && Consts.Values.UnuseOptionValue === Data.trashFolder()) || + (Enums.FolderType.Archive === iDeleteType && Consts.Values.UnuseOptionValue === Data.archiveFolder())) { bUseFolder = false; } @@ -759,19 +737,19 @@ kn.bootstart(RL); kn.showScreenPopup(PopupsFolderSystemViewModel, [nSetSystemFoldersNotification]); } else if (!bUseFolder || (Enums.FolderType.Trash === iDeleteType && - (sFromFolderFullNameRaw === oData.spamFolder() || sFromFolderFullNameRaw === oData.trashFolder()))) + (sFromFolderFullNameRaw === Data.spamFolder() || sFromFolderFullNameRaw === Data.trashFolder()))) { kn.showScreenPopup(PopupsAskViewModel, [Utils.i18n('POPUPS_ASK/DESC_WANT_DELETE_MESSAGES'), function () { self.messagesDeleteHelper(sFromFolderFullNameRaw, aUidForRemove); - oData.removeMessagesFromList(sFromFolderFullNameRaw, aUidForRemove); + Data.removeMessagesFromList(sFromFolderFullNameRaw, aUidForRemove); }]); } else if (oMoveFolder) { this.messagesMoveHelper(sFromFolderFullNameRaw, oMoveFolder.fullNameRaw, aUidForRemove); - oData.removeMessagesFromList(sFromFolderFullNameRaw, aUidForRemove, oMoveFolder.fullNameRaw); + Data.removeMessagesFromList(sFromFolderFullNameRaw, aUidForRemove, oMoveFolder.fullNameRaw); } }; @@ -786,8 +764,8 @@ kn.bootstart(RL); if (sFromFolderFullNameRaw !== sToFolderFullNameRaw && Utils.isArray(aUidForMove) && 0 < aUidForMove.length) { var - oFromFolder = RL.cache().getFolderFromCacheList(sFromFolderFullNameRaw), - oToFolder = RL.cache().getFolderFromCacheList(sToFolderFullNameRaw) + oFromFolder = Cache.getFolderFromCacheList(sFromFolderFullNameRaw), + oToFolder = Cache.getFolderFromCacheList(sToFolderFullNameRaw) ; if (oFromFolder && oToFolder) @@ -801,7 +779,7 @@ kn.bootstart(RL); this.messagesMoveHelper(oFromFolder.fullNameRaw, oToFolder.fullNameRaw, aUidForMove); } - RL.data().removeMessagesFromList(oFromFolder.fullNameRaw, aUidForMove, oToFolder.fullNameRaw, bCopy); + Data.removeMessagesFromList(oFromFolder.fullNameRaw, aUidForMove, oToFolder.fullNameRaw, bCopy); return true; } } @@ -817,7 +795,7 @@ kn.bootstart(RL); this.data().foldersLoading(true); this.remote().folders(_.bind(function (sResult, oData) { - RL.data().foldersLoading(false); + Data.foldersLoading(false); if (Enums.StorageResultType.Success === sResult) { this.data().setFolders(oData); @@ -838,12 +816,12 @@ kn.bootstart(RL); RainLoopApp.prototype.reloadOpenPgpKeys = function () { - if (RL.data().capaOpenPGP()) + if (Data.capaOpenPGP()) { var aKeys = [], oEmail = new EmailModel(), - oOpenpgpKeyring = RL.data().openpgpKeyring, + oOpenpgpKeyring = Data.openpgpKeyring, oOpenpgpKeys = oOpenpgpKeyring ? oOpenpgpKeyring.getAllKeys() : [] ; @@ -875,41 +853,39 @@ kn.bootstart(RL); } }); - RL.data().openpgpkeys(aKeys); + Data.openpgpkeys(aKeys); } }; RainLoopApp.prototype.accountsAndIdentities = function () { - var oRainLoopData = RL.data(); + Data.accountsLoading(true); + Data.identitiesLoading(true); - oRainLoopData.accountsLoading(true); - oRainLoopData.identitiesLoading(true); + Remote.accountsAndIdentities(function (sResult, oData) { - RL.remote().accountsAndIdentities(function (sResult, oData) { - - oRainLoopData.accountsLoading(false); - oRainLoopData.identitiesLoading(false); + Data.accountsLoading(false); + Data.identitiesLoading(false); if (Enums.StorageResultType.Success === sResult && oData.Result) { var sParentEmail = RL.settingsGet('ParentEmail'), - sAccountEmail = oRainLoopData.accountEmail() + sAccountEmail = Data.accountEmail() ; sParentEmail = '' === sParentEmail ? sAccountEmail : sParentEmail; if (Utils.isArray(oData.Result['Accounts'])) { - oRainLoopData.accounts(_.map(oData.Result['Accounts'], function (sValue) { + Data.accounts(_.map(oData.Result['Accounts'], function (sValue) { return new AccountModel(sValue, sValue !== sParentEmail); })); } if (Utils.isArray(oData.Result['Identities'])) { - oRainLoopData.identities(_.map(oData.Result['Identities'], function (oIdentityData) { + Data.identities(_.map(oData.Result['Identities'], function (oIdentityData) { var sId = Utils.pString(oIdentityData['Id']), @@ -935,8 +911,8 @@ kn.bootstart(RL); Utils.isArray(oData.Result) && 1 < oData.Result.length && Utils.isPosNumeric(oData.Result[0], true) && Utils.isPosNumeric(oData.Result[1], true)) { - RL.data().userQuota(Utils.pInt(oData.Result[1]) * 1024); - RL.data().userUsageSize(Utils.pInt(oData.Result[0]) * 1024); + Data.userQuota(Utils.pInt(oData.Result[1]) * 1024); + Data.userUsageSize(Utils.pInt(oData.Result[0]) * 1024); } }); }; @@ -956,8 +932,8 @@ kn.bootstart(RL); { var iUtc = moment().unix(), - sHash = RL.cache().getFolderHash(oData.Result.Folder), - oFolder = RL.cache().getFolderFromCacheList(oData.Result.Folder), + sHash = Cache.getFolderHash(oData.Result.Folder), + oFolder = Cache.getFolderFromCacheList(oData.Result.Folder), bCheck = false, sUid = '', aList = [], @@ -971,7 +947,7 @@ kn.bootstart(RL); if (oData.Result.Hash) { - RL.cache().setFolderHash(oData.Result.Folder, oData.Result.Hash); + Cache.setFolderHash(oData.Result.Folder, oData.Result.Hash); } if (Utils.isNormal(oData.Result.MessageCount)) @@ -991,7 +967,7 @@ kn.bootstart(RL); if (bUnreadCountChange) { - RL.cache().clearMessageFlagsFromCacheByFolder(oFolder.fullNameRaw); + Cache.clearMessageFlagsFromCacheByFolder(oFolder.fullNameRaw); } if (oData.Result.Flags) @@ -1002,7 +978,7 @@ kn.bootstart(RL); { bCheck = true; oFlags = oData.Result.Flags[sUid]; - RL.cache().storeMessageFlagsToCacheByFolderAndUid(oFolder.fullNameRaw, sUid.toString(), [ + Cache.storeMessageFlagsToCacheByFolderAndUid(oFolder.fullNameRaw, sUid.toString(), [ !oFlags['IsSeen'], !!oFlags['IsFlagged'], !!oFlags['IsAnswered'], !!oFlags['IsForwarded'], !!oFlags['IsReadReceipt'] ]); } @@ -1014,11 +990,11 @@ kn.bootstart(RL); } } - RL.data().initUidNextAndNewMessages(oFolder.fullNameRaw, oData.Result.UidNext, oData.Result.NewMessages); + Data.initUidNextAndNewMessages(oFolder.fullNameRaw, oData.Result.UidNext, oData.Result.NewMessages); if (oData.Result.Hash !== sHash || '' === sHash) { - if (oFolder.fullNameRaw === RL.data().currentFolderFullNameRaw()) + if (oFolder.fullNameRaw === Data.currentFolderFullNameRaw()) { RL.reloadMessageList(); } @@ -1029,9 +1005,9 @@ kn.bootstart(RL); } else if (bUnreadCountChange) { - if (oFolder.fullNameRaw === RL.data().currentFolderFullNameRaw()) + if (oFolder.fullNameRaw === Data.currentFolderFullNameRaw()) { - aList = RL.data().messageList(); + aList = Data.messageList(); if (Utils.isNonEmptyArray(aList)) { RL.folderInformation(oFolder.fullNameRaw, aList); @@ -1054,7 +1030,7 @@ kn.bootstart(RL); var iUtc = moment().unix(), - aFolders = RL.data().getNextFolderNames(bBoot) + aFolders = Data.getNextFolderNames(bBoot) ; if (Utils.isNonEmptyArray(aFolders)) @@ -1068,8 +1044,8 @@ kn.bootstart(RL); var aList = [], - sHash = RL.cache().getFolderHash(oItem.Folder), - oFolder = RL.cache().getFolderFromCacheList(oItem.Folder), + sHash = Cache.getFolderHash(oItem.Folder), + oFolder = Cache.getFolderFromCacheList(oItem.Folder), bUnreadCountChange = false ; @@ -1079,7 +1055,7 @@ kn.bootstart(RL); if (oItem.Hash) { - RL.cache().setFolderHash(oItem.Folder, oItem.Hash); + Cache.setFolderHash(oItem.Folder, oItem.Hash); } if (Utils.isNormal(oItem.MessageCount)) @@ -1099,21 +1075,21 @@ kn.bootstart(RL); if (bUnreadCountChange) { - RL.cache().clearMessageFlagsFromCacheByFolder(oFolder.fullNameRaw); + Cache.clearMessageFlagsFromCacheByFolder(oFolder.fullNameRaw); } if (oItem.Hash !== sHash || '' === sHash) { - if (oFolder.fullNameRaw === RL.data().currentFolderFullNameRaw()) + if (oFolder.fullNameRaw === Data.currentFolderFullNameRaw()) { RL.reloadMessageList(); } } else if (bUnreadCountChange) { - if (oFolder.fullNameRaw === RL.data().currentFolderFullNameRaw()) + if (oFolder.fullNameRaw === Data.currentFolderFullNameRaw()) { - aList = RL.data().messageList(); + aList = Data.messageList(); if (Utils.isNonEmptyArray(aList)) { RL.folderInformation(oFolder.fullNameRaw, aList); @@ -1139,33 +1115,33 @@ kn.bootstart(RL); { oMessage.unseen(false); - var oFolder = RL.cache().getFolderFromCacheList(oMessage.folderFullNameRaw); + var oFolder = Cache.getFolderFromCacheList(oMessage.folderFullNameRaw); if (oFolder) { oFolder.messageCountUnread(0 <= oFolder.messageCountUnread() - 1 ? oFolder.messageCountUnread() - 1 : 0); } - RL.cache().storeMessageFlagsToCache(oMessage); + Cache.storeMessageFlagsToCache(oMessage); RL.reloadFlagsCurrentMessageListAndMessageFromCache(); } - RL.remote().messageSetSeen(Utils.emptyFunction, oMessage.folderFullNameRaw, [oMessage.uid], true); + Remote.messageSetSeen(Utils.emptyFunction, oMessage.folderFullNameRaw, [oMessage.uid], true); }; RainLoopApp.prototype.googleConnect = function () { - window.open(RL.link().socialGoogle(), 'Google', 'left=200,top=100,width=650,height=600,menubar=no,status=no,resizable=yes,scrollbars=yes'); + window.open(LinkBuilder.socialGoogle(), 'Google', 'left=200,top=100,width=650,height=600,menubar=no,status=no,resizable=yes,scrollbars=yes'); }; RainLoopApp.prototype.twitterConnect = function () { - window.open(RL.link().socialTwitter(), 'Twitter', 'left=200,top=100,width=650,height=350,menubar=no,status=no,resizable=yes,scrollbars=yes'); + window.open(LinkBuilder.socialTwitter(), 'Twitter', 'left=200,top=100,width=650,height=350,menubar=no,status=no,resizable=yes,scrollbars=yes'); }; RainLoopApp.prototype.facebookConnect = function () { - window.open(RL.link().socialFacebook(), 'Facebook', 'left=200,top=100,width=650,height=335,menubar=no,status=no,resizable=yes,scrollbars=yes'); + window.open(LinkBuilder.socialFacebook(), 'Facebook', 'left=200,top=100,width=650,height=335,menubar=no,status=no,resizable=yes,scrollbars=yes'); }; /** @@ -1173,60 +1149,58 @@ kn.bootstart(RL); */ RainLoopApp.prototype.socialUsers = function (bFireAllActions) { - var oRainLoopData = RL.data(); - if (bFireAllActions) { - oRainLoopData.googleActions(true); - oRainLoopData.facebookActions(true); - oRainLoopData.twitterActions(true); + Data.googleActions(true); + Data.facebookActions(true); + Data.twitterActions(true); } - RL.remote().socialUsers(function (sResult, oData) { + Remote.socialUsers(function (sResult, oData) { if (Enums.StorageResultType.Success === sResult && oData && oData.Result) { - oRainLoopData.googleUserName(oData.Result['Google'] || ''); - oRainLoopData.facebookUserName(oData.Result['Facebook'] || ''); - oRainLoopData.twitterUserName(oData.Result['Twitter'] || ''); + Data.googleUserName(oData.Result['Google'] || ''); + Data.facebookUserName(oData.Result['Facebook'] || ''); + Data.twitterUserName(oData.Result['Twitter'] || ''); } else { - oRainLoopData.googleUserName(''); - oRainLoopData.facebookUserName(''); - oRainLoopData.twitterUserName(''); + Data.googleUserName(''); + Data.facebookUserName(''); + Data.twitterUserName(''); } - oRainLoopData.googleLoggined('' !== oRainLoopData.googleUserName()); - oRainLoopData.facebookLoggined('' !== oRainLoopData.facebookUserName()); - oRainLoopData.twitterLoggined('' !== oRainLoopData.twitterUserName()); + Data.googleLoggined('' !== Data.googleUserName()); + Data.facebookLoggined('' !== Data.facebookUserName()); + Data.twitterLoggined('' !== Data.twitterUserName()); - oRainLoopData.googleActions(false); - oRainLoopData.facebookActions(false); - oRainLoopData.twitterActions(false); + Data.googleActions(false); + Data.facebookActions(false); + Data.twitterActions(false); }); }; RainLoopApp.prototype.googleDisconnect = function () { - RL.data().googleActions(true); - RL.remote().googleDisconnect(function () { + Data.googleActions(true); + Remote.googleDisconnect(function () { RL.socialUsers(); }); }; RainLoopApp.prototype.facebookDisconnect = function () { - RL.data().facebookActions(true); - RL.remote().facebookDisconnect(function () { + Data.facebookActions(true); + Remote.facebookDisconnect(function () { RL.socialUsers(); }); }; RainLoopApp.prototype.twitterDisconnect = function () { - RL.data().twitterActions(true); - RL.remote().twitterDisconnect(function () { + Data.twitterActions(true); + Remote.twitterDisconnect(function () { RL.socialUsers(); }); }; @@ -1370,7 +1344,7 @@ kn.bootstart(RL); aData = [] ; - RL.remote().suggestions(function (sResult, oData) { + Remote.suggestions(function (sResult, oData) { if (Enums.StorageResultType.Success === sResult && oData && Utils.isArray(oData.Result)) { aData = _.map(oData.Result, function (aItem) { @@ -1393,7 +1367,7 @@ kn.bootstart(RL); */ RainLoopApp.prototype.getContactTagsAutocomplete = function (sQuery, fCallback) { - fCallback(_.filter(RL.data().contactTags(), function (oContactTag) { + fCallback(_.filter(Data.contactTags(), function (oContactTag) { return oContactTag && oContactTag.filterHelper(sQuery); })); }; @@ -1438,7 +1412,7 @@ kn.bootstart(RL); RL.pub('rl.bootstart'); AbstractApp.prototype.bootstart.call(this); - RL.data().populateDataOnStart(); + Data.populateDataOnStart(); var sCustomLoginLink = '', @@ -1451,51 +1425,51 @@ kn.bootstart(RL); if (!RL.settingsGet('ChangePasswordIsAllowed')) { - Utils.removeSettingsViewModel(SettingsChangePasswordScreen); + kn.removeSettingsViewModel(SettingsChangePasswordScreen); } if (!RL.settingsGet('ContactsIsAllowed')) { - Utils.removeSettingsViewModel(SettingsContacts); + kn.removeSettingsViewModel(SettingsContacts); } if (!RL.capa(Enums.Capa.AdditionalAccounts)) { - Utils.removeSettingsViewModel(SettingsAccounts); + kn.removeSettingsViewModel(SettingsAccounts); } if (RL.capa(Enums.Capa.AdditionalIdentities)) { - Utils.removeSettingsViewModel(SettingsIdentity); + kn.removeSettingsViewModel(SettingsIdentity); } else { - Utils.removeSettingsViewModel(SettingsIdentities); + kn.removeSettingsViewModel(SettingsIdentities); } if (!RL.capa(Enums.Capa.OpenPGP)) { - Utils.removeSettingsViewModel(SettingsOpenPGP); + kn.removeSettingsViewModel(SettingsOpenPGP); } if (!RL.capa(Enums.Capa.TwoFactor)) { - Utils.removeSettingsViewModel(SettingsSecurity); + kn.removeSettingsViewModel(SettingsSecurity); } if (!RL.capa(Enums.Capa.Themes)) { - Utils.removeSettingsViewModel(SettingsThemes); + kn.removeSettingsViewModel(SettingsThemes); } if (!RL.capa(Enums.Capa.Filters)) { - Utils.removeSettingsViewModel(SettingsFilters); + kn.removeSettingsViewModel(SettingsFilters); } if (!bGoogle && !bFacebook && !bTwitter) { - Utils.removeSettingsViewModel(SettingsSocialScreen); + kn.removeSettingsViewModel(SettingsSocialScreen); } Utils.initOnStartOrLangChange(function () { @@ -1536,11 +1510,11 @@ kn.bootstart(RL); { if (window.$LAB && window.crypto && window.crypto.getRandomValues && RL.capa(Enums.Capa.OpenPGP)) { - window.$LAB.script(window.openpgp ? '' : RL.link().openPgpJs()).wait(function () { + window.$LAB.script(window.openpgp ? '' : LinkBuilder.openPgpJs()).wait(function () { if (window.openpgp) { - RL.data().openpgpKeyring = new window.openpgp.Keyring(); - RL.data().capaOpenPGP(true); + Data.openpgpKeyring = new window.openpgp.Keyring(); + Data.capaOpenPGP(true); RL.pub('openpgp.init'); @@ -1550,7 +1524,7 @@ kn.bootstart(RL); } else { - RL.data().capaOpenPGP(false); + Data.capaOpenPGP(false); } kn.startScreens([MailBoxScreen, SettingsScreen]); @@ -1565,7 +1539,7 @@ kn.bootstart(RL); }); RL.sub('interval.2m', function () { - var sF = RL.data().currentFolderFullNameRaw(); + var sF = Data.currentFolderFullNameRaw(); if ('INBOX' !== sF) { RL.folderInformation(sF); @@ -1659,7 +1633,7 @@ kn.bootstart(RL); else { kn.routeOff(); - kn.setHash(RL.link().root(), true); + kn.setHash(LinkBuilder.root(), true); kn.routeOff(); _.defer(function () { @@ -1671,7 +1645,7 @@ kn.bootstart(RL); if (bGoogle) { window['rl_' + sJsHash + '_google_service'] = function () { - RL.data().googleActions(true); + Data.googleActions(true); RL.socialUsers(); }; } @@ -1679,7 +1653,7 @@ kn.bootstart(RL); if (bFacebook) { window['rl_' + sJsHash + '_facebook_service'] = function () { - RL.data().facebookActions(true); + Data.facebookActions(true); RL.socialUsers(); }; } @@ -1687,7 +1661,7 @@ kn.bootstart(RL); if (bTwitter) { window['rl_' + sJsHash + '_twitter_service'] = function () { - RL.data().twitterActions(true); + Data.twitterActions(true); RL.socialUsers(); }; } @@ -1703,7 +1677,7 @@ kn.bootstart(RL); module.exports = new RainLoopApp(); }(module)); -},{"../Common/Consts.js":4,"../Common/Enums.js":5,"../Common/Globals.js":6,"../Common/Plugins.js":7,"../Common/Utils.js":8,"../External/jquery.js":16,"../External/underscore.js":19,"../External/window.js":20,"../Knoin/Knoin.js":21,"./AbstractApp.js":2}],4:[function(require,module,exports){ +},{"../Common/Consts.js":4,"../Common/Enums.js":5,"../Common/Globals.js":6,"../Common/LinkBuilder.js":7,"../Common/Plugins.js":8,"../Common/Utils.js":9,"../External/jquery.js":19,"../External/moment.js":22,"../External/underscore.js":24,"../External/window.js":25,"../Knoin/Knoin.js":26,"../Storages/WebMailAjaxRemoteStorage.js":39,"../Storages/WebMailCacheStorage.js":40,"../Storages/WebMailDataStorage.js":41,"../ViewModels/Popups/PopupsAskViewModel.js":42,"./AbstractApp.js":2}],4:[function(require,module,exports){ /* RainLoop Webmail (c) RainLoop Team | Licensed under CC BY-NC-SA 3.0 */ (function (module) { @@ -2455,11 +2429,340 @@ kn.bootstart(RL); 'settings-removed': [], 'settings-disabled': [] }; - + module.exports = Globals; }(module)); -},{"../External/$html.js":10,"../External/ko.js":17,"../External/window.js":20}],7:[function(require,module,exports){ +},{"../External/$html.js":12,"../External/ko.js":21,"../External/window.js":25}],7:[function(require,module,exports){ +/* RainLoop Webmail (c) RainLoop Team | Licensed under CC BY-NC-SA 3.0 */ + +(function (module) { + + 'use strict'; + + var + window = require('../External/window.js'), + Utils = require('./Utils.js') + ; + + /** + * @constructor + */ + function LinkBuilder() + { + this.sBase = '#/'; + this.sServer = './?'; + this.sVersion = RL.settingsGet('Version'); + this.sSpecSuffix = RL.settingsGet('AuthAccountHash') || '0'; + this.sStaticPrefix = RL.settingsGet('StaticPrefix') || 'rainloop/v/' + this.sVersion + '/static/'; + } + + /** + * @return {string} + */ + LinkBuilder.prototype.root = function () + { + return this.sBase; + }; + + /** + * @param {string} sDownload + * @return {string} + */ + LinkBuilder.prototype.attachmentDownload = function (sDownload) + { + return this.sServer + '/Raw/' + this.sSpecSuffix + '/Download/' + sDownload; + }; + + /** + * @param {string} sDownload + * @return {string} + */ + LinkBuilder.prototype.attachmentPreview = function (sDownload) + { + return this.sServer + '/Raw/' + this.sSpecSuffix + '/View/' + sDownload; + }; + + /** + * @param {string} sDownload + * @return {string} + */ + LinkBuilder.prototype.attachmentPreviewAsPlain = function (sDownload) + { + return this.sServer + '/Raw/' + this.sSpecSuffix + '/ViewAsPlain/' + sDownload; + }; + + /** + * @return {string} + */ + LinkBuilder.prototype.upload = function () + { + return this.sServer + '/Upload/' + this.sSpecSuffix + '/'; + }; + + /** + * @return {string} + */ + LinkBuilder.prototype.uploadContacts = function () + { + return this.sServer + '/UploadContacts/' + this.sSpecSuffix + '/'; + }; + + /** + * @return {string} + */ + LinkBuilder.prototype.uploadBackground = function () + { + return this.sServer + '/UploadBackground/' + this.sSpecSuffix + '/'; + }; + + /** + * @return {string} + */ + LinkBuilder.prototype.append = function () + { + return this.sServer + '/Append/' + this.sSpecSuffix + '/'; + }; + + /** + * @param {string} sEmail + * @return {string} + */ + LinkBuilder.prototype.change = function (sEmail) + { + return this.sServer + '/Change/' + this.sSpecSuffix + '/' + window.encodeURIComponent(sEmail) + '/'; + }; + + /** + * @param {string=} sAdd + * @return {string} + */ + LinkBuilder.prototype.ajax = function (sAdd) + { + return this.sServer + '/Ajax/' + this.sSpecSuffix + '/' + sAdd; + }; + + /** + * @param {string} sRequestHash + * @return {string} + */ + LinkBuilder.prototype.messageViewLink = function (sRequestHash) + { + return this.sServer + '/Raw/' + this.sSpecSuffix + '/ViewAsPlain/' + sRequestHash; + }; + + /** + * @param {string} sRequestHash + * @return {string} + */ + LinkBuilder.prototype.messageDownloadLink = function (sRequestHash) + { + return this.sServer + '/Raw/' + this.sSpecSuffix + '/Download/' + sRequestHash; + }; + + /** + * @param {string} sEmail + * @return {string} + */ + LinkBuilder.prototype.avatarLink = function (sEmail) + { + return this.sServer + '/Raw/0/Avatar/' + window.encodeURIComponent(sEmail) + '/'; + // return '//secure.gravatar.com/avatar/' + Utils.md5(sEmail.toLowerCase()) + '.jpg?s=80&d=mm'; + }; + + /** + * @return {string} + */ + LinkBuilder.prototype.inbox = function () + { + return this.sBase + 'mailbox/Inbox'; + }; + + /** + * @return {string} + */ + LinkBuilder.prototype.messagePreview = function () + { + return this.sBase + 'mailbox/message-preview'; + }; + + /** + * @param {string=} sScreenName + * @return {string} + */ + LinkBuilder.prototype.settings = function (sScreenName) + { + var sResult = this.sBase + 'settings'; + if (!Utils.isUnd(sScreenName) && '' !== sScreenName) + { + sResult += '/' + sScreenName; + } + + return sResult; + }; + + /** + * @param {string} sScreenName + * @return {string} + */ + LinkBuilder.prototype.admin = function (sScreenName) + { + var sResult = this.sBase; + switch (sScreenName) { + case 'AdminDomains': + sResult += 'domains'; + break; + case 'AdminSecurity': + sResult += 'security'; + break; + case 'AdminLicensing': + sResult += 'licensing'; + break; + } + + return sResult; + }; + + /** + * @param {string} sFolder + * @param {number=} iPage = 1 + * @param {string=} sSearch = '' + * @return {string} + */ + LinkBuilder.prototype.mailBox = function (sFolder, iPage, sSearch) + { + iPage = Utils.isNormal(iPage) ? Utils.pInt(iPage) : 1; + sSearch = Utils.pString(sSearch); + + var sResult = this.sBase + 'mailbox/'; + if ('' !== sFolder) + { + sResult += encodeURI(sFolder); + } + if (1 < iPage) + { + sResult = sResult.replace(/[\/]+$/, ''); + sResult += '/p' + iPage; + } + if ('' !== sSearch) + { + sResult = sResult.replace(/[\/]+$/, ''); + sResult += '/' + encodeURI(sSearch); + } + + return sResult; + }; + + /** + * @return {string} + */ + LinkBuilder.prototype.phpInfo = function () + { + return this.sServer + 'Info'; + }; + + /** + * @param {string} sLang + * @return {string} + */ + LinkBuilder.prototype.langLink = function (sLang) + { + return this.sServer + '/Lang/0/' + encodeURI(sLang) + '/' + this.sVersion + '/'; + }; + + /** + * @return {string} + */ + LinkBuilder.prototype.exportContactsVcf = function () + { + return this.sServer + '/Raw/' + this.sSpecSuffix + '/ContactsVcf/'; + }; + + /** + * @return {string} + */ + LinkBuilder.prototype.exportContactsCsv = function () + { + return this.sServer + '/Raw/' + this.sSpecSuffix + '/ContactsCsv/'; + }; + + /** + * @return {string} + */ + LinkBuilder.prototype.emptyContactPic = function () + { + return this.sStaticPrefix + 'css/images/empty-contact.png'; + }; + + /** + * @param {string} sFileName + * @return {string} + */ + LinkBuilder.prototype.sound = function (sFileName) + { + return this.sStaticPrefix + 'sounds/' + sFileName; + }; + + /** + * @param {string} sTheme + * @return {string} + */ + LinkBuilder.prototype.themePreviewLink = function (sTheme) + { + var sPrefix = 'rainloop/v/' + this.sVersion + '/'; + if ('@custom' === sTheme.substr(-7)) + { + sTheme = Utils.trim(sTheme.substring(0, sTheme.length - 7)); + sPrefix = ''; + } + + return sPrefix + 'themes/' + encodeURI(sTheme) + '/images/preview.png'; + }; + + /** + * @return {string} + */ + LinkBuilder.prototype.notificationMailIcon = function () + { + return this.sStaticPrefix + 'css/images/icom-message-notification.png'; + }; + + /** + * @return {string} + */ + LinkBuilder.prototype.openPgpJs = function () + { + return this.sStaticPrefix + 'js/openpgp.min.js'; + }; + + /** + * @return {string} + */ + LinkBuilder.prototype.socialGoogle = function () + { + return this.sServer + 'SocialGoogle' + ('' !== this.sSpecSuffix ? '/' + this.sSpecSuffix + '/' : ''); + }; + + /** + * @return {string} + */ + LinkBuilder.prototype.socialTwitter = function () + { + return this.sServer + 'SocialTwitter' + ('' !== this.sSpecSuffix ? '/' + this.sSpecSuffix + '/' : ''); + }; + + /** + * @return {string} + */ + LinkBuilder.prototype.socialFacebook = function () + { + return this.sServer + 'SocialFacebook' + ('' !== this.sSpecSuffix ? '/' + this.sSpecSuffix + '/' : ''); + }; + + module.exports = new LinkBuilder(); + +}(module)); +},{"../External/window.js":25,"./Utils.js":9}],8:[function(require,module,exports){ /* RainLoop Webmail (c) RainLoop Team | Licensed under CC BY-NC-SA 3.0 */ (function (module) { @@ -2468,7 +2771,9 @@ kn.bootstart(RL); var Plugins = {}, - Utils = require('./Utils.js') + Utils = require('./Utils.js'), + Remote = require('../Remote.js'), + RL = require('../RL.js') ; /** @@ -2532,7 +2837,7 @@ kn.bootstart(RL); */ Plugins.mainSettingsGet = function (sName) { - return RL ? RL.settingsGet(sName) : null; // TODO cjs + return RL ? RL().settingsGet(sName) : null; }; /** @@ -2545,9 +2850,9 @@ kn.bootstart(RL); */ Plugins.remoteRequest = function (fCallback, sAction, oParameters, iTimeout, sGetAdd, aAbortActions) { - if (RL) // TODO cjs + if (Remote) { - RL.remote().defaultRequest(fCallback, sAction, oParameters, iTimeout, sGetAdd, aAbortActions); // TODO cjs + Remote().defaultRequest(fCallback, sAction, oParameters, iTimeout, sGetAdd, aAbortActions); } }; @@ -2566,7 +2871,7 @@ kn.bootstart(RL); module.exports = Plugins; }(module)); -},{"./Utils.js":8}],8:[function(require,module,exports){ +},{"../RL.js":32,"../Remote.js":33,"./Utils.js":9}],9:[function(require,module,exports){ /* RainLoop Webmail (c) RainLoop Team | Licensed under CC BY-NC-SA 3.0 */ (function (module) { @@ -2575,13 +2880,20 @@ kn.bootstart(RL); var Utils = {}, + $ = require('../External/jquery.js'), _ = require('../External/underscore.js'), ko = require('../External/ko.js'), + key = require('../External/key.js'), window = require('../External/window.js'), $window = require('../External/$window.js'), $doc = require('../External/$doc.js'), NotificationClass = require('../External/NotificationClass.js'), + + LocalStorage = require('../Storages/LocalStorage.js'), + + kn = require('../Knoin/Knoin.js'), + Enums = require('./Enums.js'), Globals = require('./Globals.js') ; @@ -3809,7 +4121,7 @@ kn.bootstart(RL); */ Utils.isFolderExpanded = function (sFullNameHash) { - var aExpandedList = /** @type {Array|null} */ RL.local().get(Enums.ClientSideKeyName.ExpandedFolders); + var aExpandedList = /** @type {Array|null} */ LocalStorage.get(Enums.ClientSideKeyName.ExpandedFolders); return _.isArray(aExpandedList) && -1 !== _.indexOf(aExpandedList, sFullNameHash); }; @@ -3819,7 +4131,7 @@ kn.bootstart(RL); */ Utils.setExpandedFolder = function (sFullNameHash, bExpanded) { - var aExpandedList = /** @type {Array|null} */ RL.local().get(Enums.ClientSideKeyName.ExpandedFolders); + var aExpandedList = /** @type {Array|null} */ LocalStorage.get(Enums.ClientSideKeyName.ExpandedFolders); if (!_.isArray(aExpandedList)) { aExpandedList = []; @@ -3835,7 +4147,7 @@ kn.bootstart(RL); aExpandedList = _.without(aExpandedList, sFullNameHash); } - RL.local().set(Enums.ClientSideKeyName.ExpandedFolders, aExpandedList); + LocalStorage.set(Enums.ClientSideKeyName.ExpandedFolders, aExpandedList); }; Utils.initLayoutResizer = function (sLeft, sRight, sClientSideKeyName) @@ -3846,7 +4158,7 @@ kn.bootstart(RL); oLeft = $(sLeft), oRight = $(sRight), - mLeftWidth = RL.local().get(sClientSideKeyName) || null, + mLeftWidth = LocalStorage.get(sClientSideKeyName) || null, fSetWidth = function (iWidth) { if (iWidth) @@ -3870,7 +4182,7 @@ kn.bootstart(RL); else { oLeft.resizable('enable'); - var iWidth = Utils.pInt(RL.local().get(sClientSideKeyName)) || iMinWidth; + var iWidth = Utils.pInt(LocalStorage.get(sClientSideKeyName)) || iMinWidth; fSetWidth(iWidth > iMinWidth ? iWidth : iMinWidth); } }, @@ -3878,7 +4190,7 @@ kn.bootstart(RL); fResizeFunction = function (oEvent, oObject) { if (oObject && oObject.size && oObject.size.width) { - RL.local().set(sClientSideKeyName, oObject.size.width); + LocalStorage.set(sClientSideKeyName, oObject.size.width); oRight.css({ 'left': '' + oObject.size.width + 'px' @@ -3970,61 +4282,6 @@ kn.bootstart(RL); } }; - /** - * @param {string} sName - * @param {Function} ViewModelClass - * @param {Function=} AbstractViewModel = KnoinAbstractViewModel - */ - Utils.extendAsViewModel = function (sName, ViewModelClass, AbstractViewModel) - { - if (ViewModelClass) - { - if (!AbstractViewModel) - { - AbstractViewModel = KnoinAbstractViewModel; - } - - ViewModelClass.__name = sName; - Plugins.regViewModelHook(sName, ViewModelClass); - _.extend(ViewModelClass.prototype, AbstractViewModel.prototype); - } - }; - - /** - * @param {Function} SettingsViewModelClass - * @param {string} sLabelName - * @param {string} sTemplate - * @param {string} sRoute - * @param {boolean=} bDefault - */ - Utils.addSettingsViewModel = function (SettingsViewModelClass, sTemplate, sLabelName, sRoute, bDefault) - { - SettingsViewModelClass.__rlSettingsData = { - 'Label': sLabelName, - 'Template': sTemplate, - 'Route': sRoute, - 'IsDefault': !!bDefault - }; - - Globals.aViewModels['settings'].push(SettingsViewModelClass); - }; - - /** - * @param {Function} SettingsViewModelClass - */ - Utils.removeSettingsViewModel = function (SettingsViewModelClass) - { - Globals.aViewModels['settings-removed'].push(SettingsViewModelClass); - }; - - /** - * @param {Function} SettingsViewModelClass - */ - Utils.disableSettingsViewModel = function (SettingsViewModelClass) - { - Globals.aViewModels['settings-disabled'].push(SettingsViewModelClass); - }; - Utils.convertThemeName = function (sTheme) { if ('@custom' === sTheme.substr(-7)) @@ -4079,7 +4336,7 @@ kn.bootstart(RL); while (sResult.length < iLen) { - sResult += sLine.substr(Math.round(Math.random() * sLine.length), 1); + sResult += sLine.substr(window.Math.round(window.Math.random() * sLine.length), 1); } return sResult; @@ -4143,7 +4400,7 @@ kn.bootstart(RL); Utils.i18nToNode(oBody); - Knoin.prototype.applyExternal(oViewModel, $('#rl-content', oBody)[0]); + kn.applyExternal(oViewModel, $('#rl-content', oBody)[0]); window[sFunc] = null; @@ -4673,34 +4930,47 @@ kn.bootstart(RL); module.exports = Utils; }(module)); -},{"../External/$doc.js":9,"../External/$window.js":11,"../External/NotificationClass.js":13,"../External/jquery.js":16,"../External/ko.js":17,"../External/underscore.js":19,"../External/window.js":20,"./Enums.js":5,"./Globals.js":6}],9:[function(require,module,exports){ +},{"../External/$doc.js":11,"../External/$window.js":13,"../External/NotificationClass.js":16,"../External/jquery.js":19,"../External/key.js":20,"../External/ko.js":21,"../External/underscore.js":24,"../External/window.js":25,"../Knoin/Knoin.js":26,"../Storages/LocalStorage.js":36,"./Enums.js":5,"./Globals.js":6}],10:[function(require,module,exports){ +/* RainLoop Webmail (c) RainLoop Team | Licensed under CC BY-NC-SA 3.0 */ + +'use strict'; + +module.exports = require('./jquery.js')('
'); + +},{"./jquery.js":19}],11:[function(require,module,exports){ /* RainLoop Webmail (c) RainLoop Team | Licensed under CC BY-NC-SA 3.0 */ 'use strict'; module.exports = require('./jquery.js')(window.document); -},{"./jquery.js":16}],10:[function(require,module,exports){ +},{"./jquery.js":19}],12:[function(require,module,exports){ /* RainLoop Webmail (c) RainLoop Team | Licensed under CC BY-NC-SA 3.0 */ 'use strict'; module.exports = require('./jquery.js')('html'); -},{"./jquery.js":16}],11:[function(require,module,exports){ +},{"./jquery.js":19}],13:[function(require,module,exports){ /* RainLoop Webmail (c) RainLoop Team | Licensed under CC BY-NC-SA 3.0 */ 'use strict'; module.exports = require('./jquery.js')(window); -},{"./jquery.js":16}],12:[function(require,module,exports){ +},{"./jquery.js":19}],14:[function(require,module,exports){ /* RainLoop Webmail (c) RainLoop Team | Licensed under CC BY-NC-SA 3.0 */ 'use strict'; module.exports = require('./window.js')['rainloopAppData'] || {}; -},{"./window.js":20}],13:[function(require,module,exports){ +},{"./window.js":25}],15:[function(require,module,exports){ +/* RainLoop Webmail (c) RainLoop Team | Licensed under CC BY-NC-SA 3.0 */ + +'use strict'; + +module.exports = JSON; +},{}],16:[function(require,module,exports){ /* RainLoop Webmail (c) RainLoop Team | Licensed under CC BY-NC-SA 3.0 */ 'use strict'; @@ -4710,25 +4980,31 @@ var ; module.exports = window.Notification && window.Notification.requestPermission ? window.Notification : null; -},{"./window.js":20}],14:[function(require,module,exports){ +},{"./window.js":25}],17:[function(require,module,exports){ /* RainLoop Webmail (c) RainLoop Team | Licensed under CC BY-NC-SA 3.0 */ 'use strict'; module.exports = crossroads; -},{}],15:[function(require,module,exports){ +},{}],18:[function(require,module,exports){ /* RainLoop Webmail (c) RainLoop Team | Licensed under CC BY-NC-SA 3.0 */ 'use strict'; module.exports = hasher; -},{}],16:[function(require,module,exports){ +},{}],19:[function(require,module,exports){ /* RainLoop Webmail (c) RainLoop Team | Licensed under CC BY-NC-SA 3.0 */ 'use strict'; module.exports = $; -},{}],17:[function(require,module,exports){ +},{}],20:[function(require,module,exports){ +/* RainLoop Webmail (c) RainLoop Team | Licensed under CC BY-NC-SA 3.0 */ + +'use strict'; + +module.exports = key; +},{}],21:[function(require,module,exports){ /* RainLoop Webmail (c) RainLoop Team | Licensed under CC BY-NC-SA 3.0 */ (function (module) { @@ -4741,8 +5017,11 @@ module.exports = $; window = require('./window.js'), $window = require('./$window.js'), $doc = require('./$doc.js'), + Globals = require('../Common/Globals.js'), - Utils = require('../Common/Utils.js') + Utils = require('../Common/Utils.js'), + + RL = require('../RL.js') ; ko.bindingHandlers.tooltip = { @@ -5286,7 +5565,7 @@ module.exports = $; 'focusCallback': fFocusCallback, 'inputDelimiters': [',', ';'], 'autoCompleteSource': function (oData, fResponse) { - RL.getAutocomplete(oData.term, function (aData) { + RL().getAutocomplete(oData.term, function (aData) { fResponse(_.map(aData, function (oEmailItem) { return oEmailItem.toLine(false); })); @@ -5361,7 +5640,7 @@ module.exports = $; 'inputDelimiters': [',', ';'], 'outputDelimiter': ',', 'autoCompleteSource': function (oData, fResponse) { - RL.getContactTagsAutocomplete(oData.term, function (aData) { // TODO cjs + RL().getContactTagsAutocomplete(oData.term, function (aData) { fResponse(_.map(aData, function (oTagItem) { return oTagItem.toLine(false); })); @@ -5593,26 +5872,32 @@ module.exports = $; module.exports = ko; }(module)); -},{"../Common/Globals.js":6,"../Common/Utils.js":8,"./$doc.js":9,"./$window.js":11,"./jquery.js":16,"./underscore.js":19,"./window.js":20}],18:[function(require,module,exports){ +},{"../Common/Globals.js":6,"../Common/Utils.js":9,"../RL.js":32,"./$doc.js":11,"./$window.js":13,"./jquery.js":19,"./underscore.js":24,"./window.js":25}],22:[function(require,module,exports){ +/* RainLoop Webmail (c) RainLoop Team | Licensed under CC BY-NC-SA 3.0 */ + +'use strict'; + +module.exports = moment; +},{}],23:[function(require,module,exports){ /* RainLoop Webmail (c) RainLoop Team | Licensed under CC BY-NC-SA 3.0 */ 'use strict'; module.exports = ssm; -},{}],19:[function(require,module,exports){ +},{}],24:[function(require,module,exports){ /* RainLoop Webmail (c) RainLoop Team | Licensed under CC BY-NC-SA 3.0 */ 'use strict'; module.exports = window; -},{}],20:[function(require,module,exports){ +},{}],25:[function(require,module,exports){ /* RainLoop Webmail (c) RainLoop Team | Licensed under CC BY-NC-SA 3.0 */ 'use strict'; module.exports = window; -},{}],21:[function(require,module,exports){ +},{}],26:[function(require,module,exports){ /* RainLoop Webmail (c) RainLoop Team | Licensed under CC BY-NC-SA 3.0 */ (function (module) { @@ -5626,9 +5911,11 @@ module.exports = window; hasher = require('../External/hasher.js'), crossroads = require('../External/crossroads.js'), $html = require('../External/$html.js'), - Utils = require('../Common/Utils.js'), Globals = require('../Common/Globals.js'), - Enums = require('../Common/Enums.js') + Enums = require('../Common/Enums.js'), + Plugins = require('../Common/Plugins.js'), + Utils = require('../Common/Utils.js'), + KnoinAbstractViewModel = require('../Knoin/KnoinAbstractViewModel.js') ; /** @@ -5638,6 +5925,7 @@ module.exports = window; { this.sDefaultScreenName = ''; this.oScreens = {}; + this.oBoot = null; this.oCurrentScreen = null; } @@ -5654,6 +5942,7 @@ module.exports = window; Knoin.prototype.sDefaultScreenName = ''; Knoin.prototype.oScreens = {}; + Knoin.prototype.oBoot = null; Knoin.prototype.oCurrentScreen = null; Knoin.prototype.hideLoading = function () @@ -5661,6 +5950,82 @@ module.exports = window; $('#rl-loading').hide(); }; + Knoin.prototype.rl = function () + { + return this.oBoot; + }; + + Knoin.prototype.remote = function () + { + return this.oRemote; + }; + + /** + * @param {Object} thisObject + */ + Knoin.prototype.constructorEnd = function (thisObject) + { + if (Utils.isFunc(thisObject['__constructor_end'])) + { + thisObject['__constructor_end'].call(thisObject); + } + }; + + /** + * @param {string} sName + * @param {Function} ViewModelClass + * @param {Function=} AbstractViewModel = KnoinAbstractViewModel + */ + Knoin.prototype.extendAsViewModel = function (sName, ViewModelClass, AbstractViewModel) + { + if (ViewModelClass) + { + if (!AbstractViewModel) + { + AbstractViewModel = KnoinAbstractViewModel; + } + + ViewModelClass.__name = sName; + Plugins.regViewModelHook(sName, ViewModelClass); + _.extend(ViewModelClass.prototype, AbstractViewModel.prototype); + } + }; + + /** + * @param {Function} SettingsViewModelClass + * @param {string} sLabelName + * @param {string} sTemplate + * @param {string} sRoute + * @param {boolean=} bDefault + */ + Knoin.prototype.addSettingsViewModel = function (SettingsViewModelClass, sTemplate, sLabelName, sRoute, bDefault) + { + SettingsViewModelClass.__rlSettingsData = { + 'Label': sLabelName, + 'Template': sTemplate, + 'Route': sRoute, + 'IsDefault': !!bDefault + }; + + Globals.aViewModels['settings'].push(SettingsViewModelClass); + }; + + /** + * @param {Function} SettingsViewModelClass + */ + Knoin.prototype.removeSettingsViewModel = function (SettingsViewModelClass) + { + Globals.aViewModels['settings-removed'].push(SettingsViewModelClass); + }; + + /** + * @param {Function} SettingsViewModelClass + */ + Knoin.prototype.disableSettingsViewModel = function (SettingsViewModelClass) + { + Globals.aViewModels['settings-disabled'].push(SettingsViewModelClass); + }; + Knoin.prototype.routeOff = function () { hasher.changed.active = false; @@ -6017,8 +6382,11 @@ module.exports = window; /** * @return {Knoin} */ - Knoin.prototype.bootstart = function (RL) + Knoin.prototype.bootstart = function (RL, Remote) { + this.oBoot = RL; + this.oRemote = Remote; + var window = require('../External/window.js'), $window = require('../External/$window.js'), @@ -6044,7 +6412,7 @@ module.exports = window; window['rl']['settingsGet'] = Plugins.mainSettingsGet; window['rl']['remoteRequest'] = Plugins.remoteRequest; window['rl']['pluginSettingsGet'] = Plugins.settingsGet; - window['rl']['addSettingsViewModel'] = Utils.addSettingsViewModel; + window['rl']['addSettingsViewModel'] = _.bind(this.addSettingsViewModel, this); window['rl']['createCommand'] = Utils.createCommand; window['rl']['EmailModel'] = EmailModel; @@ -6079,7 +6447,7 @@ module.exports = window; module.exports = new Knoin(); }(module)); -},{"../Common/Enums.js":5,"../Common/Globals.js":6,"../Common/Plugins.js":7,"../Common/Utils.js":8,"../External/$html.js":10,"../External/$window.js":11,"../External/crossroads.js":14,"../External/hasher.js":15,"../External/jquery.js":16,"../External/ko.js":17,"../External/underscore.js":19,"../External/window.js":20,"../Models/EmailModel.js":23}],22:[function(require,module,exports){ +},{"../Common/Enums.js":5,"../Common/Globals.js":6,"../Common/Plugins.js":8,"../Common/Utils.js":9,"../External/$html.js":12,"../External/$window.js":13,"../External/crossroads.js":17,"../External/hasher.js":18,"../External/jquery.js":19,"../External/ko.js":21,"../External/underscore.js":24,"../External/window.js":25,"../Knoin/KnoinAbstractViewModel.js":28,"../Models/EmailModel.js":30}],27:[function(require,module,exports){ /* RainLoop Webmail (c) RainLoop Team | Licensed under CC BY-NC-SA 3.0 */ (function (module) { @@ -6102,7 +6470,370 @@ module.exports = window; module.exports = KnoinAbstractBoot; }(module)); -},{}],23:[function(require,module,exports){ +},{}],28:[function(require,module,exports){ +/* RainLoop Webmail (c) RainLoop Team | Licensed under CC BY-NC-SA 3.0 */ + +(function (module) { + + 'use strict'; + + var + ko = require('../External/ko.js'), + $window = require('../External/$window.js'), + Utils = require('../Common/Utils.js'), + Enums = require('../Common/Enums.js') + ; + + /** + * @param {string=} sPosition = '' + * @param {string=} sTemplate = '' + * @constructor + */ + function KnoinAbstractViewModel(sPosition, sTemplate) + { + this.bDisabeCloseOnEsc = false; + this.sPosition = Utils.pString(sPosition); + this.sTemplate = Utils.pString(sTemplate); + + this.sDefaultKeyScope = Enums.KeyState.None; + this.sCurrentKeyScope = this.sDefaultKeyScope; + + this.viewModelName = ''; + this.viewModelVisibility = ko.observable(false); + this.modalVisibility = ko.observable(false).extend({'rateLimit': 0}); + + this.viewModelDom = null; + } + + /** + * @type {string} + */ + KnoinAbstractViewModel.prototype.sPosition = ''; + + /** + * @type {string} + */ + KnoinAbstractViewModel.prototype.sTemplate = ''; + + /** + * @type {string} + */ + KnoinAbstractViewModel.prototype.viewModelName = ''; + + /** + * @type {?} + */ + KnoinAbstractViewModel.prototype.viewModelDom = null; + + /** + * @return {string} + */ + KnoinAbstractViewModel.prototype.viewModelTemplate = function () + { + return this.sTemplate; + }; + + /** + * @return {string} + */ + KnoinAbstractViewModel.prototype.viewModelPosition = function () + { + return this.sPosition; + }; + + KnoinAbstractViewModel.prototype.cancelCommand = KnoinAbstractViewModel.prototype.closeCommand = function () + { + }; + + KnoinAbstractViewModel.prototype.storeAndSetKeyScope = function () + { + this.sCurrentKeyScope = RL.data().keyScope(); // TODO cjs + RL.data().keyScope(this.sDefaultKeyScope); // TODO cjs + }; + + KnoinAbstractViewModel.prototype.restoreKeyScope = function () + { + RL.data().keyScope(this.sCurrentKeyScope); // TODO cjs + }; + + KnoinAbstractViewModel.prototype.registerPopupKeyDown = function () + { + var self = this; + $window.on('keydown', function (oEvent) { + if (oEvent && self.modalVisibility && self.modalVisibility()) + { + if (!this.bDisabeCloseOnEsc && Enums.EventKeyCode.Esc === oEvent.keyCode) + { + Utils.delegateRun(self, 'cancelCommand'); + return false; + } + else if (Enums.EventKeyCode.Backspace === oEvent.keyCode && !Utils.inFocus()) + { + return false; + } + } + + return true; + }); + }; + + module.exports = KnoinAbstractViewModel; + +}(module)); +},{"../Common/Enums.js":5,"../Common/Utils.js":9,"../External/$window.js":13,"../External/ko.js":21}],29:[function(require,module,exports){ +/* RainLoop Webmail (c) RainLoop Team | Licensed under CC BY-NC-SA 3.0 */ + +(function (module) { + + 'use strict'; + + var + window = require('../External/window.js'), + Globals = require('../Common/Globals.js'), + Utils = require('../Common/Utils.js'), + LinkBuilder = require('../Common/LinkBuilder.js') + ; + + /** + * @constructor + */ + function AttachmentModel() + { + this.mimeType = ''; + this.fileName = ''; + this.estimatedSize = 0; + this.friendlySize = ''; + this.isInline = false; + this.isLinked = false; + this.cid = ''; + this.cidWithOutTags = ''; + this.contentLocation = ''; + this.download = ''; + this.folder = ''; + this.uid = ''; + this.mimeIndex = ''; + } + + /** + * @static + * @param {AjaxJsonAttachment} oJsonAttachment + * @return {?AttachmentModel} + */ + AttachmentModel.newInstanceFromJson = function (oJsonAttachment) + { + var oAttachmentModel = new AttachmentModel(); + return oAttachmentModel.initByJson(oJsonAttachment) ? oAttachmentModel : null; + }; + + AttachmentModel.prototype.mimeType = ''; + AttachmentModel.prototype.fileName = ''; + AttachmentModel.prototype.estimatedSize = 0; + AttachmentModel.prototype.friendlySize = ''; + AttachmentModel.prototype.isInline = false; + AttachmentModel.prototype.isLinked = false; + AttachmentModel.prototype.cid = ''; + AttachmentModel.prototype.cidWithOutTags = ''; + AttachmentModel.prototype.contentLocation = ''; + AttachmentModel.prototype.download = ''; + AttachmentModel.prototype.folder = ''; + AttachmentModel.prototype.uid = ''; + AttachmentModel.prototype.mimeIndex = ''; + + /** + * @param {AjaxJsonAttachment} oJsonAttachment + */ + AttachmentModel.prototype.initByJson = function (oJsonAttachment) + { + var bResult = false; + if (oJsonAttachment && 'Object/Attachment' === oJsonAttachment['@Object']) + { + this.mimeType = (oJsonAttachment.MimeType || '').toLowerCase(); + this.fileName = oJsonAttachment.FileName; + this.estimatedSize = Utils.pInt(oJsonAttachment.EstimatedSize); + this.isInline = !!oJsonAttachment.IsInline; + this.isLinked = !!oJsonAttachment.IsLinked; + this.cid = oJsonAttachment.CID; + this.contentLocation = oJsonAttachment.ContentLocation; + this.download = oJsonAttachment.Download; + + this.folder = oJsonAttachment.Folder; + this.uid = oJsonAttachment.Uid; + this.mimeIndex = oJsonAttachment.MimeIndex; + + this.friendlySize = Utils.friendlySize(this.estimatedSize); + this.cidWithOutTags = this.cid.replace(/^<+/, '').replace(/>+$/, ''); + + bResult = true; + } + + return bResult; + }; + + /** + * @return {boolean} + */ + AttachmentModel.prototype.isImage = function () + { + return -1 < Utils.inArray(this.mimeType.toLowerCase(), + ['image/png', 'image/jpg', 'image/jpeg', 'image/gif'] + ); + }; + + /** + * @return {boolean} + */ + AttachmentModel.prototype.isText = function () + { + return 'text/' === this.mimeType.substr(0, 5) && + -1 === Utils.inArray(this.mimeType, ['text/html']); + }; + + /** + * @return {boolean} + */ + AttachmentModel.prototype.isPdf = function () + { + return Globals.bAllowPdfPreview && 'application/pdf' === this.mimeType; + }; + + /** + * @return {string} + */ + AttachmentModel.prototype.linkDownload = function () + { + return LinkBuilder.attachmentDownload(this.download); // TODO cjs + }; + + /** + * @return {string} + */ + AttachmentModel.prototype.linkPreview = function () + { + return LinkBuilder.attachmentPreview(this.download); // TODO cjs + }; + + /** + * @return {string} + */ + AttachmentModel.prototype.linkPreviewAsPlain = function () + { + return LinkBuilder.attachmentPreviewAsPlain(this.download); + }; + + /** + * @return {string} + */ + AttachmentModel.prototype.generateTransferDownloadUrl = function () + { + var sLink = this.linkDownload(); + if ('http' !== sLink.substr(0, 4)) + { + sLink = window.location.protocol + '//' + window.location.host + window.location.pathname + sLink; + } + + return this.mimeType + ':' + this.fileName + ':' + sLink; + }; + + /** + * @param {AttachmentModel} oAttachment + * @param {*} oEvent + * @return {boolean} + */ + AttachmentModel.prototype.eventDragStart = function (oAttachment, oEvent) + { + var oLocalEvent = oEvent.originalEvent || oEvent; + if (oAttachment && oLocalEvent && oLocalEvent.dataTransfer && oLocalEvent.dataTransfer.setData) + { + oLocalEvent.dataTransfer.setData('DownloadURL', this.generateTransferDownloadUrl()); + } + + return true; + }; + + AttachmentModel.prototype.iconClass = function () + { + var + aParts = this.mimeType.toLocaleString().split('/'), + sClass = 'icon-file' + ; + + if (aParts && aParts[1]) + { + if ('image' === aParts[0]) + { + sClass = 'icon-file-image'; + } + else if ('text' === aParts[0]) + { + sClass = 'icon-file-text'; + } + else if ('audio' === aParts[0]) + { + sClass = 'icon-file-music'; + } + else if ('video' === aParts[0]) + { + sClass = 'icon-file-movie'; + } + else if (-1 < Utils.inArray(aParts[1], + ['zip', '7z', 'tar', 'rar', 'gzip', 'bzip', 'bzip2', 'x-zip', 'x-7z', 'x-rar', 'x-tar', 'x-gzip', 'x-bzip', 'x-bzip2', 'x-zip-compressed', 'x-7z-compressed', 'x-rar-compressed'])) + { + sClass = 'icon-file-zip'; + } + // else if (-1 < Utils.inArray(aParts[1], + // ['pdf', 'x-pdf'])) + // { + // sClass = 'icon-file-pdf'; + // } + // else if (-1 < Utils.inArray(aParts[1], [ + // 'exe', 'x-exe', 'x-winexe', 'bat' + // ])) + // { + // sClass = 'icon-console'; + // } + else if (-1 < Utils.inArray(aParts[1], [ + 'rtf', 'msword', 'vnd.msword', 'vnd.openxmlformats-officedocument.wordprocessingml.document', + 'vnd.openxmlformats-officedocument.wordprocessingml.template', + 'vnd.ms-word.document.macroEnabled.12', + 'vnd.ms-word.template.macroEnabled.12' + ])) + { + sClass = 'icon-file-text'; + } + else if (-1 < Utils.inArray(aParts[1], [ + 'excel', 'ms-excel', 'vnd.ms-excel', + 'vnd.openxmlformats-officedocument.spreadsheetml.sheet', + 'vnd.openxmlformats-officedocument.spreadsheetml.template', + 'vnd.ms-excel.sheet.macroEnabled.12', + 'vnd.ms-excel.template.macroEnabled.12', + 'vnd.ms-excel.addin.macroEnabled.12', + 'vnd.ms-excel.sheet.binary.macroEnabled.12' + ])) + { + sClass = 'icon-file-excel'; + } + else if (-1 < Utils.inArray(aParts[1], [ + 'powerpoint', 'ms-powerpoint', 'vnd.ms-powerpoint', + 'vnd.openxmlformats-officedocument.presentationml.presentation', + 'vnd.openxmlformats-officedocument.presentationml.template', + 'vnd.openxmlformats-officedocument.presentationml.slideshow', + 'vnd.ms-powerpoint.addin.macroEnabled.12', + 'vnd.ms-powerpoint.presentation.macroEnabled.12', + 'vnd.ms-powerpoint.template.macroEnabled.12', + 'vnd.ms-powerpoint.slideshow.macroEnabled.12' + ])) + { + sClass = 'icon-file-chart-graph'; + } + } + + return sClass; + }; + + module.exports = AttachmentModel; + +}(module)); +},{"../Common/Globals.js":6,"../Common/LinkBuilder.js":7,"../Common/Utils.js":9,"../External/window.js":25}],30:[function(require,module,exports){ /* RainLoop Webmail (c) RainLoop Team | Licensed under CC BY-NC-SA 3.0 */ (function (module) { @@ -6481,4 +7212,4573 @@ module.exports = window; module.exports = EmailModel; }(module)); -},{"../Common/Enums.js":5,"../Common/Utils.js":8}]},{},[1]); +},{"../Common/Enums.js":5,"../Common/Utils.js":9}],31:[function(require,module,exports){ +/* RainLoop Webmail (c) RainLoop Team | Licensed under CC BY-NC-SA 3.0 */ + +(function (module) { + + 'use strict'; + + var + window = require('../External/window.js'), + $ = require('../External/jquery.js'), + _ = require('../External/underscore.js'), + ko = require('../External/ko.js'), + moment = require('../External/moment.js'), + $window = require('../External/$window.js'), + $div = require('../External/$div.js'), + + Enums = require('../Common/Enums.js'), + Utils = require('../Common/Utils.js'), + LinkBuilder = require('../Common/LinkBuilder.js'), + + EmailModel = require('./EmailModel.js'), + AttachmentModel = require('./AttachmentModel.js') + ; + + /** + * @constructor + */ + function MessageModel() + { + this.folderFullNameRaw = ''; + this.uid = ''; + this.hash = ''; + this.requestHash = ''; + this.subject = ko.observable(''); + this.subjectPrefix = ko.observable(''); + this.subjectSuffix = ko.observable(''); + this.size = ko.observable(0); + this.dateTimeStampInUTC = ko.observable(0); + this.priority = ko.observable(Enums.MessagePriority.Normal); + + this.proxy = false; + + this.fromEmailString = ko.observable(''); + this.fromClearEmailString = ko.observable(''); + this.toEmailsString = ko.observable(''); + this.toClearEmailsString = ko.observable(''); + + this.senderEmailsString = ko.observable(''); + this.senderClearEmailsString = ko.observable(''); + + this.emails = []; + + this.from = []; + this.to = []; + this.cc = []; + this.bcc = []; + this.replyTo = []; + this.deliveredTo = []; + + this.newForAnimation = ko.observable(false); + + this.deleted = ko.observable(false); + this.unseen = ko.observable(false); + this.flagged = ko.observable(false); + this.answered = ko.observable(false); + this.forwarded = ko.observable(false); + this.isReadReceipt = ko.observable(false); + + this.focused = ko.observable(false); + this.selected = ko.observable(false); + this.checked = ko.observable(false); + this.hasAttachments = ko.observable(false); + this.attachmentsMainType = ko.observable(''); + + this.moment = ko.observable(moment(moment.unix(0))); + + this.attachmentIconClass = ko.computed(function () { + var sClass = ''; + if (this.hasAttachments()) + { + sClass = 'icon-attachment'; + switch (this.attachmentsMainType()) + { + case 'image': + sClass = 'icon-image'; + break; + case 'archive': + sClass = 'icon-file-zip'; + break; + case 'doc': + sClass = 'icon-file-text'; + break; + // case 'pdf': + // sClass = 'icon-file-pdf'; + // break; + } + } + return sClass; + }, this); + + this.fullFormatDateValue = ko.computed(function () { + return MessageModel.calculateFullFromatDateValue(this.dateTimeStampInUTC()); + }, this); + + this.momentDate = Utils.createMomentDate(this); + this.momentShortDate = Utils.createMomentShortDate(this); + + this.dateTimeStampInUTC.subscribe(function (iValue) { + var iNow = moment().unix(); + this.moment(moment.unix(iNow < iValue ? iNow : iValue)); + }, this); + + this.body = null; + this.plainRaw = ''; + this.isHtml = ko.observable(false); + this.hasImages = ko.observable(false); + this.attachments = ko.observableArray([]); + + this.isPgpSigned = ko.observable(false); + this.isPgpEncrypted = ko.observable(false); + this.pgpSignedVerifyStatus = ko.observable(Enums.SignedVerifyStatus.None); + this.pgpSignedVerifyUser = ko.observable(''); + + this.priority = ko.observable(Enums.MessagePriority.Normal); + this.readReceipt = ko.observable(''); + + this.aDraftInfo = []; + this.sMessageId = ''; + this.sInReplyTo = ''; + this.sReferences = ''; + + this.parentUid = ko.observable(0); + this.threads = ko.observableArray([]); + this.threadsLen = ko.observable(0); + this.hasUnseenSubMessage = ko.observable(false); + this.hasFlaggedSubMessage = ko.observable(false); + + this.lastInCollapsedThread = ko.observable(false); + this.lastInCollapsedThreadLoading = ko.observable(false); + + this.threadsLenResult = ko.computed(function () { + var iCount = this.threadsLen(); + return 0 === this.parentUid() && 0 < iCount ? iCount + 1 : ''; + }, this); + } + + /** + * @static + * @param {AjaxJsonMessage} oJsonMessage + * @return {?MessageModel} + */ + MessageModel.newInstanceFromJson = function (oJsonMessage) + { + var oMessageModel = new MessageModel(); + return oMessageModel.initByJson(oJsonMessage) ? oMessageModel : null; + }; + + /** + * @static + * @param {number} iTimeStampInUTC + * @return {string} + */ + MessageModel.calculateFullFromatDateValue = function (iTimeStampInUTC) + { + return 0 < iTimeStampInUTC ? moment.unix(iTimeStampInUTC).format('LLL') : ''; + }; + + /** + * @static + * @param {Array} aEmail + * @param {boolean=} bFriendlyView + * @param {boolean=} bWrapWithLink = false + * @return {string} + */ + MessageModel.emailsToLine = function (aEmail, bFriendlyView, bWrapWithLink) + { + var + aResult = [], + iIndex = 0, + iLen = 0 + ; + + if (Utils.isNonEmptyArray(aEmail)) + { + for (iIndex = 0, iLen = aEmail.length; iIndex < iLen; iIndex++) + { + aResult.push(aEmail[iIndex].toLine(bFriendlyView, bWrapWithLink)); + } + } + + return aResult.join(', '); + }; + + /** + * @static + * @param {Array} aEmail + * @return {string} + */ + MessageModel.emailsToLineClear = function (aEmail) + { + var + aResult = [], + iIndex = 0, + iLen = 0 + ; + + if (Utils.isNonEmptyArray(aEmail)) + { + for (iIndex = 0, iLen = aEmail.length; iIndex < iLen; iIndex++) + { + if (aEmail[iIndex] && aEmail[iIndex].email && '' !== aEmail[iIndex].name) + { + aResult.push(aEmail[iIndex].email); + } + } + } + + return aResult.join(', '); + }; + + /** + * @static + * @param {?Array} aJsonEmails + * @return {Array.} + */ + MessageModel.initEmailsFromJson = function (aJsonEmails) + { + var + iIndex = 0, + iLen = 0, + oEmailModel = null, + aResult = [] + ; + + if (Utils.isNonEmptyArray(aJsonEmails)) + { + for (iIndex = 0, iLen = aJsonEmails.length; iIndex < iLen; iIndex++) + { + oEmailModel = EmailModel.newInstanceFromJson(aJsonEmails[iIndex]); + if (oEmailModel) + { + aResult.push(oEmailModel); + } + } + } + + return aResult; + }; + + /** + * @static + * @param {Array.} aMessageEmails + * @param {Object} oLocalUnic + * @param {Array} aLocalEmails + */ + MessageModel.replyHelper = function (aMessageEmails, oLocalUnic, aLocalEmails) + { + if (aMessageEmails && 0 < aMessageEmails.length) + { + var + iIndex = 0, + iLen = aMessageEmails.length + ; + + for (; iIndex < iLen; iIndex++) + { + if (Utils.isUnd(oLocalUnic[aMessageEmails[iIndex].email])) + { + oLocalUnic[aMessageEmails[iIndex].email] = true; + aLocalEmails.push(aMessageEmails[iIndex]); + } + } + } + }; + + MessageModel.prototype.clear = function () + { + this.folderFullNameRaw = ''; + this.uid = ''; + this.hash = ''; + this.requestHash = ''; + this.subject(''); + this.subjectPrefix(''); + this.subjectSuffix(''); + this.size(0); + this.dateTimeStampInUTC(0); + this.priority(Enums.MessagePriority.Normal); + + this.proxy = false; + + this.fromEmailString(''); + this.fromClearEmailString(''); + this.toEmailsString(''); + this.toClearEmailsString(''); + this.senderEmailsString(''); + this.senderClearEmailsString(''); + + this.emails = []; + + this.from = []; + this.to = []; + this.cc = []; + this.bcc = []; + this.replyTo = []; + this.deliveredTo = []; + + this.newForAnimation(false); + + this.deleted(false); + this.unseen(false); + this.flagged(false); + this.answered(false); + this.forwarded(false); + this.isReadReceipt(false); + + this.selected(false); + this.checked(false); + this.hasAttachments(false); + this.attachmentsMainType(''); + + this.body = null; + this.isHtml(false); + this.hasImages(false); + this.attachments([]); + + this.isPgpSigned(false); + this.isPgpEncrypted(false); + this.pgpSignedVerifyStatus(Enums.SignedVerifyStatus.None); + this.pgpSignedVerifyUser(''); + + this.priority(Enums.MessagePriority.Normal); + this.readReceipt(''); + this.aDraftInfo = []; + this.sMessageId = ''; + this.sInReplyTo = ''; + this.sReferences = ''; + + this.parentUid(0); + this.threads([]); + this.threadsLen(0); + this.hasUnseenSubMessage(false); + this.hasFlaggedSubMessage(false); + + this.lastInCollapsedThread(false); + this.lastInCollapsedThreadLoading(false); + }; + + MessageModel.prototype.computeSenderEmail = function () + { + var + sSent = RL.data().sentFolder(), + sDraft = RL.data().draftFolder() + ; + + this.senderEmailsString(this.folderFullNameRaw === sSent || this.folderFullNameRaw === sDraft ? + this.toEmailsString() : this.fromEmailString()); + + this.senderClearEmailsString(this.folderFullNameRaw === sSent || this.folderFullNameRaw === sDraft ? + this.toClearEmailsString() : this.fromClearEmailString()); + }; + + /** + * @param {AjaxJsonMessage} oJsonMessage + * @return {boolean} + */ + MessageModel.prototype.initByJson = function (oJsonMessage) + { + var bResult = false; + if (oJsonMessage && 'Object/Message' === oJsonMessage['@Object']) + { + this.folderFullNameRaw = oJsonMessage.Folder; + this.uid = oJsonMessage.Uid; + this.hash = oJsonMessage.Hash; + this.requestHash = oJsonMessage.RequestHash; + + this.proxy = !!oJsonMessage.ExternalProxy; + + this.size(Utils.pInt(oJsonMessage.Size)); + + this.from = MessageModel.initEmailsFromJson(oJsonMessage.From); + this.to = MessageModel.initEmailsFromJson(oJsonMessage.To); + this.cc = MessageModel.initEmailsFromJson(oJsonMessage.Cc); + this.bcc = MessageModel.initEmailsFromJson(oJsonMessage.Bcc); + this.replyTo = MessageModel.initEmailsFromJson(oJsonMessage.ReplyTo); + this.deliveredTo = MessageModel.initEmailsFromJson(oJsonMessage.DeliveredTo); + + this.subject(oJsonMessage.Subject); + if (Utils.isArray(oJsonMessage.SubjectParts)) + { + this.subjectPrefix(oJsonMessage.SubjectParts[0]); + this.subjectSuffix(oJsonMessage.SubjectParts[1]); + } + else + { + this.subjectPrefix(''); + this.subjectSuffix(this.subject()); + } + + this.dateTimeStampInUTC(Utils.pInt(oJsonMessage.DateTimeStampInUTC)); + this.hasAttachments(!!oJsonMessage.HasAttachments); + this.attachmentsMainType(oJsonMessage.AttachmentsMainType); + + this.fromEmailString(MessageModel.emailsToLine(this.from, true)); + this.fromClearEmailString(MessageModel.emailsToLineClear(this.from)); + this.toEmailsString(MessageModel.emailsToLine(this.to, true)); + this.toClearEmailsString(MessageModel.emailsToLineClear(this.to)); + + this.parentUid(Utils.pInt(oJsonMessage.ParentThread)); + this.threads(Utils.isArray(oJsonMessage.Threads) ? oJsonMessage.Threads : []); + this.threadsLen(Utils.pInt(oJsonMessage.ThreadsLen)); + + this.initFlagsByJson(oJsonMessage); + this.computeSenderEmail(); + + bResult = true; + } + + return bResult; + }; + + /** + * @param {AjaxJsonMessage} oJsonMessage + * @return {boolean} + */ + MessageModel.prototype.initUpdateByMessageJson = function (oJsonMessage) + { + var + bResult = false, + iPriority = Enums.MessagePriority.Normal + ; + + if (oJsonMessage && 'Object/Message' === oJsonMessage['@Object']) + { + iPriority = Utils.pInt(oJsonMessage.Priority); + this.priority(-1 < Utils.inArray(iPriority, [Enums.MessagePriority.High, Enums.MessagePriority.Low]) ? + iPriority : Enums.MessagePriority.Normal); + + this.aDraftInfo = oJsonMessage.DraftInfo; + + this.sMessageId = oJsonMessage.MessageId; + this.sInReplyTo = oJsonMessage.InReplyTo; + this.sReferences = oJsonMessage.References; + + this.proxy = !!oJsonMessage.ExternalProxy; + + if (RL.data().capaOpenPGP()) // TODO cjs + { + this.isPgpSigned(!!oJsonMessage.PgpSigned); + this.isPgpEncrypted(!!oJsonMessage.PgpEncrypted); + } + + this.hasAttachments(!!oJsonMessage.HasAttachments); + this.attachmentsMainType(oJsonMessage.AttachmentsMainType); + + this.foundedCIDs = Utils.isArray(oJsonMessage.FoundedCIDs) ? oJsonMessage.FoundedCIDs : []; + this.attachments(this.initAttachmentsFromJson(oJsonMessage.Attachments)); + + this.readReceipt(oJsonMessage.ReadReceipt || ''); + + this.computeSenderEmail(); + + bResult = true; + } + + return bResult; + }; + + /** + * @param {(AjaxJsonAttachment|null)} oJsonAttachments + * @return {Array} + */ + MessageModel.prototype.initAttachmentsFromJson = function (oJsonAttachments) + { + var + iIndex = 0, + iLen = 0, + oAttachmentModel = null, + aResult = [] + ; + + if (oJsonAttachments && 'Collection/AttachmentCollection' === oJsonAttachments['@Object'] && + Utils.isNonEmptyArray(oJsonAttachments['@Collection'])) + { + for (iIndex = 0, iLen = oJsonAttachments['@Collection'].length; iIndex < iLen; iIndex++) + { + oAttachmentModel = AttachmentModel.newInstanceFromJson(oJsonAttachments['@Collection'][iIndex]); + if (oAttachmentModel) + { + if ('' !== oAttachmentModel.cidWithOutTags && 0 < this.foundedCIDs.length && + 0 <= Utils.inArray(oAttachmentModel.cidWithOutTags, this.foundedCIDs)) + { + oAttachmentModel.isLinked = true; + } + + aResult.push(oAttachmentModel); + } + } + } + + return aResult; + }; + + /** + * @param {AjaxJsonMessage} oJsonMessage + * @return {boolean} + */ + MessageModel.prototype.initFlagsByJson = function (oJsonMessage) + { + var bResult = false; + + if (oJsonMessage && 'Object/Message' === oJsonMessage['@Object']) + { + this.unseen(!oJsonMessage.IsSeen); + this.flagged(!!oJsonMessage.IsFlagged); + this.answered(!!oJsonMessage.IsAnswered); + this.forwarded(!!oJsonMessage.IsForwarded); + this.isReadReceipt(!!oJsonMessage.IsReadReceipt); + + bResult = true; + } + + return bResult; + }; + + /** + * @param {boolean} bFriendlyView + * @param {boolean=} bWrapWithLink = false + * @return {string} + */ + MessageModel.prototype.fromToLine = function (bFriendlyView, bWrapWithLink) + { + return MessageModel.emailsToLine(this.from, bFriendlyView, bWrapWithLink); + }; + + /** + * @param {boolean} bFriendlyView + * @param {boolean=} bWrapWithLink = false + * @return {string} + */ + MessageModel.prototype.toToLine = function (bFriendlyView, bWrapWithLink) + { + return MessageModel.emailsToLine(this.to, bFriendlyView, bWrapWithLink); + }; + + /** + * @param {boolean} bFriendlyView + * @param {boolean=} bWrapWithLink = false + * @return {string} + */ + MessageModel.prototype.ccToLine = function (bFriendlyView, bWrapWithLink) + { + return MessageModel.emailsToLine(this.cc, bFriendlyView, bWrapWithLink); + }; + + /** + * @param {boolean} bFriendlyView + * @param {boolean=} bWrapWithLink = false + * @return {string} + */ + MessageModel.prototype.bccToLine = function (bFriendlyView, bWrapWithLink) + { + return MessageModel.emailsToLine(this.bcc, bFriendlyView, bWrapWithLink); + }; + + /** + * @return string + */ + MessageModel.prototype.lineAsCcc = function () + { + var aResult = []; + if (this.deleted()) + { + aResult.push('deleted'); + } + if (this.selected()) + { + aResult.push('selected'); + } + if (this.checked()) + { + aResult.push('checked'); + } + if (this.flagged()) + { + aResult.push('flagged'); + } + if (this.unseen()) + { + aResult.push('unseen'); + } + if (this.answered()) + { + aResult.push('answered'); + } + if (this.forwarded()) + { + aResult.push('forwarded'); + } + if (this.focused()) + { + aResult.push('focused'); + } + if (this.hasAttachments()) + { + aResult.push('withAttachments'); + switch (this.attachmentsMainType()) + { + case 'image': + aResult.push('imageOnlyAttachments'); + break; + case 'archive': + aResult.push('archiveOnlyAttachments'); + break; + } + } + if (this.newForAnimation()) + { + aResult.push('new'); + } + if ('' === this.subject()) + { + aResult.push('emptySubject'); + } + if (0 < this.parentUid()) + { + aResult.push('hasParentMessage'); + } + if (0 < this.threadsLen() && 0 === this.parentUid()) + { + aResult.push('hasChildrenMessage'); + } + if (this.hasUnseenSubMessage()) + { + aResult.push('hasUnseenSubMessage'); + } + if (this.hasFlaggedSubMessage()) + { + aResult.push('hasFlaggedSubMessage'); + } + + return aResult.join(' '); + }; + + /** + * @return {boolean} + */ + MessageModel.prototype.hasVisibleAttachments = function () + { + return !!_.find(this.attachments(), function (oAttachment) { + return !oAttachment.isLinked; + }); + }; + + /** + * @param {string} sCid + * @return {*} + */ + MessageModel.prototype.findAttachmentByCid = function (sCid) + { + var + oResult = null, + aAttachments = this.attachments() + ; + + if (Utils.isNonEmptyArray(aAttachments)) + { + sCid = sCid.replace(/^<+/, '').replace(/>+$/, ''); + oResult = _.find(aAttachments, function (oAttachment) { + return sCid === oAttachment.cidWithOutTags; + }); + } + + return oResult || null; + }; + + /** + * @param {string} sContentLocation + * @return {*} + */ + MessageModel.prototype.findAttachmentByContentLocation = function (sContentLocation) + { + var + oResult = null, + aAttachments = this.attachments() + ; + + if (Utils.isNonEmptyArray(aAttachments)) + { + oResult = _.find(aAttachments, function (oAttachment) { + return sContentLocation === oAttachment.contentLocation; + }); + } + + return oResult || null; + }; + + + /** + * @return {string} + */ + MessageModel.prototype.messageId = function () + { + return this.sMessageId; + }; + + /** + * @return {string} + */ + MessageModel.prototype.inReplyTo = function () + { + return this.sInReplyTo; + }; + + /** + * @return {string} + */ + MessageModel.prototype.references = function () + { + return this.sReferences; + }; + + /** + * @return {string} + */ + MessageModel.prototype.fromAsSingleEmail = function () + { + return Utils.isArray(this.from) && this.from[0] ? this.from[0].email : ''; + }; + + /** + * @return {string} + */ + MessageModel.prototype.viewLink = function () + { + return LinkBuilder.messageViewLink(this.requestHash);// TODO cjs + }; + + /** + * @return {string} + */ + MessageModel.prototype.downloadLink = function () + { + return LinkBuilder.messageDownloadLink(this.requestHash);// TODO cjs + }; + + /** + * @param {Object} oExcludeEmails + * @return {Array} + */ + MessageModel.prototype.replyEmails = function (oExcludeEmails) + { + var + aResult = [], + oUnic = Utils.isUnd(oExcludeEmails) ? {} : oExcludeEmails + ; + + MessageModel.replyHelper(this.replyTo, oUnic, aResult); + if (0 === aResult.length) + { + MessageModel.replyHelper(this.from, oUnic, aResult); + } + + return aResult; + }; + + /** + * @param {Object} oExcludeEmails + * @return {Array.} + */ + MessageModel.prototype.replyAllEmails = function (oExcludeEmails) + { + var + aToResult = [], + aCcResult = [], + oUnic = Utils.isUnd(oExcludeEmails) ? {} : oExcludeEmails + ; + + MessageModel.replyHelper(this.replyTo, oUnic, aToResult); + if (0 === aToResult.length) + { + MessageModel.replyHelper(this.from, oUnic, aToResult); + } + + MessageModel.replyHelper(this.to, oUnic, aToResult); + MessageModel.replyHelper(this.cc, oUnic, aCcResult); + + return [aToResult, aCcResult]; + }; + + /** + * @return {string} + */ + MessageModel.prototype.textBodyToString = function () + { + return this.body ? this.body.html() : ''; + }; + + /** + * @return {string} + */ + MessageModel.prototype.attachmentsToStringLine = function () + { + var aAttachLines = _.map(this.attachments(), function (oItem) { + return oItem.fileName + ' (' + oItem.friendlySize + ')'; + }); + + return aAttachLines && 0 < aAttachLines.length ? aAttachLines.join(', ') : ''; + }; + + /** + * @return {Object} + */ + MessageModel.prototype.getDataForWindowPopup = function () + { + return { + 'popupFrom': this.fromToLine(false), + 'popupTo': this.toToLine(false), + 'popupCc': this.ccToLine(false), + 'popupBcc': this.bccToLine(false), + 'popupSubject': this.subject(), + 'popupDate': this.fullFormatDateValue(), + 'popupAttachments': this.attachmentsToStringLine(), + 'popupBody': this.textBodyToString() + }; + }; + + /** + * @param {boolean=} bPrint = false + */ + MessageModel.prototype.viewPopupMessage = function (bPrint) + { + Utils.windowPopupKnockout(this.getDataForWindowPopup(), 'PopupsWindowSimpleMessage', this.subject(), function (oPopupWin) { + if (oPopupWin && oPopupWin.document && oPopupWin.document.body) + { + $('img.lazy', oPopupWin.document.body).each(function (iIndex, oImg) { + + var + $oImg = $(oImg), + sOrig = $oImg.data('original'), + sSrc = $oImg.attr('src') + ; + + if (0 <= iIndex && sOrig && !sSrc) + { + $oImg.attr('src', sOrig); + } + }); + + if (bPrint) + { + window.setTimeout(function () { + oPopupWin.print(); + }, 100); + } + } + }); + }; + + MessageModel.prototype.printMessage = function () + { + this.viewPopupMessage(true); + }; + + /** + * @returns {string} + */ + MessageModel.prototype.generateUid = function () + { + return this.folderFullNameRaw + '/' + this.uid; + }; + + /** + * @param {MessageModel} oMessage + * @return {MessageModel} + */ + MessageModel.prototype.populateByMessageListItem = function (oMessage) + { + this.folderFullNameRaw = oMessage.folderFullNameRaw; + this.uid = oMessage.uid; + this.hash = oMessage.hash; + this.requestHash = oMessage.requestHash; + this.subject(oMessage.subject()); + this.subjectPrefix(this.subjectPrefix()); + this.subjectSuffix(this.subjectSuffix()); + + this.size(oMessage.size()); + this.dateTimeStampInUTC(oMessage.dateTimeStampInUTC()); + this.priority(oMessage.priority()); + + this.proxy = oMessage.proxy; + + this.fromEmailString(oMessage.fromEmailString()); + this.fromClearEmailString(oMessage.fromClearEmailString()); + this.toEmailsString(oMessage.toEmailsString()); + this.toClearEmailsString(oMessage.toClearEmailsString()); + + this.emails = oMessage.emails; + + this.from = oMessage.from; + this.to = oMessage.to; + this.cc = oMessage.cc; + this.bcc = oMessage.bcc; + this.replyTo = oMessage.replyTo; + this.deliveredTo = oMessage.deliveredTo; + + this.unseen(oMessage.unseen()); + this.flagged(oMessage.flagged()); + this.answered(oMessage.answered()); + this.forwarded(oMessage.forwarded()); + this.isReadReceipt(oMessage.isReadReceipt()); + + this.selected(oMessage.selected()); + this.checked(oMessage.checked()); + this.hasAttachments(oMessage.hasAttachments()); + this.attachmentsMainType(oMessage.attachmentsMainType()); + + this.moment(oMessage.moment()); + + this.body = null; + + this.priority(Enums.MessagePriority.Normal); + this.aDraftInfo = []; + this.sMessageId = ''; + this.sInReplyTo = ''; + this.sReferences = ''; + + this.parentUid(oMessage.parentUid()); + this.threads(oMessage.threads()); + this.threadsLen(oMessage.threadsLen()); + + this.computeSenderEmail(); + + return this; + }; + + MessageModel.prototype.showExternalImages = function (bLazy) + { + if (this.body && this.body.data('rl-has-images')) + { + var sAttr = ''; + bLazy = Utils.isUnd(bLazy) ? false : bLazy; + + this.hasImages(false); + this.body.data('rl-has-images', false); + + sAttr = this.proxy ? 'data-x-additional-src' : 'data-x-src'; + $('[' + sAttr + ']', this.body).each(function () { + if (bLazy && $(this).is('img')) + { + $(this) + .addClass('lazy') + .attr('data-original', $(this).attr(sAttr)) + .removeAttr(sAttr) + ; + } + else + { + $(this).attr('src', $(this).attr(sAttr)).removeAttr(sAttr); + } + }); + + sAttr = this.proxy ? 'data-x-additional-style-url' : 'data-x-style-url'; + $('[' + sAttr + ']', this.body).each(function () { + var sStyle = Utils.trim($(this).attr('style')); + sStyle = '' === sStyle ? '' : (';' === sStyle.substr(-1) ? sStyle + ' ' : sStyle + '; '); + $(this).attr('style', sStyle + $(this).attr(sAttr)).removeAttr(sAttr); + }); + + if (bLazy) + { + $('img.lazy', this.body).addClass('lazy-inited').lazyload({ + 'threshold' : 400, + 'effect' : 'fadeIn', + 'skip_invisible' : false, + 'container': $('.RL-MailMessageView .messageView .messageItem .content')[0] + }); + + $window.resize(); + } + + Utils.windowResize(500); + } + }; + + MessageModel.prototype.showInternalImages = function (bLazy) + { + if (this.body && !this.body.data('rl-init-internal-images')) + { + this.body.data('rl-init-internal-images', true); + + bLazy = Utils.isUnd(bLazy) ? false : bLazy; + + var self = this; + + $('[data-x-src-cid]', this.body).each(function () { + + var oAttachment = self.findAttachmentByCid($(this).attr('data-x-src-cid')); + if (oAttachment && oAttachment.download) + { + if (bLazy && $(this).is('img')) + { + $(this) + .addClass('lazy') + .attr('data-original', oAttachment.linkPreview()); + } + else + { + $(this).attr('src', oAttachment.linkPreview()); + } + } + }); + + $('[data-x-src-location]', this.body).each(function () { + + var oAttachment = self.findAttachmentByContentLocation($(this).attr('data-x-src-location')); + if (!oAttachment) + { + oAttachment = self.findAttachmentByCid($(this).attr('data-x-src-location')); + } + + if (oAttachment && oAttachment.download) + { + if (bLazy && $(this).is('img')) + { + $(this) + .addClass('lazy') + .attr('data-original', oAttachment.linkPreview()); + } + else + { + $(this).attr('src', oAttachment.linkPreview()); + } + } + }); + + $('[data-x-style-cid]', this.body).each(function () { + + var + sStyle = '', + sName = '', + oAttachment = self.findAttachmentByCid($(this).attr('data-x-style-cid')) + ; + + if (oAttachment && oAttachment.linkPreview) + { + sName = $(this).attr('data-x-style-cid-name'); + if ('' !== sName) + { + sStyle = Utils.trim($(this).attr('style')); + sStyle = '' === sStyle ? '' : (';' === sStyle.substr(-1) ? sStyle + ' ' : sStyle + '; '); + $(this).attr('style', sStyle + sName + ': url(\'' + oAttachment.linkPreview() + '\')'); + } + } + }); + + if (bLazy) + { + (function ($oImg, oContainer) { + _.delay(function () { + $oImg.addClass('lazy-inited').lazyload({ + 'threshold' : 400, + 'effect' : 'fadeIn', + 'skip_invisible' : false, + 'container': oContainer + }); + }, 300); + }($('img.lazy', self.body), $('.RL-MailMessageView .messageView .messageItem .content')[0])); + } + + Utils.windowResize(500); + } + }; + + MessageModel.prototype.storeDataToDom = function () + { + if (this.body) + { + this.body.data('rl-is-html', !!this.isHtml()); + this.body.data('rl-has-images', !!this.hasImages()); + + this.body.data('rl-plain-raw', this.plainRaw); + + if (RL.data().capaOpenPGP()) // TODO cjs + { + this.body.data('rl-plain-pgp-signed', !!this.isPgpSigned()); + this.body.data('rl-plain-pgp-encrypted', !!this.isPgpEncrypted()); + this.body.data('rl-pgp-verify-status', this.pgpSignedVerifyStatus()); + this.body.data('rl-pgp-verify-user', this.pgpSignedVerifyUser()); + } + } + }; + + MessageModel.prototype.storePgpVerifyDataToDom = function () + { + if (this.body && RL.data().capaOpenPGP()) // TODO cjs + { + this.body.data('rl-pgp-verify-status', this.pgpSignedVerifyStatus()); + this.body.data('rl-pgp-verify-user', this.pgpSignedVerifyUser()); + } + }; + + MessageModel.prototype.fetchDataToDom = function () + { + if (this.body) + { + this.isHtml(!!this.body.data('rl-is-html')); + this.hasImages(!!this.body.data('rl-has-images')); + + this.plainRaw = Utils.pString(this.body.data('rl-plain-raw')); + + if (RL.data().capaOpenPGP()) // TODO cjs + { + this.isPgpSigned(!!this.body.data('rl-plain-pgp-signed')); + this.isPgpEncrypted(!!this.body.data('rl-plain-pgp-encrypted')); + this.pgpSignedVerifyStatus(this.body.data('rl-pgp-verify-status')); + this.pgpSignedVerifyUser(this.body.data('rl-pgp-verify-user')); + } + else + { + this.isPgpSigned(false); + this.isPgpEncrypted(false); + this.pgpSignedVerifyStatus(Enums.SignedVerifyStatus.None); + this.pgpSignedVerifyUser(''); + } + } + }; + + MessageModel.prototype.verifyPgpSignedClearMessage = function () + { + if (this.isPgpSigned()) + { + var + aRes = [], + mPgpMessage = null, + sFrom = this.from && this.from[0] && this.from[0].email ? this.from[0].email : '', + aPublicKeys = RL.data().findPublicKeysByEmail(sFrom), // TODO cjs + oValidKey = null, + oValidSysKey = null, + sPlain = '' + ; + + this.pgpSignedVerifyStatus(Enums.SignedVerifyStatus.Error); + this.pgpSignedVerifyUser(''); + + try + { + mPgpMessage = window.openpgp.cleartext.readArmored(this.plainRaw); + if (mPgpMessage && mPgpMessage.getText) + { + this.pgpSignedVerifyStatus( + aPublicKeys.length ? Enums.SignedVerifyStatus.Unverified : Enums.SignedVerifyStatus.UnknownPublicKeys); + + aRes = mPgpMessage.verify(aPublicKeys); + if (aRes && 0 < aRes.length) + { + oValidKey = _.find(aRes, function (oItem) { + return oItem && oItem.keyid && oItem.valid; + }); + + if (oValidKey) + { + oValidSysKey = RL.data().findPublicKeyByHex(oValidKey.keyid.toHex()); // TODO cjs + if (oValidSysKey) + { + sPlain = mPgpMessage.getText(); + + this.pgpSignedVerifyStatus(Enums.SignedVerifyStatus.Success); + this.pgpSignedVerifyUser(oValidSysKey.user); + + sPlain = + $div.empty().append( + $('
').text(sPlain)
+								   ).html()
+							   ;
+
+							   $div.empty();
+
+							   this.replacePlaneTextBody(sPlain);
+						   }
+					   }
+				   }
+			   }
+		   }
+		   catch (oExc) {}
+
+		   this.storePgpVerifyDataToDom();
+	   }
+	};
+
+	MessageModel.prototype.decryptPgpEncryptedMessage = function (sPassword)
+	{
+	   if (this.isPgpEncrypted())
+	   {
+		   var
+			   aRes = [],
+			   mPgpMessage = null,
+			   mPgpMessageDecrypted = null,
+			   sFrom = this.from && this.from[0] && this.from[0].email ? this.from[0].email : '',
+			   aPublicKey = RL.data().findPublicKeysByEmail(sFrom), // TODO cjs
+			   oPrivateKey = RL.data().findSelfPrivateKey(sPassword), // TODO cjs
+			   oValidKey = null,
+			   oValidSysKey = null,
+			   sPlain = ''
+		   ;
+
+		   this.pgpSignedVerifyStatus(Enums.SignedVerifyStatus.Error);
+		   this.pgpSignedVerifyUser('');
+
+		   if (!oPrivateKey)
+		   {
+			   this.pgpSignedVerifyStatus(Enums.SignedVerifyStatus.UnknownPrivateKey);
+		   }
+
+		   try
+		   {
+			   mPgpMessage = window.openpgp.message.readArmored(this.plainRaw);
+			   if (mPgpMessage && oPrivateKey && mPgpMessage.decrypt)
+			   {
+				   this.pgpSignedVerifyStatus(Enums.SignedVerifyStatus.Unverified);
+
+				   mPgpMessageDecrypted = mPgpMessage.decrypt(oPrivateKey);
+				   if (mPgpMessageDecrypted)
+				   {
+					   aRes = mPgpMessageDecrypted.verify(aPublicKey);
+					   if (aRes && 0 < aRes.length)
+					   {
+						   oValidKey = _.find(aRes, function (oItem) {
+							   return oItem && oItem.keyid && oItem.valid;
+						   });
+
+						   if (oValidKey)
+						   {
+							   oValidSysKey = RL.data().findPublicKeyByHex(oValidKey.keyid.toHex()); // TODO cjs
+							   if (oValidSysKey)
+							   {
+								   this.pgpSignedVerifyStatus(Enums.SignedVerifyStatus.Success);
+								   this.pgpSignedVerifyUser(oValidSysKey.user);
+							   }
+						   }
+					   }
+
+					   sPlain = mPgpMessageDecrypted.getText();
+
+					   sPlain =
+						   $div.empty().append(
+							   $('
').text(sPlain)
+						   ).html()
+					   ;
+
+					   $div.empty();
+
+					   this.replacePlaneTextBody(sPlain);
+				   }
+			   }
+		   }
+		   catch (oExc) {}
+
+		   this.storePgpVerifyDataToDom();
+	   }
+	};
+
+	MessageModel.prototype.replacePlaneTextBody = function (sPlain)
+	{
+	   if (this.body)
+	   {
+		   this.body.html(sPlain).addClass('b-text-part plain');
+	   }
+	};
+
+	/**
+	* @return {string}
+	*/
+	MessageModel.prototype.flagHash = function ()
+	{
+	   return [this.deleted(), this.unseen(), this.flagged(), this.answered(), this.forwarded(),
+		   this.isReadReceipt()].join('');
+	};
+
+	module.exports = MessageModel;
+
+}(module));
+},{"../Common/Enums.js":5,"../Common/LinkBuilder.js":7,"../Common/Utils.js":9,"../External/$div.js":10,"../External/$window.js":13,"../External/jquery.js":19,"../External/ko.js":21,"../External/moment.js":22,"../External/underscore.js":24,"../External/window.js":25,"./AttachmentModel.js":29,"./EmailModel.js":30}],32:[function(require,module,exports){
+/* RainLoop Webmail (c) RainLoop Team | Licensed under CC BY-NC-SA 3.0 */
+
+'use strict';
+
+module.exports = function () {
+	return require('./Knoin/Knoin.js').rl();
+};
+},{"./Knoin/Knoin.js":26}],33:[function(require,module,exports){
+/* RainLoop Webmail (c) RainLoop Team | Licensed under CC BY-NC-SA 3.0 */
+
+'use strict';
+
+module.exports = function () {
+	return require('./Knoin/Knoin.js').remote();
+};
+},{"./Knoin/Knoin.js":26}],34:[function(require,module,exports){
+/* RainLoop Webmail (c) RainLoop Team | Licensed under CC BY-NC-SA 3.0 */
+
+(function (module) {
+
+	'use strict';
+
+	var
+		window = require('../External/window.js'),
+		$ = require('../External/jquery.js'),
+
+		Consts = require('../Common/Consts.js'),
+		Enums = require('../Common/Enums.js'),
+		Globals = require('../Common/Globals.js'),
+		Utils = require('../Common/Utils.js'),
+		Plugins = require('../Common/Plugins.js'),
+		LinkBuilder = require('../Common/LinkBuilder.js'),
+
+		RL = require('../RL.js')
+	;
+
+	/**
+	* @constructor
+	*/
+   function AbstractAjaxRemoteStorage()
+   {
+	   this.oRequests = {};
+   }
+
+   AbstractAjaxRemoteStorage.prototype.oRequests = {};
+
+   /**
+	* @param {?Function} fCallback
+	* @param {string} sRequestAction
+	* @param {string} sType
+	* @param {?AjaxJsonDefaultResponse} oData
+	* @param {boolean} bCached
+	* @param {*=} oRequestParameters
+	*/
+   AbstractAjaxRemoteStorage.prototype.defaultResponse = function (fCallback, sRequestAction, sType, oData, bCached, oRequestParameters)
+   {
+	   var
+		   fCall = function () {
+			   if (Enums.StorageResultType.Success !== sType && Globals.bUnload)
+			   {
+				   sType = Enums.StorageResultType.Unload;
+			   }
+
+			   if (Enums.StorageResultType.Success === sType && oData && !oData.Result)
+			   {
+				   if (oData && -1 < Utils.inArray(oData.ErrorCode, [
+					   Enums.Notification.AuthError, Enums.Notification.AccessError,
+					   Enums.Notification.ConnectionError, Enums.Notification.DomainNotAllowed, Enums.Notification.AccountNotAllowed,
+					   Enums.Notification.MailServerError,	Enums.Notification.UnknownNotification, Enums.Notification.UnknownError
+				   ]))
+				   {
+					   Globals.iAjaxErrorCount++;
+				   }
+
+				   if (oData && Enums.Notification.InvalidToken === oData.ErrorCode)
+				   {
+					   Globals.iTokenErrorCount++;
+				   }
+
+				   if (Consts.Values.TokenErrorLimit < Globals.iTokenErrorCount)
+				   {
+					   RL().loginAndLogoutReload(true);
+				   }
+
+				   if (oData.Logout || Consts.Values.AjaxErrorLimit < Globals.iAjaxErrorCount)
+				   {
+					   if (window.__rlah_clear)
+					   {
+						   window.__rlah_clear();
+					   }
+
+					   RL().loginAndLogoutReload(true);
+				   }
+			   }
+			   else if (Enums.StorageResultType.Success === sType && oData && oData.Result)
+			   {
+				   Globals.iAjaxErrorCount = 0;
+				   Globals.iTokenErrorCount = 0;
+			   }
+
+			   if (fCallback)
+			   {
+				   Plugins.runHook('ajax-default-response', [sRequestAction, Enums.StorageResultType.Success === sType ? oData : null, sType, bCached, oRequestParameters]);
+
+				   fCallback(
+					   sType,
+					   Enums.StorageResultType.Success === sType ? oData : null,
+					   bCached,
+					   sRequestAction,
+					   oRequestParameters
+				   );
+			   }
+		   }
+	   ;
+
+	   switch (sType)
+	   {
+		   case 'success':
+			   sType = Enums.StorageResultType.Success;
+			   break;
+		   case 'abort':
+			   sType = Enums.StorageResultType.Abort;
+			   break;
+		   default:
+			   sType = Enums.StorageResultType.Error;
+			   break;
+	   }
+
+	   if (Enums.StorageResultType.Error === sType)
+	   {
+		   _.delay(fCall, 300);
+	   }
+	   else
+	   {
+		   fCall();
+	   }
+   };
+
+   /**
+	* @param {?Function} fResultCallback
+	* @param {Object} oParameters
+	* @param {?number=} iTimeOut = 20000
+	* @param {string=} sGetAdd = ''
+	* @param {Array=} aAbortActions = []
+	* @return {jQuery.jqXHR}
+	*/
+   AbstractAjaxRemoteStorage.prototype.ajaxRequest = function (fResultCallback, oParameters, iTimeOut, sGetAdd, aAbortActions)
+   {
+	   var
+		   self = this,
+		   bPost = '' === sGetAdd,
+		   oHeaders = {},
+		   iStart = (new window.Date()).getTime(),
+		   oDefAjax = null,
+		   sAction = ''
+	   ;
+
+	   oParameters = oParameters || {};
+	   iTimeOut = Utils.isNormal(iTimeOut) ? iTimeOut : 20000;
+	   sGetAdd = Utils.isUnd(sGetAdd) ? '' : Utils.pString(sGetAdd);
+	   aAbortActions = Utils.isArray(aAbortActions) ? aAbortActions : [];
+
+	   sAction = oParameters.Action || '';
+
+	   if (sAction && 0 < aAbortActions.length)
+	   {
+		   _.each(aAbortActions, function (sActionToAbort) {
+			   if (self.oRequests[sActionToAbort])
+			   {
+				   self.oRequests[sActionToAbort].__aborted = true;
+				   if (self.oRequests[sActionToAbort].abort)
+				   {
+					   self.oRequests[sActionToAbort].abort();
+				   }
+				   self.oRequests[sActionToAbort] = null;
+			   }
+		   });
+	   }
+
+	   if (bPost)
+	   {
+		   oParameters['XToken'] = RL.settingsGet('Token'); // TODO cjs
+	   }
+
+	   oDefAjax = $.ajax({
+		   'type': bPost ? 'POST' : 'GET',
+		   'url': LinkBuilder.ajax(sGetAdd),
+		   'async': true,
+		   'dataType': 'json',
+		   'data': bPost ? oParameters : {},
+		   'headers': oHeaders,
+		   'timeout': iTimeOut,
+		   'global': true
+	   });
+
+	   oDefAjax.always(function (oData, sType) {
+
+		   var bCached = false;
+		   if (oData && oData['Time'])
+		   {
+			   bCached = Utils.pInt(oData['Time']) > (new window.Date()).getTime() - iStart;
+		   }
+
+		   if (sAction && self.oRequests[sAction])
+		   {
+			   if (self.oRequests[sAction].__aborted)
+			   {
+				   sType = 'abort';
+			   }
+
+			   self.oRequests[sAction] = null;
+		   }
+
+		   self.defaultResponse(fResultCallback, sAction, sType, oData, bCached, oParameters);
+	   });
+
+	   if (sAction && 0 < aAbortActions.length && -1 < Utils.inArray(sAction, aAbortActions))
+	   {
+		   if (this.oRequests[sAction])
+		   {
+			   this.oRequests[sAction].__aborted = true;
+			   if (this.oRequests[sAction].abort)
+			   {
+				   this.oRequests[sAction].abort();
+			   }
+			   this.oRequests[sAction] = null;
+		   }
+
+		   this.oRequests[sAction] = oDefAjax;
+	   }
+
+	   return oDefAjax;
+   };
+
+   /**
+	* @param {?Function} fCallback
+	* @param {string} sAction
+	* @param {Object=} oParameters
+	* @param {?number=} iTimeout
+	* @param {string=} sGetAdd = ''
+	* @param {Array=} aAbortActions = []
+	*/
+   AbstractAjaxRemoteStorage.prototype.defaultRequest = function (fCallback, sAction, oParameters, iTimeout, sGetAdd, aAbortActions)
+   {
+	   oParameters = oParameters || {};
+	   oParameters.Action = sAction;
+
+	   sGetAdd = Utils.pString(sGetAdd);
+
+	   Plugins.runHook('ajax-default-request', [sAction, oParameters, sGetAdd]);
+
+	   this.ajaxRequest(fCallback, oParameters,
+		   Utils.isUnd(iTimeout) ? Consts.Defaults.DefaultAjaxTimeout : Utils.pInt(iTimeout), sGetAdd, aAbortActions);
+   };
+
+   /**
+	* @param {?Function} fCallback
+	*/
+   AbstractAjaxRemoteStorage.prototype.noop = function (fCallback)
+   {
+	   this.defaultRequest(fCallback, 'Noop');
+   };
+
+   /**
+	* @param {?Function} fCallback
+	* @param {string} sMessage
+	* @param {string} sFileName
+	* @param {number} iLineNo
+	* @param {string} sLocation
+	* @param {string} sHtmlCapa
+	* @param {number} iTime
+	*/
+   AbstractAjaxRemoteStorage.prototype.jsError = function (fCallback, sMessage, sFileName, iLineNo, sLocation, sHtmlCapa, iTime)
+   {
+	   this.defaultRequest(fCallback, 'JsError', {
+		   'Message': sMessage,
+		   'FileName': sFileName,
+		   'LineNo': iLineNo,
+		   'Location': sLocation,
+		   'HtmlCapa': sHtmlCapa,
+		   'TimeOnPage': iTime
+	   });
+   };
+
+   /**
+	* @param {?Function} fCallback
+	* @param {string} sType
+	* @param {Array=} mData = null
+	* @param {boolean=} bIsError = false
+	*/
+   AbstractAjaxRemoteStorage.prototype.jsInfo = function (fCallback, sType, mData, bIsError)
+   {
+	   this.defaultRequest(fCallback, 'JsInfo', {
+		   'Type': sType,
+		   'Data': mData,
+		   'IsError': (Utils.isUnd(bIsError) ? false : !!bIsError) ? '1' : '0'
+	   });
+   };
+
+   /**
+	* @param {?Function} fCallback
+	*/
+   AbstractAjaxRemoteStorage.prototype.getPublicKey = function (fCallback)
+   {
+	   this.defaultRequest(fCallback, 'GetPublicKey');
+   };
+
+   /**
+	* @param {?Function} fCallback
+	* @param {string} sVersion
+	*/
+   AbstractAjaxRemoteStorage.prototype.jsVersion = function (fCallback, sVersion)
+   {
+	   this.defaultRequest(fCallback, 'Version', {
+		   'Version': sVersion
+	   });
+   };
+
+	module.exports = AbstractAjaxRemoteStorage;
+
+}(module));
+},{"../Common/Consts.js":4,"../Common/Enums.js":5,"../Common/Globals.js":6,"../Common/LinkBuilder.js":7,"../Common/Plugins.js":8,"../Common/Utils.js":9,"../External/jquery.js":19,"../External/window.js":25,"../RL.js":32}],35:[function(require,module,exports){
+/* RainLoop Webmail (c) RainLoop Team | Licensed under CC BY-NC-SA 3.0 */
+
+(function (module) {
+
+	'use strict';
+
+	var
+		ko = require('../External/ko.js'),
+		key = require('../External/key.js'),
+		Enums = require('../Common/Enums.js'),
+		Globals = require('../Common/Globals.js'),
+		Utils = require('../Common/Utils.js')
+	;
+	
+	/**
+	 * @constructor
+	 */
+	function AbstractData()
+	{
+		this.leftPanelDisabled = ko.observable(false);
+		this.useKeyboardShortcuts = ko.observable(true);
+
+		this.keyScopeReal = ko.observable(Enums.KeyState.All);
+		this.keyScopeFake = ko.observable(Enums.KeyState.All);
+
+		this.keyScope = ko.computed({
+			'owner': this,
+			'read': function () {
+				return this.keyScopeFake();
+			},
+			'write': function (sValue) {
+
+				if (Enums.KeyState.Menu !== sValue)
+				{
+					if (Enums.KeyState.Compose === sValue)
+					{
+						Utils.disableKeyFilter();
+					}
+					else
+					{
+						Utils.restoreKeyFilter();
+					}
+
+					this.keyScopeFake(sValue);
+					if (Globals.dropdownVisibility())
+					{
+						sValue = Enums.KeyState.Menu;
+					}
+				}
+
+				this.keyScopeReal(sValue);
+			}
+		});
+
+		this.keyScopeReal.subscribe(function (sValue) {
+	//		window.console.log(sValue);
+			key.setScope(sValue);
+		});
+
+		this.leftPanelDisabled.subscribe(function (bValue) {
+			RL.pub('left-panel.' + (bValue ? 'off' : 'on')); // TODO cjs
+		});
+
+		Globals.dropdownVisibility.subscribe(function (bValue) {
+			if (bValue)
+			{
+				Globals.tooltipTrigger(!Globals.tooltipTrigger());
+				this.keyScope(Enums.KeyState.Menu);
+			}
+			else if (Enums.KeyState.Menu === key.getScope())
+			{
+				this.keyScope(this.keyScopeFake());
+			}
+		}, this);
+
+		Utils.initDataConstructorBySettings(this);
+	}
+
+	AbstractData.prototype.populateDataOnStart = function()
+	{
+		var
+			mLayout = Utils.pInt(RL.settingsGet('Layout')), // TODO cjs
+			aLanguages = RL.settingsGet('Languages'),
+			aThemes = RL.settingsGet('Themes')
+		;
+
+		if (Utils.isArray(aLanguages))
+		{
+			this.languages(aLanguages);
+		}
+
+		if (Utils.isArray(aThemes))
+		{
+			this.themes(aThemes);
+		}
+
+		this.mainLanguage(RL.settingsGet('Language'));
+		this.mainTheme(RL.settingsGet('Theme'));
+
+		this.capaAdditionalAccounts(RL.capa(Enums.Capa.AdditionalAccounts));
+		this.capaAdditionalIdentities(RL.capa(Enums.Capa.AdditionalIdentities));
+		this.capaGravatar(RL.capa(Enums.Capa.Gravatar));
+		this.determineUserLanguage(!!RL.settingsGet('DetermineUserLanguage'));
+		this.determineUserDomain(!!RL.settingsGet('DetermineUserDomain'));
+
+		this.capaThemes(RL.capa(Enums.Capa.Themes));
+		this.allowLanguagesOnLogin(!!RL.settingsGet('AllowLanguagesOnLogin'));
+		this.allowLanguagesOnSettings(!!RL.settingsGet('AllowLanguagesOnSettings'));
+		this.useLocalProxyForExternalImages(!!RL.settingsGet('UseLocalProxyForExternalImages'));
+
+		this.editorDefaultType(RL.settingsGet('EditorDefaultType'));
+		this.showImages(!!RL.settingsGet('ShowImages'));
+		this.contactsAutosave(!!RL.settingsGet('ContactsAutosave'));
+		this.interfaceAnimation(RL.settingsGet('InterfaceAnimation'));
+
+		this.mainMessagesPerPage(RL.settingsGet('MPP'));
+
+		this.desktopNotifications(!!RL.settingsGet('DesktopNotifications'));
+		this.useThreads(!!RL.settingsGet('UseThreads'));
+		this.replySameFolder(!!RL.settingsGet('ReplySameFolder'));
+		this.useCheckboxesInList(!!RL.settingsGet('UseCheckboxesInList'));
+
+		this.layout(Enums.Layout.SidePreview);
+		if (-1 < Utils.inArray(mLayout, [Enums.Layout.NoPreview, Enums.Layout.SidePreview, Enums.Layout.BottomPreview]))
+		{
+			this.layout(mLayout);
+		}
+		this.facebookSupported(!!RL.settingsGet('SupportedFacebookSocial'));
+		this.facebookEnable(!!RL.settingsGet('AllowFacebookSocial'));
+		this.facebookAppID(RL.settingsGet('FacebookAppID'));
+		this.facebookAppSecret(RL.settingsGet('FacebookAppSecret'));
+
+		this.twitterEnable(!!RL.settingsGet('AllowTwitterSocial'));
+		this.twitterConsumerKey(RL.settingsGet('TwitterConsumerKey'));
+		this.twitterConsumerSecret(RL.settingsGet('TwitterConsumerSecret'));
+
+		this.googleEnable(!!RL.settingsGet('AllowGoogleSocial'));
+		this.googleClientID(RL.settingsGet('GoogleClientID'));
+		this.googleClientSecret(RL.settingsGet('GoogleClientSecret'));
+		this.googleApiKey(RL.settingsGet('GoogleApiKey'));
+
+		this.dropboxEnable(!!RL.settingsGet('AllowDropboxSocial'));
+		this.dropboxApiKey(RL.settingsGet('DropboxApiKey'));
+
+		this.contactsIsAllowed(!!RL.settingsGet('ContactsIsAllowed'));
+	};
+
+	module.exports = AbstractData;
+
+}(module));
+},{"../Common/Enums.js":5,"../Common/Globals.js":6,"../Common/Utils.js":9,"../External/key.js":20,"../External/ko.js":21}],36:[function(require,module,exports){
+/* RainLoop Webmail (c) RainLoop Team | Licensed under CC BY-NC-SA 3.0 */
+
+(function (module) {
+
+	'use strict';
+
+	var
+		_ = require('../External/underscore.js'),
+		CookieDriver = require('./LocalStorages/CookieDriver.js'),
+		LocalStorageDriver = require('./LocalStorages/LocalStorageDriver.js')
+	;
+
+	/**
+	 * @constructor
+	 */
+	function LocalStorage()
+	{
+		var
+			NextStorageDriver = _.find([LocalStorageDriver, CookieDriver], function (NextStorageDriver) {
+				return NextStorageDriver.supported();
+			})
+		;
+
+		if (NextStorageDriver)
+		{
+			NextStorageDriver = /** @type {?Function} */ NextStorageDriver;
+			this.oDriver = new NextStorageDriver();
+		}
+	}
+
+	LocalStorage.prototype.oDriver = null;
+
+	/**
+	 * @param {number} iKey
+	 * @param {*} mData
+	 * @return {boolean}
+	 */
+	LocalStorage.prototype.set = function (iKey, mData)
+	{
+		return this.oDriver ? this.oDriver.set('p' + iKey, mData) : false;
+	};
+
+	/**
+	 * @param {number} iKey
+	 * @return {*}
+	 */
+	LocalStorage.prototype.get = function (iKey)
+	{
+		return this.oDriver ? this.oDriver.get('p' + iKey) : null;
+	};
+
+	module.exports = new LocalStorage();
+
+}(module));
+},{"../External/underscore.js":24,"./LocalStorages/CookieDriver.js":37,"./LocalStorages/LocalStorageDriver.js":38}],37:[function(require,module,exports){
+/* RainLoop Webmail (c) RainLoop Team | Licensed under CC BY-NC-SA 3.0 */
+
+(function (module) {
+
+	'use strict';
+
+	var
+		$ = require('../../External/jquery.js'),
+		JSON = require('../../External/JSON.js'),
+		Consts = require('../../Common/Consts.js'),
+		Utils = require('../../Common/Utils.js')
+	;
+
+	/**
+	 * @constructor
+	 */
+	function CookieDriver()
+	{
+
+	}
+
+	CookieDriver.supported = function ()
+	{
+		return true;
+	};
+
+	/**
+	 * @param {string} sKey
+	 * @param {*} mData
+	 * @returns {boolean}
+	 */
+	CookieDriver.prototype.set = function (sKey, mData)
+	{
+		var
+			mCokieValue = $.cookie(Consts.Values.ClientSideCookieIndexName),
+			bResult = false,
+			mResult = null
+		;
+
+		try
+		{
+			mResult = null === mCokieValue ? null : JSON.parse(mCokieValue);
+			if (!mResult)
+			{
+				mResult = {};
+			}
+
+			mResult[sKey] = mData;
+			$.cookie(Consts.Values.ClientSideCookieIndexName, JSON.stringify(mResult), {
+				'expires': 30
+			});
+
+			bResult = true;
+		}
+		catch (oException) {}
+
+		return bResult;
+	};
+
+	/**
+	 * @param {string} sKey
+	 * @returns {*}
+	 */
+	CookieDriver.prototype.get = function (sKey)
+	{
+		var
+			mCokieValue = $.cookie(Consts.Values.ClientSideCookieIndexName),
+			mResult = null
+		;
+
+		try
+		{
+			mResult = null === mCokieValue ? null : JSON.parse(mCokieValue);
+			if (mResult && !Utils.isUnd(mResult[sKey]))
+			{
+				mResult = mResult[sKey];
+			}
+			else
+			{
+				mResult = null;
+			}
+		}
+		catch (oException) {}
+
+		return mResult;
+	};
+
+	module.exports = CookieDriver;
+
+}(module));
+},{"../../Common/Consts.js":4,"../../Common/Utils.js":9,"../../External/JSON.js":15,"../../External/jquery.js":19}],38:[function(require,module,exports){
+/* RainLoop Webmail (c) RainLoop Team | Licensed under CC BY-NC-SA 3.0 */
+
+(function (module) {
+
+	'use strict';
+
+	var
+		window = require('../../External/window.js'),
+		JSON = require('../../External/JSON.js'),
+		Consts = require('../../Common/Consts.js'),
+		Utils = require('../../Common/Utils.js')
+	;
+
+	/**
+	 * @constructor
+	 */
+	function LocalStorageDriver()
+	{
+	}
+
+	LocalStorageDriver.supported = function ()
+	{
+		return !!window.localStorage;
+	};
+
+	/**
+	 * @param {string} sKey
+	 * @param {*} mData
+	 * @returns {boolean}
+	 */
+	LocalStorageDriver.prototype.set = function (sKey, mData)
+	{
+		var
+			mCookieValue = window.localStorage[Consts.Values.ClientSideCookieIndexName] || null,
+			bResult = false,
+			mResult = null
+		;
+
+		try
+		{
+			mResult = null === mCookieValue ? null : JSON.parse(mCookieValue);
+			if (!mResult)
+			{
+				mResult = {};
+			}
+
+			mResult[sKey] = mData;
+			window.localStorage[Consts.Values.ClientSideCookieIndexName] = JSON.stringify(mResult);
+
+			bResult = true;
+		}
+		catch (oException) {}
+
+		return bResult;
+	};
+
+	/**
+	 * @param {string} sKey
+	 * @returns {*}
+	 */
+	LocalStorageDriver.prototype.get = function (sKey)
+	{
+		var
+			mCokieValue = window.localStorage[Consts.Values.ClientSideCookieIndexName] || null,
+			mResult = null
+		;
+
+		try
+		{
+			mResult = null === mCokieValue ? null : JSON.parse(mCokieValue);
+			if (mResult && !Utils.isUnd(mResult[sKey]))
+			{
+				mResult = mResult[sKey];
+			}
+			else
+			{
+				mResult = null;
+			}
+		}
+		catch (oException) {}
+
+		return mResult;
+	};
+	
+	module.exports = LocalStorageDriver;
+
+}(module));
+},{"../../Common/Consts.js":4,"../../Common/Utils.js":9,"../../External/JSON.js":15,"../../External/window.js":25}],39:[function(require,module,exports){
+/* RainLoop Webmail (c) RainLoop Team | Licensed under CC BY-NC-SA 3.0 */
+
+(function (module) {
+
+	'use strict';
+
+	var
+		_ = require('../External/underscore.js'),
+
+		Utils = require('../Common/Utils.js'),
+
+		Cache = require('../Storages/WebMailCacheStorage.js'),
+		
+		AbstractAjaxRemoteStorage = require('./AbstractAjaxRemoteStorage.js')
+	;
+
+	/**
+	 * @constructor
+	 * @extends AbstractAjaxRemoteStorage
+	 */
+	function WebMailAjaxRemoteStorage()
+	{
+		AbstractAjaxRemoteStorage.call(this);
+
+		this.oRequests = {};
+	}
+
+	_.extend(WebMailAjaxRemoteStorage.prototype, AbstractAjaxRemoteStorage.prototype);
+
+	/**
+	 * @param {?Function} fCallback
+	 */
+	WebMailAjaxRemoteStorage.prototype.folders = function (fCallback)
+	{
+		this.defaultRequest(fCallback, 'Folders', {
+			'SentFolder': RL.settingsGet('SentFolder'),
+			'DraftFolder': RL.settingsGet('DraftFolder'),
+			'SpamFolder': RL.settingsGet('SpamFolder'),
+			'TrashFolder': RL.settingsGet('TrashFolder'),
+			'ArchiveFolder': RL.settingsGet('ArchiveFolder')
+		}, null, '', ['Folders']);
+	};
+
+	/**
+	 * @param {?Function} fCallback
+	 * @param {string} sEmail
+	 * @param {string} sLogin
+	 * @param {string} sPassword
+	 * @param {boolean} bSignMe
+	 * @param {string=} sLanguage
+	 * @param {string=} sAdditionalCode
+	 * @param {boolean=} bAdditionalCodeSignMe
+	 */
+	WebMailAjaxRemoteStorage.prototype.login = function (fCallback, sEmail, sLogin, sPassword, bSignMe, sLanguage, sAdditionalCode, bAdditionalCodeSignMe)
+	{
+		this.defaultRequest(fCallback, 'Login', {
+			'Email': sEmail,
+			'Login': sLogin,
+			'Password': sPassword,
+			'Language': sLanguage || '',
+			'AdditionalCode': sAdditionalCode || '',
+			'AdditionalCodeSignMe': bAdditionalCodeSignMe ? '1' : '0',
+			'SignMe': bSignMe ? '1' : '0'
+		});
+	};
+
+	/**
+	 * @param {?Function} fCallback
+	 */
+	WebMailAjaxRemoteStorage.prototype.getTwoFactor = function (fCallback)
+	{
+		this.defaultRequest(fCallback, 'GetTwoFactorInfo');
+	};
+
+	/**
+	 * @param {?Function} fCallback
+	 */
+	WebMailAjaxRemoteStorage.prototype.createTwoFactor = function (fCallback)
+	{
+		this.defaultRequest(fCallback, 'CreateTwoFactorSecret');
+	};
+
+	/**
+	 * @param {?Function} fCallback
+	 */
+	WebMailAjaxRemoteStorage.prototype.clearTwoFactor = function (fCallback)
+	{
+		this.defaultRequest(fCallback, 'ClearTwoFactorInfo');
+	};
+
+	/**
+	 * @param {?Function} fCallback
+	 */
+	WebMailAjaxRemoteStorage.prototype.showTwoFactorSecret = function (fCallback)
+	{
+		this.defaultRequest(fCallback, 'ShowTwoFactorSecret');
+	};
+
+	/**
+	 * @param {?Function} fCallback
+	 * @param {string} sCode
+	 */
+	WebMailAjaxRemoteStorage.prototype.testTwoFactor = function (fCallback, sCode)
+	{
+		this.defaultRequest(fCallback, 'TestTwoFactorInfo', {
+			'Code': sCode
+		});
+	};
+
+	/**
+	 * @param {?Function} fCallback
+	 * @param {boolean} bEnable
+	 */
+	WebMailAjaxRemoteStorage.prototype.enableTwoFactor = function (fCallback, bEnable)
+	{
+		this.defaultRequest(fCallback, 'EnableTwoFactor', {
+			'Enable': bEnable ? '1' : '0'
+		});
+	};
+
+	/**
+	 * @param {?Function} fCallback
+	 */
+	WebMailAjaxRemoteStorage.prototype.clearTwoFactorInfo = function (fCallback)
+	{
+		this.defaultRequest(fCallback, 'ClearTwoFactorInfo');
+	};
+
+	/**
+	 * @param {?Function} fCallback
+	 */
+	WebMailAjaxRemoteStorage.prototype.contactsSync = function (fCallback)
+	{
+		this.defaultRequest(fCallback, 'ContactsSync', null, Consts.Defaults.ContactsSyncAjaxTimeout);
+	};
+
+	/**
+	 * @param {?Function} fCallback
+	 * @param {boolean} bEnable
+	 * @param {string} sUrl
+	 * @param {string} sUser
+	 * @param {string} sPassword
+	 */
+	WebMailAjaxRemoteStorage.prototype.saveContactsSyncData = function (fCallback, bEnable, sUrl, sUser, sPassword)
+	{
+		this.defaultRequest(fCallback, 'SaveContactsSyncData', {
+			'Enable': bEnable ? '1' : '0',
+			'Url': sUrl,
+			'User': sUser,
+			'Password': sPassword
+		});
+	};
+
+	/**
+	 * @param {?Function} fCallback
+	 * @param {string} sEmail
+	 * @param {string} sLogin
+	 * @param {string} sPassword
+	 */
+	WebMailAjaxRemoteStorage.prototype.accountAdd = function (fCallback, sEmail, sLogin, sPassword)
+	{
+		this.defaultRequest(fCallback, 'AccountAdd', {
+			'Email': sEmail,
+			'Login': sLogin,
+			'Password': sPassword
+		});
+	};
+
+	/**
+	 * @param {?Function} fCallback
+	 * @param {string} sEmailToDelete
+	 */
+	WebMailAjaxRemoteStorage.prototype.accountDelete = function (fCallback, sEmailToDelete)
+	{
+		this.defaultRequest(fCallback, 'AccountDelete', {
+			'EmailToDelete': sEmailToDelete
+		});
+	};
+
+	/**
+	 * @param {?Function} fCallback
+	 * @param {string} sId
+	 * @param {string} sEmail
+	 * @param {string} sName
+	 * @param {string} sReplyTo
+	 * @param {string} sBcc
+	 */
+	WebMailAjaxRemoteStorage.prototype.identityUpdate = function (fCallback, sId, sEmail, sName, sReplyTo, sBcc)
+	{
+		this.defaultRequest(fCallback, 'IdentityUpdate', {
+			'Id': sId,
+			'Email': sEmail,
+			'Name': sName,
+			'ReplyTo': sReplyTo,
+			'Bcc': sBcc
+		});
+	};
+
+	/**
+	 * @param {?Function} fCallback
+	 * @param {string} sIdToDelete
+	 */
+	WebMailAjaxRemoteStorage.prototype.identityDelete = function (fCallback, sIdToDelete)
+	{
+		this.defaultRequest(fCallback, 'IdentityDelete', {
+			'IdToDelete': sIdToDelete
+		});
+	};
+
+	/**
+	 * @param {?Function} fCallback
+	 */
+	WebMailAjaxRemoteStorage.prototype.accountsAndIdentities = function (fCallback)
+	{
+		this.defaultRequest(fCallback, 'AccountsAndIdentities');
+	};
+
+	/**
+	 * @param {?Function} fCallback
+	 * @param {string} sFolderFullNameRaw
+	 * @param {number=} iOffset = 0
+	 * @param {number=} iLimit = 20
+	 * @param {string=} sSearch = ''
+	 * @param {boolean=} bSilent = false
+	 */
+	WebMailAjaxRemoteStorage.prototype.messageList = function (fCallback, sFolderFullNameRaw, iOffset, iLimit, sSearch, bSilent)
+	{
+		sFolderFullNameRaw = Utils.pString(sFolderFullNameRaw);
+
+		var
+			oData = RL.data(),
+			sFolderHash = Cache.getFolderHash(sFolderFullNameRaw)
+		;
+
+		bSilent = Utils.isUnd(bSilent) ? false : !!bSilent;
+		iOffset = Utils.isUnd(iOffset) ? 0 : Utils.pInt(iOffset);
+		iLimit = Utils.isUnd(iOffset) ? 20 : Utils.pInt(iLimit);
+		sSearch = Utils.pString(sSearch);
+
+		if ('' !== sFolderHash && ('' === sSearch || -1 === sSearch.indexOf('is:')))
+		{
+			this.defaultRequest(fCallback, 'MessageList', {},
+				'' === sSearch ? Consts.Defaults.DefaultAjaxTimeout : Consts.Defaults.SearchAjaxTimeout,
+				'MessageList/' + Base64.urlsafe_encode([
+					sFolderFullNameRaw,
+					iOffset,
+					iLimit,
+					sSearch,
+					oData.projectHash(),
+					sFolderHash,
+					'INBOX' === sFolderFullNameRaw ? Cache.getFolderUidNext(sFolderFullNameRaw) : '',
+					oData.threading() && oData.useThreads() ? '1' : '0',
+					oData.threading() && sFolderFullNameRaw === oData.messageListThreadFolder() ? oData.messageListThreadUids().join(',') : ''
+				].join(String.fromCharCode(0))), bSilent ? [] : ['MessageList']);
+		}
+		else
+		{
+			this.defaultRequest(fCallback, 'MessageList', {
+				'Folder': sFolderFullNameRaw,
+				'Offset': iOffset,
+				'Limit': iLimit,
+				'Search': sSearch,
+				'UidNext': 'INBOX' === sFolderFullNameRaw ? Cache.getFolderUidNext(sFolderFullNameRaw) : '',
+				'UseThreads': RL.data().threading() && RL.data().useThreads() ? '1' : '0',
+				'ExpandedThreadUid': oData.threading() && sFolderFullNameRaw === oData.messageListThreadFolder() ? oData.messageListThreadUids().join(',') : ''
+			}, '' === sSearch ? Consts.Defaults.DefaultAjaxTimeout : Consts.Defaults.SearchAjaxTimeout, '', bSilent ? [] : ['MessageList']);
+		}
+	};
+
+	/**
+	 * @param {?Function} fCallback
+	 * @param {Array} aDownloads
+	 */
+	WebMailAjaxRemoteStorage.prototype.messageUploadAttachments = function (fCallback, aDownloads)
+	{
+		this.defaultRequest(fCallback, 'MessageUploadAttachments', {
+			'Attachments': aDownloads
+		}, 999000);
+	};
+
+	/**
+	 * @param {?Function} fCallback
+	 * @param {string} sFolderFullNameRaw
+	 * @param {number} iUid
+	 * @return {boolean}
+	 */
+	WebMailAjaxRemoteStorage.prototype.message = function (fCallback, sFolderFullNameRaw, iUid)
+	{
+		sFolderFullNameRaw = Utils.pString(sFolderFullNameRaw);
+		iUid = Utils.pInt(iUid);
+
+		if (Cache.getFolderFromCacheList(sFolderFullNameRaw) && 0 < iUid)
+		{
+			this.defaultRequest(fCallback, 'Message', {}, null,
+				'Message/' + Base64.urlsafe_encode([
+					sFolderFullNameRaw,
+					iUid,
+					RL.data().projectHash(),
+					RL.data().threading() && RL.data().useThreads() ? '1' : '0'
+				].join(String.fromCharCode(0))), ['Message']);
+
+			return true;
+		}
+
+		return false;
+	};
+
+	/**
+	 * @param {?Function} fCallback
+	 * @param {Array} aExternals
+	 */
+	WebMailAjaxRemoteStorage.prototype.composeUploadExternals = function (fCallback, aExternals)
+	{
+		this.defaultRequest(fCallback, 'ComposeUploadExternals', {
+			'Externals': aExternals
+		}, 999000);
+	};
+
+	/**
+	 * @param {?Function} fCallback
+	 * @param {string} sUrl
+	 * @param {string} sAccessToken
+	 */
+	WebMailAjaxRemoteStorage.prototype.composeUploadDrive = function (fCallback, sUrl, sAccessToken)
+	{
+		this.defaultRequest(fCallback, 'ComposeUploadDrive', {
+			'AccessToken': sAccessToken,
+			'Url': sUrl
+		}, 999000);
+	};
+
+	/**
+	 * @param {?Function} fCallback
+	 * @param {string} sFolder
+	 * @param {Array=} aList = []
+	 */
+	WebMailAjaxRemoteStorage.prototype.folderInformation = function (fCallback, sFolder, aList)
+	{
+		var
+			bRequest = true,
+			aUids = []
+		;
+
+		if (Utils.isArray(aList) && 0 < aList.length)
+		{
+			bRequest = false;
+			_.each(aList, function (oMessageListItem) {
+				if (!Cache.getMessageFlagsFromCache(oMessageListItem.folderFullNameRaw, oMessageListItem.uid))
+				{
+					aUids.push(oMessageListItem.uid);
+				}
+
+				if (0 < oMessageListItem.threads().length)
+				{
+					_.each(oMessageListItem.threads(), function (sUid) {
+						if (!Cache.getMessageFlagsFromCache(oMessageListItem.folderFullNameRaw, sUid))
+						{
+							aUids.push(sUid);
+						}
+					});
+				}
+			});
+
+			if (0 < aUids.length)
+			{
+				bRequest = true;
+			}
+		}
+
+		if (bRequest)
+		{
+			this.defaultRequest(fCallback, 'FolderInformation', {
+				'Folder': sFolder,
+				'FlagsUids': Utils.isArray(aUids) ? aUids.join(',') : '',
+				'UidNext': 'INBOX' === sFolder ? Cache.getFolderUidNext(sFolder) : ''
+			});
+		}
+		else if (RL.data().useThreads())
+		{
+			RL.reloadFlagsCurrentMessageListAndMessageFromCache();
+		}
+	};
+
+	/**
+	 * @param {?Function} fCallback
+	 * @param {Array} aFolders
+	 */
+	WebMailAjaxRemoteStorage.prototype.folderInformationMultiply = function (fCallback, aFolders)
+	{
+		this.defaultRequest(fCallback, 'FolderInformationMultiply', {
+			'Folders': aFolders
+		});
+	};
+
+	/**
+	 * @param {?Function} fCallback
+	 */
+	WebMailAjaxRemoteStorage.prototype.logout = function (fCallback)
+	{
+		this.defaultRequest(fCallback, 'Logout');
+	};
+
+	/**
+	 * @param {?Function} fCallback
+	 * @param {string} sFolderFullNameRaw
+	 * @param {Array} aUids
+	 * @param {boolean} bSetFlagged
+	 */
+	WebMailAjaxRemoteStorage.prototype.messageSetFlagged = function (fCallback, sFolderFullNameRaw, aUids, bSetFlagged)
+	{
+		this.defaultRequest(fCallback, 'MessageSetFlagged', {
+			'Folder': sFolderFullNameRaw,
+			'Uids': aUids.join(','),
+			'SetAction': bSetFlagged ? '1' : '0'
+		});
+	};
+
+	/**
+	 * @param {?Function} fCallback
+	 * @param {string} sFolderFullNameRaw
+	 * @param {Array} aUids
+	 * @param {boolean} bSetSeen
+	 */
+	WebMailAjaxRemoteStorage.prototype.messageSetSeen = function (fCallback, sFolderFullNameRaw, aUids, bSetSeen)
+	{
+		this.defaultRequest(fCallback, 'MessageSetSeen', {
+			'Folder': sFolderFullNameRaw,
+			'Uids': aUids.join(','),
+			'SetAction': bSetSeen ? '1' : '0'
+		});
+	};
+
+	/**
+	 * @param {?Function} fCallback
+	 * @param {string} sFolderFullNameRaw
+	 * @param {boolean} bSetSeen
+	 */
+	WebMailAjaxRemoteStorage.prototype.messageSetSeenToAll = function (fCallback, sFolderFullNameRaw, bSetSeen)
+	{
+		this.defaultRequest(fCallback, 'MessageSetSeenToAll', {
+			'Folder': sFolderFullNameRaw,
+			'SetAction': bSetSeen ? '1' : '0'
+		});
+	};
+
+	/**
+	 * @param {?Function} fCallback
+	 * @param {string} sMessageFolder
+	 * @param {string} sMessageUid
+	 * @param {string} sDraftFolder
+	 * @param {string} sFrom
+	 * @param {string} sTo
+	 * @param {string} sCc
+	 * @param {string} sBcc
+	 * @param {string} sSubject
+	 * @param {boolean} bTextIsHtml
+	 * @param {string} sText
+	 * @param {Array} aAttachments
+	 * @param {(Array|null)} aDraftInfo
+	 * @param {string} sInReplyTo
+	 * @param {string} sReferences
+	 */
+	WebMailAjaxRemoteStorage.prototype.saveMessage = function (fCallback, sMessageFolder, sMessageUid, sDraftFolder,
+		sFrom, sTo, sCc, sBcc, sSubject, bTextIsHtml, sText, aAttachments, aDraftInfo, sInReplyTo, sReferences)
+	{
+		this.defaultRequest(fCallback, 'SaveMessage', {
+			'MessageFolder': sMessageFolder,
+			'MessageUid': sMessageUid,
+			'DraftFolder': sDraftFolder,
+			'From': sFrom,
+			'To': sTo,
+			'Cc': sCc,
+			'Bcc': sBcc,
+			'Subject': sSubject,
+			'TextIsHtml': bTextIsHtml ? '1' : '0',
+			'Text': sText,
+			'DraftInfo': aDraftInfo,
+			'InReplyTo': sInReplyTo,
+			'References': sReferences,
+			'Attachments': aAttachments
+		}, Consts.Defaults.SaveMessageAjaxTimeout);
+	};
+
+
+	/**
+	 * @param {?Function} fCallback
+	 * @param {string} sMessageFolder
+	 * @param {string} sMessageUid
+	 * @param {string} sReadReceipt
+	 * @param {string} sSubject
+	 * @param {string} sText
+	 */
+	WebMailAjaxRemoteStorage.prototype.sendReadReceiptMessage = function (fCallback, sMessageFolder, sMessageUid, sReadReceipt, sSubject, sText)
+	{
+		this.defaultRequest(fCallback, 'SendReadReceiptMessage', {
+			'MessageFolder': sMessageFolder,
+			'MessageUid': sMessageUid,
+			'ReadReceipt': sReadReceipt,
+			'Subject': sSubject,
+			'Text': sText
+		});
+	};
+
+	/**
+	 * @param {?Function} fCallback
+	 * @param {string} sMessageFolder
+	 * @param {string} sMessageUid
+	 * @param {string} sSentFolder
+	 * @param {string} sFrom
+	 * @param {string} sTo
+	 * @param {string} sCc
+	 * @param {string} sBcc
+	 * @param {string} sSubject
+	 * @param {boolean} bTextIsHtml
+	 * @param {string} sText
+	 * @param {Array} aAttachments
+	 * @param {(Array|null)} aDraftInfo
+	 * @param {string} sInReplyTo
+	 * @param {string} sReferences
+	 * @param {boolean} bRequestReadReceipt
+	 */
+	WebMailAjaxRemoteStorage.prototype.sendMessage = function (fCallback, sMessageFolder, sMessageUid, sSentFolder,
+		sFrom, sTo, sCc, sBcc, sSubject, bTextIsHtml, sText, aAttachments, aDraftInfo, sInReplyTo, sReferences, bRequestReadReceipt)
+	{
+		this.defaultRequest(fCallback, 'SendMessage', {
+			'MessageFolder': sMessageFolder,
+			'MessageUid': sMessageUid,
+			'SentFolder': sSentFolder,
+			'From': sFrom,
+			'To': sTo,
+			'Cc': sCc,
+			'Bcc': sBcc,
+			'Subject': sSubject,
+			'TextIsHtml': bTextIsHtml ? '1' : '0',
+			'Text': sText,
+			'DraftInfo': aDraftInfo,
+			'InReplyTo': sInReplyTo,
+			'References': sReferences,
+			'ReadReceiptRequest': bRequestReadReceipt ? '1' : '0',
+			'Attachments': aAttachments
+		}, Consts.Defaults.SendMessageAjaxTimeout);
+	};
+
+	/**
+	 * @param {?Function} fCallback
+	 * @param {Object} oData
+	 */
+	WebMailAjaxRemoteStorage.prototype.saveSystemFolders = function (fCallback, oData)
+	{
+		this.defaultRequest(fCallback, 'SystemFoldersUpdate', oData);
+	};
+
+	/**
+	 * @param {?Function} fCallback
+	 * @param {Object} oData
+	 */
+	WebMailAjaxRemoteStorage.prototype.saveSettings = function (fCallback, oData)
+	{
+		this.defaultRequest(fCallback, 'SettingsUpdate', oData);
+	};
+
+	/**
+	 * @param {?Function} fCallback
+	 * @param {string} sPrevPassword
+	 * @param {string} sNewPassword
+	 */
+	WebMailAjaxRemoteStorage.prototype.changePassword = function (fCallback, sPrevPassword, sNewPassword)
+	{
+		this.defaultRequest(fCallback, 'ChangePassword', {
+			'PrevPassword': sPrevPassword,
+			'NewPassword': sNewPassword
+		});
+	};
+
+	/**
+	 * @param {?Function} fCallback
+	 * @param {string} sNewFolderName
+	 * @param {string} sParentName
+	 */
+	WebMailAjaxRemoteStorage.prototype.folderCreate = function (fCallback, sNewFolderName, sParentName)
+	{
+		this.defaultRequest(fCallback, 'FolderCreate', {
+			'Folder': sNewFolderName,
+			'Parent': sParentName
+		}, null, '', ['Folders']);
+	};
+
+	/**
+	 * @param {?Function} fCallback
+	 * @param {string} sFolderFullNameRaw
+	 */
+	WebMailAjaxRemoteStorage.prototype.folderDelete = function (fCallback, sFolderFullNameRaw)
+	{
+		this.defaultRequest(fCallback, 'FolderDelete', {
+			'Folder': sFolderFullNameRaw
+		}, null, '', ['Folders']);
+	};
+
+	/**
+	 * @param {?Function} fCallback
+	 * @param {string} sPrevFolderFullNameRaw
+	 * @param {string} sNewFolderName
+	 */
+	WebMailAjaxRemoteStorage.prototype.folderRename = function (fCallback, sPrevFolderFullNameRaw, sNewFolderName)
+	{
+		this.defaultRequest(fCallback, 'FolderRename', {
+			'Folder': sPrevFolderFullNameRaw,
+			'NewFolderName': sNewFolderName
+		}, null, '', ['Folders']);
+	};
+
+	/**
+	 * @param {?Function} fCallback
+	 * @param {string} sFolderFullNameRaw
+	 */
+	WebMailAjaxRemoteStorage.prototype.folderClear = function (fCallback, sFolderFullNameRaw)
+	{
+		this.defaultRequest(fCallback, 'FolderClear', {
+			'Folder': sFolderFullNameRaw
+		});
+	};
+
+	/**
+	 * @param {?Function} fCallback
+	 * @param {string} sFolderFullNameRaw
+	 * @param {boolean} bSubscribe
+	 */
+	WebMailAjaxRemoteStorage.prototype.folderSetSubscribe = function (fCallback, sFolderFullNameRaw, bSubscribe)
+	{
+		this.defaultRequest(fCallback, 'FolderSubscribe', {
+			'Folder': sFolderFullNameRaw,
+			'Subscribe': bSubscribe ? '1' : '0'
+		});
+	};
+
+	/**
+	 * @param {?Function} fCallback
+	 * @param {string} sFolder
+	 * @param {string} sToFolder
+	 * @param {Array} aUids
+	 * @param {string=} sLearning
+	 */
+	WebMailAjaxRemoteStorage.prototype.messagesMove = function (fCallback, sFolder, sToFolder, aUids, sLearning)
+	{
+		this.defaultRequest(fCallback, 'MessageMove', {
+			'FromFolder': sFolder,
+			'ToFolder': sToFolder,
+			'Uids': aUids.join(','),
+			'Learning': sLearning || ''
+		}, null, '', ['MessageList']);
+	};
+
+	/**
+	 * @param {?Function} fCallback
+	 * @param {string} sFolder
+	 * @param {string} sToFolder
+	 * @param {Array} aUids
+	 */
+	WebMailAjaxRemoteStorage.prototype.messagesCopy = function (fCallback, sFolder, sToFolder, aUids)
+	{
+		this.defaultRequest(fCallback, 'MessageCopy', {
+			'FromFolder': sFolder,
+			'ToFolder': sToFolder,
+			'Uids': aUids.join(',')
+		});
+	};
+
+	/**
+	 * @param {?Function} fCallback
+	 * @param {string} sFolder
+	 * @param {Array} aUids
+	 */
+	WebMailAjaxRemoteStorage.prototype.messagesDelete = function (fCallback, sFolder, aUids)
+	{
+		this.defaultRequest(fCallback, 'MessageDelete', {
+			'Folder': sFolder,
+			'Uids': aUids.join(',')
+		}, null, '', ['MessageList']);
+	};
+
+	/**
+	 * @param {?Function} fCallback
+	 */
+	WebMailAjaxRemoteStorage.prototype.appDelayStart = function (fCallback)
+	{
+		this.defaultRequest(fCallback, 'AppDelayStart');
+	};
+
+	/**
+	 * @param {?Function} fCallback
+	 */
+	WebMailAjaxRemoteStorage.prototype.quota = function (fCallback)
+	{
+		this.defaultRequest(fCallback, 'Quota');
+	};
+
+	/**
+	 * @param {?Function} fCallback
+	 * @param {number} iOffset
+	 * @param {number} iLimit
+	 * @param {string} sSearch
+	 */
+	WebMailAjaxRemoteStorage.prototype.contacts = function (fCallback, iOffset, iLimit, sSearch)
+	{
+		this.defaultRequest(fCallback, 'Contacts', {
+			'Offset': iOffset,
+			'Limit': iLimit,
+			'Search': sSearch
+		}, null, '', ['Contacts']);
+	};
+
+	/**
+	 * @param {?Function} fCallback
+	 */
+	WebMailAjaxRemoteStorage.prototype.contactSave = function (fCallback, sRequestUid, sUid, sTags, aProperties)
+	{
+		this.defaultRequest(fCallback, 'ContactSave', {
+			'RequestUid': sRequestUid,
+			'Uid': Utils.trim(sUid),
+			'Tags': Utils.trim(sTags),
+			'Properties': aProperties
+		});
+	};
+
+	/**
+	 * @param {?Function} fCallback
+	 * @param {Array} aUids
+	 */
+	WebMailAjaxRemoteStorage.prototype.contactsDelete = function (fCallback, aUids)
+	{
+		this.defaultRequest(fCallback, 'ContactsDelete', {
+			'Uids': aUids.join(',')
+		});
+	};
+
+	/**
+	 * @param {?Function} fCallback
+	 * @param {string} sQuery
+	 * @param {number} iPage
+	 */
+	WebMailAjaxRemoteStorage.prototype.suggestions = function (fCallback, sQuery, iPage)
+	{
+		this.defaultRequest(fCallback, 'Suggestions', {
+			'Query': sQuery,
+			'Page': iPage
+		}, null, '', ['Suggestions']);
+	};
+
+	/**
+	 * @param {?Function} fCallback
+	 */
+	WebMailAjaxRemoteStorage.prototype.facebookUser = function (fCallback)
+	{
+		this.defaultRequest(fCallback, 'SocialFacebookUserInformation');
+	};
+
+	/**
+	 * @param {?Function} fCallback
+	 */
+	WebMailAjaxRemoteStorage.prototype.facebookDisconnect = function (fCallback)
+	{
+		this.defaultRequest(fCallback, 'SocialFacebookDisconnect');
+	};
+
+	/**
+	 * @param {?Function} fCallback
+	 */
+	WebMailAjaxRemoteStorage.prototype.twitterUser = function (fCallback)
+	{
+		this.defaultRequest(fCallback, 'SocialTwitterUserInformation');
+	};
+
+	/**
+	 * @param {?Function} fCallback
+	 */
+	WebMailAjaxRemoteStorage.prototype.twitterDisconnect = function (fCallback)
+	{
+		this.defaultRequest(fCallback, 'SocialTwitterDisconnect');
+	};
+
+	/**
+	 * @param {?Function} fCallback
+	 */
+	WebMailAjaxRemoteStorage.prototype.googleUser = function (fCallback)
+	{
+		this.defaultRequest(fCallback, 'SocialGoogleUserInformation');
+	};
+
+	/**
+	 * @param {?Function} fCallback
+	 */
+	WebMailAjaxRemoteStorage.prototype.googleDisconnect = function (fCallback)
+	{
+		this.defaultRequest(fCallback, 'SocialGoogleDisconnect');
+	};
+
+	/**
+	 * @param {?Function} fCallback
+	 */
+	WebMailAjaxRemoteStorage.prototype.socialUsers = function (fCallback)
+	{
+		this.defaultRequest(fCallback, 'SocialUsers');
+	};
+
+	module.exports = new WebMailAjaxRemoteStorage();
+
+}(module));
+},{"../Common/Utils.js":9,"../External/underscore.js":24,"../Storages/WebMailCacheStorage.js":40,"./AbstractAjaxRemoteStorage.js":34}],40:[function(require,module,exports){
+/* RainLoop Webmail (c) RainLoop Team | Licensed under CC BY-NC-SA 3.0 */
+
+(function (module) {
+
+	'use strict';
+
+	var
+		_ = require('../External/underscore.js'),
+		
+		Enums = require('../Common/Enums.js'),
+		Utils = require('../Common/Utils.js'),
+		LinkBuilder = require('../Common/LinkBuilder.js'),
+
+		RL = require('../RL.js')
+	;
+
+	/**
+	 * @constructor
+	 */
+	function WebMailCacheStorage()
+	{
+		this.oFoldersCache = {};
+		this.oFoldersNamesCache = {};
+		this.oFolderHashCache = {};
+		this.oFolderUidNextCache = {};
+		this.oMessageListHashCache = {};
+		this.oMessageFlagsCache = {};
+		this.oNewMessage = {};
+		this.oRequestedMessage = {};
+
+		this.bCapaGravatar = RL().capa(Enums.Capa.Gravatar);
+	}
+
+	/**
+	 * @type {boolean}
+	 */
+	WebMailCacheStorage.prototype.bCapaGravatar = false;
+
+	/**
+	 * @type {Object}
+	 */
+	WebMailCacheStorage.prototype.oFoldersCache = {};
+
+	/**
+	 * @type {Object}
+	 */
+	WebMailCacheStorage.prototype.oFoldersNamesCache = {};
+
+	/**
+	 * @type {Object}
+	 */
+	WebMailCacheStorage.prototype.oFolderHashCache = {};
+
+	/**
+	 * @type {Object}
+	 */
+	WebMailCacheStorage.prototype.oFolderUidNextCache = {};
+
+	/**
+	 * @type {Object}
+	 */
+	WebMailCacheStorage.prototype.oMessageListHashCache = {};
+
+	/**
+	 * @type {Object}
+	 */
+	WebMailCacheStorage.prototype.oMessageFlagsCache = {};
+
+	/**
+	 * @type {Object}
+	 */
+	WebMailCacheStorage.prototype.oBodies = {};
+
+	/**
+	 * @type {Object}
+	 */
+	WebMailCacheStorage.prototype.oNewMessage = {};
+
+	/**
+	 * @type {Object}
+	 */
+	WebMailCacheStorage.prototype.oRequestedMessage = {};
+
+	WebMailCacheStorage.prototype.clear = function ()
+	{
+		this.oFoldersCache = {};
+		this.oFoldersNamesCache = {};
+		this.oFolderHashCache = {};
+		this.oFolderUidNextCache = {};
+		this.oMessageListHashCache = {};
+		this.oMessageFlagsCache = {};
+		this.oBodies = {};
+	};
+
+
+	/**
+	 * @param {string} sEmail
+	 * @param {Function} fCallback
+	 * @return {string}
+	 */
+	WebMailCacheStorage.prototype.getUserPic = function (sEmail, fCallback)
+	{
+		sEmail = Utils.trim(sEmail);
+		fCallback(this.bCapaGravatar && '' !== sEmail ? LinkBuilder.avatarLink(sEmail) : '', sEmail);
+	};
+
+	/**
+	 * @param {string} sFolderFullNameRaw
+	 * @param {string} sUid
+	 * @return {string}
+	 */
+	WebMailCacheStorage.prototype.getMessageKey = function (sFolderFullNameRaw, sUid)
+	{
+		return sFolderFullNameRaw + '#' + sUid;
+	};
+
+	/**
+	 * @param {string} sFolder
+	 * @param {string} sUid
+	 */
+	WebMailCacheStorage.prototype.addRequestedMessage = function (sFolder, sUid)
+	{
+		this.oRequestedMessage[this.getMessageKey(sFolder, sUid)] = true;
+	};
+
+	/**
+	 * @param {string} sFolder
+	 * @param {string} sUid
+	 * @return {boolean}
+	 */
+	WebMailCacheStorage.prototype.hasRequestedMessage = function (sFolder, sUid)
+	{
+		return true === this.oRequestedMessage[this.getMessageKey(sFolder, sUid)];
+	};
+
+	/**
+	 * @param {string} sFolderFullNameRaw
+	 * @param {string} sUid
+	 */
+	WebMailCacheStorage.prototype.addNewMessageCache = function (sFolderFullNameRaw, sUid)
+	{
+		this.oNewMessage[this.getMessageKey(sFolderFullNameRaw, sUid)] = true;
+	};
+
+	/**
+	 * @param {string} sFolderFullNameRaw
+	 * @param {string} sUid
+	 */
+	WebMailCacheStorage.prototype.hasNewMessageAndRemoveFromCache = function (sFolderFullNameRaw, sUid)
+	{
+		if (this.oNewMessage[this.getMessageKey(sFolderFullNameRaw, sUid)])
+		{
+			this.oNewMessage[this.getMessageKey(sFolderFullNameRaw, sUid)] = null;
+			return true;
+		}
+
+		return false;
+	};
+
+	WebMailCacheStorage.prototype.clearNewMessageCache = function ()
+	{
+		this.oNewMessage = {};
+	};
+
+	/**
+	 * @param {string} sFolderHash
+	 * @return {string}
+	 */
+	WebMailCacheStorage.prototype.getFolderFullNameRaw = function (sFolderHash)
+	{
+		return '' !== sFolderHash && this.oFoldersNamesCache[sFolderHash] ? this.oFoldersNamesCache[sFolderHash] : '';
+	};
+
+	/**
+	 * @param {string} sFolderHash
+	 * @param {string} sFolderFullNameRaw
+	 */
+	WebMailCacheStorage.prototype.setFolderFullNameRaw = function (sFolderHash, sFolderFullNameRaw)
+	{
+		this.oFoldersNamesCache[sFolderHash] = sFolderFullNameRaw;
+	};
+
+	/**
+	 * @param {string} sFolderFullNameRaw
+	 * @return {string}
+	 */
+	WebMailCacheStorage.prototype.getFolderHash = function (sFolderFullNameRaw)
+	{
+		return '' !== sFolderFullNameRaw && this.oFolderHashCache[sFolderFullNameRaw] ? this.oFolderHashCache[sFolderFullNameRaw] : '';
+	};
+
+	/**
+	 * @param {string} sFolderFullNameRaw
+	 * @param {string} sFolderHash
+	 */
+	WebMailCacheStorage.prototype.setFolderHash = function (sFolderFullNameRaw, sFolderHash)
+	{
+		this.oFolderHashCache[sFolderFullNameRaw] = sFolderHash;
+	};
+
+	/**
+	 * @param {string} sFolderFullNameRaw
+	 * @return {string}
+	 */
+	WebMailCacheStorage.prototype.getFolderUidNext = function (sFolderFullNameRaw)
+	{
+		return '' !== sFolderFullNameRaw && this.oFolderUidNextCache[sFolderFullNameRaw] ? this.oFolderUidNextCache[sFolderFullNameRaw] : '';
+	};
+
+	/**
+	 * @param {string} sFolderFullNameRaw
+	 * @param {string} sUidNext
+	 */
+	WebMailCacheStorage.prototype.setFolderUidNext = function (sFolderFullNameRaw, sUidNext)
+	{
+		this.oFolderUidNextCache[sFolderFullNameRaw] = sUidNext;
+	};
+
+	/**
+	 * @param {string} sFolderFullNameRaw
+	 * @return {?FolderModel}
+	 */
+	WebMailCacheStorage.prototype.getFolderFromCacheList = function (sFolderFullNameRaw)
+	{
+		return '' !== sFolderFullNameRaw && this.oFoldersCache[sFolderFullNameRaw] ? this.oFoldersCache[sFolderFullNameRaw] : null;
+	};
+
+	/**
+	 * @param {string} sFolderFullNameRaw
+	 * @param {?FolderModel} oFolder
+	 */
+	WebMailCacheStorage.prototype.setFolderToCacheList = function (sFolderFullNameRaw, oFolder)
+	{
+		this.oFoldersCache[sFolderFullNameRaw] = oFolder;
+	};
+
+	/**
+	 * @param {string} sFolderFullNameRaw
+	 */
+	WebMailCacheStorage.prototype.removeFolderFromCacheList = function (sFolderFullNameRaw)
+	{
+		this.setFolderToCacheList(sFolderFullNameRaw, null);
+	};
+
+	/**
+	 * @param {string} sFolderFullName
+	 * @param {string} sUid
+	 * @return {?Array}
+	 */
+	WebMailCacheStorage.prototype.getMessageFlagsFromCache = function (sFolderFullName, sUid)
+	{
+		return this.oMessageFlagsCache[sFolderFullName] && this.oMessageFlagsCache[sFolderFullName][sUid] ?
+			this.oMessageFlagsCache[sFolderFullName][sUid] : null;
+	};
+
+	/**
+	 * @param {string} sFolderFullName
+	 * @param {string} sUid
+	 * @param {Array} aFlagsCache
+	 */
+	WebMailCacheStorage.prototype.setMessageFlagsToCache = function (sFolderFullName, sUid, aFlagsCache)
+	{
+		if (!this.oMessageFlagsCache[sFolderFullName])
+		{
+			this.oMessageFlagsCache[sFolderFullName] = {};
+		}
+
+		this.oMessageFlagsCache[sFolderFullName][sUid] = aFlagsCache;
+	};
+
+	/**
+	 * @param {string} sFolderFullName
+	 */
+	WebMailCacheStorage.prototype.clearMessageFlagsFromCacheByFolder = function (sFolderFullName)
+	{
+		this.oMessageFlagsCache[sFolderFullName] = {};
+	};
+
+	/**
+	 * @param {(MessageModel|null)} oMessage
+	 */
+	WebMailCacheStorage.prototype.initMessageFlagsFromCache = function (oMessage)
+	{
+		if (oMessage)
+		{
+			var
+				self = this,
+				aFlags = this.getMessageFlagsFromCache(oMessage.folderFullNameRaw, oMessage.uid),
+				mUnseenSubUid = null,
+				mFlaggedSubUid = null
+			;
+
+			if (aFlags && 0 < aFlags.length)
+			{
+				oMessage.unseen(!!aFlags[0]);
+				oMessage.flagged(!!aFlags[1]);
+				oMessage.answered(!!aFlags[2]);
+				oMessage.forwarded(!!aFlags[3]);
+				oMessage.isReadReceipt(!!aFlags[4]);
+			}
+
+			if (0 < oMessage.threads().length)
+			{
+				mUnseenSubUid = _.find(oMessage.threads(), function (iSubUid) {
+					var aFlags = self.getMessageFlagsFromCache(oMessage.folderFullNameRaw, iSubUid);
+					return aFlags && 0 < aFlags.length && !!aFlags[0];
+				});
+
+				mFlaggedSubUid = _.find(oMessage.threads(), function (iSubUid) {
+					var aFlags = self.getMessageFlagsFromCache(oMessage.folderFullNameRaw, iSubUid);
+					return aFlags && 0 < aFlags.length && !!aFlags[1];
+				});
+
+				oMessage.hasUnseenSubMessage(mUnseenSubUid && 0 < Utils.pInt(mUnseenSubUid));
+				oMessage.hasFlaggedSubMessage(mFlaggedSubUid && 0 < Utils.pInt(mFlaggedSubUid));
+			}
+		}
+	};
+
+	/**
+	 * @param {(MessageModel|null)} oMessage
+	 */
+	WebMailCacheStorage.prototype.storeMessageFlagsToCache = function (oMessage)
+	{
+		if (oMessage)
+		{
+			this.setMessageFlagsToCache(
+				oMessage.folderFullNameRaw,
+				oMessage.uid,
+				[oMessage.unseen(), oMessage.flagged(), oMessage.answered(), oMessage.forwarded(), oMessage.isReadReceipt()]
+			);
+		}
+	};
+	/**
+	 * @param {string} sFolder
+	 * @param {string} sUid
+	 * @param {Array} aFlags
+	 */
+	WebMailCacheStorage.prototype.storeMessageFlagsToCacheByFolderAndUid = function (sFolder, sUid, aFlags)
+	{
+		if (Utils.isArray(aFlags) && 0 < aFlags.length)
+		{
+			this.setMessageFlagsToCache(sFolder, sUid, aFlags);
+		}
+	};
+
+	module.exports = new WebMailCacheStorage();
+
+}(module));
+},{"../Common/Enums.js":5,"../Common/LinkBuilder.js":7,"../Common/Utils.js":9,"../External/underscore.js":24,"../RL.js":32}],41:[function(require,module,exports){
+/* RainLoop Webmail (c) RainLoop Team | Licensed under CC BY-NC-SA 3.0 */
+
+(function (module) {
+
+	'use strict';
+
+	var
+		window = require('../External/window.js'),
+		$ = require('../External/jquery.js'),
+		_ = require('../External/underscore.js'),
+		ko = require('../External/ko.js'),
+		moment = require('../External/moment.js'),
+		$div = require('../External/$div.js'),
+		NotificationClass = require('../External/NotificationClass.js'),
+		
+		Consts = require('../Common/Consts.js'),
+		Enums = require('../Common/Enums.js'),
+		Globals = require('../Common/Globals.js'),
+		Utils = require('../Common/Utils.js'),
+		LinkBuilder = require('../Common/LinkBuilder.js'),
+
+		Cache = require('../Storages/WebMailCacheStorage.js'),
+		Remote = require('../Storages/WebMailAjaxRemoteStorage.js'),
+		
+		kn = require('../Knoin/Knoin.js'),
+
+		MessageModel = require('../Models/MessageModel.js'),
+
+		LocalStorage = require('./LocalStorage.js'),
+		AbstractData = require('./AbstractData.js')
+	;
+
+	/**
+	 * @constructor
+	 * @extends AbstractData
+	 */
+	function WebMailDataStorage()
+	{
+		AbstractData.call(this);
+
+		var
+			fRemoveSystemFolderType = function (observable) {
+				return function () {
+					var oFolder = Cache.getFolderFromCacheList(observable()); // TODO cjs
+					if (oFolder)
+					{
+						oFolder.type(Enums.FolderType.User);
+					}
+				};
+			},
+			fSetSystemFolderType = function (iType) {
+				return function (sValue) {
+					var oFolder = Cache.getFolderFromCacheList(sValue); // TODO cjs
+					if (oFolder)
+					{
+						oFolder.type(iType);
+					}
+				};
+			}
+		;
+
+		this.devEmail = '';
+		this.devPassword = '';
+
+		this.accountEmail = ko.observable('');
+		this.accountIncLogin = ko.observable('');
+		this.accountOutLogin = ko.observable('');
+		this.projectHash = ko.observable('');
+		this.threading = ko.observable(false);
+
+		this.lastFoldersHash = '';
+		this.remoteSuggestions = false;
+
+		// system folders
+		this.sentFolder = ko.observable('');
+		this.draftFolder = ko.observable('');
+		this.spamFolder = ko.observable('');
+		this.trashFolder = ko.observable('');
+		this.archiveFolder = ko.observable('');
+
+		this.sentFolder.subscribe(fRemoveSystemFolderType(this.sentFolder), this, 'beforeChange');
+		this.draftFolder.subscribe(fRemoveSystemFolderType(this.draftFolder), this, 'beforeChange');
+		this.spamFolder.subscribe(fRemoveSystemFolderType(this.spamFolder), this, 'beforeChange');
+		this.trashFolder.subscribe(fRemoveSystemFolderType(this.trashFolder), this, 'beforeChange');
+		this.archiveFolder.subscribe(fRemoveSystemFolderType(this.archiveFolder), this, 'beforeChange');
+
+		this.sentFolder.subscribe(fSetSystemFolderType(Enums.FolderType.SentItems), this);
+		this.draftFolder.subscribe(fSetSystemFolderType(Enums.FolderType.Draft), this);
+		this.spamFolder.subscribe(fSetSystemFolderType(Enums.FolderType.Spam), this);
+		this.trashFolder.subscribe(fSetSystemFolderType(Enums.FolderType.Trash), this);
+		this.archiveFolder.subscribe(fSetSystemFolderType(Enums.FolderType.Archive), this);
+
+		this.draftFolderNotEnabled = ko.computed(function () {
+			return '' === this.draftFolder() || Consts.Values.UnuseOptionValue === this.draftFolder();
+		}, this);
+
+		// personal
+		this.displayName = ko.observable('');
+		this.signature = ko.observable('');
+		this.signatureToAll = ko.observable(false);
+		this.replyTo = ko.observable('');
+
+		// security
+		this.enableTwoFactor = ko.observable(false);
+
+		// accounts
+		this.accounts = ko.observableArray([]);
+		this.accountsLoading = ko.observable(false).extend({'throttle': 100});
+
+		// identities
+		this.defaultIdentityID = ko.observable('');
+		this.identities = ko.observableArray([]);
+		this.identitiesLoading = ko.observable(false).extend({'throttle': 100});
+
+		// contacts
+		this.contactTags = ko.observableArray([]);
+		this.contacts = ko.observableArray([]);
+		this.contacts.loading = ko.observable(false).extend({'throttle': 200});
+		this.contacts.importing = ko.observable(false).extend({'throttle': 200});
+		this.contacts.syncing = ko.observable(false).extend({'throttle': 200});
+		this.contacts.exportingVcf = ko.observable(false).extend({'throttle': 200});
+		this.contacts.exportingCsv = ko.observable(false).extend({'throttle': 200});
+
+		this.allowContactsSync = ko.observable(false);
+		this.enableContactsSync = ko.observable(false);
+		this.contactsSyncUrl = ko.observable('');
+		this.contactsSyncUser = ko.observable('');
+		this.contactsSyncPass = ko.observable('');
+
+		this.allowContactsSync = ko.observable(!!RL.settingsGet('ContactsSyncIsAllowed')); // TODO cjs
+		this.enableContactsSync = ko.observable(!!RL.settingsGet('EnableContactsSync'));
+		this.contactsSyncUrl = ko.observable(RL.settingsGet('ContactsSyncUrl'));
+		this.contactsSyncUser = ko.observable(RL.settingsGet('ContactsSyncUser'));
+		this.contactsSyncPass = ko.observable(RL.settingsGet('ContactsSyncPassword'));
+
+		// folders
+		this.namespace = '';
+		this.folderList = ko.observableArray([]);
+		this.folderList.focused = ko.observable(false);
+
+		this.foldersListError = ko.observable('');
+
+		this.foldersLoading = ko.observable(false);
+		this.foldersCreating = ko.observable(false);
+		this.foldersDeleting = ko.observable(false);
+		this.foldersRenaming = ko.observable(false);
+
+		this.foldersChanging = ko.computed(function () {
+			var
+				bLoading = this.foldersLoading(),
+				bCreating = this.foldersCreating(),
+				bDeleting = this.foldersDeleting(),
+				bRenaming = this.foldersRenaming()
+			;
+			return bLoading || bCreating || bDeleting || bRenaming;
+		}, this);
+
+		this.foldersInboxUnreadCount = ko.observable(0);
+
+		this.currentFolder = ko.observable(null).extend({'toggleSubscribe': [null,
+			function (oPrev) {
+				if (oPrev)
+				{
+					oPrev.selected(false);
+				}
+			}, function (oNext) {
+				if (oNext)
+				{
+					oNext.selected(true);
+				}
+			}
+		]});
+
+		this.currentFolderFullNameRaw = ko.computed(function () {
+			return this.currentFolder() ? this.currentFolder().fullNameRaw : '';
+		}, this);
+
+		this.currentFolderFullName = ko.computed(function () {
+			return this.currentFolder() ? this.currentFolder().fullName : '';
+		}, this);
+
+		this.currentFolderFullNameHash = ko.computed(function () {
+			return this.currentFolder() ? this.currentFolder().fullNameHash : '';
+		}, this);
+
+		this.currentFolderName = ko.computed(function () {
+			return this.currentFolder() ? this.currentFolder().name() : '';
+		}, this);
+
+		this.folderListSystemNames = ko.computed(function () {
+
+			var
+				aList = ['INBOX'],
+				aFolders = this.folderList(),
+				sSentFolder = this.sentFolder(),
+				sDraftFolder = this.draftFolder(),
+				sSpamFolder = this.spamFolder(),
+				sTrashFolder = this.trashFolder(),
+				sArchiveFolder = this.archiveFolder()
+			;
+
+			if (Utils.isArray(aFolders) && 0 < aFolders.length)
+			{
+				if ('' !== sSentFolder && Consts.Values.UnuseOptionValue !== sSentFolder)
+				{
+					aList.push(sSentFolder);
+				}
+				if ('' !== sDraftFolder && Consts.Values.UnuseOptionValue !== sDraftFolder)
+				{
+					aList.push(sDraftFolder);
+				}
+				if ('' !== sSpamFolder && Consts.Values.UnuseOptionValue !== sSpamFolder)
+				{
+					aList.push(sSpamFolder);
+				}
+				if ('' !== sTrashFolder && Consts.Values.UnuseOptionValue !== sTrashFolder)
+				{
+					aList.push(sTrashFolder);
+				}
+				if ('' !== sArchiveFolder && Consts.Values.UnuseOptionValue !== sArchiveFolder)
+				{
+					aList.push(sArchiveFolder);
+				}
+			}
+
+			return aList;
+
+		}, this);
+
+		this.folderListSystem = ko.computed(function () {
+			return _.compact(_.map(this.folderListSystemNames(), function (sName) {
+				return Cache.getFolderFromCacheList(sName); // TODO cjs
+			}));
+		}, this);
+
+		this.folderMenuForMove = ko.computed(function () {
+			return RL.folderListOptionsBuilder(this.folderListSystem(), this.folderList(), [// TODO cjs
+				this.currentFolderFullNameRaw()
+			], null, null, null, null, function (oItem) {
+				return oItem ? oItem.localName() : '';
+			});
+		}, this);
+
+		// message list
+		this.staticMessageList = [];
+
+		this.messageList = ko.observableArray([]).extend({'rateLimit': 0});
+
+		this.messageListCount = ko.observable(0);
+		this.messageListSearch = ko.observable('');
+		this.messageListPage = ko.observable(1);
+
+		this.messageListThreadFolder = ko.observable('');
+		this.messageListThreadUids = ko.observableArray([]);
+
+		this.messageListThreadFolder.subscribe(function () {
+			this.messageListThreadUids([]);
+		}, this);
+
+		this.messageListEndFolder = ko.observable('');
+		this.messageListEndSearch = ko.observable('');
+		this.messageListEndPage = ko.observable(1);
+
+		this.messageListEndHash = ko.computed(function () {
+			return this.messageListEndFolder() + '|' + this.messageListEndSearch() + '|' + this.messageListEndPage();
+		}, this);
+
+		this.messageListPageCount = ko.computed(function () {
+			var iPage = window.Math.ceil(this.messageListCount() / this.messagesPerPage());
+			return 0 >= iPage ? 1 : iPage;
+		}, this);
+
+		this.mainMessageListSearch = ko.computed({
+			'read': this.messageListSearch,
+			'write': function (sValue) {
+				kn.setHash(LinkBuilder.mailBox( // TODO cjs
+					this.currentFolderFullNameHash(), 1, Utils.trim(sValue.toString())
+				));
+			},
+			'owner': this
+		});
+
+		this.messageListError = ko.observable('');
+
+		this.messageListLoading = ko.observable(false);
+		this.messageListIsNotCompleted = ko.observable(false);
+		this.messageListCompleteLoadingThrottle = ko.observable(false).extend({'throttle': 200});
+
+		this.messageListCompleteLoading = ko.computed(function () {
+			var
+				bOne = this.messageListLoading(),
+				bTwo = this.messageListIsNotCompleted()
+			;
+			return bOne || bTwo;
+		}, this);
+
+		this.messageListCompleteLoading.subscribe(function (bValue) {
+			this.messageListCompleteLoadingThrottle(bValue);
+		}, this);
+
+		this.messageList.subscribe(_.debounce(function (aList) {
+			_.each(aList, function (oItem) {
+				if (oItem.newForAnimation())
+				{
+					oItem.newForAnimation(false);
+				}
+			});
+		}, 500));
+
+		// message preview
+		this.staticMessageList = new MessageModel();// TODO cjs
+		this.message = ko.observable(null);
+		this.messageLoading = ko.observable(false);
+		this.messageLoadingThrottle = ko.observable(false).extend({'throttle': 50});
+
+		this.message.focused = ko.observable(false);
+
+		this.message.subscribe(function (oMessage) {
+			if (!oMessage)
+			{
+				this.message.focused(false);
+				this.messageFullScreenMode(false);
+				this.hideMessageBodies();
+
+				if (Enums.Layout.NoPreview === RL.data().layout() &&// TODO cjs
+					-1 < window.location.hash.indexOf('message-preview'))
+				{
+					RL.historyBack();// TODO cjs
+				}
+			}
+			else if (Enums.Layout.NoPreview === this.layout())
+			{
+				this.message.focused(true);
+			}
+		}, this);
+
+		this.message.focused.subscribe(function (bValue) {
+			if (bValue)
+			{
+				this.folderList.focused(false);
+				this.keyScope(Enums.KeyState.MessageView);
+			}
+			else if (Enums.KeyState.MessageView === RL.data().keyScope())// TODO cjs
+			{
+				if (Enums.Layout.NoPreview === RL.data().layout() && this.message())// TODO cjs
+				{
+					this.keyScope(Enums.KeyState.MessageView);
+				}
+				else
+				{
+					this.keyScope(Enums.KeyState.MessageList);
+				}
+			}
+		}, this);
+
+		this.folderList.focused.subscribe(function (bValue) {
+			if (bValue)
+			{
+				RL.data().keyScope(Enums.KeyState.FolderList);// TODO cjs
+			}
+			else if (Enums.KeyState.FolderList === RL.data().keyScope())// TODO cjs
+			{
+				RL.data().keyScope(Enums.KeyState.MessageList);// TODO cjs
+			}
+		});
+
+		this.messageLoading.subscribe(function (bValue) {
+			this.messageLoadingThrottle(bValue);
+		}, this);
+
+		this.messageFullScreenMode = ko.observable(false);
+
+		this.messageError = ko.observable('');
+
+		this.messagesBodiesDom = ko.observable(null);
+
+		this.messagesBodiesDom.subscribe(function (oDom) {
+			if (oDom && !(oDom instanceof $))
+			{
+				this.messagesBodiesDom($(oDom));
+			}
+		}, this);
+
+		this.messageActiveDom = ko.observable(null);
+
+		this.isMessageSelected = ko.computed(function () {
+			return null !== this.message();
+		}, this);
+
+		this.currentMessage = ko.observable(null);
+
+		this.messageListChecked = ko.computed(function () {
+			return _.filter(this.messageList(), function (oItem) {
+				return oItem.checked();
+			});
+		}, this).extend({'rateLimit': 0});
+
+		this.hasCheckedMessages = ko.computed(function () {
+			return 0 < this.messageListChecked().length;
+		}, this).extend({'rateLimit': 0});
+
+		this.messageListCheckedOrSelected = ko.computed(function () {
+
+			var
+				aChecked = this.messageListChecked(),
+				oSelectedMessage = this.currentMessage()
+			;
+
+			return _.union(aChecked, oSelectedMessage ? [oSelectedMessage] : []);
+
+		}, this);
+
+		this.messageListCheckedOrSelectedUidsWithSubMails = ko.computed(function () {
+			var aList = [];
+			_.each(this.messageListCheckedOrSelected(), function (oMessage) {
+				if (oMessage)
+				{
+					aList.push(oMessage.uid);
+					if (0 < oMessage.threadsLen() && 0 === oMessage.parentUid() && oMessage.lastInCollapsedThread())
+					{
+						aList = _.union(aList, oMessage.threads());
+					}
+				}
+			});
+			return aList;
+		}, this);
+
+		// quota
+		this.userQuota = ko.observable(0);
+		this.userUsageSize = ko.observable(0);
+		this.userUsageProc = ko.computed(function () {
+
+			var
+				iQuota = this.userQuota(),
+				iUsed = this.userUsageSize()
+			;
+
+			return 0 < iQuota ? window.Math.ceil((iUsed / iQuota) * 100) : 0;
+
+		}, this);
+
+		// other
+		this.capaOpenPGP = ko.observable(false);
+		this.openpgpkeys = ko.observableArray([]);
+		this.openpgpKeyring = null;
+
+		this.openpgpkeysPublic = this.openpgpkeys.filter(function (oItem) {
+			return !!(oItem && !oItem.isPrivate);
+		});
+
+		this.openpgpkeysPrivate = this.openpgpkeys.filter(function (oItem) {
+			return !!(oItem && oItem.isPrivate);
+		});
+
+		// google
+		this.googleActions = ko.observable(false);
+		this.googleLoggined = ko.observable(false);
+		this.googleUserName = ko.observable('');
+
+		// facebook
+		this.facebookActions = ko.observable(false);
+		this.facebookLoggined = ko.observable(false);
+		this.facebookUserName = ko.observable('');
+
+		// twitter
+		this.twitterActions = ko.observable(false);
+		this.twitterLoggined = ko.observable(false);
+		this.twitterUserName = ko.observable('');
+
+		this.customThemeType = ko.observable(Enums.CustomThemeType.Light);
+
+		this.purgeMessageBodyCacheThrottle = _.throttle(this.purgeMessageBodyCache, 1000 * 30);
+	}
+
+	_.extend(WebMailDataStorage.prototype, AbstractData.prototype);
+
+	WebMailDataStorage.prototype.purgeMessageBodyCache = function()
+	{
+		var
+			iCount = 0,
+			oMessagesBodiesDom = null,
+			iEnd = Globals.iMessageBodyCacheCount - Consts.Values.MessageBodyCacheLimit
+		;
+
+		if (0 < iEnd)
+		{
+			oMessagesBodiesDom = this.messagesBodiesDom();
+			if (oMessagesBodiesDom)
+			{
+				oMessagesBodiesDom.find('.rl-cache-class').each(function () {
+					var oItem = $(this);
+					if (iEnd > oItem.data('rl-cache-count'))
+					{
+						oItem.addClass('rl-cache-purge');
+						iCount++;
+					}
+				});
+
+				if (0 < iCount)
+				{
+					_.delay(function () {
+						oMessagesBodiesDom.find('.rl-cache-purge').remove();
+					}, 300);
+				}
+			}
+		}
+	};
+
+	WebMailDataStorage.prototype.populateDataOnStart = function()
+	{
+		AbstractData.prototype.populateDataOnStart.call(this);
+
+		this.accountEmail(RL.settingsGet('Email'));// TODO cjs
+		this.accountIncLogin(RL.settingsGet('IncLogin'));
+		this.accountOutLogin(RL.settingsGet('OutLogin'));
+		this.projectHash(RL.settingsGet('ProjectHash'));
+
+		this.defaultIdentityID(RL.settingsGet('DefaultIdentityID'));
+
+		this.displayName(RL.settingsGet('DisplayName'));
+		this.replyTo(RL.settingsGet('ReplyTo'));
+		this.signature(RL.settingsGet('Signature'));
+		this.signatureToAll(!!RL.settingsGet('SignatureToAll'));
+		this.enableTwoFactor(!!RL.settingsGet('EnableTwoFactor'));
+
+		this.lastFoldersHash = LocalStorage.get(Enums.ClientSideKeyName.FoldersLashHash) || '';
+
+		this.remoteSuggestions = !!RL.settingsGet('RemoteSuggestions');
+
+		this.devEmail = RL.settingsGet('DevEmail');
+		this.devPassword = RL.settingsGet('DevPassword');
+	};
+
+	WebMailDataStorage.prototype.initUidNextAndNewMessages = function (sFolder, sUidNext, aNewMessages)
+	{
+		if ('INBOX' === sFolder && Utils.isNormal(sUidNext) && sUidNext !== '')
+		{
+			if (Utils.isArray(aNewMessages) && 0 < aNewMessages.length)
+			{
+				var
+					iIndex = 0,
+					iLen = aNewMessages.length,
+					fNotificationHelper = function (sImageSrc, sTitle, sText)
+					{
+						var oNotification = null;
+						if (NotificationClass && RL.data().useDesktopNotifications())
+						{
+							oNotification = new NotificationClass(sTitle, {
+								'body': sText,
+								'icon': sImageSrc
+							});
+
+							if (oNotification)
+							{
+								if (oNotification.show)
+								{
+									oNotification.show();
+								}
+
+								window.setTimeout((function (oLocalNotifications) {
+									return function () {
+										if (oLocalNotifications.cancel)
+										{
+											oLocalNotifications.cancel();
+										}
+										else if (oLocalNotifications.close)
+										{
+											oLocalNotifications.close();
+										}
+									};
+								}(oNotification)), 7000);
+							}
+						}
+					}
+				;
+
+				_.each(aNewMessages, function (oItem) {
+					Cache.addNewMessageCache(sFolder, oItem.Uid);
+				});
+
+				if (3 < iLen)
+				{
+					fNotificationHelper(
+						LinkBuilder.notificationMailIcon(),
+						RL.data().accountEmail(),
+						Utils.i18n('MESSAGE_LIST/NEW_MESSAGE_NOTIFICATION', {
+							'COUNT': iLen
+						})
+					);
+				}
+				else
+				{
+					for (; iIndex < iLen; iIndex++)
+					{
+						fNotificationHelper(
+							LinkBuilder.notificationMailIcon(),
+							MessageModel.emailsToLine(MessageModel.initEmailsFromJson(aNewMessages[iIndex].From), false),
+							aNewMessages[iIndex].Subject
+						);
+					}
+				}
+			}
+
+			Cache.setFolderUidNext(sFolder, sUidNext);
+		}
+	};
+
+	/**
+	 * @param {string} sNamespace
+	 * @param {Array} aFolders
+	 * @return {Array}
+	 */
+	WebMailDataStorage.prototype.folderResponseParseRec = function (sNamespace, aFolders)
+	{
+		var
+			iIndex = 0,
+			iLen = 0,
+			oFolder = null,
+			oCacheFolder = null,
+			sFolderFullNameRaw = '',
+			aSubFolders = [],
+			aList = []
+		;
+
+		for (iIndex = 0, iLen = aFolders.length; iIndex < iLen; iIndex++)
+		{
+			oFolder = aFolders[iIndex];
+			if (oFolder)
+			{
+				sFolderFullNameRaw = oFolder.FullNameRaw;
+
+				oCacheFolder = Cache.getFolderFromCacheList(sFolderFullNameRaw);// TODO cjs
+				if (!oCacheFolder)
+				{
+					oCacheFolder = FolderModel.newInstanceFromJson(oFolder);// TODO cjs
+					if (oCacheFolder)
+					{
+						Cache.setFolderToCacheList(sFolderFullNameRaw, oCacheFolder);// TODO cjs
+						Cache.setFolderFullNameRaw(oCacheFolder.fullNameHash, sFolderFullNameRaw);// TODO cjs
+					}
+				}
+
+				if (oCacheFolder)
+				{
+					oCacheFolder.collapsed(!Utils.isFolderExpanded(oCacheFolder.fullNameHash));
+
+					if (oFolder.Extended)
+					{
+						if (oFolder.Extended.Hash)
+						{
+							Cache.setFolderHash(oCacheFolder.fullNameRaw, oFolder.Extended.Hash);// TODO cjs
+						}
+
+						if (Utils.isNormal(oFolder.Extended.MessageCount))
+						{
+							oCacheFolder.messageCountAll(oFolder.Extended.MessageCount);
+						}
+
+						if (Utils.isNormal(oFolder.Extended.MessageUnseenCount))
+						{
+							oCacheFolder.messageCountUnread(oFolder.Extended.MessageUnseenCount);
+						}
+					}
+
+					aSubFolders = oFolder['SubFolders'];
+					if (aSubFolders && 'Collection/FolderCollection' === aSubFolders['@Object'] &&
+						aSubFolders['@Collection'] && Utils.isArray(aSubFolders['@Collection']))
+					{
+						oCacheFolder.subFolders(
+							this.folderResponseParseRec(sNamespace, aSubFolders['@Collection']));
+					}
+
+					aList.push(oCacheFolder);
+				}
+			}
+		}
+
+		return aList;
+	};
+
+	/**
+	 * @param {*} oData
+	 */
+	WebMailDataStorage.prototype.setFolders = function (oData)
+	{
+		var
+			aList = [],
+			bUpdate = false,
+			oRLData = RL.data(),// TODO cjs
+			fNormalizeFolder = function (sFolderFullNameRaw) {
+				return ('' === sFolderFullNameRaw || Consts.Values.UnuseOptionValue === sFolderFullNameRaw ||
+					null !== Cache.getFolderFromCacheList(sFolderFullNameRaw)) ? sFolderFullNameRaw : '';// TODO cjs
+			}
+		;
+
+		if (oData && oData.Result && 'Collection/FolderCollection' === oData.Result['@Object'] &&
+			oData.Result['@Collection'] && Utils.isArray(oData.Result['@Collection']))
+		{
+			if (!Utils.isUnd(oData.Result.Namespace))
+			{
+				oRLData.namespace = oData.Result.Namespace;
+			}
+
+			this.threading(!!RL.settingsGet('UseImapThread') && oData.Result.IsThreadsSupported && true);// TODO cjs
+
+			aList = this.folderResponseParseRec(oRLData.namespace, oData.Result['@Collection']);
+			oRLData.folderList(aList);
+
+			// TODO cjs
+			if (oData.Result['SystemFolders'] &&
+				'' === '' + RL.settingsGet('SentFolder') + RL.settingsGet('DraftFolder') +
+				RL.settingsGet('SpamFolder') + RL.settingsGet('TrashFolder') + RL.settingsGet('ArchiveFolder') +
+				RL.settingsGet('NullFolder'))
+			{
+				// TODO Magic Numbers
+				RL.settingsSet('SentFolder', oData.Result['SystemFolders'][2] || null);
+				RL.settingsSet('DraftFolder', oData.Result['SystemFolders'][3] || null);
+				RL.settingsSet('SpamFolder', oData.Result['SystemFolders'][4] || null);
+				RL.settingsSet('TrashFolder', oData.Result['SystemFolders'][5] || null);
+				RL.settingsSet('ArchiveFolder', oData.Result['SystemFolders'][12] || null);
+
+				bUpdate = true;
+			}
+
+			// TODO cjs
+			oRLData.sentFolder(fNormalizeFolder(RL.settingsGet('SentFolder')));
+			oRLData.draftFolder(fNormalizeFolder(RL.settingsGet('DraftFolder')));
+			oRLData.spamFolder(fNormalizeFolder(RL.settingsGet('SpamFolder')));
+			oRLData.trashFolder(fNormalizeFolder(RL.settingsGet('TrashFolder')));
+			oRLData.archiveFolder(fNormalizeFolder(RL.settingsGet('ArchiveFolder')));
+
+			if (bUpdate)
+			{
+				Remote.saveSystemFolders(Utils.emptyFunction, {
+					'SentFolder': oRLData.sentFolder(),
+					'DraftFolder': oRLData.draftFolder(),
+					'SpamFolder': oRLData.spamFolder(),
+					'TrashFolder': oRLData.trashFolder(),
+					'ArchiveFolder': oRLData.archiveFolder(),
+					'NullFolder': 'NullFolder'
+				});
+			}
+
+			LocalStorage.set(Enums.ClientSideKeyName.FoldersLashHash, oData.Result.FoldersHash);
+		}
+	};
+
+	WebMailDataStorage.prototype.hideMessageBodies = function ()
+	{
+		var oMessagesBodiesDom = this.messagesBodiesDom();
+		if (oMessagesBodiesDom)
+		{
+			oMessagesBodiesDom.find('.b-text-part').hide();
+		}
+	};
+
+	/**
+	 * @param {boolean=} bBoot = false
+	 * @returns {Array}
+	 */
+	WebMailDataStorage.prototype.getNextFolderNames = function (bBoot)
+	{
+		bBoot = Utils.isUnd(bBoot) ? false : !!bBoot;
+
+		var
+			aResult = [],
+			iLimit = 10,
+			iUtc = moment().unix(),
+			iTimeout = iUtc - 60 * 5,
+			aTimeouts = [],
+			fSearchFunction = function (aList) {
+				_.each(aList, function (oFolder) {
+					if (oFolder && 'INBOX' !== oFolder.fullNameRaw &&
+						oFolder.selectable && oFolder.existen &&
+						iTimeout > oFolder.interval &&
+						(!bBoot || oFolder.subScribed()))
+					{
+						aTimeouts.push([oFolder.interval, oFolder.fullNameRaw]);
+					}
+
+					if (oFolder && 0 < oFolder.subFolders().length)
+					{
+						fSearchFunction(oFolder.subFolders());
+					}
+				});
+			}
+		;
+
+		fSearchFunction(this.folderList());
+
+		aTimeouts.sort(function(a, b) {
+			if (a[0] < b[0])
+			{
+				return -1;
+			}
+			else if (a[0] > b[0])
+			{
+				return 1;
+			}
+
+			return 0;
+		});
+
+		_.find(aTimeouts, function (aItem) {
+			var oFolder = Cache.getFolderFromCacheList(aItem[1]);// TODO cjs
+			if (oFolder)
+			{
+				oFolder.interval = iUtc;
+				aResult.push(aItem[1]);
+			}
+
+			return iLimit <= aResult.length;
+		});
+
+		return _.uniq(aResult);
+	};
+
+	/**
+	 * @param {string} sFromFolderFullNameRaw
+	 * @param {Array} aUidForRemove
+	 * @param {string=} sToFolderFullNameRaw = ''
+	 * @param {bCopy=} bCopy = false
+	 */
+	WebMailDataStorage.prototype.removeMessagesFromList = function (
+		sFromFolderFullNameRaw, aUidForRemove, sToFolderFullNameRaw, bCopy)
+	{
+		sToFolderFullNameRaw = Utils.isNormal(sToFolderFullNameRaw) ? sToFolderFullNameRaw : '';
+		bCopy = Utils.isUnd(bCopy) ? false : !!bCopy;
+
+		aUidForRemove = _.map(aUidForRemove, function (mValue) {
+			return Utils.pInt(mValue);
+		});
+
+		var
+			iUnseenCount = 0,
+			oData = RL.data(),// TODO cjs
+			aMessageList = oData.messageList(),
+			oFromFolder = Cache.getFolderFromCacheList(sFromFolderFullNameRaw),
+			oToFolder = '' === sToFolderFullNameRaw ? null : Cache.getFolderFromCacheList(sToFolderFullNameRaw || ''),
+			sCurrentFolderFullNameRaw = oData.currentFolderFullNameRaw(),
+			oCurrentMessage = oData.message(),
+			aMessages = sCurrentFolderFullNameRaw === sFromFolderFullNameRaw ? _.filter(aMessageList, function (oMessage) {
+				return oMessage && -1 < Utils.inArray(Utils.pInt(oMessage.uid), aUidForRemove);
+			}) : []
+		;
+
+		_.each(aMessages, function (oMessage) {
+			if (oMessage && oMessage.unseen())
+			{
+				iUnseenCount++;
+			}
+		});
+
+		if (oFromFolder && !bCopy)
+		{
+			oFromFolder.messageCountAll(0 <= oFromFolder.messageCountAll() - aUidForRemove.length ?
+				oFromFolder.messageCountAll() - aUidForRemove.length : 0);
+
+			if (0 < iUnseenCount)
+			{
+				oFromFolder.messageCountUnread(0 <= oFromFolder.messageCountUnread() - iUnseenCount ?
+					oFromFolder.messageCountUnread() - iUnseenCount : 0);
+			}
+		}
+
+		if (oToFolder)
+		{
+			oToFolder.messageCountAll(oToFolder.messageCountAll() + aUidForRemove.length);
+			if (0 < iUnseenCount)
+			{
+				oToFolder.messageCountUnread(oToFolder.messageCountUnread() + iUnseenCount);
+			}
+
+			oToFolder.actionBlink(true);
+		}
+
+		if (0 < aMessages.length)
+		{
+			if (bCopy)
+			{
+				_.each(aMessages, function (oMessage) {
+					oMessage.checked(false);
+				});
+			}
+			else
+			{
+				oData.messageListIsNotCompleted(true);
+
+				_.each(aMessages, function (oMessage) {
+					if (oCurrentMessage && oCurrentMessage.hash === oMessage.hash)
+					{
+						oCurrentMessage = null;
+						oData.message(null);
+					}
+
+					oMessage.deleted(true);
+				});
+
+				_.delay(function () {
+					_.each(aMessages, function (oMessage) {
+						oData.messageList.remove(oMessage);
+					});
+				}, 400);
+			}
+		}
+
+		if ('' !== sFromFolderFullNameRaw)
+		{
+			Cache.setFolderHash(sFromFolderFullNameRaw, '');
+		}
+
+		if ('' !== sToFolderFullNameRaw)
+		{
+			Cache.setFolderHash(sToFolderFullNameRaw, '');
+		}
+	};
+
+	WebMailDataStorage.prototype.setMessage = function (oData, bCached)
+	{
+		var
+			bIsHtml = false,
+			bHasExternals = false,
+			bHasInternals = false,
+			oBody = null,
+			oTextBody = null,
+			sId = '',
+			sResultHtml = '',
+			bPgpSigned = false,
+			bPgpEncrypted = false,
+			oMessagesBodiesDom = this.messagesBodiesDom(),
+			oMessage = this.message()
+		;
+
+		if (oData && oMessage && oData.Result && 'Object/Message' === oData.Result['@Object'] &&
+			oMessage.folderFullNameRaw === oData.Result.Folder && oMessage.uid === oData.Result.Uid)
+		{
+			this.messageError('');
+
+			oMessage.initUpdateByMessageJson(oData.Result);
+			Cache.addRequestedMessage(oMessage.folderFullNameRaw, oMessage.uid);// TODO cjs
+
+			if (!bCached)
+			{
+				oMessage.initFlagsByJson(oData.Result);
+			}
+
+			oMessagesBodiesDom = oMessagesBodiesDom && oMessagesBodiesDom[0] ? oMessagesBodiesDom : null;
+			if (oMessagesBodiesDom)
+			{
+				sId = 'rl-mgs-' + oMessage.hash.replace(/[^a-zA-Z0-9]/g, '');
+				oTextBody = oMessagesBodiesDom.find('#' + sId);
+				if (!oTextBody || !oTextBody[0])
+				{
+					bHasExternals = !!oData.Result.HasExternals;
+					bHasInternals = !!oData.Result.HasInternals;
+
+					oBody = $('
').hide().addClass('rl-cache-class'); + oBody.data('rl-cache-count', ++Globals.iMessageBodyCacheCount); + + if (Utils.isNormal(oData.Result.Html) && '' !== oData.Result.Html) + { + bIsHtml = true; + sResultHtml = oData.Result.Html.toString(); + } + else if (Utils.isNormal(oData.Result.Plain) && '' !== oData.Result.Plain) + { + bIsHtml = false; + sResultHtml = Utils.plainToHtml(oData.Result.Plain.toString(), false); + + if ((oMessage.isPgpSigned() || oMessage.isPgpEncrypted()) && RL.data().capaOpenPGP()) + { + oMessage.plainRaw = Utils.pString(oData.Result.Plain); + + bPgpEncrypted = /---BEGIN PGP MESSAGE---/.test(oMessage.plainRaw); + if (!bPgpEncrypted) + { + bPgpSigned = /-----BEGIN PGP SIGNED MESSAGE-----/.test(oMessage.plainRaw) && + /-----BEGIN PGP SIGNATURE-----/.test(oMessage.plainRaw); + } + + $div.empty(); + if (bPgpSigned && oMessage.isPgpSigned()) + { + sResultHtml = + $div.append( + $('
').text(oMessage.plainRaw)
+									).html()
+								;
+							}
+							else if (bPgpEncrypted && oMessage.isPgpEncrypted())
+							{
+								sResultHtml =
+									$div.append(
+										$('
').text(oMessage.plainRaw)
+									).html()
+								;
+							}
+
+							$div.empty();
+
+							oMessage.isPgpSigned(bPgpSigned);
+							oMessage.isPgpEncrypted(bPgpEncrypted);
+						}
+					}
+					else
+					{
+						bIsHtml = false;
+					}
+
+					oBody
+						.html(Utils.linkify(sResultHtml))
+						.addClass('b-text-part ' + (bIsHtml ? 'html' : 'plain'))
+					;
+
+					oMessage.isHtml(!!bIsHtml);
+					oMessage.hasImages(!!bHasExternals);
+					oMessage.pgpSignedVerifyStatus(Enums.SignedVerifyStatus.None);
+					oMessage.pgpSignedVerifyUser('');
+
+					oMessage.body = oBody;
+					if (oMessage.body)
+					{
+						oMessagesBodiesDom.append(oMessage.body);
+					}
+
+					oMessage.storeDataToDom();
+
+					if (bHasInternals)
+					{
+						oMessage.showInternalImages(true);
+					}
+
+					if (oMessage.hasImages() && this.showImages())
+					{
+						oMessage.showExternalImages(true);
+					}
+
+					this.purgeMessageBodyCacheThrottle();
+				}
+				else
+				{
+					oMessage.body = oTextBody;
+					if (oMessage.body)
+					{
+						oMessage.body.data('rl-cache-count', ++Globals.iMessageBodyCacheCount);
+						oMessage.fetchDataToDom();
+					}
+				}
+
+				this.messageActiveDom(oMessage.body);
+
+				this.hideMessageBodies();
+				oMessage.body.show();
+
+				if (oBody)
+				{
+					Utils.initBlockquoteSwitcher(oBody);
+				}
+			}
+
+			Cache.initMessageFlagsFromCache(oMessage);
+			if (oMessage.unseen())
+			{
+				RL.setMessageSeen(oMessage);
+			}
+
+			Utils.windowResize();
+		}
+	};
+
+	/**
+	 * @param {Array} aList
+	 * @returns {string}
+	 */
+	WebMailDataStorage.prototype.calculateMessageListHash = function (aList)
+	{
+		return _.map(aList, function (oMessage) {
+			return '' + oMessage.hash + '_' + oMessage.threadsLen() + '_' + oMessage.flagHash();
+		}).join('|');
+	};
+
+	WebMailDataStorage.prototype.setMessageList = function (oData, bCached)
+	{
+		if (oData && oData.Result && 'Collection/MessageCollection' === oData.Result['@Object'] &&
+			oData.Result['@Collection'] && Utils.isArray(oData.Result['@Collection']))
+		{
+			var
+				oRainLoopData = RL.data(),
+				mLastCollapsedThreadUids = null,
+				iIndex = 0,
+				iLen = 0,
+				iCount = 0,
+				iOffset = 0,
+				aList = [],
+				iUtc = moment().unix(),
+				aStaticList = oRainLoopData.staticMessageList,
+				oJsonMessage = null,
+				oMessage = null,
+				oFolder = null,
+				iNewCount = 0,
+				bUnreadCountChange = false
+			;
+
+			iCount = Utils.pInt(oData.Result.MessageResultCount);
+			iOffset = Utils.pInt(oData.Result.Offset);
+
+			if (Utils.isNonEmptyArray(oData.Result.LastCollapsedThreadUids))
+			{
+				mLastCollapsedThreadUids = oData.Result.LastCollapsedThreadUids;
+			}
+
+			oFolder = Cache.getFolderFromCacheList(
+				Utils.isNormal(oData.Result.Folder) ? oData.Result.Folder : '');
+
+			if (oFolder && !bCached)
+			{
+				oFolder.interval = iUtc;
+
+				Cache.setFolderHash(oData.Result.Folder, oData.Result.FolderHash);
+
+				if (Utils.isNormal(oData.Result.MessageCount))
+				{
+					oFolder.messageCountAll(oData.Result.MessageCount);
+				}
+
+				if (Utils.isNormal(oData.Result.MessageUnseenCount))
+				{
+					if (Utils.pInt(oFolder.messageCountUnread()) !== Utils.pInt(oData.Result.MessageUnseenCount))
+					{
+						bUnreadCountChange = true;
+					}
+
+					oFolder.messageCountUnread(oData.Result.MessageUnseenCount);
+				}
+
+				this.initUidNextAndNewMessages(oFolder.fullNameRaw, oData.Result.UidNext, oData.Result.NewMessages);
+			}
+
+			if (bUnreadCountChange && oFolder)
+			{
+				Cache.clearMessageFlagsFromCacheByFolder(oFolder.fullNameRaw);
+			}
+
+			for (iIndex = 0, iLen = oData.Result['@Collection'].length; iIndex < iLen; iIndex++)
+			{
+				oJsonMessage = oData.Result['@Collection'][iIndex];
+				if (oJsonMessage && 'Object/Message' === oJsonMessage['@Object'])
+				{
+					oMessage = aStaticList[iIndex];
+					if (!oMessage || !oMessage.initByJson(oJsonMessage))
+					{
+						oMessage = MessageModel.newInstanceFromJson(oJsonMessage);
+					}
+
+					if (oMessage)
+					{
+						if (Cache.hasNewMessageAndRemoveFromCache(oMessage.folderFullNameRaw, oMessage.uid) && 5 >= iNewCount)
+						{
+							iNewCount++;
+							oMessage.newForAnimation(true);
+						}
+
+						oMessage.deleted(false);
+
+						if (bCached)
+						{
+							Cache.initMessageFlagsFromCache(oMessage);
+						}
+						else
+						{
+							Cache.storeMessageFlagsToCache(oMessage);
+						}
+
+						oMessage.lastInCollapsedThread(mLastCollapsedThreadUids && -1 < Utils.inArray(Utils.pInt(oMessage.uid), mLastCollapsedThreadUids) ? true : false);
+
+						aList.push(oMessage);
+					}
+				}
+			}
+
+			oRainLoopData.messageListCount(iCount);
+			oRainLoopData.messageListSearch(Utils.isNormal(oData.Result.Search) ? oData.Result.Search : '');
+			oRainLoopData.messageListPage(Math.ceil((iOffset / oRainLoopData.messagesPerPage()) + 1));
+			oRainLoopData.messageListEndFolder(Utils.isNormal(oData.Result.Folder) ? oData.Result.Folder : '');
+			oRainLoopData.messageListEndSearch(Utils.isNormal(oData.Result.Search) ? oData.Result.Search : '');
+			oRainLoopData.messageListEndPage(oRainLoopData.messageListPage());
+
+			oRainLoopData.messageList(aList);
+			oRainLoopData.messageListIsNotCompleted(false);
+
+			if (aStaticList.length < aList.length)
+			{
+				oRainLoopData.staticMessageList = aList;
+			}
+
+			Cache.clearNewMessageCache();
+
+			if (oFolder && (bCached || bUnreadCountChange || RL.data().useThreads()))
+			{
+				RL.folderInformation(oFolder.fullNameRaw, aList);
+			}
+		}
+		else
+		{
+			RL.data().messageListCount(0);
+			RL.data().messageList([]);
+			RL.data().messageListError(Utils.getNotification(
+				oData && oData.ErrorCode ? oData.ErrorCode : Enums.Notification.CantGetMessageList
+			));
+		}
+	};
+
+	WebMailDataStorage.prototype.findPublicKeyByHex = function (sHash)
+	{
+		return _.find(this.openpgpkeysPublic(), function (oItem) {
+			return oItem && sHash === oItem.id;
+		});
+	};
+
+	WebMailDataStorage.prototype.findPublicKeysByEmail = function (sEmail)
+	{
+		return _.compact(_.map(this.openpgpkeysPublic(), function (oItem) {
+
+			var oKey = null;
+			if (oItem && sEmail === oItem.email)
+			{
+				try
+				{
+					oKey = window.openpgp.key.readArmored(oItem.armor);
+					if (oKey && !oKey.err && oKey.keys && oKey.keys[0])
+					{
+						return oKey.keys[0];
+					}
+				}
+				catch (e) {}
+			}
+
+			return null;
+
+		}));
+	};
+
+	/**
+	 * @param {string} sEmail
+	 * @param {string=} sPassword
+	 * @returns {?}
+	 */
+	WebMailDataStorage.prototype.findPrivateKeyByEmail = function (sEmail, sPassword)
+	{
+		var
+			oPrivateKey = null,
+			oKey = _.find(this.openpgpkeysPrivate(), function (oItem) {
+				return oItem && sEmail === oItem.email;
+			})
+		;
+
+		if (oKey)
+		{
+			try
+			{
+				oPrivateKey = window.openpgp.key.readArmored(oKey.armor);
+				if (oPrivateKey && !oPrivateKey.err && oPrivateKey.keys && oPrivateKey.keys[0])
+				{
+					oPrivateKey = oPrivateKey.keys[0];
+					oPrivateKey.decrypt(Utils.pString(sPassword));
+				}
+				else
+				{
+					oPrivateKey = null;
+				}
+			}
+			catch (e)
+			{
+				oPrivateKey = null;
+			}
+		}
+
+		return oPrivateKey;
+	};
+
+	/**
+	 * @param {string=} sPassword
+	 * @returns {?}
+	 */
+	WebMailDataStorage.prototype.findSelfPrivateKey = function (sPassword)
+	{
+		return this.findPrivateKeyByEmail(this.accountEmail(), sPassword);
+	};
+
+	module.exports = new WebMailDataStorage();
+
+}(module));
+
+},{"../Common/Consts.js":4,"../Common/Enums.js":5,"../Common/Globals.js":6,"../Common/LinkBuilder.js":7,"../Common/Utils.js":9,"../External/$div.js":10,"../External/NotificationClass.js":16,"../External/jquery.js":19,"../External/ko.js":21,"../External/moment.js":22,"../External/underscore.js":24,"../External/window.js":25,"../Knoin/Knoin.js":26,"../Models/MessageModel.js":31,"../Storages/WebMailAjaxRemoteStorage.js":39,"../Storages/WebMailCacheStorage.js":40,"./AbstractData.js":35,"./LocalStorage.js":36}],42:[function(require,module,exports){
+/* RainLoop Webmail (c) RainLoop Team | Licensed under CC BY-NC-SA 3.0 */
+
+(function (module) {
+
+	'use strict';
+
+	var
+		ko = require('../../External/ko.js'),
+		key = require('../../External/key.js'),
+		Enums = require('../../Common/Enums.js'),
+		Utils = require('../../Common/Utils.js'),
+		kn = require('../../Knoin/Knoin.js'),
+		KnoinAbstractViewModel = require('../../Knoin/KnoinAbstractViewModel.js')
+	;
+
+	/**
+	 * @constructor
+	 * @extends KnoinAbstractViewModel
+	 */
+	function PopupsAskViewModel()
+	{
+		KnoinAbstractViewModel.call(this, 'Popups', 'PopupsAsk');
+
+		this.askDesc = ko.observable('');
+		this.yesButton = ko.observable('');
+		this.noButton = ko.observable('');
+
+		this.yesFocus = ko.observable(false);
+		this.noFocus = ko.observable(false);
+
+		this.fYesAction = null;
+		this.fNoAction = null;
+
+		this.bDisabeCloseOnEsc = true;
+		this.sDefaultKeyScope = Enums.KeyState.PopupAsk;
+
+		kn.constructorEnd(this);
+	}
+
+	kn.extendAsViewModel('PopupsAskViewModel', PopupsAskViewModel);
+
+	PopupsAskViewModel.prototype.clearPopup = function ()
+	{
+		this.askDesc('');
+		this.yesButton(Utils.i18n('POPUPS_ASK/BUTTON_YES'));
+		this.noButton(Utils.i18n('POPUPS_ASK/BUTTON_NO'));
+
+		this.yesFocus(false);
+		this.noFocus(false);
+
+		this.fYesAction = null;
+		this.fNoAction = null;
+	};
+
+	PopupsAskViewModel.prototype.yesClick = function ()
+	{
+		this.cancelCommand();
+
+		if (Utils.isFunc(this.fYesAction))
+		{
+			this.fYesAction.call(null);
+		}
+	};
+
+	PopupsAskViewModel.prototype.noClick = function ()
+	{
+		this.cancelCommand();
+
+		if (Utils.isFunc(this.fNoAction))
+		{
+			this.fNoAction.call(null);
+		}
+	};
+
+	/**
+	 * @param {string} sAskDesc
+	 * @param {Function=} fYesFunc
+	 * @param {Function=} fNoFunc
+	 * @param {string=} sYesButton
+	 * @param {string=} sNoButton
+	 */
+	PopupsAskViewModel.prototype.onShow = function (sAskDesc, fYesFunc, fNoFunc, sYesButton, sNoButton)
+	{
+		this.clearPopup();
+
+		this.fYesAction = fYesFunc || null;
+		this.fNoAction = fNoFunc || null;
+
+		this.askDesc(sAskDesc || '');
+		if (sYesButton)
+		{
+			this.yesButton(sYesButton);
+		}
+
+		if (sYesButton)
+		{
+			this.yesButton(sNoButton);
+		}
+	};
+
+	PopupsAskViewModel.prototype.onFocus = function ()
+	{
+		this.yesFocus(true);
+	};
+
+	PopupsAskViewModel.prototype.onBuild = function ()
+	{
+		key('tab, shift+tab, right, left', Enums.KeyState.PopupAsk, _.bind(function () {
+			if (this.yesFocus())
+			{
+				this.noFocus(true);
+			}
+			else
+			{
+				this.yesFocus(true);
+			}
+			return false;
+		}, this));
+
+		key('esc', Enums.KeyState.PopupAsk, _.bind(function () {
+			this.noClick();
+			return false;
+		}, this));
+	};
+
+	module.exports = new PopupsAskViewModel();
+
+}(module));
+},{"../../Common/Enums.js":5,"../../Common/Utils.js":9,"../../External/key.js":20,"../../External/ko.js":21,"../../Knoin/Knoin.js":26,"../../Knoin/KnoinAbstractViewModel.js":28}]},{},[1]);